通过调用C#代码的JS更新Blazor

问题描述 投票:0回答:4

[我试图在由Blazor生成的事件上更新我的js页面。Js与interop调用事件上的C#代码,我需要以某种方式在c#回调中调用this.StateHasChanged

JS

window.methods = {
    timeout: null,
    setTimeout: function () {
        timeout = window.setInterval(async function () {
            console.log("From js timeout occured ,sending to .net");
            await DotNet.invokeMethodAsync('[assembly name]', "TimeoutCallback", Date.now().toString());
        }, 2000);
    },

    clearTimeout: function () {
        if (this.timeout == null || this.timeout == undefined) {
            return;
        }
        console.log("Clearing timeout");
        window.clearTimeout(timeout);
    }
}

C#

@inherits StuffBase
@page "/test"

Current value: @val
<button onclick="@(async()=>await StartTimeout())">Start timeout </button>
<button onclick="@(async()=>await ClearTimeout())">Clear timeout</button>

public class StuffBase : BlazorComponent {

        protected static string val { get; set; }
        protected async Task StartTimeout() {
            await JSMethods.SetTimeout();
        }
        [JSInvokable("TimeoutCallback")]  //gets called by js on event !
        public static async Task TimeoutCallback(string data) {

            val = data; 
            Console.WriteLine("From callback ,received:" + data); //gets updated
            await Task.Delay(1000);
           //how can i call this.StateHasChanged
        }
        protected async Task ClearInterval() {
            await JSMethods.ClearInterval();
        }
    }

Interop

public class JSMethods {
        public static async Task SetTimeout() {
            await JSRuntime.Current.InvokeAsync<string>("methods.setTimeout");
        }
        public static async Task ClearTimeout() {
            await JSRuntime.Current.InvokeAsync<string>("methods.clearTimeout");
        }   
    }

如您所见,首先我从c#-> setTimeout进行调用,该代码在js中将超时值与其处理程序附加在一起。发生的是,我设法从TimeoutCallback中调用了js,但是在console中,我更新了我的值,因此我需要以某种方式通知UI进行自我更新。

由于我从.NET have(根据文档)被调用的所有js方法都设为static,我该如何实现?

javascript interop blazor
4个回答
1
投票

那么如果它们是静态的呢?这是否意味着您不能调用StateHasChanged方法。只需在TimeoutCallback方法的末尾键入以下内容:StateHasChanged();

[无论如何,如果是这样,并且您无法从TimeoutCallback方法调用StateHasChanged方法,则可以从TimeoutCallback方法调用事件处理程序,如下所示:TimeoutCallbackLoaded?.Invoke(data);然后从那里调用StateHasChanged();

编辑:好的,我现在注意到,您已经定义了一个名为JSMethods的类,它具有两个调用SetTimeout和ClearTimeout的方法。在这种情况下,更好的设计是在该类中还定义TimeoutCallback。毕竟相关,对吗?然后,如上所述定义事件处理程序,该事件处理程序将事件的发生通知订阅者(您的UI代码),并将从JSIterop返回的数据传递给该事件处理程序,然后在处理UI代码中事件的方法中,可以调用[C0 ]


2
投票

我认为将C#实例传递给JS并让您的JS回调到该C#实例是一个更好的选择。

StuffBase.cs

StateHasChanged();

JS

    public class StuffBase : ComponentBase
    {
        protected static string val { get; set; }

        protected async Task StartTimeout()
        {
            await JSRuntime.Current.InvokeAsync<string>("methods.setTimeout", new DotNetObjectRef(this));
        }

        [JSInvokable("TimeoutCallback")]  //gets called by js on event !
        public async Task TimeoutCallback(string data)
        {
            val = data;
            Console.WriteLine("From callback ,received:" + data); //gets updated
            await Task.Delay(1000);
            StateHasChanged();
        }
        protected async Task ClearTimeout()
        {
            await JSMethods.ClearTimeout();
        }
    }

1
投票

由于用户@Isaac建议添加事件,并从其回调中调用window.methods = { timeout: null, setTimeout: function (stuffBaseInstance) { timeout = window.setInterval(async function () { console.log("From js timeout occured ,sending to .net"); await stuffBaseInstance.invokeMethodAsync('TimeoutCallback', Date.now().toString()); }, 2000); }, clearTimeout: function () { if (this.timeout == null || this.timeout == undefined) { return; } console.log("Clearing timeout"); window.clearTimeout(timeout); } } ,我已解决了问题:

StateHasChanged

0
投票

经过对以上答案的大量讨论后,我无法使它们在核心3.1和Blazor Web程序集中工作。对于客户端blazor,JSInvokable仅适用于静态方法。因此,我的解决方案是让index.html中的javascript单击剃刀页面中定义的隐藏按钮:

index.html

public class StuffBase : BlazorComponent {

        protected static string val { get; set; }
        protected  delegate void OnTimeout(string data);
        private static event OnTimeout OnTimeOutOccured;
        protected override void OnInit() {
            OnTimeOutOccured += x => {
                this.StateHasChanged();
            };
        }

        protected async Task StartTimeout() {
            await JSMethods.SetTimeout();
        }
        [JSInvokable("TimeoutCallback")]
        public static  async Task TimeoutCallback(string data) {

            val = data;
            Console.WriteLine("From callback ,received:" + data);
            await Task.Delay(1000);
            OnTimeOutOccured?.Invoke(data);

        }
        protected async Task ClearTimeout() {
            await JSMethods.ClearTimeout();
        }
    }

然后在JSInteropRazor中,添加一个隐藏按钮以触发非静态方法以触发状态已更改,或者就我而言,刷新剃刀页面中的数据。

JSInterop.razor

<script language="javascript">

        window.resetjs = function () {
            document.getElementById('jspromptbutton').click();
        }
    </script>
</head>

<body>

    <button type="button" class="btn btn-primary"
            onclick="resetjs()">
        fire prompt
    </button>

种类繁多,但我一直在努力,直到找到一个更好的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.