龙空技术网

WinForm混合Blazor(中)

桂素伟 293

前言:

今天朋友们对“winformhtml界面”大约比较关切,各位老铁们都需要了解一些“winformhtml界面”的相关内容。那么小编在网摘上汇集了一些关于“winformhtml界面””的相关文章,希望兄弟们能喜欢,姐妹们一起来了解一下吧!

在上一篇中介绍了一下razor文件中,js与c#之间的相互调用,但WinForm和Blazor混合中,没有真正与WinForm进行交互,本篇来说明一下。

WinForm中混合Blazor是通过ServiceCollection来完成的,如果想WinForm和Blazor交互,可以通过向ServiceCollection注入一个中介服务来达到互相调用,大体思路是定义一个服务,这个服务里有方法和事件,方法被调用,触发订阅者。比如调用方是WinForm的话,订阅者就是对应js的方法了;如果调用方是js,那订阅事件的就是WinForm里的方法了。

WinForm是不可能直接调用到JS的,主要通过IJSRuntime来调用js方法,同样,js也不能直接调WinForm,是通过js调razor中方法,razor方法再调用WinForm来实现,总体上就是razor中的C#层,是中间桥梁。razor中的 C#与WinForm就是通过注入ServiceCollection中的事件服务来互通协作(有点绕,多读几次)。

本例中定义了一个IEventHub接口和EventHub一个实现类完成封装。在这组服务中,既有CSharp的调用方法,又有JS调用方法,有CSharp事件,也有JS事件,代码如下:

IEventHub接口

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace WinFormsBlazor01{    public delegate Task<object> EventHubHandlerAsync<TEventArgs>(object sender, TEventArgs? eventArgs);     public interface IEventHub    {        string? EventName { get; set; }                event EventHubHandlerAsync<object?[]>? OnCallJSAsync;        Task<object> CallJSAsync(string eventName, params object?[]? eventArgs);        event EventHubHandlerAsync<object?[]>? OnCallCSharpAsync;        Task<object> CallCSharpAsync(string eventName, params object?[]? eventArgs);    }}

EvnetHub类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace WinFormsBlazor01{    public class EventHub : IEventHub    {        public string? EventName { get; set; }        public event EventHubHandlerAsync<object?[]>? OnCallJSAsync;        public async Task<object> CallJSAsync(string eventName, params object?[]? eventArgs)        {            if (OnCallJSAsync != null)            {                EventName = eventName;                return await OnCallJSAsync(this, eventArgs);                           }            return await Task.FromResult("");        }        public event EventHubHandlerAsync<object?[]>? OnCallCSharpAsync;        public async Task<object> CallCSharpAsync(string eventName, params object?[]? eventArgs)        {            if (OnCallCSharpAsync != null)            {                EventName = eventName;                return await OnCallCSharpAsync(this, eventArgs);                      }            return "";        }    }}

再定义一个BlazorService类型,用来统一创建ServiceCollection:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Microsoft.AspNetCore.Components;using Microsoft.AspNetCore.Components.Rendering;using Microsoft.AspNetCore.Components.WebView.WindowsForms;using Microsoft.Extensions.DependencyInjection;using Microsoft.JSInterop;namespace WinFormsBlazor01.Razors{    public class BlazorService    {        public static IEventHub CretaeBlazorService<IService, Service, RazorPage>(BlazorWebView blazorWebView)            where IService : class            where Service : class, IService            where RazorPage : IComponent        {            var services = new ServiceCollection();            services.AddWindowsFormsBlazorWebView();            services.AddSingleton<IService, Service>();            var eventHub = new EventHub();            services.AddSingleton<IEventHub>(eventHub);            blazorWebView.HostPage = "wwwroot\\index.html";            blazorWebView.Services = services.BuildServiceProvider();            blazorWebView.RootComponents.Add<RazorPage>("#app");            return eventHub;        }        public static IEventHub CretaeBlazorService<RazorPage>(BlazorWebView blazorWebView) where RazorPage : IComponent        {            var services = new ServiceCollection();            services.AddWindowsFormsBlazorWebView();               var eventHub = new EventHub();            services.AddSingleton<IEventHub>(eventHub);            blazorWebView.HostPage = "wwwroot\\index.html";            blazorWebView.Services = services.BuildServiceProvider();            blazorWebView.RootComponents.Add<RazorPage>("#app");            return eventHub;        }    }}

为了使很多个razor页面都有这个能力,还需要封装一个ComponentBase子类,来充当每个razor的父类,这样可以省略在每个razor中订单事件,代码如下:

