2026年2月16日 星期一

Blazor 使用 Ant Design Blazor 自訂主題範例

Blazor 使用 Ant Design Blazor 自訂主題範例

當在使用 AntDesign for Blazor 這個套件時,預設的主題是基於 Ant Design 的預設主題,但有時候我們可能會想要自訂主題以符合我們的品牌或設計需求。幸運的是,AntDesign for Blazor 提供了簡單的方式來自訂主題。

例如,底下的畫面是使用 AntDesign for Blazor 的預設主題所呈現的畫面:

現在想要變更原有的預設主題,

建立 Blazor 專案

  • 開啟 Visual Studio 2026
  • 選擇「建立新專案」
  • 在 [建立新專案] 視窗中,在右方清單內,找到並選擇「Blazor Web 應用程式」 項目
  • 然後點擊右下方「下一步」按鈕
  • 此時將會看到 [設定新的專案] 對話窗
  • 在該對話窗的 [專案名稱] 欄位中,輸入專案名稱,例如 [csBlazorCustomTheme]
  • 然後點擊右下方「下一步」按鈕
  • 接著會看到 [其他資訊] 對話窗
  • 在這個對話窗內,確認使用底下的選項
    • 架構:.NET 10.0 (或更新版本)
    • 驗證類型:無
    • 勾選 針對 HTTPS 進行設定
    • 互動式轉譯模式:伺服器
    • 互動功能位置:全球
    • 勾選 包和範例頁面
    • 勾選 不要使用最上層陳述式 (這是我的個人習慣)
    • 不要勾選 在應用程式 URL 中使用 .dev.localhost TLD
    • 不要勾選 在 .NET Aspire 協調流程中登錄
  • 然後點擊右下方「建立」按鈕
  • 現在,已經完成了這個 Blazor 專案的建立

安裝 AntDesign 套件

套件 AntDesign 是一個流行的 UI 組件庫,提供了許多現成的 UI 元件,可以幫助開發者快速建立美觀且功能豐富的使用者介面。在這個專案中,我們將使用 AntDesign Blazor 這個套件來實現自訂主題的功能。

使用底下方式進行安裝此套件

  • 在 Visual Studio 的「方案總管」視窗中,右鍵點擊專案名稱
  • 從右鍵選單中,選擇「管理 NuGet 套件」
  • 在 NuGet 套件管理器視窗中,切換到「瀏覽」標籤頁
  • 在搜尋框中,輸入 "AntDesign" 並按下 Enter 鍵
  • 從搜尋結果中,找到 "AntDesign" 套件 並點擊它
  • 在這裡的範例中,使用該套件的版本為 1.5.0
  • 在右側的詳細資訊面板中,點擊「安裝」按鈕

建立客製的主題

  • 在專案的根目錄下,建立一個新的資料夾,命名為 "wwwroot"
  • 在 "wwwroot" 資料夾內,建立一個新的 CSS 檔案,命名為 "site.css"
  • 在 "site.css" 檔案中,加入以下 CSS 內容:
:root {
    --ant-primary-color: #3b7f1a;
    --ant-primary-color-hover: #2b5814;
    --ant-primary-color-active: #3b7f1a;
    --ant-link-color: #1DA57A;
    --ant-success-color: #3b7f1a;
    --ant-warning-color: #9714fa;
    --ant-error-color: #ff6a00;
    --ant-font-size-base: 24px;
    --ant-line-height-base: 1.8;
    --ant-border-radius-base: 8px;
    /* 標題字體大小 (基於 24px) */
    --ant-font-size-h1: 48px; /* 2倍 */
    --ant-font-size-h2: 38px; /* 1.6倍 */
    --ant-font-size-h3: 31px; /* 1.3倍 */
    --ant-padding-xs: 10px;
    --ant-padding-sm: 12px;
    --ant-padding-md: 20px;
    --ant-padding-lg: 32px;
}

h1 {
    font-size: var(--ant-font-size-h1);
    line-height: 1.4;
    margin-bottom: 20px;
}

h2 {
    font-size: var(--ant-font-size-h2);
    line-height: 1.4;
}

h3 {
    font-size: var(--ant-font-size-h3);
    line-height: 1.5;
}

.ant-btn,
.ant-btn-default,
.ant-btn-primary,
.ant-btn-dashed,
.ant-btn-link,
.ant-btn-text,
.ant-btn-dangerous {
    font-size: var(--ant-font-size-base);
    padding: 8px 24px;
    height: auto;
    min-height: 48px;
    line-height: var(--ant-line-height-base);
}

