У меня есть кнопка, подобная приведенной ниже на странице компонента сервера бритвы. Цель состоит в том, чтобы при нажатии кнопки она переходила в отключенный режим до тех пор, пока задача не будет завершена. Это работает на одной из страниц, но мне не удается заставить его работать на других страницах в том же приложении. Кнопка запускает функцию DoSearch() и обновляет содержимое по завершении, но не обновляет себя на полпути. Любые идеи, почему, пожалуйста?
<button type = "button" class = "btn btn-primary" @onclick = "DoSearch" disabled = "@SearchDisabled">@SearchBtnName</button>
protected bool SearchDisabled { get; set; } = false;
protected string SearchBtnName { get; set; } = "Search";
protected async Task DoSearch()
{
SearchDisabled = true;
SearchBtnName = "Searching ...";
List<string> log = new();
try
{
//Do some work which takes a few seconds ....
}
finally
{
SearchDisabled = false;
SearchBtnName = "Search";
}
}
Я попытался изменить способ кодирования onclick, например: @onclick="@(async() => ждите DoSearch())"
Я попытался вызвать StateHasChanged() и await InvokeAsync(StateHasChanged); Я также пытался посмотреть, что еще может отличаться на этой странице, но не смог понять.
Ваш код будет работать, только если выполнить некоторую работу. Если это блок синхронного кода, завернутый в Task
, то у рендерера не будет времени на обновление пользовательского интерфейса до тех пор, пока не будет завершена какая-то работа, и вы не вернете поля статуса в состояние завершения.
Чтобы процитировать ответ на аналогичный вопрос сегодня:
Вызов StateHasChanged не отображает компонент. Он ставит RenderFragment компонента в очередь Renderer. Эта очередь обслуживается [рендерером и визуализируемым компонентом] только тогда, когда рендерер получает время для запуска потока.
В приведенном ниже коде я ввел yield после обновления полей состояния, чтобы убедиться, что пользовательский интерфейс обновляется в этот момент.
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
<div class = "m-2 p-2">
<button type = "button" class = "btn btn-primary" @onclick = "DoSearch" disabled = "@SearchDisabled">@this.SearchBtnName</button>
</div>
@code {
protected bool SearchDisabled = false;
protected string SearchBtnName = "Search";
private async Task DoSearch()
{
SearchDisabled = true;
SearchBtnName = "Searching ...";
// make sure we yield to update the UI
// Do work may be a block of synchronous wrapped in a Task!
// Some people will suggest you do await Task.Delay(1) here Take your choice
await Task.Yield();
//await Task.Delay(1);
await this.DoWork();
SearchDisabled = false;
SearchBtnName = "Search";
}
private async Task DoWork()
{
// emulate real async work
await Task.Delay(2000);
}
}
Большое спасибо! Это сработало.
Delay(1)
рулит, Yield()
разочаровывает.
@HH - ;-) - Я знал, что ты поднимешься до этого. Я почти квалифицировал некоторых людей в комментарии к коду!
Можете показать, что у вас внутри блока
try
. Ваш код работает нормально: blazorfiddle.com/s/7voq7qi4