2019年1月16日 星期三

TPL TAP 1 透過 Task.Status 取得正在執行中的工作狀態


TPL TAP 1 透過 Task.Status 取得正在執行中的工作狀態

當需要進行 Task 非同步的計算,可以選擇這些方法:建立一個 Task 物件 ,呼叫該物件的 Task.Start 方法、或者使用 TaskFactory.StartNew 來取得一個 Task 物件,又或者可以使用 Task.Run 方法來啟動一個 Task 非同步工作。
在這篇文章的範例中,則是使用 Task.Run 靜態方法,建立一個委派非同步工作,不過,在這個委派方法中,則是只有一行的程式碼,那就是拋出一個例外異常;由於在 Task 工作內所發生的例外異常,會被 Task 物件捕捉起來,並不會造成該應用程式異常結束,不過,在設計這樣的應用程式的時候,該如何知道這個工作發生了例外異常呢?在 Task 物件內,可以透過 Task.Status 這個屬性來得知該工作的執行結果或者當時的狀態。
其中 Task.Status 共會有這些列舉值 : Canceled , Created , Faulted , RanToCompletion , Running , WaitingForActivation , WaitingForChildrenToComplete , WaitingToRun
在底下的範例程式碼中,在主執行緒下會先使用 Task.Run 建立一個非同步委派工作,接著,主執行緒會休息 800ms ,最後,會顯示這個工作物件的狀態與最後結果的相關屬性值,分別是:IsCompleted 表示這個工作已經正常執行完成、 IsCanceled 這個工作取消了、最後是 IsFaulted 表示這個工作在執行上產生了例外異常。
C Sharp / C#
var fooTask = Task.Run( () =>
{
    throw new Exception("發生了例外異常");
});
Thread.Sleep(800);
Console.WriteLine($"Status : {fooTask.Status}");
Console.WriteLine($"IsCompleted : fooTask.IsCompleted}");
Console.WriteLine($"IsCanceled : fooTask.IsCanceled}");
Console.WriteLine($"IsFaulted : {fooTask.IsFaulted}");
var exceptionStatusX = (fooTask.Exception == null) ?"沒有 AggregateException 物件" : "有 ggregateException 物件";
Console.WriteLine($"Exception : {exceptionStatusX}")
Console.WriteLine("Press any key for continuing...")
Console.ReadKey();
現在,透過 Visual Studio 2017 的除錯組態進行這個範例程式碼除錯與執行, 可以,竟然偶而會看到底下的輸出結果,也就是看到該工作的狀態為 WaitingForActivation,想要不看這樣不正常的結果,因此,當要執行這個範例程式碼,請不要使用 Visual Studio 2017 來進行執行,因為,這樣會有可能得到 fooTask 物件的 Status 狀態值為 WaitingForActivation,所以,請在命令提示字元視窗下來執行。
Console
Status : WaitingForActivation
IsCompleted : False
IsCanceled : False
IsFaulted : False
Exception : 沒有 AggregateException 物件
Press any key for continuing...
當把這個範例程式碼,直接透過 命令提示字元視窗下來執行,此時,就會看到了所期望的結果,這個非同步委派工作最後的工作狀態應該是 Faulted,並且 Exception 這個屬性是有物件的。
Console
Status : Faulted
IsCompleted : True
IsCanceled : False
IsFaulted : True
Exception : 有 AggregateException 物件
Press any key for continuing...


2018年12月6日 星期四

Blazor 4 Bootstrap 對話窗顯示與關閉練習

Blazor 4 Bootstrap 對話窗顯示與關閉練習

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

通常在進行開發一個類似 CRUD 的應用程式,使用者可能會點選某一筆紀錄,接著進行修該該紀錄的內容,接著就會點選 儲存 按鈕,此時大多會在網頁上顯示一個對話窗,詢問使用者是否要儲存該筆紀錄,不會使用者點選了 確定 或者 放棄 按鈕,該對話窗將會從螢幕上再度隱藏並且消失了。在這篇文章中,將會說明如何使用 Blazor 開發出這樣的應用,當然,還是秉持著完全都使用 .NET C# 的方式,而沒有使用到 JavaScript 來進行開發的精神;在這裡使用了 Bootstrap Modal 功能,來模擬使用者要刪除一筆員工紀錄的時候,會顯示一個對話窗詢問使用者,真的要刪除這筆紀錄嗎?該對話窗內會有該員工紀錄的詳細資料,並且還有兩個按鈕,分別是 是 與 否,而不論使用者點選了哪個按鈕,在這個元件上都會有一個 .NET C# 的按鈕事件綁定在一起。本篇文章的範例原始碼,可以從 BlazorModal 取得。