.ant-btn-primary {
    background-color: var(--ant-primary-color);
    border-color: var(--ant-primary-color);
}

.ant-btn-primary:hover {
    background-color: var(--ant-primary-color-hover);
    border-color: var(--ant-primary-color-hover);
}

.ant-alert {
    font-size: var(--ant-font-size-base);
    padding: 12px 20px;
    line-height: var(--ant-line-height-base);
}

.ant-alert-message {
    font-size: var(--ant-font-size-base);
    line-height: var(--ant-line-height-base);
}

.ant-alert-icon {
    font-size: 28px;  /* 圖示稍大於文字 */
    line-height: 1.8;
}

.ant-alert-with-description {
    padding: 16px 24px;
}

.ant-alert-description {
    font-size: 20px;  /* 描述文字稍小 */
}

.ant-input,
.ant-select-selector,
.ant-picker {
    font-size: var(--ant-font-size-base);
    padding: 8px 16px;
    line-height: var(--ant-line-height-base);
}

body,
p,
span,
div {
    font-size: var(--ant-font-size-base);
    line-height: var(--ant-line-height-base);
  • 在專案根目錄下,找到 [App.razor] 檔案,並打開它
  • 在 [App.razor] 檔案中
  • 找到 </head> 加入以下程式碼:
<link href="css/site.css" rel="stylesheet" />

設定 AntDesign

  • 在專案根目錄下,找到 [App.razor] 檔案,並打開它
  • 在 [App.razor] 檔案中
  • 找到 </head> 加入以下程式碼:
<link href="_content/AntDesign/css/ant-design-blazor.css" rel="stylesheet">
  • 在 [App.razor] 檔案中
  • 找到 </body> 加入以下程式碼:
<script src="_content/AntDesign/js/ant-design-blazor.js"></script> 
<script antblazor-js></script>

修正 Component 頁面

  • 在專案根目錄下,找到 [Components] > [Pages] 目錄下
  • 找到並且打開 [Home.razor] 檔案
  • 在 [Home.razor] 檔案中,將原有的內容全,使用底下程式碼取代:
@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<Button Type="@ButtonType.Primary">主按钮</Button>
<Button Type="@ButtonType.Default">默认按钮</Button>
<Button Danger>危险按钮</Button>

<Alert Message="成功" Type="AlertType.Success" ShowIcon="true" />
<Alert Message="警告" Type="AlertType.Warning" ShowIcon="true" />
<Alert Message="错误" Type="AlertType.Error" ShowIcon="true" />

執行程式

首先先來看這個專案的執行結果:

  • 按下 F5 鍵或點擊「開始」按鈕來執行程式
  • 現在將會看到底下畫面 

 




Blazor 跳轉 1 : 動態路由參數,傳遞與接收路由參數

Blazor 跳轉 1 : 動態路由參數,傳遞與接收路由參數

使用 Blazor 開發框架進行開發 Web 專案的時候,經常會需要在不同的頁面之間進行跳轉,並且在跳轉的過程中,將一些參數傳遞給目標頁面,以便在目標頁面中根據這些參數來顯示相應的內容或進行相應的操作。這裡將會透過兩篇文章說明如何在不同的頁面間來傳遞這些參數,並且在目標頁面中來接收這些參數。

首先將會使用路由 Routing 的方式來進行傳遞參數,這裡將會在 URL 中來傳遞參數,並且在目標頁面中來接收這些參數。接著,在下一篇文章中,將會說明如何使用 Query String 的方式來傳遞參數,這裡將會在 URL 的查詢字串中來傳遞參數,並且在目標頁面中來接收這些參數。

透過底下的開發實作說明,將會說明如何在 Blazor 中來實現這些功能,並且在實際的開發過程中,將會提供一些程式碼範例來說明這些功能的實現方式。

建立 Blazor 專案

  • 開啟 Visual Studio 2026
  • 選擇「建立新專案」
  • 在 [建立新專案] 視窗中,在右方清單內,找到並選擇「Blazor Web 應用程式」 項目
  • 然後點擊右下方「下一步」按鈕
  • 此時將會看到 [設定新的專案] 對話窗
  • 在該對話窗的 [專案名稱] 欄位中,輸入專案名稱,例如 "csBlazorRoutingParameter"
  • 然後點擊右下方「下一步」按鈕
  • 接著會看到 [其他資訊] 對話窗
  • 在這個對話窗內,確認使用底下的選項
    • 架構:.NET 10.0 (或更新版本)
    • 驗證類型:無
    • 勾選 針對 HTTPS 進行設定
    • 互動式轉譯模式:伺服器
    • 互動功能位置:全球
    • 勾選 包和範例頁面
    • 勾選 不要使用最上層陳述式 (這是我的個人習慣)
    • 不要勾選 在應用程式 URL 中使用 .dev.localhost TLD
    • 不要勾選 在 .NET Aspire 協調流程中登錄
  • 然後點擊右下方「建立」按鈕
  • 現在,已經完成了這個 Blazor 專案的建立

建立 Product 資料模型

當 Blazor 專案建立好之後,接下來將會建立一個 Product 的資料模型,這個資料模型將會用來表示產品的相關資訊,例如產品的 ID、名稱、價格、庫存數量以及上架日期等。

  • 在專案根目錄下,滑鼠右擊 [Components] > [Pages] 資料夾
  • 從右鍵選單中,選擇「加入」>「新增項目」
  • 這裡將會使用 [顯示精簡檢視] 的方式來輸入要新增的項目
  • 在 [新增項目] 對話窗內的文字輸入盒內,輸入 [Product.cs]
  • 然後點擊「加入」按鈕

  • 現在,已經成功建立了 Product.cs 類別檔案
  • 接著,打開 Product.cs 類別檔案,並將以下程式碼複製貼上到該檔案中:
namespace csBlazorRoutingParameter.Components.Pages;

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public int StockQuantity { get; set; }
    public DateTime LaunchDate { get; set; }
}

