来自子组件的 Blazor onclick 不会导致重新渲染
Blazor onclick from child component does not cause rerender
我有一个包含一个子组件的组件
<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 方法被执行但视图没有改变。我没有看到带有 "I'm busy" 文本的跨度。
我什至尝试在 MyBtn 中创建一个 EventCallback
<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>
但这也无济于事。
我不明白为什么单击组件中的按钮时父状态没有改变,我该如何解决?
除了在 IsBusy 上手动调用 StateHasChanged 属性 更改。
如果我在 MyBtn 组件中将我的参数从 ICommand 更改为 EventCallback 并传递 ExecuteAsync 方法,它将起作用。为什么?如何通过将 ICommand 作为参数传递并调用 Execute 方法使其工作?
编辑:
我刚刚发现如果我从 EventCallback 工厂中删除 lambda,它会起作用,但我不知道为什么
var onClick = EventCallback.Factory.Create(Receiver, Command.Execute);
这是您问题的有效代码...
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 创建了一个委托,其目标 属性 设置为注册事件的对象,即父组件零件。如果您不希望父组件成为事件的目标,请改用 Action 或 Func 委托。
我有一个包含一个子组件的组件
<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 方法被执行但视图没有改变。我没有看到带有 "I'm busy" 文本的跨度。
我什至尝试在 MyBtn 中创建一个 EventCallback
<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>
但这也无济于事。
我不明白为什么单击组件中的按钮时父状态没有改变,我该如何解决? 除了在 IsBusy 上手动调用 StateHasChanged 属性 更改。
如果我在 MyBtn 组件中将我的参数从 ICommand 更改为 EventCallback 并传递 ExecuteAsync 方法,它将起作用。为什么?如何通过将 ICommand 作为参数传递并调用 Execute 方法使其工作?
编辑: 我刚刚发现如果我从 EventCallback 工厂中删除 lambda,它会起作用,但我不知道为什么
var onClick = EventCallback.Factory.Create(Receiver, Command.Execute);
这是您问题的有效代码...
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 创建了一个委托,其目标 属性 设置为注册事件的对象,即父组件零件。如果您不希望父组件成为事件的目标,请改用 Action 或 Func 委托。