【C#】Winform NanUI 0.77版本 JS和C#相互调用
目录
一、导入插件
用的NanUI版本0.77
参考官方地址:https://docs.formium.net/zh-hans/tutorial/first-app.html
二、常用方法
基础代码:
using NetDimension.NanUI; using NetDimension.NanUI.Browser; class MainWindow : Formium { //网页的地址 public override string StartUrl => "https://www.google.com"; //边框模式 public override HostWindowType WindowType => HostWindowType.Standard; //这里写null就好 protected override Control LaunchScreen => null; public MainWindow() { Title = "第一个NanUI应用" } protected override void OnWindowReady(IWebBrowserHandler browserClient) { } protected override void OnRegisterGlobalObject(JSObject global) { } //网页的大小和布局 protected override void OnStandardFormStyle(IStandardHostWindowStyle style) { base.OnStandardFormStyle(style); style.Width = 1280; style.Height = 720; style.Icon = System.Drawing.SystemIcons.WinLogo; style.StartPosition = FormStartPosition.CenterScreen; } }
启动页面也需要修改一下:
using NetDimension.NanUI; static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //Application.Run(new Form1()); Bootstrap .Initialize() .Run(() => new MainWindow()); } }
三、C#和JS相互调用
1.C# 调用JS
假设页面中有如下Javascript的函数sayHello,它的作用是在DOM中创建一个包含有“Hello NanUI!”字样的p元素。
function sayHello() { var p = document.createElement("p"); p.innerText = "Hello NanUI!"; var container = document.getElementById("hello-container"); container.appendChild(p); }
示例中,该函数并没有在Javascript环境里调用,而是在页面加载完成后使用NanUI的ExecuteJavascript方法来调用它。ExecuteJavascript方法执行的返回结果为一个bool类型,它指示了这次有没有成功执行。
在窗体的构造函数中,通过注册 Formium 的 LoadHandler 中的 OnLoadEnd 事件来监测页面加载完成的情况,并在页面加载成功后调用JS环境中的函数 sayHello。
C#:
protected override void OnWindowReady(IWebBrowserHandler browserClient) { browserClient.LoadHandler.OnLoadEnd += LoadHandler_OnLoadEnd; } private void LoadHandler_OnLoadEnd(object sender, Chromium.Event.CfxOnLoadEndEventArgs e) { if (e.Frame.IsMain) { //C#调用网页中的JS脚本中sayHollo方法,这里,并没有返回参数,仅仅是让浏览器打印一个log而已 WebBrowser.ExecuteJavascript("sayHollo()"); //C#调用网页中JS脚本 带有返回参数的方法 WebBrowser.EvaluateJavascript("returnValue('C#')", (value, exception) => { if (value.IsString) { var jsValue = value.StringValue; MessageBox.Show(jsValue); } }); } }
这里调用了JS中的两个方法:sayHollo,returnValue
JS:
function sayHollo() { alert("网页alert: Hollo!"); } function returnValue() { return "JS 返回 嘻嘻嘻!"; }
效果:
===============================
在需要获取返回值的情况下
上面的例子中通过ExecuteJavascript方法来成功调用了JS环境中的函数。但不难发现,这种调用方式C#是没有接收到任何返回值的。但实际的项目里,我们是需要从JS环境获取到返回值的,这时候使用ExecuteJavascript将不能满足需求,使用另外一个方法EvaluateJavascript可以帮助我们从JS环境中获得JS函数的返回值。
假如有另外一个Javascript函数sayHelloToSomeone,它能接收一个字符传参数,在函数体中拼接并返回拼接后的字符串。
function sayHelloToSomeone(who) { return "Hello " + who + "!"; }
同样的,在上面例子LoadHandler的OnLoadEnd事件中我们来执行sayHelloToSomeone,并通过C#传递参数并获取拼接后的返回值。EvaluateJavascript方法通过一个回调Action来获取JS环境中的返回值。这个Action有两个参数,第一个是返回值的集合,第二个是JS环境的异常对象,如果函数正确执行,那么第二个参数为null。
namespace CommunicateBetweenJsAndCSharp { using NetDimension.NanUI; public partial class Form1 : Formium { public Form1() : base("http://res.app.local/www/index.html",false) { InitializeComponent(); LoadHandler.OnLoadEnd += LoadHandler_OnLoadEnd; } private void LoadHandler_OnLoadEnd(object sender, Chromium.Event.CfxOnLoadEndEventArgs e) { // Check if it is the main frame when page has loaded. if(e.Frame.IsMain) { EvaluateJavascript("sayHelloToSomeone('C#')", (value, exception) => { if(value.IsString) { // Get value from Javascript. var jsValue = value.StringValue; MessageBox.Show(jsValue); } }); } } } }
在上面的示例中,通过我们可以明确知道JS函数sayHelloToSomeone的返回值一定为String类型,因此在C#的回调中直接使用Value的StringValue属性来获取JS函数的字符传返回值。但在实际的应用中,有可能并不完全知道返回值的类型,因此需要使用Value中内置的各个判断属性来逐一筛选返回值。
需要注意的是,Value的类是是ChromiumFX中的CfrV8Value类型,它是一个非常重要的类型,基本上所有在C#与CEF间的通信都是由这个类型来完成的。
2.JS调用C#方法
上面演示了如何用 C# 来调用 Javascript 中的函数,那么下面的内容将介绍如何使用 Javascript 来调用C#中的对象、属性和各种方法。
在此之前,需要介绍NanUI窗体基类Formium中的重要属性GlobalObject,您可以把他理解成Javascript环境中的window对象。如果您需要在Javascript环境下使用C#中的各种对象、属性和方法,都需要将这些对象、属性、方法注册到GlobalObject里。
C#:
protected override void OnRegisterGlobalObject(JSObject global) { var myObject = global.AddObject("my"); #region 添加属性 //添加一个属性:name var nameProp = myObject.AddDynamicProperty("name"); //Get属性 nameProp.PropertyGet += (prop, args) => { //要返回的字符串 args.Retval = "这是C#的一个Get属性:name"; args.SetReturnValue(true); }; //Set属性 nameProp.PropertySet += (prop, args) => { var value = args.Value; args.SetReturnValue(true); }; #endregion #region 添加方法 //添加一个方法 showCSharpMessageBox var showMessageBoxFunc = myObject.AddFunction("showCSharpMessageBox"); showMessageBoxFunc.Execute += (func, args) => { var stringArgument = args.Arguments.FirstOrDefault(p => p.IsString); if (stringArgument != null) MessageBox.Show(stringArgument.StringValue); else MessageBox.Show("Js传递的参数为空!"); }; //添加一个具有返回参数的方法 var getArrayFromCSFunc = myObject.AddFunction("getArrayFromCSharp"); getArrayFromCSFunc.Execute += (func, args) => { var jsArray = args.Arguments.FirstOrDefault(p => p.IsArray); if (jsArray != null) { //获取数组的长度 int len = jsArray.ArrayLength; //创建一个新的数组 CfrV8Value arr = CfrV8Value.CreateArray(len); for (int i = 0; i < len; i++) { //获取JS传过来数组的值 int v = jsArray.GetValue(i).IntValue; //+1后,放入新的数组 arr.SetValue(i, CfrV8Value.CreateInt(v + 1)); } //作为返回参数 args.SetReturnValue(arr); } }; //接收JS的回调,并将自己的参数传递过去 var callbackTestFunc = myObject.AddFunction("callbackTest"); callbackTestFunc.Execute += (func, args) => { var callback = args.Arguments.FirstOrDefault(p => p.IsFunction); if (callback != null) { //创建一个Object类型的变量 var callbackArgs = CfrV8Value.CreateObject(new CfrV8Accessor()); //添加一个Bool类型的值:success callbackArgs.SetValue("success", CfrV8Value.CreateBool(true), CfxV8PropertyAttribute.ReadOnly); //添加一个string类型的值:text callbackArgs.SetValue("text", CfrV8Value.CreateString("Message from C#"), CfxV8PropertyAttribute.ReadOnly); //用ExecuteFunction执行JS传递过来的回调,并将自己设置的变量callbackArgs传递给JS callback.ExecuteFunction(null, new CfrV8Value[] { callbackArgs }); } }; #endregion }
JS添加一个按钮,用来调用C#注入的方法:
function on_Click() { // alert("点击了按钮"); //调用C#中注入的属性 alert(my.name); //调用C#中注入的方法(无返回值) my.showCSharpMessageBox("我是参数!"); //调用C#中注入的方法(返回一个数组) var arr = [1, 2, 3]; var retArr = my.getArrayFromCSharp(arr); if (retArr) { alert("网页alert:" + retArr); } //调用C#并传入一个JS的回调 my.callbackTest(sayByeBye); }; function sayByeBye(obj) { var str = "参数success:" + obj.success + " 参数text:" + obj.text alert("网页alert: " + str); }
3.完整版C#代码
using Chromium; using Chromium.Remote; using NetDimension.NanUI; using NetDimension.NanUI.Browser; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace CSharpCallJS { //参考:https://docs.formium.net/zh-hans/tutorial/js-context.html public class myform1 : Formium { //指定启动时访问的 Url 地址,这里用的是本地地址 public override string StartUrl => @"E:\CSharp Project\NanUI_Test\CSharpCallJS\Viwe\index.html"; //指定 WindowType 属性,选择窗体以原生样式显示还是使用无边框样式 public override HostWindowType WindowType => HostWindowType.Standard; protected override Control LaunchScreen => null; public myform1() { Title = "第一个NanUI应用"; } protected override void OnWindowReady(IWebBrowserHandler browserClient) { browserClient.LoadHandler.OnLoadEnd += LoadHandler_OnLoadEnd; } protected override void OnRegisterGlobalObject(JSObject global) { var myObject = global.AddObject("my"); #region 添加属性 //添加一个属性:name var nameProp = myObject.AddDynamicProperty("name"); //Get属性 nameProp.PropertyGet += (prop, args) => { //要返回的字符串 args.Retval = "这是C#的一个Get属性:name"; args.SetReturnValue(true); }; //Set属性 nameProp.PropertySet += (prop, args) => { var value = args.Value; args.SetReturnValue(true); }; #endregion #region 添加方法 //添加一个方法 showCSharpMessageBox var showMessageBoxFunc = myObject.AddFunction("showCSharpMessageBox"); showMessageBoxFunc.Execute += (func, args) => { var stringArgument = args.Arguments.FirstOrDefault(p => p.IsString); if (stringArgument != null) MessageBox.Show(stringArgument.StringValue); else MessageBox.Show("Js传递的参数为空!"); }; //添加一个具有返回参数的方法 var getArrayFromCSFunc = myObject.AddFunction("getArrayFromCSharp"); getArrayFromCSFunc.Execute += (func, args) => { var jsArray = args.Arguments.FirstOrDefault(p => p.IsArray); if (jsArray != null) { //获取数组的长度 int len = jsArray.ArrayLength; //创建一个新的数组 CfrV8Value arr = CfrV8Value.CreateArray(len); for (int i = 0; i < len; i++) { //获取JS传过来数组的值 int v = jsArray.GetValue(i).IntValue; //+1后,放入新的数组 arr.SetValue(i, CfrV8Value.CreateInt(v + 1)); } //作为返回参数 args.SetReturnValue(arr); } }; //接收JS的回调,并将自己的参数传递过去 var callbackTestFunc = myObject.AddFunction("callbackTest"); callbackTestFunc.Execute += (func, args) => { var callback = args.Arguments.FirstOrDefault(p => p.IsFunction); if (callback != null) { //创建一个Object类型的变量 var callbackArgs = CfrV8Value.CreateObject(new CfrV8Accessor()); //添加一个Bool类型的值:success callbackArgs.SetValue("success", CfrV8Value.CreateBool(true), CfxV8PropertyAttribute.ReadOnly); //添加一个string类型的值:text callbackArgs.SetValue("text", CfrV8Value.CreateString("Message from C#"), CfxV8PropertyAttribute.ReadOnly); //用ExecuteFunction执行JS传递过来的回调,并将自己设置的变量callbackArgs传递给JS callback.ExecuteFunction(null, new CfrV8Value[] { callbackArgs }); } }; #endregion } protected override void OnStandardFormStyle(IStandardHostWindowStyle style) { base.OnStandardFormStyle(style); style.Width = 800; style.Height = 600; style.Icon = System.Drawing.SystemIcons.WinLogo; style.StartPosition = FormStartPosition.CenterScreen; } private void LoadHandler_OnLoadEnd(object sender, Chromium.Event.CfxOnLoadEndEventArgs e) { if (e.Frame.IsMain) { //C#调用网页中的JS脚本中sayHollo方法,这里,并没有返回参数,仅仅是让浏览器打印一个log而已 WebBrowser.ExecuteJavascript("sayHollo()"); //C#调用网页中JS脚本 带有返回参数的方法 WebBrowser.EvaluateJavascript("returnValue('C#')", (value, exception) => { if (value.IsString) { var jsValue = value.StringValue; MessageBox.Show(jsValue); } }); } } } }
4.完整版JS代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script> function on_Click() { // alert("点击了按钮"); //调用C#中注入的属性 alert(my.name); //调用C#中注入的方法(无返回值) my.showCSharpMessageBox("我是参数!"); //调用C#中注入的方法(返回一个数组) var arr = [1, 2, 3]; var retArr = my.getArrayFromCSharp(arr); if (retArr) { alert("网页alert:" + retArr); } //调用C#并传入一个JS的回调 my.callbackTest(sayByeBye); }; function sayHollo() { alert("网页alert: Hollo!"); } function sayByeBye(obj) { var str = "参数success:" + obj.success + " 参数text:" + obj.text alert("网页alert: " + str); } function returnValue() { return "JS 返回 嘻嘻嘻!"; } </script> </head> <body> <div>我的网页</div> <div> <button onclick="on_Click()">按钮</button> </div> </body> </html>
结束
如果这个帖子对你有用,欢迎 关注 + 点赞 + 留言,谢谢
end
原文链接https://blog.csdn.net/qq_38693757/article/details/109804336
猜你喜欢
- 【C#】Winform NanUI 0.88版本 JS和C#相互调用
- 目录一、需求版本二、实例JS调用C#注册的只读属性JS调用C#注册的字段JS调用C#注册的同步方法JS调用C#注册的异步方法C#注册一个方法,JS调用并传递参数C#注册一个方法,JS调用并接收C#返回值C#注册一个方法,接收JS的数组参数C#注册一个方法,接收JS的一个函数,执行这个JS函数,并将C#的值传递过去三、结束一、需求在软件的界面和软件逻辑分离后,最重要的就是要处理参数的传递,和函数的调用,因此存在JS中和C#相互调用的需求。版本NanUI 版本:0.8.80.191二、实例using
- 【C#】c#Windows桌面程序退入托盘及右键菜单
- 一. 退出托盘功能窗体加组件notifyIcon修改属性,属性中加入要在托盘显示时呈现的图标。添加MouseClick事件编辑代码:private void Form_Main_FormClosing(object sender, FormClosingEventArgs e) { e.Cancel = true; this.Hid
- 【C#】C# Winform 三层架构
- 一、介绍三层架构是 C# 桌面开发中比较常用的框架,是由 表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构组成,目的是为了 “高内聚,低耦合”。开发人员分工更明确,将精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工作。从三层架构可以看到,很类似于 Web 前端开发的 MVC 框架(视图View,模型Model,控制Contorller),但本质上也有不同的地方,比如都有视图(三层中叫 UI),Mod
- 【C#】CSDK/IDE-VSCode 搭建 C# 开发环境
- 最近准备写 C# 的笔记总结专栏 bug 笔记本硬盘空间实在是不够用了 根本没有办法再安装一个 Visual Studio 集成开发环境了!!! 在学 Java 的过程中基本都是用记事本和命令提示符……再也不想经历了 &nbs
- 【C#】Winform解决方案打包成.exe 安装版Windows桌面应用程序
- 踩了几天的坑,慢慢爬出来了。帮助一下新手友人吧,高手请绕路。IDE Version:Visual Studio 20191.安装Microsoft Visual Studio Installer Project(1)打开Visual Studio 2019,扩展->管理扩展(2)搜索install,下载图中的扩展即可(我已经安装了,所以没有下载按钮)按照操作安装即可2.打包(1)右键 解决方案->添加->新建项目(2)搜索setup->选择 Setup Project-&
- 【C#】C# Winform DataGridView 控件和 DataTable
- 目录一、概述二、DataTable 的用法1.创建表和列2.添加行3.取值和赋值4.删除行5.遍历 DataTable6.判断 DataTable 列中是否存在某个值7.设置主键8.获取 DataRow 所在的行号9.DataTable 转换为 List10.将 List 转 DataTable三、DataGridView 的用法1.绑定数据2.获取绑定的数据源3.获取 / 设置 选中单元格的数据4.设置单元格的宽高结束一、概述DataGridView 控件提供用于
- 【C#】C# Winfrom Chart 图表控件 柱状图、折线图
- 目录一、参考二、柱状图1.新建项目2.修改图表样式3.绑定数据4.删除Series1图例1)使用属性窗体删除2)使用代码删除5.自定义X轴的刻度值1)使用List绑定2)使用LabelStyle.Format绑定6.自定义Y轴的刻度值7.X轴刻度值显示不全的解决方法8.修改X Y刻度值的字体样式9.X轴刻度值旋转90°10.禁用Y轴刻度线11.去掉Y轴刻度值12.改变柱子的宽度13.设置网格线的颜色14.设置网格线的线型三、折线图1.图表设置2.绑定数据结束效果:一、参考c# Chart设置样式
- 【C#】C# Winform 相册功能,图片缩放,拖拽,预览图分页
- 一、前言在一些项目中也会用到预览图片的功能,至于为什么有一个添加图片的按钮,是因为有些项目,比如视觉相关的项目,摄像头拍摄图片,然后显示在界面上,拍一次显示一张。另一个,就是分页功能,当预览图位置不够用时就会用到。当前软件的功能1.添加图片如果8个预览图都满了,会自动分页,就可以点击上一页,或者下一页了。2.点击预览图显示大图点击预览图,之前的拖拽和放大会自动复位3.大图可以拖拽,放大,缩小如果图片比较小,有这个功能就看到图片的更多细节了。4.图片倒序排列最后拍摄的图片,始终显示在前面,方便用户
- 【PHP】Your requirements could not be resolved to an installable set of packages.
- 【PHP】CI,ThinkPHP,YII,Laravel框架比较
- 【PHP】PHP8.1新特性大讲解之Fibers with a grain of salt
- 【VUE】Vue3+Vite+TypeScript常用项目模块详解
- 【PHP】PHP中的array_values()函数获取数组中的值
- 【PHP】php中实现3DES算法(ECB加密模式PKCS5Padding填充)
- 【前端】PHP、Vue和React:如何选择最适合的前端框架?
- 【Python】最全整理!37 个 Python Web 开发框架总结
- 【PHP】php-fpm调优方法详解
- 【Python】如何使用Python中的字符串操作函数处理大规模文本数据