NanUI文档 - 如何实现C#与Javascript的相互通信

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,以及showCSharpMessageBoxgetArrayFromCSharpgetObjectFromCSharp三个函数。

//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 functionvar 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
https://github.com/NetDimension/NanUI/

交流群QQ群
521854872

转载于:https://www.cnblogs.com/Jeely/p/11077397.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/424405.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring学习(40):注入数组类型

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

PS教程:如何拼图调色出高大上的作品

Hello&#xff0c;小伙伴们&#xff0c;是不是每每看到一些创意海报&#xff0c;就苦于自己不会做&#xff0c;其实合成并不难&#xff0c;掌握原理与技法&#xff0c;接下来就是拼图调色啦&#xff01;首先我们先来看下最终的效果图&#xff0c;铛铛铛&#xff01; 下面我们就…

spring学习(41):属性注入

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

【JS】实时监控页面,input框数值自动求和

需求&#xff1a; 有一个页面需要将input框填入的各个费用自动相加&#xff0c;添加到“合计费用”里。 解决方案&#xff1a; 使用jquery的blur实践&#xff0c;每个费用的Input框检测到失去焦点时&#xff0c;将所有的input框数值相加求和&#xff0c;然后写入到“合计费用”…

spring学习(30):定义第一个bean

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

通过字符串引入模块下的属性

flask中可以配置一个字符串导入settings下的配置文件 app.config.from_object("settings.ProductionConfig")这里就是来讲解一下这个到底是怎么实现的。 例&#xff1a; 这是just_xxx.py里面的内容 # -*- coding: utf-8 -*- # Time : 2019/6/17 上午 11:50 # Auth…

spring学习(42):属性注入注入数组和列表的说明

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

spring学习(43):属性注入中注入引用对象

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

spring学习(44):p名称空间注入

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

A*算法

文章出处&#xff1a;极客时间《数据结构和算法之美》-作者&#xff1a;王争。该系列文章是本人的学习笔记。 Dijkstra不能解决的问题 在Dijkstra类似BFS&#xff0c;从起始节点找到距离最短的节点&#xff0c;一层一层向外扩展&#xff0c;直到找到目标节点。 在有些时候这种…

spring学习(45):util名称空间注入

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

Jmeter_http request的简单设置和应用

http request 协议、地址、端口号 参数类型 正则搜索 帮助文档 相等的关系 匹配正则的结果&#xff08;jmeter一般都用分组取想用的数据&#xff09; 转载于:https://www.cnblogs.com/rychh/articles/11087537.html

spring学习(46):spring的单例bean

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

943. Find the Shortest Superstring

目录题目描述暴力搜索分析暴力搜索优化动态规划参考链接题目描述 输入&#xff1a;字符串数组String[] A 输出&#xff1a;一个字符串result&#xff0c;A中每一个字符串是result的子串&#xff0c;并且reuslt是符合这个条件的最短的字符串。 举例&#xff1a; 输入: [“alex”…

spring学习(47):bean的作用域

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

visual studio 2017 显示行号

1.Tools中选择Options...&#xff0c; Options界面中Test Editor -> All Languages&#xff08;当然也可以设置对应的语言&#xff09; -> General&#xff0c; 在Settings中勾选 Line numbers。 2.行号就显示出来了&#xff0c;便于我们去定位代码。 转载于:https://www…

spring学习(48):自动装配中定义的bean的作用域

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

212. Word Search II:多个单词查找

写在前面&#xff1a;这两周持续看花花酱整理的题目列表和视频讲解&#xff0c;也得益于自己持续多年刷题&#xff0c;今天刷这道题目的想法是&#xff1a;会trie树居然就能攻克hard题目&#xff01;我也离独立攻破hard题目不远了嘛。前段时间看王争在极客时间的系列课程&#…

spring学习(49):javaconfig里面定义bean的作用域

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

spring学习(50):延迟加载

目录结构 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…