Blazor onclick от дочернего компонента не вызывает повторного рендеринга - PullRequest
0 голосов
/ 19 октября 2019

У меня есть компонент с одним дочерним компонентом

<MyBtn Command="@ShowBusyCommand"></MyBtn>

@if(IsBusy)
{
<span>I'm busy</span>
}

@code{
 public bool IsBusy { get; set; }

 public ICommand ShowBusyCommand => RegisterCommand(() => ShowBusyCommand, CanExecute, ExecuteAsync);

 public async Task ExecuteAsync()
    {
        try
        {
            IsBusy = true;
            await Task.Delay(2000);
        }
        finally
        {
            IsBusy = false;
        }
    }
}

И компонент MyBtn

<button @onclick="@Execute">Show busy</button>

@code {
    [Parameter]
    public ICommand Command { get; set; }

    public void Execute()
    {
        Command.Execute(null);
    }
}

Когда я нажимаю кнопку, выполняется метод ExecuteAsync, но представление не изменяется. Я не вижу свой промежуток с текстом «Я занят».

Я даже пытался создать EventCallback в MyBtn

<button @onclick="@OnClickHandler">Show busy</button>

@code {
    [Parameter]
    public ICommand Command { get; set; }

    [Parameter] 
    public object Receiver { get; set; }

    public async Task OnClickHandler()
    {
        var onClick = EventCallback.Factory.Create(Receiver, () => Command.Execute(null));
        await onClick.InvokeAsync(null);
    }
}


  <MyBtn Command="@ShowBusyCommand" Receiver="this"></MyBtn>

, но это тоже не помогло.

Я не могу понять, почему не изменяется родительское состояние при нажатии кнопки в компоненте, и как я могу это исправить? За исключением вызова вручную StateHasChanged при изменении свойства IsBusy.

Если я изменю свой параметр с ICommand на EventCallback в компоненте MyBtn и передам метод ExecuteAsync, он будет работать. Почему? Как я могу заставить его работать, передавая ICommand в качестве параметра и вызывая метод Execute?

EDIT: я только что понял, удаляю ли я lambda из фабрики EventCallback, это работает, но я не знаю, почему

var onClick = EventCallback.Factory.Create(Receiver, Command.Execute);

1 Ответ

1 голос
/ 19 октября 2019

Это рабочий код вашего вопроса ...

Index.razor

@page "/"

<MyBtn Func="@ShowBusyAsync"></MyBtn>

@if(IsBusy)
{
<span>I'm busy</span>
}

@code{
 public bool IsBusy { get; set; }

 public async Task ShowBusyAsync(int delay)
    {
        try
        {
            IsBusy = true;
            await Task.Delay(delay);
        }
        finally
        {
            IsBusy = false;
        }
    }
}

MyBtn.razor

<h3>MyBtn</h3>

<button @onclick="@ExecuteAsync">Show busy</button>

@code {
    [Parameter]
    public EventCallback <int> Func { get; set; }

    public async void ExecuteAsync()
    {
        await Func.InvokeAsync(3000);
    }
    }

Примечание: Вы должны использоватьEventCallback, если вы хотите повторно визуализировать родительский компонент, так как EventCallback создает делегата, свойство Target которого установлено для объекта, который зарегистрировал событие, то есть родительский компонент. Если вы не хотите, чтобы родительский компонент был целью события, используйте вместо него делегаты Action или Func.

...