建立 ProductService 服務

剛剛建立了一個 [Product] 的資料模型,接下來將會建立一個 ProductService 服務,這個服務將會用來提供一些產品的相關資訊,例如產品的清單等。這裡將會在 ProductService 服務中建立一個 GetProducts 方法,這個方法將會回傳所有產品清單,為了簡化這個範例內容,這裡將不會採用資料庫的存取方式來讀取這些產品清單,而是將這些產品紀錄儲存在記憶體中,這些產品清單將會用來在後續的頁面中來顯示產品的相關資訊。

  • 滑鼠右擊專案根目錄節點
  • 從右鍵選單中,選擇「加入」>「新增資料夾」
  • 輸入 [Services] 作為資料夾名稱,然後按下 Enter 鍵
  • 現在,已經成功建立了 [Services] 資料夾
  • 在專案根目錄下,滑鼠右擊 [Services] 資料夾
  • 從右鍵選單中,選擇「加入」>「新增項目」
  • 這裡將會使用 [顯示精簡檢視] 的方式來輸入要新增的項目
  • 在 [新增項目] 對話窗內的文字輸入盒內,輸入 [ProductService.cs]
  • 然後點擊「加入」按鈕
  • 現在,已經成功建立了 ProductService.cs 類別檔案
  • 接著,打開 ProductService.cs 類別檔案,並將以下程式碼複製貼上到該檔案中:
using csBlazorRoutingParameter.Components.Pages;

namespace csBlazorRoutingParameter.Services;

public class ProductService
{
    public List<Product> Products { get; set; } = new();
    public ProductService()
    {
        Products = new List<Product>
        {
            new Product { Id = 1, Name = "智慧型手機", Price = 15999, StockQuantity = 120, LaunchDate = new DateTime(2025, 1, 15) },
            new Product { Id = 2, Name = "筆記型電腦", Price = 32000, StockQuantity = 45, LaunchDate = new DateTime(2024, 11, 20) },
            new Product { Id = 3, Name = "無線耳機", Price = 3500, StockQuantity = 200, LaunchDate = new DateTime(2025, 3, 10) },
            new Product { Id = 4, Name = "智慧手錶", Price = 5999, StockQuantity = 75, LaunchDate = new DateTime(2025, 2, 5) },
            new Product { Id = 5, Name = "平板電腦", Price = 12500, StockQuantity = 60, LaunchDate = new DateTime(2024, 12, 1) },
            new Product { Id = 6, Name = "藍牙喇叭", Price = 2800, StockQuantity = 150, LaunchDate = new DateTime(2025, 4, 25) },
            new Product { Id = 7, Name = "遊戲主機", Price = 12000, StockQuantity = 30, LaunchDate = new DateTime(2024, 10, 15) },
            new Product { Id = 8, Name = "無線滑鼠", Price = 1200, StockQuantity = 180, LaunchDate = new DateTime(2025, 5, 10) },
            new Product { Id = 9, Name = "機械鍵盤", Price = 3200, StockQuantity = 90, LaunchDate = new DateTime(2025, 3, 15) },
            new Product { Id = 10, Name = "電競顯示器", Price = 8500, StockQuantity = 40, LaunchDate = new DateTime(2024, 9, 5) }
        };
    }
    public List<Product> GetProducts()
    {
        return Products;
    }
}

