js 使用 DotNetObjectReference 调用 c# 函数

网上的方法

1,用 JSInvokable 标记需要被 js 调用的静态方法

    /// <summary>
    /// 页面窗口改变事件回调
    /// </summary>
    /// <param name="windowWidth"></param>
    /// <param name="windowHeight"></param>
    [JSInvokable]
    public static void ClientWindowResizeCallback(int windowWidth, int windowHeight)
    {
        PageResizeExcuter?.Invoke(windowWidth, windowHeight);
    }

2,js 通过 DotNet.invokeMethodAsync 调用这个方法

    window.addEventListener("resize", (event) => {
        console.log(`窗口尺寸改变了!!!! w:${window.innerWidth} h:${window.innerHeight}`);
        // DotNet 是 blazor 内置的对象
        // param 1 : 指定程序集
        // param 2 : JSInvokable 标记的方法
        // 后面跟方法的参数
        DotNet.invokeMethodAsync("AJR.AGV.Experience", "ClientWindowResizeCallback", window.innerWidth, window.innerHeight);
    });

 

使用 DotNet.invokeMethodAsync 时,你不需要关心 JSInvokable 方法所在的类,只要需要提供该方法的程序集;

 

但是这种做法有个缺陷,因为是静态方法,当多个浏览器触发同一事件时,只有最后打开的浏览器能正确触发回调

 

改进版

不再使用静态方法,也不再使用内置的 DotNet 对象;

C# 仍然用 JSInvokable 标记需要被调用的方法

public class JSEventReceiver
{
    public event Func<int, int, Task>? OnPageResize;
    /// <summary>
    /// 页面窗口改变事件回调
    /// </summary>
    /// <param name="windowWidth"></param>
    /// <param name="windowHeight"></param>
    [JSInvokable]
    public void ClientWindowResizeCallback(int windowWidth, int windowHeight)
    {
        if (OnPageResize is null) return;
        var delegates = OnPageResize.GetInvocationList();
        foreach (Func<int, int, Task> delegated in delegates)
        {
            try
            {
                delegated.Invoke(windowWidth, windowHeight);
            }
            catch (Exception ex)
            {
                OnPageResize -= delegated;
            }
        }
    }
}

 

在页面上我们直接用 JSEventReceiver 创建一个 DotNetObjectReference 对象,并把这个对象传给前端 js,这样前端用到的 DoNet 对象就是由当前页面创建的,多个页面不会互相干扰;

这里的 JSEventReceiver 对象可以使用 Scope 注入,不想用注入就直接 new JSEventReceiver(); 效果是一样的

razor

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    await base.OnAfterRenderAsync(firstRender);

    if (firstRender)
    {
        #region 一个 js 调用 c# 的例子
        _JsEventReceiver.OnPageResize -= HandlePageResize;
        _JsEventReceiver.OnPageResize += HandlePageResize;

        // 使用 DotNetObjectReference 向 JS 传递实例
        var dotNetObjectRef = DotNetObjectReference.Create(_JsEventReceiver);

        // 注册 JavaScript 事件
        await _IJsRuntime.InvokeVoidAsync("eventRegistResize", dotNetObjectRef);
        #endregion
    }
}

 

如果使用传入的 DoNetObjectReference 对象,js 里就不再需要指定程序集了

js

    function eventRegistResize(dotNetObjectRef) {
        window.addEventListener("resize", (event) => {
            console.log(`窗口尺寸改变了!!!! w:${window.innerWidth} h:${window.innerHeight}`);
            dotNetObjectRef.invokeMethodAsync("ClientWindowResizeCallback", window.innerWidth, window.innerHeight);
        });
    }

 

 

另:

如果在 razor 组件里使用事件,别忘了在组件销毁时释放事件,必须实现 IDisposable 接口,Dispose 方法才生效

@page "/"
@implements IDisposable

@code
{
    public void Dispose()
    {
        _JsEventReceiver.OnPageResize -= HandlePageResize;
    }
}

 

posted @ 2024-05-31 14:34  cchong005  阅读(120)  评论(0编辑  收藏  举报