深入浅出Blazor webassembly之使用State container机制实现两组件联动

前面已经介绍了两种组件之间联动的方案, 加上这篇 State container 方案, 共三种方案, 简单总结一下:

1 CascadingValue 组件方案, 使用简单, 但场景限制较大, 只能完成上层组件向下层组件传值。

2. EventCallback方案,稍微复杂点, 但场景适用更多。

3. State container 方案,功能更加强大, 代码比EventCallback方案更优美一些, 对于大型项目, 推荐使用。

 

State container 就是一个blazor wasm应用注入的一个全局单例对象,因为是全局内存对象, 也很适合作为 SessionStorage 。

State container 作为event发布者和订阅者的中介, 解耦两者关系, 实现组件联动。

 

======================================

思路

======================================

以示例说明思路:

一个组件 ProvinceSelector 用于输入省份, 该省份需要传值到 CitySelector 组件, 以便联动City 的选择.

步骤:

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: Data\AppStateContainer.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: Shared\ProvinceSelector.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: Shared\CitySelector.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 ;
    }
}

 

效果示意图

posted @ 2021-09-04 21:26  harrychinese  阅读(218)  评论(0编辑  收藏  举报