Blazor 组件通讯示例,包含联级传参、双向绑定、服务传参 3 种方式。
Son.razor
1 @using BlazorApp.Shared.Services; 2 <div style="border:inherit;margin:inherit;background-color:ivory;"> 3 <h3>Son---@Value<input class="btn btn-info" type="button" value="自身+1,同时Self组件值+1" @onclick="ChangeValue" /></h3> 4 5 <input type="text" @bind-value="@sunValue" /> 6 <input class="btn btn-info" type="button" value="控制Grand组件显示值" @onclick="ChangeGrandValue" /> 7 8 <h6>来自Parent组件 @ParentValue</h6> 9 <input type="text" name="name" @bind-value="@Ceshi" /> 10 <button @onclick="@Henfgu">给邻居发消息</button> 11 </div> 12 @code { 13 [Parameter] 14 public int? Value { get; set; } = 0; 15 16 public string? Ceshi { get; set; } 17 [Inject] 18 public CommunicationToString? communicationToString { get; set; } 19 20 private async Task ChangeValue() 21 { 22 Value++; 23 if (OnValueChanged.HasDelegate) 24 { 25 await OnValueChanged.InvokeAsync(Value); 26 } 27 } 28 29 public string? sunValue { get; set; } = "Sun"; 30 31 /// <summary> 32 /// 获取Name为GrandValue的Grand组件 33 /// </summary> 34 [CascadingParameter(Name = "GrandValue")] 35 Grand? grand { get; set; } 36 37 public async Task ChangeGrandValue() 38 { 39 await InvokeAsync(grand?.State_HasChanged(() => { grand.SetValue($"来自Sun组件 {sunValue}"); })!); 40 } 41 42 public async Task Henfgu() 43 { 44 if (communicationToString != null) 45 communicationToString.Callback(Ceshi ?? ""); 46 47 await Task.CompletedTask; 48 } 49 50 [CascadingParameter(Name = "ParentValue")] 51 string? ParentValue { get; set; } 52 53 [Parameter] 54 public EventCallback<int?> OnValueChanged { get; set; } 55 }
Self.razor
1 <div style="border:inherit;margin:inherit;background-color:#e4e4b5;"> 2 <h3>Self---@Value<input class="btn btn-info" type="button" value="+1" @onclick="OnInput" /></h3> 3 4 <h6>来自Family组件 @family?._familyValue</h6> 5 <Son Value="@Value" OnValueChanged="OnValueChanged" /> 6 </div> 7 @code { 8 [Parameter] 9 public int? Value { get; set; } = 0; 10 11 public void OnInput() 12 { 13 Value++; 14 } 15 16 /// <summary> 17 /// 获取上级Name为FamilyValue的Family组件 18 /// </summary> 19 [CascadingParameter(Name = "FamilyValue")] 20 Family? family { get; set; } 21 22 private void OnValueChanged(int? val) 23 { 24 Value = val; 25 } 26 }
Parent.razor
1 <div style="border:inherit;margin:inherit;background-color:#f6df6e;"> 2 <h3>Parent---@Value<input class="btn btn-info" type="button" value="+1" @onclick="OnInput" /></h3> 3 4 <input type="text" name="name" @bind-value="_parentValue" /> 5 <CascadingValue Value="@_parentValue" Name="ParentValue"> 6 <Self Value="@Value" /> 7 </CascadingValue> 8 </div> 9 @code { 10 [Parameter] 11 public int? Value { get; set; } = 0; 12 13 private string _parentValue = "ParentValue"; 14 15 16 public void OnInput() 17 { 18 Value++; 19 } 20 }
Grand.razor
1 <div style="border:inherit;margin:1.5rem 5rem 5rem 5rem;background-color:forestgreen;"> 2 <h3>Grand---@Value<input class="btn btn-info" type="button" value="点击+1,同时改变Family的值" @onclick="OnInput" /></h3> 3 双向绑定:<input type="text" name="name" value="@Value" @onchange="ChangeParentValue" /> 4 <h6>@value</h6> 5 <CascadingValue Value="this" Name="GrandValue"> 6 <Parent Value="@Value" /> 7 </CascadingValue> 8 </div> 9 @code { 10 #region 双向绑定 11 [Parameter] 12 public int? Value { get; set; } = 0; 13 14 /// <summary> 15 /// 命名方法 绑定的参数名+Changed 16 /// </summary> 17 [Parameter] 18 public EventCallback<int?> ValueChanged { get; set; } 19 20 private async Task ChangeParentValue(ChangeEventArgs e) 21 { 22 if (e != null) 23 { 24 int.TryParse(e.Value!.ToString(), out var str); 25 await ValueChanged.InvokeAsync(str); 26 } 27 } 28 #endregion 29 30 public async Task OnInput() 31 { 32 Value++; 33 await ValueChanged.InvokeAsync(Value); 34 } 35 36 public string value { get; set; } = "Grand"; 37 38 public void SetValue(string value) 39 { 40 this.value = value; 41 } 42 43 public Action<string> Test => (value) => { this.value = value; StateHasChanged(); }; 44 45 public Action? State_HasChanged(Action Execute) => Execute + StateHasChanged; 46 }
Family.razor
1 @page "/family" 2 <Neighbor /> 3 <Divider /> 4 <div style="border:solid;background-color:lightsteelblue;"> 5 <h3>Family---@Value<input class="btn btn-info" type="button" value="+1" @onclick="OnInput" /></h3> 6 7 <input type="text" name="name" @bind-value="_familyValue" /> 8 <CascadingValue Value="this" Name="FamilyValue"> 9 <Grand @bind-Value="@Value" /> 10 </CascadingValue> 11 12 </div> 13 @code { 14 public int? Value { get; set; } = 0; 15 16 public string _familyValue = "FamilyValue"; 17 18 public void OnInput() 19 { 20 Value++; 21 } 22 23 }
Neighbor.razor
1 @using BlazorApp.Shared.Services; 2 <div style="border:solid;background-color:lightsteelblue;"> 3 <h3>Neighbor</h3> 4 <h5>来至邻居家的: @Test</h5> 5 </div> 6 @code { 7 public string? Test { get; set; } 8 9 10 [Inject] 11 public CommunicationToString? communicationToString { get; set; } 12 13 protected override void OnInitialized() 14 { 15 base.OnInitialized(); 16 //注册服务 17 communicationToString?.Register(Ceshi); 18 } 19 20 21 public Task Ceshi(string value) 22 { 23 Test = value; 24 StateHasChanged(); 25 return Task.CompletedTask; 26 } 27 }
CommunicationToString.cs
1 namespace BlazorApp.Shared.Services 2 { 3 public class CommunicationToString : ServiceBase<string> 4 { 5 6 } 7 }
ServiceBase.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Threading.Tasks; 4 5 namespace BlazorApp.Shared.Services 6 { 7 public abstract class ServiceBase<TOption> 8 { 9 private Func<TOption, Task>? _Callback { get; set; } 10 11 private IDictionary<string, Func<TOption, Task>>? _Callbacks { get; set; } = new Dictionary<string, Func<TOption, Task>>(); 12 13 /// <summary> 14 /// 注册方法 15 /// </summary> 16 /// <param name="callback"></param> 17 internal void Register(Func<TOption, Task> callback) => _Callback = callback; 18 19 /// <summary> 20 /// 回调方法 21 /// </summary> 22 /// <param name="option"></param> 23 /// <returns></returns> 24 public virtual void Callback(TOption option) => _Callback?.Invoke(option); 25 26 /// <summary> 27 /// 注册方法到集合 28 /// </summary> 29 /// <param name="key"></param> 30 /// <param name="callback"></param> 31 internal void Register(string key, Func<TOption, Task> callback) => _Callbacks?.Add(key, callback); 32 33 /// <summary> 34 /// 根据key值回调方法 35 /// </summary> 36 /// <param name="key"></param> 37 /// <param name="option"></param> 38 public virtual void Callback(string key, TOption option) 39 { 40 if (_Callbacks != null && _Callbacks.TryGetValue(key, out var callback)) 41 { 42 callback.Invoke(option); 43 } 44 } 45 } 46 }