ASP.NET Core Blazor SynchronizationContext 同步內容
在這篇文章所提到的專案原始碼,可以從 GitHub 下載
現在,將在 Blazor 專案內建立一個 Razor 元件,該元件的 HTML 宣告標記與 C# 程式碼將會如下:
在這個 Razor 元件中,將會宣告三個按鈕,分別為
@using System.Threading
<h3>Blazor 有無使用同步內容之研究</h3>
<button class="btn btn-primary" @onclick="UsingBlazorEvent">使用 Blazor 內建事件機制</button>
<button class="btn btn-outline-danger" @onclick="UsingExternalThread">使用外部執行緒</button>
<button class="btn btn-success" @onclick="UsingExternalThreadBySynchronizationContext">使用外部執行緒但透過同步內容</button>
<div class="display-4 text-warning">
@Message
</div>
@code {
public string Message { get; set; }
async void UsingBlazorEvent()
{
Message = "使用 Blazor 內建事件機制更新內容";
}
async void UsingExternalThread()
{
await Task.Run(() =>
{
Message = "不使用同步內容來透過外部執行緒更新內容";
StateHasChanged();
});
}
async void UsingExternalThreadBySynchronizationContext()
{
await Task.Run(async () =>
{
await InvokeAsync(() =>
{
Message = "使用同步內容來透過外部執行緒更新內容";
StateHasChanged();
});
});
}
}
- 使用 Blazor 內建事件機制當這個按鈕被點選之後,將會立即更新 Message 這個屬性值內容,因為該屬性有綁定到 HTML 上,因此,將會透資料綁定的運作機制,重新更新轉譯樹 Render Tree 的內容,並且把有差異的地方,傳送到瀏覽器端來更新 DOM 內容,也就會造成瀏覽器的畫面有所更新。
- 使用外部執行緒當點選這個按鈕之後,將會透過
Task.Run
方法,產生一個新的執行緒,使用非同步的方式來更新 Message 這個屬性的內容值,由於當更新這個屬性值的時候,是在另外一個執行緒下,而不是在 SynchronizationContext 同步內容 下來執行,因此,當執行了StateHasChanged();
方法要來更新轉譯樹的時候,就會產生底下的錯誤訊息。
System.InvalidOperationException: 'The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.'
- 使用外部執行緒但透過同步內容正確的做法則是,當要更新資料綁定的 UI 內容的時候,記得要使用
InvokeAsync
方法,讓指定的委派方法可以在 SynchronizationContext 下來執行,這樣,就不會發生問題了。
更多關於 Blazor 教學影片,可以參考 Blazor 教學影片播放清單 或者 Blazor 快速體驗教學影片撥放清單。也歡迎訂閱本 .NET / Blazor / Xamarin.Forms 影片頻道 。
在這篇文章中,將要來實際體驗一下,Blazor 專案內的 同步內容 SynchronizationContext 使用注意事項與正確使用方式。