Blazor 组件之间使用 EventCallback 进行通信
翻译自 Waqas Anwar 2021年3月28日的文章 《Communication between Blazor Components using EventCallback》 [1]

Blazor 应用程序是相互交互的多个 Blazor 组件的集合,我们可以在其他父组件中使用子组件。在实际的应用程序中,将数据或事件信息从一个组件传递到另一组件是一种十分常见的场景。您可能会有一个页面,其中一个组件中发生的用户操作需要更新其他组件中的某些 UI。通常使用 EventCallback 委托来处理这种类型的通信。在本教程中,我将介绍如何使用 EventCallback 在父组件和子组件之间进行通信。
下面是使用 EventCallback 从子组件到父组件进行通信所涉及的通用步骤。
- 在子组件中声明一个
EventCallback或EventCallback<T>委托 - 在父组件中附加一个到子组件的
EventCallback或EventCallback<T>的回调方法 - 当子组件想要与父组件通信时,可以使用以下方法之一调用父组件的回调方法。
- InvokeAsync(Object) – 如果使用的是
EventCallback - InvokeAsync(T) – 如果使用的是
EventCallback<T>
- InvokeAsync(Object) – 如果使用的是
为了理解上述步骤,让我们创建一个简单的待办事项列表(To Do List)示例。首先,在 Data 文件夹中创建以下 ToDo.cs 类。这是一个简单类,用于存储每个待办事项的 Title 和 Minutes 属性。Minutes 属性指定完成特定待办事项所需的时间。
ToDo.cs
public class ToDo
{
public string Title { get; set; }
public int Minutes { get; set; }
}
在项目中添加以下 ToDoList.razor 组件,并在其中编写以下代码:
ToDoList.razor
@page "/todos"
@using BlazorEventHandlingDemo.Data
<div class="row">
<div class="col"><h3>To Do List</h3></div>
<div class="col"><h5 class="float-right">Total Minutes: @TotalMinutes</h5></div>
</div>
<br />
<table class="table">
<tr>
<th>Title</th>
<th>Minutes</th>
<th></th>
</tr>
@foreach (var todo in ToDos)
{
<ToDoItem Item="todo" />
}
</table>
@code {
public List<ToDo> ToDos { get; set; }
public int TotalMinutes { get; set; }
protected override void OnInitialized()
{
ToDos = new List<ToDo>()
{
new ToDo() { Title = "Analysis", Minutes = 40 },
new ToDo() { Title = "Design", Minutes = 30 },
new ToDo() { Title = "Implementation", Minutes = 75 },
new ToDo() { Title = "Testing", Minutes = 40 }
};
UpdateTotalMinutes();
}
public void UpdateTotalMinutes()
{
TotalMinutes = ToDos.Sum(x => x.Minutes);
}
}
在上面的 @code 代码块中,我们声明了两个属性 ToDos 和 TotalMinutes。 其中 ToDos 属性存储待办事项的列表,TotalMinutes 存储所有待办事项花费分钟数的总和。
public List<ToDo> ToDos { get; set; }
public int TotalMinutes { get; set; }
接下来,我们在 Blazor 组件生命周期方法之一的名为 OnInitialized 的方法中使用一些待办事项对象来初始化我们的 ToDos 列表。我们还调用了 UpdateTotalMinutes 方法,该方法简单地计算 ToDos 列表中所有 ToDo 对象的 Minutes 属性的总和。
protected override void OnInitialized()
{
ToDos = new List<ToDo>()
{
new ToDo() { Title = "Analysis", Minutes = 40 },
new ToDo() { Title = "Design", Minutes = 30 },
new ToDo() { Title = "Implementation", Minutes = 75 },
new ToDo() { Title = "Testing", Minutes = 40 }
};
UpdateTotalMinutes();
}
HTML 代码也非常简单,我们将 TotalMinutes 属性显示在带有页面标题的页面顶部。
<h5 class="float-right">Total Minutes: @TotalMinutes</h5>
我们还在页面上生成了一个 HTML 表格,接下来的 foreach 循环遍历 ToDos 列表并渲染一个名为 ToDoItem 的子组件,我们还使用其 Item 属性将每个 ToDo 对象传入子组件中。
@foreach (var todo in ToDos)
{
<ToDoItem Item="todo" />
}
让我们在 Shared 文件夹中创建一个子组件 ToDoItem.razor 并在其中添加以下代码。该子组件有一个 Item 属性(我们在父组件的 foreach 循环中设置了属性)。该子组件简单地使用 <tr> 元素生成一个表格行,并在表格单元格中显示 Title 和 Minutes 属性。
ToDoItem.razor
@using BlazorEventHandlingDemo.Data
<tr>
<td>@Item.Title</td>
<td>@Item.Minutes</td>
<td>
<button type="button" class="btn btn-success btn-sm float-right">
+ Add Minutes
</button>
</td>
</tr>
@code {
[Parameter]
public ToDo Item { get; set; }
}
运行该应用程序,您会看到一个类似于如下内容的页面:

如果此时您点击子组件中的 Add Minutes 按钮,则不会有任何反应,因为我们还没有将 click 事件与 Add Minutes 按钮关联起来。让我们更新一下 Add Minutes 按钮的代码,添加调用 AddMinute 方法的 @onclick 特性。
<button type="button" class="btn btn-success btn-sm float-right" @onclick="AddMinute">
+ Add Minutes
</button>
当用户每次点击 Add Minutes 按钮时,事件处理方法 AddMinute 简单地将 Minutes 属性加 1。
public async Task AddMinute(MouseEventArgs e)
{
Item.Minutes += 1;
}
再次运行应用程序并尝试点击每个待办事项的 Add Minutes 按钮。您将注意到每个待办事项显示的分钟数会增加,但是顶部的总分钟数属性将保持不变。这是由于 TotalMinutes 属性是在父组件中计算的,而父组件并不知道子组件中的 Minutes 属性增加了。

让我们使用上面提到的步骤在我们的示例中改进一下子组件到父组件的通信,以便每次增加子组件中的 Minutes 时,能够相应地更新父组件的 UI。
步骤1:在子组件中声明一个 EventCallback 或 EventCallback<T> 委托
第一步是在我们的子组件中声明 EventCallback<T> 委托。我们声明一个委托 OnMinutesAdded,并使用 MouseEventArgs 作为 T,因为它可以为我们提供有关按钮点击事件的额外信息。
[Parameter]
public EventCallback<MouseEventArgs> OnMinutesAdded { get; set; }
步骤2:在父组件中附加一个到子组件的 EventCallback 或 EventCallback<T> 的回调方法
在这一步中,我们需要向在前面的步骤 1 中声明的子组件的 EventCallback 委托 OnMinutesAdded 附加一个回调方法。
<ToDoItem Item="todo" OnMinutesAdded="OnMinutesAddedHandler" />
在本例中我们使用的回调方法是 OnMinutesAddedHandler,该方法简单地调用同一个 UpdateTotalMinutes 方法,更新 TotalMinutes 属性。
public void OnMinutesAddedHandler(MouseEventArgs e)
{
UpdateTotalMinutes();
}
步骤3:当子组件需要与父组件通信时,使用 InvokeAsync(Object) 或 InvokeAsync(T) 方法调用父组件的回调方法。
在这一步中,我们需要调用父组件中的回调方法,因为我们希望每次用户点击 Add Minute 按钮时都会更新父组件 UI,所以最好的调用位置是在 AddMinute 方法中。
public async Task AddMinute(MouseEventArgs e)
{
Item.Minutes += 1;
await OnMinutesAdded.InvokeAsync(e);
}
这就是在 Blazor 中实现从子组件到父组件通信我们所要做的所有事情。以下是子组件 ToDoItem.razor 的完整代码:
ToDoItem.razor
@using BlazorEventHandlingDemo.Data
<tr>
<td>@Item.Title</td>
<td>@Item.Minutes</td>
<td>
<button type="button" class="btn btn-success btn-sm float-right" @onclick="AddMinute">
+ Add Minutes
</button>
</td>
</tr>
@code {
[Parameter]
public ToDo Item { get; set; }
[Parameter]
public EventCallback<MouseEventArgs> OnMinutesAdded { get; set; }
public async Task AddMinute(MouseEventArgs e)
{
Item.Minutes += 1;
await OnMinutesAdded.InvokeAsync(e);
}
}
以下是父组件 ToDoList.razor 的完整代码:
ToDoList.razor
@page "/todos"
@using BlazorEventHandlingDemo.Data
<div class="row">
<div class="col"><h3>To Do List</h3></div>
<div class="col"><h5 class="float-right">Total Minutes: @TotalCount</h5></div>
</div>
<br />
<table class="table">
<tr>
<th>Title</th>
<th>Minutes</th>
<th></th>
</tr>
@foreach (var todo in ToDos)
{
<ToDoItem Item="todo" OnMinutesAdded="OnMinutesAddedHandler" />
}
</table>
@code {
public List<ToDo> ToDos { get; set; }
public int TotalCount { get; set; }
protected override void OnInitialized()
{
ToDos = new List<ToDo>()
{
new ToDo() { Title = "Analysis", Minutes = 40 },
new ToDo() { Title = "Design", Minutes = 30 },
new ToDo() { Title = "Implementation", Minutes = 75 },
new ToDo() { Title = "Testing", Minutes = 40 }
};
UpdateTotalMinutes();
}
public void UpdateTotalMinutes()
{
TotalCount = ToDos.Sum(x => x.Minutes);
}
public void OnMinutesAddedHandler(MouseEventArgs e)
{
UpdateTotalMinutes();
}
}
在浏览器中运行应用程序,并尝试增加任一待办事项的分钟数,您会注意到父组件将自动地实时更新总分钟数。