using Microsoft.AspNetCore.Components;using Microsoft.JSInterop;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace WinFormsBlazor01.Razors{    public abstract class EventComponent : ComponentBase, IDisposable    {        protected DotNetObjectReference<EventComponent>? dotNetHelper;        protected override async Task OnInitializedAsync()        {            IEventHub? eventHub = null;            IJSRuntime? js = null;            foreach (var pro in this.GetType().GetProperties(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))            {                if (typeof(IEventHub).IsInstanceOfType(pro.GetValue(this, new object[0])))                {                    eventHub = pro.GetValue(this, new object[0]) as IEventHub;                }                if (typeof(IJSRuntime).IsInstanceOfType(pro.GetValue(this, new object[0])))                {                    js = pro.GetValue(this, new object[0]) as IJSRuntime;                }            }            if (eventHub != null && js != null)            {                eventHub.OnCallJSAsync += CallAsync;                async Task<object> CallAsync(object sender, object?[]? eventArgs)                {                    var eventhub = sender as EventHub;                    return await js.InvokeAsync<object>(eventhub?.EventName!, eventArgs);                }            }            if (js != null)            {                dotNetHelper = DotNetObjectReference.Create(this);                await js.InvokeVoidAsync("CallHelpers.DotNetHelper", dotNetHelper);            }            base.OnInitialized();        }        public void Dispose()        {            dotNetHelper?.Dispose();        }    }}

有了razor page在的父类了,怎么继承呢?定义一个_Imports.razor,来当所有razor的共公引用,这里需经继承EventComponent,同时引用注入IEventHub和IJSRuntime两个接口的子对像:

@using Microsoft.AspNetCore.Components.Web@using Microsoft.JSInterop;@inherits EventComponent@inject IEventHub eventHub@inject IJSRuntime js

所有基础工作准备好了,接下来试验一把,在index.html(这里不清楚查看前一篇《WinForm混合Blazor(上)》)添加js代码:

function showtitle(title) {    document.getElementById("title").innerText = "JS接到WinForm数据:" + title    return title}class CallHelpers {    static dotNetHelper;    static DotNetHelper(value) {        CallHelpers.dotNetHelper = value;    }    static async callForm2(name) {        const msg = await CallHelpers.dotNetHelper.invokeMethodAsync('CallForm2', name);        alert(`JS接到WinForm的返回值: "${msg}"`);    }}window.CallHelpers = CallHelpers;

razor页面文件如下:

@using Microsoft.AspNetCore.Components.Web<div class="row">    <h2>我是HTML窗体</h2></div><div class="row">    <div class="col-12">        <div class="input-group mb-3">            <input type="text" class="form-control" id="FindName" placeholder="请输入信息" @bind="InputName" aria-describedby="button-addon2">            <button class="btn btn-outline-secondary" type="button" @onclick="CallForm1" id="button-addon2">razorC#触发WinForm事件</button>            <button class="btn btn-outline-secondary" type="button" onclick="CallHelpers.callForm2(document.getElementById('FindName').value)" id="button-addon2">JS触发WinForm事件</button>        </div>    </div></div><div class="row">    <h3 id="title"></h3></div>@code {    private string? InputName="ABCDEFG123456";    #region 方法一,用@bind调razor中C#方法,再调用WinForm中方法    async void CallForm1()    {        var result = await eventHub.CallCSharpAsync("clientclick", InputName);        MessageBox.Show("razor中C#接到的返回结果:" + result.ToString());    }    #endregion    #region 方法二,通过js方法调用razor中C#方法,再调用WinForm中方法    /// <summary>    /// 这个方法是js中调过来的    /// </summary>    /// <param name="name"></param>    /// <returns></returns>    [JSInvokable]    public async Task<object> CallForm2(string name)    {        var result = await eventHub.CallCSharpAsync("clientclick",  name );        return result;    }    #endregion}

WinForm中定义如下:

WinForm窗体Designer文件

