2020年1月10日 星期五

ASP.NET Core Blazor SynchronizationContext 同步內容

ASP.NET Core Blazor SynchronizationContext 同步內容

更多關於 Blazor 教學影片,可以參考 Blazor 教學影片播放清單 或者 Blazor 快速體驗教學影片撥放清單。也歡迎訂閱本 .NET / Blazor / Xamarin.Forms 影片頻道 。


在這篇文章中,將要來實際體驗一下,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 下來執行,這樣,就不會發生問題了。


沒有留言:

張貼留言