在 Blazor 中,如何将参数从 @Body 级联回布局?
In Blazor, how to cascade a parameter from @Body back to the layout?
我需要更改 header 中微调器的 class - 在获取数据时显示它,完成后将其变为不可见。
使用级联值,我可以在布局中拥有:
<CascadingValue Value="classString">
@Body
</CascadingValue>
并且在页面中我可以使用 [CascadingParameter] string classStr
访问布局中设置的值。
如果我希望 classString
的布局受到页面中 classStr 更改的影响,我可以级联一个事件,如 here.
所示
但此示例将事件级联到具有 <ChildComponent OnStrChange="@ChangeStr">
的 child 组件,其中 OnStrChange
是使用 [Parameter] 在 child 组件上定义的。
我试过用 <CascadingValue Value="eventName" Name="event">
级联事件,但这似乎不起作用。
我可以将事件级联到使用@Body 调用的页面吗?
您可以采取非常迂回的路线,您的布局实现类似 this 的接口并将其自身作为级联参数发送。但是,它还有其他副作用。
另一种选择是为组件之间的无缝通信创建服务。基本上,您可以使用:
public class SpinnerState
{
public string SpinnerClass {get;set;}
public Func<Task> OnSpinnerClassChanged {get;set;}
public async Task SetSpinnerClass(string newClass)
{
SpinnerClass = newClass;
await OnSpinnerClassChanged.Invoke();
}
}
将此作为会话服务注入:
services.AddScoped<SpinnerState>();
然后在布局中使用
@inject SpinnerState state
@implements IDisposable
// hook and unhook event listeners in OnInitialized and Dispose methods respectively
<div class="@state.SpinnerClass"></div>
@Body //etc
@code
{
protected override void OnInitialized()
{
state.OnSpinnerClassChanged += ChangeSpinner;
}
async Task ChangeSpinner()
{
StateHasChanged();
}
}
子组件更新SpinnerClass时,布局会更新状态。
注意事项:
最好不要这样做。即不要更新 MainLayout 中的 UIs。问题是每次布局级别刷新都会导致主体刷新。反过来,可能 导致组件丢失它们的状态。相反,(在上面的示例中)让微调器组件监听该事件。这样,对状态的任何更新都仅限于微调器组件。
更新 UI 以响应一些较长的 运行 请求是您真正感兴趣的 我猜 。因此,不是传递 UI 属性更新,而是引发一些功能事件(如 "UploadingFile" )并让各个组件响应它。
--编辑--
@enet 在这个问题上先发制人,但我会把我的答案作为一个稍微更浓缩的版本。
Layout.razor
<CascadingValue Value = "this">
@AnythingThatNeedsAccesToTheSpinner
</CascadingValue>
@code {
bool IsSpinning {get; set;}
public async Task SetSpinner (bool SpinValue){
IsSpinning=SpinValue;
}
}
AnythingThatNeedsAccesToTheSpinner.razor
@code{
[CascadingParameter]
Layout Layout {get; set;}
protected override async Task OnInitializedAsync()
{
await Layout.SetSpinner(true);
await Task.Delay(5000);
await Layout.SetSpinner(false);
}
}
我需要更改 header 中微调器的 class - 在获取数据时显示它,完成后将其变为不可见。
使用级联值,我可以在布局中拥有:
<CascadingValue Value="classString">
@Body
</CascadingValue>
并且在页面中我可以使用 [CascadingParameter] string classStr
访问布局中设置的值。
如果我希望 classString
的布局受到页面中 classStr 更改的影响,我可以级联一个事件,如 here.
但此示例将事件级联到具有 <ChildComponent OnStrChange="@ChangeStr">
的 child 组件,其中 OnStrChange
是使用 [Parameter] 在 child 组件上定义的。
我试过用 <CascadingValue Value="eventName" Name="event">
级联事件,但这似乎不起作用。
我可以将事件级联到使用@Body 调用的页面吗?
您可以采取非常迂回的路线,您的布局实现类似 this 的接口并将其自身作为级联参数发送。但是,它还有其他副作用。 另一种选择是为组件之间的无缝通信创建服务。基本上,您可以使用:
public class SpinnerState
{
public string SpinnerClass {get;set;}
public Func<Task> OnSpinnerClassChanged {get;set;}
public async Task SetSpinnerClass(string newClass)
{
SpinnerClass = newClass;
await OnSpinnerClassChanged.Invoke();
}
}
将此作为会话服务注入:
services.AddScoped<SpinnerState>();
然后在布局中使用
@inject SpinnerState state
@implements IDisposable
// hook and unhook event listeners in OnInitialized and Dispose methods respectively
<div class="@state.SpinnerClass"></div>
@Body //etc
@code
{
protected override void OnInitialized()
{
state.OnSpinnerClassChanged += ChangeSpinner;
}
async Task ChangeSpinner()
{
StateHasChanged();
}
}
子组件更新SpinnerClass时,布局会更新状态。
注意事项:
最好不要这样做。即不要更新 MainLayout 中的 UIs。问题是每次布局级别刷新都会导致主体刷新。反过来,可能 导致组件丢失它们的状态。相反,(在上面的示例中)让微调器组件监听该事件。这样,对状态的任何更新都仅限于微调器组件。
更新 UI 以响应一些较长的 运行 请求是您真正感兴趣的 我猜 。因此,不是传递 UI 属性更新,而是引发一些功能事件(如 "UploadingFile" )并让各个组件响应它。
--编辑--
@enet 在这个问题上先发制人,但我会把我的答案作为一个稍微更浓缩的版本。
Layout.razor
<CascadingValue Value = "this">
@AnythingThatNeedsAccesToTheSpinner
</CascadingValue>
@code {
bool IsSpinning {get; set;}
public async Task SetSpinner (bool SpinValue){
IsSpinning=SpinValue;
}
}
AnythingThatNeedsAccesToTheSpinner.razor
@code{
[CascadingParameter]
Layout Layout {get; set;}
protected override async Task OnInitializedAsync()
{
await Layout.SetSpinner(true);
await Task.Delay(5000);
await Layout.SetSpinner(false);
}
}