前面已经介绍了两种组件之间联动的方案, 加上这篇 State container 方案, 共三种方案, 简单总结一下:
1 CascadingValue 组件方案, 使用简单, 但场景限制较大, 只能完成上层组件向下层组件传值。
2. EventCallback方案,稍微复杂点, 但场景适用更多。
3. State container 方案,功能更加强大, 代码比EventCallback方案更优美一些, 对于大型项目, 推荐使用。
State container 就是一个blazor wasm应用注入的一个全局单例对象,因为是全局内存对象, 也很适合作为 SessionStorage 。
State container 作为event发布者和订阅者的中介, 解耦两者关系, 实现组件联动。
======================================
思路
======================================
以示例说明思路:
一个组件 ProvinceSelector 用于选择城市, 需要传值到 CitySelector 组件。
步骤:
1. 增加一个 AppStateContainer C#类,
在这个类中, 定义一个 OnSelectedProvinceChange event属性, 类型为 Action, 之后事件订阅者可注入真实的 event handler。
再定义一个 SelectedProvince 属性, 该属性的 setter 方法, 要 invoke OnSelectedProvinceChange 事件。
⒉ ProvinceSelector 组件, 即事件的发布者
将要传出的信息, 封装成C#属性, 在其setter方法中, 同时更新 AppStateContainer 类的 SelectedProvince 属性, 即完成事件的发布
3. CitySelector 组件, 即事件的订阅者
在 OnInitialized() 方法中, 将内置的 StateHasChanged 委托实例注入到 AppStateContainer.OnSelectedProvinceChange 中, 完成订阅, 因为是将 StateHasChanged 用于响应通知, 所以 CitySelector 组件会自动完成状态更新.
另外, 该组件需要实现 IDisposable 接口, 在 Dispose() 方法中, 要将 StateHasChanged 委托实例从 AppStateContainer.OnSelectedProvinceChange 解绑.
======================================
代码
======================================
AppStateContainer C#类
//=========================== // file: DataAppStateContainer.cs //=========================== using System ; namespace blazorDemo1.Data { public class AppStateContainer { private string selectedProvince ; public string SelectedProvince{ get {return selectedProvince;} set{SetSelectedProvince(value);} } public event Action OnSelectedProvinceChange; public void SetSelectedProvince(string value){ selectedProvince=value ; OnSelectedProvinceChange?.Invoke(); } } }
program.cs DI 框架注入 AppStateContainer类
builder.Services.AddSingleton<AppStateContainer>();
ProvinceSelector 组件, 事件的发布者
@* //================================ *@ @* // file: SharedProvinceSelector.razor *@ @* //================================= *@ @using blazorDemo1.Data @inject AppStateContainer AppStateContainer <h2> Province Selector Component </h2> <input type="text" class="text" @bind="Province" @bind:event="oninput"> @code{ private string province ; public string Province{ get => province; set{ province=value ; AppStateContainer.SelectedProvince=province ; } } }
CitySelector 组件, 事件的订阅者
@* //================================ *@ @* // file: SharedCitySelector.razor *@ @* //================================= *@ @page "/city" @using blazorDemo1.Data @inject AppStateContainer AppStateContainer @implements IDisposable <h1> City Selector Component</h1> <p> You have selected the province: @AppStateContainer.SelectedProvince </p> <ProvinceSelector></ProvinceSelector> @code{ protected override void OnInitialized(){ AppStateContainer.OnSelectedProvinceChange+=StateHasChanged ; } public void Dispose(){ AppStateContainer.OnSelectedProvinceChange-=StateHasChanged ; } }
效果示意图