Blazor 應用程序是多個相互交互的 Blazor 組件的集合,我們還可以在其他父組件中使用子組件。在實際應用中,將數據或事件信息從一個組件傳遞到另一個組件是一種非常常見的場景。也許您有一個頁面,其中一個組件中發生的用戶操作需要更新其他組件中的某些 UI。這種類型的通信通常使用 EventCallback 委托進行處理。在本教程中,我們將介紹如何使用 EventCallback 在父組件和子組件之間進行通信。
以下是使用 EventCallback 從子組件到父組件進行通信所涉及的常見步驟。
- 在子組件中聲明 EventCallback 或 EventCallback 委托
- 將回調方法附加到子組件的 EventCallback或父組件中的 EventCallback
- 每當子組件想要與父組件通信時,它會使用以下方法之一調用父組件的回調方法
InvokeAsync(Object) – 如果我們使用
EventCallback InvokeAsync(T) – 如果我們使用 EventCallback
為了理解上述步驟,讓我們創建一個簡單的待辦事項列表示例。首先,在 Data 文件夾中創建以下 ToDo.cs 類。它是一個簡單的類,用於存儲每個待辦事項的 Title 和 Minutes 屬性。 Minutes 屬性指定完成特定 ToDo 項目需要多長時間。
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 屬性將存儲 ToDo 項目的列表,而 TotalMinutes 將存儲所有 ToDo 項目分鍾的總和。
public List<ToDo> ToDos { get; set; }
public int TotalMinutes { get; set; }
接下來,我們使用稱為 OnInitialized 的 Blazor 組件生命周期方法之一中的一些 ToDo 項對象初始化我們的 ToDo 列表。我們還調用了 UpdateTotalMinutes 方法,該方法僅計算 ToDos 列表中所有 ToDo 對象的 Sum of 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 循環內的父組件中設置該屬性。 子組件簡單地使用 元素生成一個表格行,並在表格單元格中顯示 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>
每次用戶單擊“添加分鍾”按鈕時,AddMinute 事件處理程序方法只會在 Minutes 屬性中添加 1 分鍾。
public async Task AddMinute(MouseEventArgs e)
{
Item.Minutes += 1;
}
再次運行應用程序並嘗試為每個待辦事項單擊“添加分鍾”按鈕。 您會注意到每個待辦事項顯示的分鍾數將開始增加,但頂部的總分鍾數屬性將保持不變。 這是因為 TotalMinutes 屬性是在父組件中計算的,而父組件不知道 Minutes 在子組件中是遞增的。
讓我們使用我上面提到的步驟在我們的示例中促進子級與父級的通信,以便每次我們在子組件中添加分鍾時,我們都能夠相應地更新父級 UI。
第 1 步:在子組件中聲明 EventCallback 或 EventCallback
第一步是在我們的子組件中聲明 EventCallback
[Parameter]
public EventCallback<MouseEventArgs> OnMinutesAdded { get; set; }
第二步:在子組件的 EventCallback 或父組件中的 EventCallback
在這一步中,我們需要使用我們在上面的步驟 1 中聲明的子組件的 OnMinutesAdded EventCallback 委托附加一個回調方法。
<ToDoItem Item="todo" OnMinutesAdded="OnMinutesAddedHandler" />
我們在此示例中使用的回調方法是 OnMinutesAddedHandler,該方法僅調用更新 TotalMinutes 屬性的相同 UpdateTotalMinutes 方法。
public void OnMinutesAddedHandler(MouseEventArgs e)
{
UpdateTotalMinutes();
}
第 3 步:每當子組件想要與父組件通信時,它都會使用 InvokeAsync(Object) 或 InvokeAsync(T) 方法調用父組件的回調方法。
在這一步中,我們需要調用父組件回調方法,最好的地方是 AddMinute 方法,因為我們希望在用戶每次單擊 Add Minute 按鈕時更新父組件 UI。
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();
}
}
在瀏覽器中運行應用程序並嘗試在任何 ToDo 項目中添加分鍾,您會注意到父組件會自動實時更新總分鍾數。