建立測試專案

現在可以開始建立第一個 Blazor 開發專案。
  • 啟動 Visual Studio 2017
  • 點選功能表的 [檔案] > [新增] > [專案] 功能表選項
  • 在 [新增專案] 對話窗中左邊區域,選擇 [已安裝] > [Visual C#] > [Web] > [ASP.NET Core Web 應用程式]
  • 在對話窗的下方的 [名稱] 欄位中,輸入這個練習專案的名稱 BlazorModal
  • 在對話窗的下方的 [位置] 欄位中,選擇這個專案要儲存的檔案路徑
  • 最後點選對話窗的右下方 [確定] 按鈕
  • 在 [新增 ASP.NET Core Web 應用程式] 對話窗左上方區域,在第一個下拉選單,選擇 [.NET Core] 在第二個下拉選單,請選擇最新的 ASP.NET Core 版本,在現在這個時間點,可以選擇 [ASP.NET Core 2.1]
  • 在對話窗中間區域,請點選 [Blazor] 這個項目
  • 最後點選對話窗的右下方 [確定] 按鈕

修正 Counter 元件,發佈特定事件通知

為了要做到上面提到的效果,在這裡進行修正了 Counter 元件的原始碼,當使用者按下 Click me 按鈕,且 currentCount 變數值為偶數,則將會顯示出來這個對話窗。
該對話窗已經宣告在這個元件上,不過,預設因為變數 ShowDialog 為 false,所以,該對話窗的內容不會顯示在網頁上,因此,當 currentCount 變數值為偶數的時候,將會把 ShowDialog 變數值為 true,也因此<div class="modal " tabindex="-1" style="display:block" role="dialog">...</div> 這些 HTML 標記就會顯示在網頁上,也就是該對話窗內容。
在該對話窗上的兩個回應按鈕,也透過了 Blazor 的按鈕事件綁定方式,綁定到該元件內的特定方法,例如,對於 是 這個按鈕,將會使用 <button class="btn btn-danger" onclick="@CloseModalYes">是</button> 這樣的標籤來宣告,當按下了這個按鈕之後,將會執行該元件內的 CloseModalYes 委派事件方法,此時,該變數 DeleteResult 將會設定為 是的,刪除這筆員工資料 這個文字字串,而該變數也綁定在網頁之上,因此,在網頁上也會看到這個文字;而對於 否 按鈕,將會使用 <button class="btn btn-warning" onclick="@CloseModalNo">否</button> 這個 HTML 標籤來宣告,當 CloseModalNo 方法被觸發之後,因為變數 DeleteResult 將會設定為 不,放棄刪除這筆員工資料 這個文字字串,而該變數也綁定在網頁之上,因此,在網頁上也會看到這個文字。
現在,請依照底下說明來修正專案程式碼
  • 請打開 [Pages] 資料夾內的 [Counter.cshtml] 檔案
  • 使用底下程式碼替換掉 [Counter.cshtml] 檔案內容
 Pages > Counter.cshtml
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

<p>刪除選擇:@DeleteResult</p>

<div class="modal" role="dialog">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title">Modal title</h4>
            </div>
            <div class="modal-body">
                <p>Contents go here...</p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>
@if (ShowDialog)
{
    <div class="modal " tabindex="-1" style="display:block" role="dialog">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h3 class="modal-title">刪除員工資料</h3>
                </div>
                <div class="modal-body">
                    <h4>你確定要刪除這筆員工資料嗎 ??</h4>
                    <table class="table">
                        <tr>
                            <td>姓名</td>
                            <td>@emp.Name</td>
                        </tr>
                        <tr>
                            <td>性別</td>
                            <td>@emp.Gender</td>
                        </tr>
                        <tr>
                            <td>部門</td>
                            <td>@emp.Department</td>
                        </tr>
                        <tr>
                            <td>城市</td>
                            <td>@emp.City</td>
                        </tr>
                    </table>
                </div>
                <div class="modal-footer">
                    <button class="btn btn-danger" onclick="@CloseModalYes">是</button>
                    <button class="btn btn-warning" onclick="@CloseModalNo">否</button>
                </div>
            </div>
        </div>
    </div>
}


@functions {
    int currentCount = 0;
    bool ShowDialog = false;
    string DeleteResult = "";

    public class Empolyee
    {
        public string Name { get; set; }
        public string Gender { get; set; }
        public string Department { get; set; }
        public string City { get; set; }
    }
    Empolyee emp = new Empolyee()
    {
        Name = "Vulcan Lee",
        Gender = "M",
        City = "Kaohsiung",
        Department = "IT"
    };

    void IncrementCount()
    {
        currentCount++;
        DeleteResult = "";

        if (currentCount % 2 == 1)
        {
            ShowDialog = true;
        }
    }

    void CloseModalYes()
    {
        ShowDialog = false;
        DeleteResult = "是的,刪除這筆員工資料";
    }

    void CloseModalNo()
    {
        ShowDialog = false;
        DeleteResult = "不,放棄刪除這筆員工資料";
    }
}

執行結果

現在,請執行這個專案,點選左邊側邊攔的 Counter 項目,接著在網頁中間來點選 Click me 這個按鈕,現在將會發現到,若 currentCount 這個變數為奇數的時候,網頁上將會出現了 刪除員工資料 這個對話窗
若在對話窗中點選 是 這個按鈕,則該對話窗將會消失,且網頁上會出現 是的,刪除這筆員工資料 文字內容
若在對話窗中點選 否 這個按鈕,則該對話窗將會消失,且網頁上會出現 不,放棄刪除這筆員工資料 文字內容




2018年12月2日 星期日

Blazor 3 使用事件聚合器來動態顯示或者隱藏控制練習

Blazor 3 使用事件聚合器來動態顯示或者隱藏控制練習

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

當在使用 Blazor 開發框架進行開發的時候,將會設計許多的 元件 Component ,也就是網頁中的特定 UI 畫面,藉由組合這些 元件 就會形成整個網頁內容;然而,有些時候將會需要在某個 元件A 中進行操作的時候,想要變更其他 元件B 的顯示狀態,也許 元件B 是 元件A 的 父元件或者是 子元件,這個時候將會有幾個技術可以選擇。第一個就是透過 JavaScript 來變更網頁上的 DOM 項目 Element 的 屬相 Attribut 或者變更其 CSS 設定;另外就是直接使用 .NET C# 中的技術,不去使用 JavaScript 程式語言,這樣對於 .NET C# 的開發者而言,可以更佳的輕鬆、自在的使用自己所孰悉的技術。
在 .NET C# 開發環境下,想要完成這樣的需求,可以使用 委派 Delegate 或者 事件 Event,然而對於這兩個技術想要在 Blazor 開發環境下來使用,讓不同的階層的 元件 可以彼此溝通訊息,對於 委派 而言,可以透過元件參數傳遞委派到子元件內,而對於事件而言,開發者必須宣告一個靜態事件,透過這樣全域靜態方法,讓各個子元件可以訂閱與觸發特定的事件,但是,這樣的設計方式也是非常的不好,因為這個靜態事件會存在於整個應用程式生命週期內,若有個子元件訂閱了這個事件,並且該子元件不再使用到了,該子元件必須要解除訂閱這個事件,否則,該子元件物件是沒有辦法被 .NET CLR 資源回收 Garbage Collection GC (關於 GC 的內容,可以參考 記憶體回收的基本概念 ),並且會有記憶體洩漏 Memory Leak 的嚴重問題產生。
在這篇文章將會使用 事件聚合器 Event Aggregator 這個設計模式,提供各 子元件 間的通訊通知之用,在事件聚合器設計模式下,提供了 訂閱 Subscribe 事件與 發布 Publish 事件兩個方法,當使用者執行了 發布 特定事件的時候,所有 訂閱 該特定事件的物件,就可以執行其對應的程式碼。不過,在這裡將不會說明如何從無到有的設計出 事件聚合器 這樣的設計模式程式碼,因為,我們不需要為了要使用輪子,而去發明另外一個輪子;在這裡將會從 Prism 這個開發框架內,抽取出該 Prism 所設計的 事件聚合器程式碼,並且在這個範例專案中來使用。
使用 Prism 所提供的 事件聚合器 程式碼的好處是:可以使用相依性注入的方式來注入 IEventAggregator 的具體實作物件、對於所綁定特定事件的訂閱方法,採用的 弱式參考 WeakReference 的方式來訂閱,因此,當某個 子元件 在 .NET 環境下不被在使用的時候,不會因為該 子元件 內還有訂閱 事件聚合器 內的某個事件,而導致該 子元件 物件不會被 .NET CLR 資源回收 Garbage Collection GC ,這是因為採用的 弱式參考 架構來訂閱事件,所以,不再使用到的 子元件 還是會被 .NET CLR 資源回收 Garbage Collection 機制進行從記憶體內回收該物件所佔用的記憶體空間。
這個說明範例將會修改 Blazor 專案範本建立的專案,修正該網頁的最上方會有一個 Login 按鈕,當使用者在 Counter 元件中點選按鈕,且當時的計數器值為偶數的時候,Login 按鈕會隱藏起來,而 Logout 按鈕會顯示出來,反之若當時計數器值為奇數的時候,Login 按鈕便會顯示出來,Logout 按鈕就會隱藏起來;而在這裏的顯示與隱藏功能,將會使用 Bootstrap 4 內宣告的 collapse 來實作出來, 本篇文章的範例原始碼,可以從 BlazorEventAggregator 取得。

建立測試專案

現在可以開始建立第一個 Blazor 開發專案。
  • 啟動 Visual Studio 2017
  • 點選功能表的 [檔案] > [新增] > [專案] 功能表選項
  • 在 [新增專案] 對話窗中左邊區域,選擇 [已安裝] > [Visual C#] > [Web] > [ASP.NET Core Web 應用程式]
  • 在對話窗的下方的 [名稱] 欄位中,輸入這個練習專案的名稱 BlazorEventAggregator
  • 在對話窗的下方的 [位置] 欄位中,選擇這個專案要儲存的檔案路徑
  • 最後點選對話窗的右下方 [確定] 按鈕
  • 在 [新增 ASP.NET Core Web 應用程式] 對話窗左上方區域,在第一個下拉選單,選擇 [.NET Core] 在第二個下拉選單,請選擇最新的 ASP.NET Core 版本,在現在這個時間點,可以選擇 [ASP.NET Core 2.1]
  • 在對話窗中間區域,請點選 [Blazor] 這個項目
  • 最後點選對話窗的右下方 [確定] 按鈕
  • 使用滑鼠右擊在最上方的方案節點,選擇 [加入] > [新增專案]
  • 在 [新增專案] 對話窗中,點選左方的 [已安裝] > [Visual C#]
  • 接著,在對話窗的中間,點選 [類別庫 .NET Standard]
  • 在對話窗下方的名稱欄位,輸入 EventAggreators ,最後點選 [確定] 按鈕,完成建立這個 .NET Standard 類別庫
  • 請將 BlazorEventAggregator 這個 Github Repository 內專案名稱為 EventAggreators 下的 Events 目錄,複製到剛剛建立的 EventAggreators 專案下。
  • 滑鼠右擊 BlazorEventAggregator 專案內的 [相依性] 節點,選擇 [加入參考]
  • 當 [參考管理員] 對話窗出現之後,點選左方的 [專案] 節點,在勾選中間的 EventAggregators 組件名稱
  • 點選 [確定] 按鈕
  • 底下是完成後的專案架構

進行 Prism 事件聚合器的 DI 容器註冊

當使用 事件聚合器 的時候,在這個專案內需要有個全域的 事件聚合器 物件,這樣才能夠讓各個 子元件 來進行訂閱特定事件的需求;在 Blazor 專案內,將會使用 IoC 容器 Container 機制進行 事件聚合器 介面與具體實作類別的註冊,而在每個 子元件 若要透過 事件聚合器 進行特定事件的訂閱或者發布的時候,就可以注入 IEventAggregator 這個介面,便可以取得 Prism 事件聚合器 的實作物件。
  • 打開專案內的 [StartUp.cs] 檔案
  • 找到 [ConfigureServices] 方法,使用 AddSingleton 方法來進行註冊,這裡可以使用 services.AddSingleton<IEventAggregator, EventAggregator>(); 這個方法。
 Startup.cs
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IEventAggregator, EventAggregator>();
    }
    public void Configure(IBlazorApplicationBuilder app)
    {
        app.AddComponent<App>("app");
    }
}

建立 事件聚合器 會用到的 事件資料模型

接下來要建立兩個 事件聚合器 的事件 ShowLoginEvent 與 ShowLogoutEvent 兩個類別,這兩個類別都需要繼承 PubSubEvent 這個類別,其中泛型型別的 T 為該特定事件發布與觸發的時候,所要傳送與接收的資料型別。
  • 滑鼠右擊 BlazorEventAggregator 專案節點,選擇 [加入] > [新增資料夾],並且輸入 [Models] 資料夾名稱
  • 建立 ShowLoginEvent 事件類別
    • 滑鼠右擊 [Models] 資料夾節點,選擇 [加入] > [類別]
    • 在 [新增項目] 對話窗中,點選 [已安裝] > [ASP.NET Core] > [密碼] > [類別] 選項,接著,在下方名稱欄位,輸入 ShowLoginEvent.cs ,最後點選右下方的 [新增] 按鈕
  • 將底下程式碼輸入到剛剛建立的 ShowLoginEvent 類別內
 Models > ShowLoginEvent.cs
public class ShowLoginEvent : PubSubEvent<ShowLoginEventPayload>
{
}
public class ShowLoginEventPayload
{
    public bool IsShow { get; set; }
}
  • 建立 ShowLogoutEvent 事件類別
    • 滑鼠右擊 [Models] 資料夾節點,選擇 [加入] > [類別]
    • 在 [新增項目] 對話窗中,點選 [已安裝] > [ASP.NET Core] > [密碼] > [類別] 選項,接著,在下方名稱欄位,輸入 ShowLogoutEvent.cs ,最後點選右下方的 [新增] 按鈕
  • 將底下程式碼輸入到剛剛建立的 ShowLogoutEvent 類別內
 Models > ShowLogoutEvent.cs
public class ShowLogoutEvent : PubSubEvent<ShowLogoutEventPayload>
{
}
public class ShowLogoutEventPayload
{
    public bool IsShow { get; set; }
}

修正網頁共用版型元件

在這裡將會要在網頁的最上方加入兩個按鈕: Login 與 Logout ,整個網頁在一啟動的時候,將只會顯示 Login 按鈕,而 Logout 按鈕將會收起隱藏起來,這裡將會透過 單向資料綁定 功能,在這裡兩個按鈕上分別使用 @ShowLogin 與 @ShowLogout 在 class 屬性上,進而來綁定 .NET C# 中的 ShowLogin / ShowLogout 這兩個變數。因此,當想要顯示某個 DOM 項目的時候,僅需要把特定變數的字串值設定為空字串,若要隱藏某個 DOM 項目 Element 的時候,便可以設定特定變數的字串值為 collapse。
那麼,要在哪個地方來進行變更特定 DOM 項目的顯示與隱藏的變數值設定呢?此時,先要宣告這個 元件 需要自動注入 IEventAggregator 這個 事件聚合器 物件,因此,在最上方使用 @inject IEventAggregator eventAggregator 陳述式,這樣,在這個元件內就可以使用 eventAggregator 這個變數來操作 Prism 的事件聚合器;而在接下來的設計過程,將會需要使用到剛剛建立的兩個事件類別,因此,使用 @using BlazorEventAggregator.Models 陳述式,宣告這個元件可以使用 BlazorEventAggregator.Models 命名空間內的型別。
最後,在這個元件內需要進行 事件 訂閱 的設計,也就是當其他元件要把登入按鈕隱藏起來,並且顯示登出按鈕,在這個訂閱事件內便可以處理這些需求,那麼,該在哪裡設計這樣的需球,這個時候需要 覆寫 override OnInit 這個方法,並且在這個方法內進行使用 事件聚合器 來訂閱特定事件的委派方法。
當要使用事件聚合器來訂閱特定事件,可以使用事件聚合器物件的 GetEvent 泛型方法,取得 特定事件型別,接著就可以使用 Subscribe 這個方法來指定一個委派方法,例如,eventAggregator.GetEvent<ShowLoginEvent>().Subscribe 這個敘述,將會使用事件聚合器物件,來進行 ShowLoginEvent 事件的訂閱。
最後,就可以在委派的訂閱事件方法內,根據使用者使用 Publish 方法所傳送過來的狀態物件,進行設定 ShowLogin 或者 ShowLogout 變數值,不過,最後一定需要執行 base.StateHasChanged(); 方法,這樣 ShowLogin 或者 ShowLogout 變數值 就會透單向資料綁定更新到網頁的 DOM 上了。關於更多關於 StateHasChanged 的說明,可以參考 Class BlazorComponent
現在,請依照底下說明來修正專案程式碼
  • 請打開 [Shared] 資料夾內的 [MainLayout.cshtml] 檔案
  • 使用底下程式碼替換掉 [MainLayout.cshtml] 檔案內容
 Shared > MainLayout.cshtml
@inherits BlazorLayoutComponent
@using Prism.Events
@using BlazorEventAggregator.Models
@inject IEventAggregator eventAggregator

<div class="sidebar">
    <NavMenu />
</div>

<div class="main">
    <div class="top-row px-8">
        <button class="btn btn-primary @ShowLogin">Login</button>
        <button class="btn btn-warning @ShowLogout">Logout</button>
        <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
    </div>

    <div class="content px-4">
        @Body
    </div>
</div>

@functions
{
    string ShowLogin = "";
    string ShowLogout = "collapse";

    protected override void OnInit()
    {
        eventAggregator.GetEvent<ShowLoginEvent>().Subscribe(x =>
        {
            if (x.IsShow == true)
            {
                ShowLogin = "";
            }
            else
            {
                ShowLogin = "collapse";
            }
            base.StateHasChanged();
        });

        eventAggregator.GetEvent<ShowLogoutEvent>().Subscribe(x =>
        {
            if (x.IsShow == true)
            {
                ShowLogout = "";
            }
            else
            {
                ShowLogout = "collapse";
            }
        });
        base.StateHasChanged();
    }
}

修正 Counter 元件,發佈特定事件通知

現在將會要來修正 Counter 元件,當使用者在 Counter 元件中點選按鈕,且當時的計數器值為偶數的時候,Login 按鈕會隱藏起來,而 Logout 按鈕會顯示出來,反之若當時計數器值為奇數的時候,Login 按鈕便會顯示出來,Logout 按鈕就會隱藏起來;而在這裏的顯示與隱藏功能。現在,先在該元件的最上方加入 @inject IEventAggregator eventAggregator 表示要注入 事件聚合器 物件與 @using BlazorEventAggregator.Models表示要參考 BlazorEventAggregator.Models 命名空間。
在按鈕事件 IncrementCount 中,判斷 currentCount 這個整數變數值為單數或者是偶數,接著可以使用 eventAggregator.GetEvent<ShowLoginEvent>().Publish 與 eventAggregator.GetEvent<ShowLogoutEvent>().Publish 方法,分別對 事件聚合器 物件送出兩個事件通知,這樣,只要有透過該 事件聚合器 物件訂閱的方法,就會被觸發執行了。
現在,請依照底下說明來修正專案程式碼
  • 請打開 [Pages] 資料夾內的 [Counter.cshtml] 檔案
  • 使用底下程式碼替換掉 [Counter.cshtml] 檔案內容
 Pages > Counter.cshtml
@page "/counter"
@using Prism.Events
@using BlazorEventAggregator.Models
@inject IEventAggregator eventAggregator

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

@functions {
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;

        if (currentCount % 2 == 0)
        {
            eventAggregator.GetEvent<ShowLoginEvent>().Publish(new ShowLoginEventPayload()
            {
                IsShow = true
            });
            eventAggregator.GetEvent<ShowLogoutEvent>().Publish(new ShowLogoutEventPayload()
            {
                IsShow = false
            });
        }
        else
        {
            eventAggregator.GetEvent<ShowLoginEvent>().Publish(new ShowLoginEventPayload()
            {
                IsShow = false
            });
            eventAggregator.GetEvent<ShowLogoutEvent>().Publish(new ShowLogoutEventPayload()
            {
                IsShow = true
            });
        }
    }
}

執行結果

現在,請執行這個專案,點選左邊側邊攔的 Counter 項目,接著在網頁中間來點選 Click me 這個按鈕,現在將會發現到,若 currentCount 這個變數為偶數的時候,上方的僅會出現 Login 按鈕
反之,若 currentCount 這個變數為奇數的時候,上方的僅會出現 Logout 按鈕