相关阅读:
- Blazor Server 和 WebAssembly 应用程序入门指南
- Blazor 组件入门指南
- Blazor 数据绑定开发指南
- Blazor 事件处理开发指南
- Blazor 组件之间使用 EventCallback 进行通信
https://www.ezzylearning.net/tutorial/communication-between-blazor-components-using-eventcallback Communication between Blazor Components using EventCallback ︎
Blazor 组件之间使用 EventCallback 进行通信的更多相关文章
- react组件之间的几种通信情况
组件之间的几种通信情况 父组件向子组件通信 子组件向父组件通信 跨级组件通信 没有嵌套关系组件之间的通信 1,父组件向子组件传递 React数据流动是单向的,父组件向子组件通信也是最常见的;父组件通过 ...
- Vue组件之间数据交互与通信
Vue 的组件作用域都是孤立的,不允许在子组件的模板内直接引用父组件的数据.必须使用特定的方法才能实现组件之间的数据传递. 一.父组件向子组件传递数据 在 Vue 中,可以使用 props 向子组件传 ...
- Blazor 组件库开发指南
翻译自 Waqas Anwar 2021年5月21日的文章 <A Developer's Guide To Blazor Component Libraries> [1] Blazor 的 ...
- 使用reflux进行react组件之间的通信
前言 组件之间为什么要通信?因为有依赖. 那么,作为React组件,怎么通信? React官网说, 进行 父-子 通信,可以直接pass props. 进行 子-父 通信,往父组件传给子组件的函数注入 ...
- react native 之子组件和父组件之间的通信
react native开发中,为了封装性经常需要自定义组件,这样就会出现父组件和子组件,那么怎么在父组件和子组件之间相互通信呢,也就是怎么在各自界面push和pop.传值. 父组件传递给子组件: 父 ...
- js组件之间的通信
应用场景: 1.在刷微博的时候,滑到某个头像上,会出现一张usercard(用户名片), 微博列表区有这个usercard, 推荐列表也有这个usercard,评论区也有. 2.在网上购物时,购物车安 ...
- react8 组件之间的通信
<body><!-- React 真实 DOM 将会插入到这里 --><div id="example"></div> <!- ...
- Intent实现Activity组件之间的通信
今天讲解的是使用Intent实现Activity组件之间的通信. 一. 使用Intent显式启动Activity,Activity1àActivity2 1. ...
- 使用Broadcast实现android组件之间的通信 分类: android 学习笔记 2015-07-09 14:16 110人阅读 评论(0) 收藏
android组件之间的通信有多种实现方式,Broadcast就是其中一种.在activity和fragment之间的通信,broadcast用的更多本文以一个activity为例. 效果如图: 布局 ...
随机推荐
- NOIP模拟测试16「Drink·blue·weed」
话说这次考试 Drink 非常棒的一道卡常练习题,适合练习卡常 真的很棒 前置卡常知识 1.char要比int快 char是最快的 输出putchar,输入getchar 在这个题快了7000豪 2. ...
- k8s-nginx二进制报Illegal instruction (core dumped)
1.环境 系统:CentOS 7.3 内核:x86 环境:虚拟机 2.问题 收到一个现场问题,k8s环境中nginx的pod都启动异常. #kubectl get pod |grep nginx ng ...
- 微软官方 Win 11 “体检工具”太烂了?开发者自己做了一个
1.Win 10 免费升级到 Win 11 最近微软官方终于宣布了 Windows 11,不仅带来了全新的 UI,而且还有很多新功能:比如支持 Android 应用. 虽然微软官方已说明 Win 10 ...
- Redis之复制
1.配置 1.1 建立复制 参与复制的Redis实例划分为主节点(master) 和从节点(slave).默认情况下,Redis都是主节点.每个从节点只能有一个主节点,而主节点可以同时具有多个从节点. ...
- 敢为人先,从阿里巴巴云原生团队实践Dapr案例,看分布式应用运行时前景
背景 Dapr是一个由微软主导的云原生开源项目,国内云计算巨头阿里云也积极参与其中,2019年10月首次发布,到今年2月正式发布V1.0版本.在不到一年半的时间内,github star数达到了1.2 ...
- Qt之先用了再说系列-串口通讯(单串口单线程)
QT 串口通讯(单串口单线程) 串口通讯在我们写程序的时候或多或少会用到,借此在这记录一下QT是如何使用串口来通讯的.本次先侃侃在单线程下使用1个串口来通讯过程.好了,废话不多说,直接看步骤,我们的宗 ...
- Gym - 101128E Wooden Signs DP
题目大意: 一共n块木板,前两个数给出最底下木块的两个端点,后面n-1个数给出第i层的一个固定端点,问你木块的所有放置情况. 分析: 状态: d[i][j]表示第i个木块,第i-1块木板的未固定端点为 ...
- CSS水平居中与垂直居中的方法
一.水平居中 1.行内元素水平居中 在父元素里添加text-align:center即可.代码如下: <style> .container-1 { height: 50px; border ...
- java:编写jar包加密工具,防止反编译
懒人方案 网盘: 链接:https://pan.baidu.com/s/1x4OB1IF2HZGgtLhd1Kr_AQ提取码:glx7 网盘内是已生成可用工具,下载可以直接使用,使用前看一下READ. ...
- QT. 学习之路 二
Qt 的信号槽机制并不仅仅是使用系统提供的那部分,还会允许我们自己设计自己的信号和槽. 举报纸和订阅者的例子:有一个报纸类 Newspaper,有一个订阅者类 Subscriber.Subscribe ...