namespace WinFormsBlazor01{    partial class AddForm    {        /// <summary>        /// Required designer variable.        /// </summary>        private System.ComponentModel.IContainer components = null;        /// <summary>        /// Clean up any resources being used.        /// </summary>        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>        protected override void Dispose(bool disposing)        {            if (disposing && (components != null))            {                components.Dispose();            }            base.Dispose(disposing);        }        #region Windows Form Designer generated code        /// <summary>        /// Required method for Designer support - do not modify        /// the contents of this method with the code editor.        /// </summary>        private void InitializeComponent()        {            this.addBlazorWebView = new Microsoft.AspNetCore.Components.WebView.WindowsForms.BlazorWebView();            this.panel1 = new System.Windows.Forms.Panel();            this.txtNo = new System.Windows.Forms.TextBox();            this.labBackMessage = new System.Windows.Forms.Label();            this.label1 = new System.Windows.Forms.Label();            this.labMessage = new System.Windows.Forms.Label();            this.button1 = new System.Windows.Forms.Button();            this.panel1.SuspendLayout();            this.SuspendLayout();            //             // addBlazorWebView            //             this.addBlazorWebView.Dock = System.Windows.Forms.DockStyle.Fill;            this.addBlazorWebView.Location = new System.Drawing.Point(0, 176);            this.addBlazorWebView.Name = "addBlazorWebView";            this.addBlazorWebView.Size = new System.Drawing.Size(967, 414);            this.addBlazorWebView.TabIndex = 1;            this.addBlazorWebView.Text = "queryBlazorWebView";            //             // panel1            //             this.panel1.Controls.Add(this.txtNo);            this.panel1.Controls.Add(this.labBackMessage);            this.panel1.Controls.Add(this.label1);            this.panel1.Controls.Add(this.labMessage);            this.panel1.Controls.Add(this.button1);            this.panel1.Dock = System.Windows.Forms.DockStyle.Top;            this.panel1.Location = new System.Drawing.Point(0, 0);            this.panel1.Name = "panel1";            this.panel1.Size = new System.Drawing.Size(967, 176);            this.panel1.TabIndex = 2;            //             // txtNo            //             this.txtNo.Location = new System.Drawing.Point(423, 39);            this.txtNo.Name = "txtNo";            this.txtNo.Size = new System.Drawing.Size(362, 23);            this.txtNo.TabIndex = 6;            //             // labBackMessage            //             this.labBackMessage.AutoSize = true;            this.labBackMessage.Location = new System.Drawing.Point(423, 111);            this.labBackMessage.Name = "labBackMessage";            this.labBackMessage.Size = new System.Drawing.Size(73, 17);            this.labBackMessage.TabIndex = 5;            this.labBackMessage.Text = "-------------";            //             // label1            //             this.label1.AutoSize = true;            this.label1.Font = new System.Drawing.Font("Microsoft YaHei UI", 16F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);            this.label1.Location = new System.Drawing.Point(12, 9);            this.label1.Name = "label1";            this.label1.Size = new System.Drawing.Size(198, 30);            this.label1.TabIndex = 4;            this.label1.Text = "我是WinForm窗体";            //             // labMessage            //             this.labMessage.AutoSize = true;            this.labMessage.ForeColor = System.Drawing.Color.Red;            this.labMessage.Location = new System.Drawing.Point(38, 91);            this.labMessage.Name = "labMessage";            this.labMessage.Size = new System.Drawing.Size(116, 17);            this.labMessage.TabIndex = 3;            this.labMessage.Text = "============";            //             // button1            //             this.button1.Location = new System.Drawing.Point(817, 82);            this.button1.Name = "button1";            this.button1.Size = new System.Drawing.Size(121, 34);            this.button1.TabIndex = 2;            this.button1.Text = "触发Html事件";            this.button1.UseVisualStyleBackColor = true;            this.button1.Click += new System.EventHandler(this.button1_Click);            //             // AddForm            //             this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;            this.ClientSize = new System.Drawing.Size(967, 590);            this.Controls.Add(this.addBlazorWebView);            this.Controls.Add(this.panel1);            this.Name = "AddForm";            this.Text = "AddForm";            this.panel1.ResumeLayout(false);            this.panel1.PerformLayout();            this.ResumeLayout(false);        }        #endregion        private Microsoft.AspNetCore.Components.WebView.WindowsForms.BlazorWebView addBlazorWebView;        private Panel panel1;        private Button button1;        private Label labMessage;        private Label label1;        private Label labBackMessage;        private TextBox txtNo;    }}

窗体cs文件

using System;using System.Threading.Tasks;using System.Windows.Forms;using WinFormsBlazor01.Razors;namespace WinFormsBlazor01{    public partial class AddForm : Form    {        IEventHub _eventHub;        public AddForm()        {            InitializeComponent();            _eventHub = BlazorService.CretaeBlazorService<Add>(addBlazorWebView);            _eventHub.OnCallCSharpAsync += EventHub_OnCallCSharpAsync;            txtNo.Text = Guid.NewGuid().ToString("N").ToUpper();        }        private async Task<object> EventHub_OnCallCSharpAsync(object sender, object?[]? eventArgs)        {            var eventHub = sender as EventHub;            if (eventHub?.EventName == "clientclick" && eventArgs != null && eventArgs.Length > 0)            {                labMessage.Text = "JS事件传过来的参数:" + eventArgs?[0]?.ToString()!;            }            return await Task.FromResult(eventArgs?[0]?.ToString()!);        }        private async void button1_Click(object sender, EventArgs e)        {            var result = await _eventHub.CallJSAsync("showtitle", txtNo.Text);            labBackMessage.Text = "WinForm调用JS返回值:" + result.ToString();        }    }}

查看结果:

JS调用WinForm,用@bind方式

JS调用WinForm,用js方法调用

WinForm方法调用JS

附代码:

标签: #winformhtml界面 #netcore调用js