NanUI文档-如何实现C与Javascript的相互通信
suiw9 2024-10-23 18:46 14 浏览 0 评论
NanUI文档目录
- NanUI简介
- 开始使用NanUI
- 打包并使用内嵌式的HTML/CSS/JS资源
- 使用网页来设计整个窗口
- 如何实现C#与Javascript的相互通信
- 如何处理NanUI中的下载过程 - DonwloadHandler的使用(待更新。。。)
- 如何处理NanUI中的弹窗过程 - LifeSpanHandler的使用(待更新。。。)
- 如何控制Javascript对话框 - JsDialogHandler的使用(待更新。。。)
- 自定义资源处理程序 (待更新。。。)
如何实现C#与Javascript的相互通信
通过之前的文章,相信您已经对NanUI有了初步的了解。但到目前为止,我们使用NanUI仅仅只是作为呈现HTML界面的容器,并未涉及CEF与C#间数据的交互。那么本文将简单介绍如何在NanUI中使用C#调用Javascript的函数以及如何在Javascript注入C#的对象、属性和方法。
C#调用Javascript函数
不需要获取返回值的情况
假设页面中有如下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。
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)
{
ExecuteJavascript("sayHello");
}
}
}
}
运行后,可以看到界面中显示了“Hello NanUI!”字样,说明使用ExecuteJavascript能够调用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间的通信都是由这个类型来完成的。
Javascript调用C#对象及方法
简单的应用示例
上面的文章中演示了如何用C#来调用Javascript中的函数,那么下面的内容将介绍如何使用Javascript来调用C#中的对象、属性和各种方法。
在此之前,需要介绍NanUI窗体基类Formium中的重要属性GlobalObject,您可以把他理解成Javascript环境中的window对象。如果您需要在Javascript环境下使用C#中的各种对象、属性和方法,都需要将这些对象、属性、方法注册到GlobalObject里。
下面的例子,通过在Form1的构造函数中注册一个名为my的JS对象,并在my内置一个只读属性name,以及showCSharpMessageBox、getArrayFromCSharp、getObjectFromCSharp三个函数。
//register the "my" object
var myObject = GlobalObject.AddObject("my");
//add property "name" to my, you should implemnt the getter/setter of name property by using PropertyGet/PropertySet events.
var nameProp = myObject.AddDynamicProperty("name");
nameProp.PropertyGet += (prop, args) =>
{
// getter - if js code "my.name" executes, it'll get the string "NanUI".
args.Retval = CfrV8Value.CreateString("NanUI");
args.SetReturnValue(true);
};
nameProp.PropertySet += (prop, args) =>
{
// setter's value from js context, here we do nothing, so it will store or igrone by your mind.
var value = args.Value;
args.SetReturnValue(true);
};
//add a function showCSharpMessageBox
var showMessageBoxFunc = myObject.AddFunction("showCSharpMessageBox");
showMessageBoxFunc.Execute += (func, args) =>
{
//it will be raised by js code "my.showCSharpMessageBox(`some text`)" executed.
//get the first string argument in Arguments, it pass by js function.
var stringArgument = args.Arguments.FirstOrDefault(p => p.IsString);
if (stringArgument != null)
{
MessageBox.Show(this, stringArgument.StringValue, "C# Messagebox", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
};
//add a function getArrayFromCSharp, this function has an argument, it will combind C# string array with js array and return to js context.
var friends = new string { "Mr.JSON", "Mr.Lee", "Mr.BONG" };
var getArrayFromCSFunc = myObject.AddFunction("getArrayFromCSharp");
getArrayFromCSFunc.Execute += (func, args) =>
{
var jsArray = args.Arguments.FirstOrDefault(p => p.IsArray);
if (jsArray == null)
{
jsArray = CfrV8Value.CreateArray(friends.Length);
for (int i = 0; i < friends.Length; i++)
{
jsArray.SetValue(i, CfrV8Value.CreateString(friends[i]));
}
}
else
{
var newArray = CfrV8Value.CreateArray(jsArray.ArrayLength + friends.Length);
for (int i = 0; i < jsArray.ArrayLength; i++)
{
newArray.SetValue(i, jsArray.GetValue(i));
}
var jsArrayLength = jsArray.ArrayLength;
for (int i = 0; i < friends.Length; i++)
{
newArray.SetValue(i + jsArrayLength, CfrV8Value.CreateString(friends[i]));
}
jsArray = newArray;
}
//return the array to js context
args.SetReturnValue(jsArray);
//in js context, use code "my.getArrayFromCSharp" will get an array like ["Mr.JSON", "Mr.Lee", "Mr.BONG"]
};
//add a function getObjectFromCSharp, this function has no arguments, but it will return a Object to js context.
var getObjectFormCSFunc = myObject.AddFunction("getObjectFromCSharp");
getObjectFormCSFunc.Execute += (func, args) =>
{
//create the CfrV8Value object and the accssor of this Object.
var jsObjectAccessor = new CfrV8Accessor;
var jsObject = CfrV8Value.CreateObject(jsObjectAccessor);
//create a CfrV8Value array
var jsArray = CfrV8Value.CreateArray(friends.Length);
for (int i = 0; i < friends.Length; i++)
{
jsArray.SetValue(i, CfrV8Value.CreateString(friends[i]));
}
jsObject.SetValue("libName", CfrV8Value.CreateString("NanUI"), CfxV8PropertyAttribute.ReadOnly);
jsObject.SetValue("friends", jsArray, CfxV8PropertyAttribute.DontDelete);
args.SetReturnValue(jsObject);
//in js context, use code "my.getObjectFromCSharp" will get an object like { friends:["Mr.JSON", "Mr.Lee", "Mr.BONG"], libName:"NanUI" }
};
运行项目打开CEF的DevTools窗口,在Console中输入my,就能看到my对象的详细信息。
执行my.showCSharpMessageBox("SOME TEXT FROM JS")命令,将调用C#的MessageBox来现实JS函数中提供的“SOME TEXT FROM JS”字样。
执行my.getArrayFromCSharp能够从C#中取到我们内置的字符串数组中的三个字符串。如果在函数中指定了一个数组作为参数,那么指定的这个数组将和C#的字符串数组合并。
> my.getArrayFromCSharp
["Mr.JSON", "Mr.Lee", "Mr.BONG"]
> my.getArrayFromCSharp(["Js_Bison", "Js_Dick"])
["Js_Bison", "Js_Dick", "Mr.JSON", "Mr.Lee", "Mr.BONG"]
执行my.getObjectFromCSharp能够从C#返回我们拼装的对象,该对象有一个字符型的libName属性,以及一个字符串数组friends。
> my.getObjectFromCSharp
Object {libName: "NanUI", friends: Array(3)}
回调函数
回调函数是Javascript里面重要和常用的功能,如果您在JS环境中注册的方法具有函数型的参数(即回调函数),通过Execute事件的Arguments可以获得回调的function,并使用CfrV8Value的ExecuteFunction来执行回调。
//add a function with callback function
var callbackTestFunc = GlobalObject.AddFunction("callbackTest");
callbackTestFunc.Execute += (func,args)=> {
var callback = args.Arguments.FirstOrDefault(p => p.IsFunction);
if(callback != null)
{
var callbackArgs = CfrV8Value.CreateObject(new CfrV8Accessor);
callbackArgs.SetValue("success", CfrV8Value.CreateBool(true), CfxV8PropertyAttribute.ReadOnly);
callbackArgs.SetValue("text", CfrV8Value.CreateString("Message from C#"), CfxV8PropertyAttribute.ReadOnly);
callback.ExecuteFunction(null, new CfrV8Value[] { callbackArgs });
}
};
在Console中执行callbackTest(function(result){ console.log(result); })将执行匿名回调,并获取到C#回传的result对象。
> callbackTest(function(result){ console.log(result); })
Object {success: true, text: "Message from C#"}
在大多数情况下,在Javascript中回调都是因为执行了一些异步的操作,那么如果这些异步的操作是在C#执行也是可行的,只是实现起来就比较复杂。下面将演示如何实现一个异步回调。
//add a function with async callback
var asyncCallbackTestFunc = GlobalObject.AddFunction("asyncCallbackTest");
asyncCallbackTestFunc.Execute += async (func, args) => {
//save current context
var v8Context = CfrV8Context.GetCurrentContext;
var callback = args.Arguments.FirstOrDefault(p => p.IsFunction);
//simulate async methods.
await Task.Delay(5000);
if (callback != null)
{
//get render process context
var rc = callback.CreateRemoteCallContext;
//enter render process
rc.Enter;
//create render task
var task = new CfrTask;
task.Execute += (_, taskArgs) =>
{
//enter saved context
v8Context.Enter;
//create callback argument
var callbackArgs = CfrV8Value.CreateObject(new CfrV8Accessor);
callbackArgs.SetValue("success", CfrV8Value.CreateBool(true), CfxV8PropertyAttribute.ReadOnly);
callbackArgs.SetValue("text", CfrV8Value.CreateString("Message from C#"), CfxV8PropertyAttribute.ReadOnly);
//execute callback
callback.ExecuteFunction(null, new CfrV8Value[] { callbackArgs });
v8Context.Exit;
//lock task from gc
lock (task)
{
Monitor.PulseAll(task);
}
};
lock (task)
{
//post task to render process
v8Context.TaskRunner.PostTask(task);
}
rc.Exit;
GC.KeepAlive(task);
}
在Console中执行asyncCallbackTest(function(result){ console.log(result); })将执行匿名回调,大约5秒后获取到C#回传的result对象。
> asyncCallbackTest(function(result){ console.log(result); })
Object {success: true, text: "Message from C#"}
以上,您已经简单了解了使用NanUI如何做到C#和Javascript的相互通信。NanUI基于开源项目ChromiumFX开发,因此C#与Javascript的交互与ChomiumFX保持一致,如果需要开发更加复杂的功能,请自行搜索和参考ChromiumFX的相关API及示例。
示例源码
git clone https://github.com/NetDimension/NanUI-Examples-04-Communicate-Between-CSharp-And-JS.git
社群和帮助
GitHub
交流群QQ群
521854872
赞助作者
如果你喜欢我的工作,并且希望NanUI持续的发展,请对NanUI项目进行捐助以此来鼓励和支持我继续NanUI的开发工作。你可以使用微信或者支付宝来扫描下面的二维码进行捐助。
相关推荐
- 俄罗斯的 HTTPS 也要被废了?(俄罗斯网站关闭)
-
发布该推文的ScottHelme是一名黑客,SecurityHeaders和ReportUri的创始人、Pluralsight作者、BBC常驻黑客。他表示,CAs现在似乎正在停止为俄罗斯域名颁发...
- 如何强制所有流量使用 HTTPS一网上用户
-
如何强制所有流量使用HTTPS一网上用户使用.htaccess强制流量到https的最常见方法可能是使用.htaccess重定向请求。.htaccess是一个简单的文本文件,简称为“.h...
- https和http的区别(https和http有何区别)
-
“HTTPS和HTTP都是数据传输的应用层协议,区别在于HTTPS比HTTP安全”。区别在哪里,我们接着往下看:...
- 快码住!带你十分钟搞懂HTTP与HTTPS协议及请求的区别
-
什么是协议?网络协议是计算机之间为了实现网络通信从而达成的一种“约定”或“规则”,正是因为这个“规则”的存在,不同厂商的生产设备、及不同操作系统组成的计算机之间,才可以实现通信。简单来说,计算机与网络...
- 简述HTTPS工作原理(简述https原理,以及与http的区别)
-
https是在http协议的基础上加了一层SSL(由网景公司开发),加密由ssl实现,它的目的是为用户提供对网站服务器的身份认证(需要CA),以至于保护交换数据的隐私和完整性,原理如图示。1、客户端发...
- 21、HTTPS 有几次握手和挥手?HTTPS 的原理什么是(高薪 常问)
-
HTTPS是3次握手和4次挥手,和HTTP是一样的。HTTPS的原理...
- 一次安全可靠的通信——HTTPS原理
-
为什么HTTPS协议就比HTTP安全呢?一次安全可靠的通信应该包含什么东西呢,这篇文章我会尝试讲清楚这些细节。Alice与Bob的通信...
- 为什么有的网站没有使用https(为什么有的网站点不开)
-
有的网站没有使用HTTPS的原因可能涉及多个方面,以下是.com、.top域名的一些见解:服务器性能限制:HTTPS使用公钥加密和私钥解密技术,这要求服务器具备足够的计算能力来处理加解密操作。如果服务...
- HTTPS是什么?加密原理和证书。SSL/TLS握手过程
-
秘钥的产生过程非对称加密...
- 图解HTTPS「转」(图解http 完整版 彩色版 pdf)
-
我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取。所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。...
- HTTP 和 HTTPS 有何不同?一文带你全面了解
-
随着互联网时代的高速发展,Web服务器和客户端之间的安全通信需求也越来越高。HTTP和HTTPS是两种广泛使用的Web通信协议。本文将介绍HTTP和HTTPS的区别,并探讨为什么HTTPS已成为We...
- HTTP与HTTPS的区别,详细介绍(http与https有什么区别)
-
HTTP与HTTPS介绍超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的...
- 一文让你轻松掌握 HTTPS(https详解)
-
一文让你轻松掌握HTTPS原文作者:UC国际研发泽原写在最前:欢迎你来到“UC国际技术”公众号,我们将为大家提供与客户端、服务端、算法、测试、数据、前端等相关的高质量技术文章,不限于原创与翻译。...
- 如何在Spring Boot应用程序上启用HTTPS?
-
HTTPS是HTTP的安全版本,旨在提供传输层安全性(TLS)[安全套接字层(SSL)的后继产品],这是地址栏中的挂锁图标,用于在Web服务器和浏览器之间建立加密连接。HTTPS加密每个数据包以安全方...
- 一文彻底搞明白Http以及Https(http0)
-
早期以信息发布为主的Web1.0时代,HTTP已可以满足绝大部分需要。证书费用、服务器的计算资源都比较昂贵,作为HTTP安全扩展的HTTPS,通常只应用在登录、交易等少数环境中。但随着越来越多的重要...
你 发表评论:
欢迎- 一周热门
-
-
Linux:Ubuntu22.04上安装python3.11,简单易上手
-
宝马阿布达比分公司推出独特M4升级套件,整套升级约在20万
-
MATLAB中图片保存的五种方法(一)(matlab中保存图片命令)
-
别再傻傻搞不清楚Workstation Player和Workstation Pro的区别了
-
Linux上使用tinyproxy快速搭建HTTP/HTTPS代理器
-
如何提取、修改、强刷A卡bios a卡刷bios工具
-
Element Plus 的 Dialog 组件实现点击遮罩层不关闭对话框
-
日本组合“岚”将于2020年12月31日停止团体活动
-
SpringCloud OpenFeign 使用 okhttp 发送 HTTP 请求与 HTTP/2 探索
-
tinymce 号称富文本编辑器世界第一,大家同意么?
-
- 最近发表
- 标签列表
-
- dialog.js (57)
- importnew (44)
- windows93网页版 (44)
- yii2框架的优缺点 (45)
- tinyeditor (45)
- qt5.5 (60)
- windowsserver2016镜像下载 (52)
- okhttputils (51)
- android-gif-drawable (53)
- 时间轴插件 (56)
- docker systemd (65)
- slider.js (47)
- android webview缓存 (46)
- pagination.js (59)
- loadjs (62)
- openssl1.0.2 (48)
- velocity模板引擎 (48)
- pcre library (47)
- zabbix微信报警脚本 (63)
- jnetpcap (49)
- pdfrenderer (43)
- fastutil (48)
- uinavigationcontroller (53)
- bitbucket.org (44)
- python websocket-client (47)