如果我有一个名为DoAction
的Blazor组件,它只包含以下内容…
@code {
public void DoItNow(Action action) =>
action();
}
…我在另一个组件中使用它,如下所示…
<p>@((MarkupString)_msg)</p>
<br/><button @onclick="DoItNow">Do it now</button>
<DoAction @ref="_doAction" />
@code {
private string _msg;
private DoAction _doAction;
private void DoItNow() =>
_doAction.DoItNow(() => _msg += $"<br/>{DateTime.Now.ToLongTimeString()}: DoItNow");
}
…那就没问题了。我可以点击按钮,显示就会更新。
然而,如果我改变这一点,使DoAction
显示一个按钮,只有当按钮被点击时才执行动作,它不工作,见下文。
更新DoAction
组件…
<button class="btn btn-primary" @onclick="ButtonClicked">Click me</button>
@code {
private bool _showButton = false;
private Action _action;
public void DoItAfterButtonClick(Action action) {
// Hold on to the action for use below
_action = action;
_showButton = true;
}
private void ButtonClicked() {
_action();
_showButton = false;
}
}
更新父组件…
<p>@((MarkupString)_msg)</p>
<br/><button @onclick="DoItAfterButtonClick">Do it after button click</button>
<DoAction @ref="_doAction" />
@code {
private DoAction _doAction;
private void DoItAfterButtonClick() =>
_doAction.DoItAfterButtonClick(
() => _msg += $"<br/>{DateTime.Now.ToLongTimeString()}: DoItAfterButtonClick");
}
…然后,当我单击父组件中的按钮时,出现DoAction
组件中的按钮,但是当我单击该按钮时,在其他东西更新UI之前什么都不会发生。此时,我看到了当我单击DoAction
组件的按钮时没有显示的消息。
我尝试在DoAction
中添加对StateHasChanged()
的调用,但它没有任何区别。我能让它工作的唯一方法是,如果我在父组件中调用StateHasChanged()
…
private void DoItAfterButtonClick() =>
_doAction.DoItAfterButtonClick(
() => {
_msg += $"<br/>{DateTime.Now.ToLongTimeString()}: DoItAfterButtonClick";
StateHasChanged();
});
有人知道为什么UI没有在第二种情况下更新吗?
欢迎…
我不太明白你想达到什么目的。我建议你现在不要这样做,以后也不要……注意:Action委托封装了父组件拥有的方法(代码),而不是DoAction组件,并且它只从DoAction组件执行
在第一个版本中当你点击"DoItNow"按钮时,从DoAction组件调用委托,呈现过程通知父组件事件已经发生(调用stathaschanged方法),并且它应该重新呈现。请注意,当涉及到UI事件时,框架会自动调用StateHasChanged方法,就像当前单击"doitnow"的情况一样。按钮
public void DoItNow(Action action) =>
action();
父组件被重新呈现,因此显示得到更新。
在第二个版本中,当单击"ButtonClicked"
按钮时调用Action委托_action,呈现进程通知DoAction事件已经发生(调用StateHasChanged方法;再次是UI事件),它应该重新渲染。DoAction组件当然会被重新渲染,ButtonClicked"按钮,如您所见,在设置:_showButton = false;
后没有呈现,但是父组件不知道这一点。父组件不知道它所经历的变化,因为调用了封装了它所拥有的(方法)代码的Action委托…
_doAction.DoItAfterButtonClick(
() => { _msg += $"<br/>{DateTime.Now.ToLongTimeString()}: DoItAfterButtonClick"; StateHasChanged(); });
当然你已经找到解决方案了…我希望现在你已经找到了为什么UI没有在第二种情况下更新的解释…
奖金:
尽可能使用EventCallback 'delegate'…使用组件参数…你可以在DoAction中定义一个EventCallback组件参数,当它被调用时,可以在父组件上执行代码,而不需要调用StateHasChanged方法,也不会对这里发生的事情感到困惑……