在這個 [ProductService] 服務中,建立了一個 [Products] 屬性,這個屬性用來儲存所有的產品清單,並且在建構子中初始化了這些產品清單。

另外,建立了一個 [GetProducts] 方法,這個方法用來回傳所有的產品清單。如此,便可以將這些資料顯示在網頁中。

將 ProductService 服務註冊到 DI 容器中

  • 打開 Program.cs 類別檔案
  • 在該檔案中,找到這個程式碼 var app = builder.Build();
  • 在這行程式碼的上方,加入底下這行程式碼,將 ProductService 服務註冊到 DI 容器中:
builder.Services.AddSingleton<Services.ProductService>();

建立 ProductListPage 頁面

現在已經建立了 [Product] 的資料模型,以及 [ProductService] 服務,接下來將會建立一個 [ProductListPage] 頁面,這個頁面將會用來顯示所有產品的清單。

接著,將會在每一筆產品紀錄上,提供一個連結,當使用者點選該連結時,將會跳轉到產品詳細資訊的頁面,並且在 URL 中傳遞該產品的 ID 參數。

  • 在專案根目錄下,滑鼠右擊 [Components] > [Pages] 資料夾
  • 從右鍵選單中,選擇「加入」>「新增項目」
  • 這裡將會使用 [顯示精簡檢視] 的方式來輸入要新增的項目
  • 在 [新增項目] 對話窗內的文字輸入盒內,輸入 [ProductListPage.razor]
  • 然後點擊「加入」按鈕
  • 現在,已經成功建立了 ProductListPage.razor 元件
  • 接著,打開 ProductListPage.razor 元件,並將以下程式碼複製貼上到該元件中:
@page "/ProductList"

@inject NavigationManager NavigationManager

@inject csBlazorRoutingParameter.Services.ProductService ProductService

<h3>產品清單</h3>

<table class="table table-striped">
    <thead>
        <tr>
            <th>產品 ID</th>
            <th>產品名稱</th>
            <th>價格</th>
            <th>庫存數量</th>
            <th>上架日期</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var product in products)
        {
            <tr class="cursor-pointer"
            @onclick="()=>OnProductSelected(product)">
                <td>@product.Id</td>
                <td>@product.Name</td>
                <td>@product.Price.ToString("C")</td>
                <td>@product.StockQuantity</td>
                <td>@product.LaunchDate.ToShortDateString()</td>
            </tr>
        }
    </tbody>
</table>

<style>
    .cursor-pointer {
        cursor: pointer;
    }
</style>

@code {

    private List<Product> products = new();

    protected override void OnInitialized()
    {
        products = ProductService.Products;
    }

    void OnProductSelected(Product product)
    {
        // 導航到產品詳細頁面,並傳遞產品 ID
        NavigationManager.NavigateTo($"/product/{product.Id}/345");
    }
}

在這個 [ProductListPage] 頁面中,使用了 @page 指令來定義這個頁面的路由為 "/ProductList",這樣當使用者訪問這個 URL 時,就會顯示這個頁面。在這個頁面中,使用了 @inject 指令來注入了 NavigationManager 服務以及 ProductService 服務,這樣就可以在這個頁面中來使用這些服務。 接著,在頁面中使用了一個 HTML 的 table 元素來顯示產品的清單,並且在每一筆產品紀錄上,提供了一個 @onclick 事件處理器,當使用者點選該產品紀錄時,將會呼叫 OnProductSelected 方法,並且在該方法中使用 NavigationManager 服務來導航到產品詳細頁面,並且在 URL 中傳遞該產品的 ID 參數。

在 @code 的 C# 程式碼區塊中,定義了一個 products 的私有欄位,用來儲存從 ProductService 服務中取得的產品清單。在 OnInitialized 方法中,從 ProductService 服務中取得產品清單並賦值給 products 欄位。接著,在 OnProductSelected 方法中,使用 NavigationManager 服務來導航到產品詳細頁面,並且在 URL 中傳遞該產品的 ID 參數,這裡使用的方式為 $"/product/{product.Id}/345",這樣在 URL 中就會包含該產品的 ID 參數,這樣在產品詳細頁面中就可以接收這個參數並且根據這個參數來顯示相應的產品資訊。

