Обновление Blazor через JS, который вызывает код C # - PullRequest
0 голосов
/ 18 февраля 2019

Я пытаюсь обновить страницу Blazor для события, сгенерированного js. Js, с помощью взаимодействия вызывает код C # для события, и мне нужно каким-то образом вызвать this.StateHasChanged в обратном вызове c #:

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 методы, которые вызываются из js , имеют (согласно документации), равным static?

Ответы [ 3 ]

0 голосов
/ 18 февраля 2019

Я решил это благодаря предложению пользователя @Isaac добавить событие и вызвать StateHasChanged из его обратного вызова:

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();
        }
    }
0 голосов
/ 18 февраля 2019

Я думаю, что было бы неплохо передать экземпляр C # в JS и сделать так, чтобы ваш JS вызывал этот экземпляр C #.

StuffBase.cs

    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();
        }
    }

JS

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);
    }
}
0 голосов
/ 18 февраля 2019

Так что, если они статичны ... Значит ли это, что вы не можете вызвать метод StateHasChanged.Просто введите это в конце метода TimeoutCallback: StateHasChanged();

В любом случае, если это правда, и вы не можете вызвать метод StateHasChanged из метода TimeoutCallback, вы можете вызвать обработчик события из TimeoutCallbackметод, подобный этому: TimeoutCallbackLoaded?.Invoke(data); И оттуда вызовите StateHasChanged();

Редактировать: ОК, я заметил, что вы определили класс с именем JSMethods с двумя методами, вызывающими SetTimeout и ClearTimeout.В этом случае, и это лучший дизайн, также определить TimeoutCallback в этом классе.После того, как все связаны, верно?Затем определите описанный выше обработчик события, который уведомляет подписчика (ваш код пользовательского интерфейса) о возникновении события, передавая ему данные, возвращенные из JSIterop, и в методе, который обрабатывает событие в коде пользовательского интерфейса, вы можете вызвать StateHasChanged();

...