Поддержание SynchronizationContext для вложенных (не первых или последних) методов в Blazor - PullRequest
1 голос
/ 05 февраля 2020

Используя проект по умолчанию, который загружается вместе с Visual Studio 2019 при создании нового проекта на стороне сервера Blazor в .NetCore 3.1, рассмотрите следующий пример (небольшое изменение на собственной странице примера счетчика):

<button class="btn btn-primary" @onclick="SingleMethodUpdate">Click Me</button>
<label>Update from same method: @result</label>
<button class="btn btn-primary" @onclick="NestedMethodUpdate">Click Me</button>
<label>Update from nested method: @nestedResult</label>

И выделенный код выглядит следующим образом:

int result = 0;
int nestedResult = 0;
int nestedCounter = 0;

protected async Task SingleMethodUpdate()
{
    result++;
}

protected async Task NestedMethodUpdate()
{
    await NestedUpdate(++nestedCounter);
    await Task.Delay(1000);
    await NestedUpdate(++nestedCounter);
    await Task.Delay(1000);
    await NestedUpdate(++nestedCounter);
}

protected Task NestedUpdate(int update)
{
    nestedResult = update;
    return Task.FromResult(0);
}

Первая кнопка и метка просты, нажмите кнопку, и счетчик обновится в интерфейсе, как только вы нажмете его, как и ожидалось. Однако вторая кнопка более сложна.

Это средний await NestedUpdate(++nestedCounter) вызов, который не отражается в интерфейсе пользователя. Первый и последний вызовы (первый и последний вызов вложенного метода) отражаются в режиме реального времени в пользовательском интерфейсе, поэтому вы видите:

Update from nested method: 1
*2 seconds go by
Update from nested method: 3

Я понимаю, что это из-за предостережений с SynchronizationContext, но мне более любопытно, как бы я go о захвате и поддержании этого контекста, чтобы каждый метод awaited, который вызывается в моем событии нажатия кнопки, использовал тот же контекст, чтобы Пользовательский интерфейс будет обновляться в режиме реального времени по мере выполнения кода. Есть ли хороший / красивый способ сделать это?

1 Ответ

0 голосов
/ 06 февраля 2020

Я понимаю, что это из-за предостережений с SynchronizationContext

Нет, не совсем. Весь этот код должен выполняться asyn c, но последовательно в главном потоке.
Ничего плохого или нуждающегося в исправлении с помощью SyncContext здесь.

То, что вы видите, происходит из-за логики StateHasChanged () c, которая на самом деле относится к State, предположительно просто логического флага.

Платформа Blazor установит этот флаг до и после вызова вашего обработчика событий, но в середине вам придется сделать это самостоятельно.

Быстрое исправление и объяснение:

protected async Task NestedMethodUpdate()
{
    // the flag is pre-set here
    await NestedUpdate(++nestedCounter);
    // the thread is available and Blazor will render '1' and reset the flag
    await Task.Delay(1000);  

    await NestedUpdate(++nestedCounter);
    // the thread is available but the flag is down: the '2' is not shown
    await Task.Delay(1000);

    await NestedUpdate(++nestedCounter);
    StatehasChanged();  // <<-- add this
    // the thread is available and the flag is up: the '3' is shown
    await Task.Delay(1000);

    // you can add more steps
    await NestedUpdate(++nestedCounter);
    StatehasChanged();  // <<-- set the flag
    await Task.Delay(1000);  // show '4'

    // this result will show '5' after the method has completed
    await NestedUpdate(++nestedCounter);
}
...