建立 ProductDetail 頁面

接下來,將會建立一個 [ProductDetail] 頁面,這個頁面將會用來顯示產品的詳細資訊。在這個頁面中,將會使用 @page 指令來定義這個頁面的路由,路由定義為 "/product/{id:int}",並且在路由中定義一個動態參數 {id},這個參數將會用來接收從產品清單頁面傳遞過來的產品 ID 參數。

接著,在這個頁面中,將會使用 ProductService 服務來根據接收到的產品 ID 參數來查詢對應的產品資訊,並且在頁面上顯示出該產品的詳細資訊。

  • 在專案根目錄下,滑鼠右擊 [Components] > [Pages] 資料夾
  • 從右鍵選單中,選擇「加入」>「新增項目」
  • 這裡將會使用 [顯示精簡檢視] 的方式來輸入要新增的項目
  • 在 [新增項目] 對話窗內的文字輸入盒內,輸入 [ProductDetail.razor]
  • 然後點擊「加入」按鈕
  • 現在,已經成功建立了 ProductDetail.razor 元件
  • 接著,打開 ProductDetail.razor 元件,並將以下程式碼複製貼上到該元件中:
@page "/product/{id:int}"
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Routing
@inject NavigationManager NavigationManager

@inject csBlazorRoutingParameter.Services.ProductService ProductService

<div class="container mt-4">
    @if (product != null)
    {
        <h3>產品詳細資訊</h3>
        <div class="card">
            <div class="card-body">
                <h5 class="card-title">@product.Name</h5>
                <div class="row mt-3">
                    <div class="col-md-6">
                        <p><strong>產品 ID:</strong> @product.Id</p>
                        <p><strong>價格:</strong> @product.Price.ToString("C")</p>
                        <p><strong>庫存數量:</strong> @product.StockQuantity</p>
                        <p><strong>上架日期:</strong> @product.LaunchDate.ToShortDateString()</p>
                    </div>
                </div>
            </div>
        </div>
    }
    else
    {
        <p>找不到指定產品。</p>
    }

    <div class="mt-3">
        <button class="btn btn-primary" @onclick="NavigateToProductList">返回產品清單</button>
    </div>
</div>

@code {
    [Parameter]
    public int Id { get; set; }

    private Product? product;

    // 當參數變更時執行
    protected override void OnParametersSet()
    {
        var products = ProductService.Products;
        product = products.FirstOrDefault(p => p.Id == Id);
    }

    // 返回產品清單頁面
    private void NavigateToProductList()
    {
        NavigationManager.NavigateTo("/ProductList");
    }
}

在這個頁面的 HTML 部分,透過了資料綁定機制來顯示產品的詳細資訊,並且提供了一個按鈕,當使用者點選該按鈕時,將會導航回產品清單頁面。

在程式碼內,使用了 [Parameter] 屬性來定義了一個 Id 的參數,這個參數用來接收從 URL 中傳遞過來的產品 ID 參數。在 OnParametersSet 方法中,從 ProductService 服務中取得所有的產品清單,並且根據接收到的 Id 參數來查詢對應的產品資訊,並且將該產品資訊賦值給 product 欄位,這樣在 HTML 部分就可以顯示出該產品的詳細資訊。

關於 Blazor 頁面生命週期內,將會有這些觸發事件:[OnInitialized]、[OnParametersSet]、[OnAfterRender] 等等,這些事件將會在頁面生命週期的不同階段被觸發,開發者可以根據實際的需求來選擇在這些事件中來執行相應的程式碼邏輯。一般來說,在頁面要顯示出來的時候,這些事件的觸發順序將會為 OnInitialized -> OnParametersSet -> OnAfterRender,當頁面上的參數變更時,將會觸發 OnParametersSet 事件,這樣就可以在該事件中來根據新的參數值來更新頁面上的內容。

執行程式

首先先來看這個專案的執行結果:

  • 按下 F5 鍵或點擊「開始」按鈕來執行程式
  • 在瀏覽器中,輸入 URL, https://localhost:7254/ProductList
  • 現在將會看到底下畫面 
  • 點選任何一個產品紀錄
  • 此時將會切轉到底下畫面,並且在畫面上顯示出該產品的 ID,此時的網址列 URL 將會轉變成為 https://localhost:7254/product/2