.NET 8 Blazor入門 - 2

by Vivid 30. 十月 2024 14:30


.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N241026603
出刊日期:2024/10/30

本篇文章將延續本站《.NET 8 Blazor入門 - 1》一文的情境,介紹如何使用Visual Studio 2022開發工具,一步、步帶領你建立一個.NET 8 Blazor的員工系統,使用SPA架構來進行資料的新增、刪除、修改與查詢作業。

回顧我們在《.NET 8 Blazor入門 - 1》一文建立的Blazor Web App專案,目前首頁「Home.razor」程式如下,使用表格顯示員工清單,不過在元件的@code程式碼區段之中,直接定義存放員工資料的「employees」陣列:

@page "/"
@using HRApp.Models
<PageTitle> HR App </PageTitle>

<table class = "table table-striped">
  <thead>
    <tr>
      <th> Employee ID </th>
      <th> Employee Name </th>
      <th> Birthday </th>
      <th> Marital Status </th>
      <th> Job Type </th>
    </tr>
  </thead>
  <tbody>
    @foreach ( var employee in employees ) {
      <tr>
        <td> @employee.Id </td>
        <td> @employee.EmployeeName </td>
        <td> @employee.BirthDay.ToShortDateString( ) </td>
        <td> @( employee.IsMarried ? "Married" : "Single" ) </td>
        <td> @employee.JobType </td>
      </tr>
    }
  </tbody>
</table>

@code {
  private Employee[] employees = new Employee[] {
        new Employee { Id = 1, EmployeeName = "John Doe", BirthDay = new DateOnly(1990, 5, 15), IsMarried = true, JobType = "Manager" },
        new Employee { Id = 2, EmployeeName = "Jane Smith", BirthDay = new DateOnly(1985, 10, 20), IsMarried = false, JobType = "Developer" },
        new Employee { Id = 3, EmployeeName = "Mike Johnson", BirthDay = new DateOnly(1992, 3, 8), IsMarried = true, JobType = "Designer" },
        new Employee { Id = 4, EmployeeName = "Emily Davis", BirthDay = new DateOnly(1998, 7, 12), IsMarried = false, JobType = "Tester" },
        new Employee { Id = 5, EmployeeName = "David Wilson", BirthDay = new DateOnly(1994, 9, 25), IsMarried = true, JobType = "Developer" }
  };
}

 


這不是一個好做法,例如,若有兩個以上的元件要使用到相同的員工資料,目前的做法無法共用這些資料,我們應該將提供資料的程式抽出來寫在另外一個類別之中,例如包裝成服務(Service)的程式碼。


設計服務


服務類別建議放在「Services」資料夾中。從Visual Studio開發工具>「Solution Explorer」視窗>專案名稱上方按滑鼠右鍵,從快捷選單選擇「Add」>「New Folder」選項,將新建立的資料夾命名為「Services」。

在「Solution Explorer」視窗 >「Services」資料夾名稱上按滑鼠右鍵,從快捷選單選擇「Add」> 「Class」,開啟「Add New Item」對話盒,選取「Class」選項,設定名稱為「EmployeesService.cs」,然後按下「Add」按鈕,建立新類別。然後在類別中加入以下程式碼,定義一個名為「EmployeesService」的服務類別,該類別負責管理員工資料。:

using HRApp.Models;

namespace HRApp.Services {
  public class EmployeesService {

    private readonly List<Employee> employees = [
        new Employee { Id = 1, EmployeeName = "John Doe", BirthDay = new DateOnly(1990, 5, 15), IsMarried = true, JobType = "Manager" },
        new Employee { Id = 2, EmployeeName = "Jane Smith", BirthDay = new DateOnly(1985, 10, 20), IsMarried = false, JobType = "Developer" },
        new Employee { Id = 3, EmployeeName = "Mike Johnson", BirthDay = new DateOnly(1992, 3, 8), IsMarried = true, JobType = "Designer" },
        new Employee { Id = 4, EmployeeName = "Emily Davis", BirthDay = new DateOnly(1998, 7, 12), IsMarried = false, JobType = "Tester" },
        new Employee { Id = 5, EmployeeName = "David Wilson", BirthDay = new DateOnly(1994, 9, 25), IsMarried = true, JobType = "Developer" }
      ];

    public Employee[] GetEmployees( ) => [.. employees];
  }
}
 


「EmployeesService」類別中定義了一個私有且唯讀的「employees」集合,並初始化了五個「Employee」物件。每個「Employee」物件都有「Id」、「EmployeeName」、「BirthDay」、「IsMarried」和「JobType」屬性。
「Employee」類別中定義了一個「GetEmployees」方法,回傳一個「Employee」陣列,其中包含了「employees」集合中的所有員工資料。

修改「Home.razor」元件程式如下:

@page "/"
@using HRApp.Models
@using HRApp.Services
<PageTitle> HR App </PageTitle>

@if ( employees is null ) {
  <p> <em> Loading... </em> </p>
}
else {
  <table class = "table table-striped">
    <thead>
      <tr>
        <th> Employee ID </th>
        <th> Employee Name </th>
        <th> Birthday </th>
        <th> Marital Status </th>
        <th> Job Type </th>
      </tr>
    </thead>
    <tbody>
      @foreach ( var employee in employees ) {
        <tr>
          <td> @employee.Id </td>
          <td> @employee.EmployeeName </td>
          <td> @employee.BirthDay.ToShortDateString( ) </td>
          <td> @( employee.IsMarried ? "Married" : "Single" ) </td>
          <td> @employee.JobType </td>
        </tr>
      }
    </tbody>
  </table>
}

@code {
  private EmployeesService service = new( );
  private Employee[]? employees;

  protected override void OnInitialized( ) {
    employees = service.GetEmployees( );
  }
}






因為元件以非同步方式執行,我們需要在取得員工陣列的情況下再顯示表格,可利用「@if」區塊程式碼檢查「employees」是否為「null」。如果是,則顯示「Loading...」 信息;否則則顯示員工列表。

「@code」區塊程式碼中建立了一個「EmployeesService」物件。「OnInitialized」方法會在元件初始化時自動被叫用,當被叫用時,便從「EmployeesService」物件的「GetEmployees」方法取得員工資料放到「employees」變數。

在 Visual Studio 2022 開發工具中,按下 鍵盤CTRL+F5組合鍵 執行網站。目前首頁顯示的是專案中「Home.razor」元件的執行結果,請參考下圖所示:



圖 1:「Home.razor」元件的執行結果。


新增員工資料


現在我們來談談如何新增員工資料,目前專案中「Employee」模型類別的定義如下:

namespace HRApp.Models {
  public class Employee {
    public int Id { get; set; }
    public required string EmployeeName { get; set; }
    public DateOnly BirthDay { get; set; }
    public bool IsMarried { get; set; }
    public required string JobType { get; set; }
  }
}
 


為了搜集有效的資料,當使用者在網頁中新增員工資料時,我們希望「JobType」要搭配下拉式選單讓使用者從現有清單中挑選員工類型,因此我們另外在「Models」資料夾定義一個「EmployeeDetails」模型類別對應到使用者介面,其中包含「string?」型別的「JobTypeId」屬性:

namespace HRApp.Models {
  public class EmployeeDetails {
    public int Id { get; set; }
    public required string EmployeeName { get; set; }
    public DateOnly BirthDay { get; set; }
    public bool IsMarried { get; set; }
    public string? JobTypeId { get; set; }
  }
}




從Visual Studio開發工具>「Solution Explorer」視窗>「Pages」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」>「Razor Component」選項,建立元件,將新建立的檔案命名為「EditEmployee.razor」。

「EditEmployee.razor」元件包含了負責顯示和編輯員工資料的表單,在「EditEmployee.razor」加入以下程式碼:

@page "/editemployee"
@using Models
<PageTitle> New Employee </PageTitle>
<h3> New Employee </h3>

<div class = "row">
  <div class = "col-md-8 col-lg-12">
    <EditForm Model = "@employee" FormName = "editEmployee">
      <div class = "mb-3">
        <label for = "employeeName" class = "form-label"> Employee Name : </label>
        <InputText id = "employeeName" @bind-Value = "employee.EmployeeName" class = "form-control" />
      </div>
      <div class = "mb-3">
        <label for = "birthDay" class = "form-label"> Birth Day : </label>
        <InputDate id = "birthDay" @bind-Value = "employee.BirthDay" class = "form-control" />
      </div>
      <div class = "mb-3">
        <label for = "isMarried" class = "form-label"> Is Married : </label>
        <InputCheckbox id = "isMarried" @bind-Value = "employee.IsMarried" class = "form-check-input" />
      </div>
      <div class = "mb-3">
        <label for = "jobType" class = "form-label"> Job Type : </label>
        <InputSelect id = "jobType" @bind-Value = "employee.JobTypeId" class = "form-select">
        </InputSelect>
      </div>
      <button type = "submit" class = "btn btn-primary"> Submit </button>
    </EditForm>
  </div>
</div>

@code {

  private EmployeeDetails employee { get; set; } = new EmployeeDetails( ) {
      EmployeeName = string.Empty ,
      BirthDay = new DateOnly( 2000 , 1 , 1 )
    };
}



程式說明如下,「@page 」這行程式碼碼指定了這個元件的路由為「/editemployee」:

@page "/editemployee"


以下的「div」元素使用 Bootstrap 的網格系統(Grid System)來設計表單版面佈局(Layout):


<div class = "row">
  <div class = "col-md-8 col-lg-12">
...


下面這個「EditForm」元件繫結到「employee」模型,並且使用「FormName」將表單名稱為「editEmployee」:


<EditForm Model = "@employee" FormName = "editEmployee">


下面這行程式碼使用「label」標籤顯示「Employee Name :」提示字串:

<label for = "employeeName" class = "form-label"> Employee Name : </label>



下面這行程式碼使用「InputText」元件繫結到「employee.EmployeeName」屬性:

<InputText id = "employeeName" @bind-Value = "employee.EmployeeName" class = "form-control" />



下面這行程式碼使用「InputDate」元件繫結到「employee.BirthDay」屬性:

<InputDate id = "birthDay" @bind-Value = "employee.BirthDay" class = "form-control" />



下面這行程式碼使用「InputCheckbox」元件繫結到「employee.IsMarried」屬性:

<InputCheckbox id = "isMarried" @bind-Value = "employee.IsMarried" class = "form-check-input" />



下面這行程式碼使用「InputSelect」元件繫結到「employee.JobTypeId」屬性:

<InputSelect id = "jobType" @bind-Value = "employee.JobTypeId" class = "form-select">
     </InputSelect>



這個按鈕用來提交表單:

<button type = "submit" class = "btn btn-primary"> Submit </button>




「@code」區塊中定義並初始化了一個「EmployeeDetails」物件,並設定「EmployeeName」、「BirthDay」屬性的初始值:

@code {
  private EmployeeDetails employee { get; set; } = new EmployeeDetails( ) {
      EmployeeName = string.Empty ,
      = new DateOnly( 2000 , 1 , 1 )
    };
}


在 Visual Studio 2022 開發工具中,按下 鍵盤CTRL+F5組合鍵執行網站。在瀏覽器輸入URL:「http://localhost:埠號/editemployee」,將顯示修改員工的畫面,執行結果請參考下圖所示:



圖 2:修改員工資料畫面。



產生下拉式清單選項


現在我們要在員工資料修改畫面中,將員工類型的「JobTypeId」變成下拉式清單,讓使用者從清單中選擇,避免使用者輸入無效資料。在「Models」資料夾加入一個「JobType」類別,然後加入程式碼如下:

namespace HRApp.Models {
  public class JobType {
    public int Id { get; set; }
    public required string Type { get; set; }
  }
}
 

定義了一個公開的「JobType」類別,有兩個屬性:「Id」用來唯一標識每個工作類型;「Type」用來描述工作類型的名稱,並且它是必需的、不可不填。

在「Services」資料夾加入一個「JobTypeService」類別,然後加入程式碼如下:

using HRApp.Models;

namespace HRApp.Services {
  public class JobTypeService {
    private readonly JobType[] jobTypes = [
        new JobType { Id = 1, Type = "Manager" },
        new JobType { Id = 2, Type = "Developer" },
        new JobType { Id = 3, Type = "Designer" },
        new JobType { Id = 4, Type = "Tester" }
    ];

    public JobType[] GetJobTypes( ) => jobTypes;
  }
}


「JobTypeService」類別負責管理和提供工作類型資料。類別中定義了一個私有、且唯讀的「jobTypes」變數,類型為「JobType」陣列。這個陣列包含四個「JobType」物件,每一個物件都有「Id」和 「Type」 屬性。

「JobTypeService」類別還定義一個「GetJobTypes()」方法,這個方法回傳一個「JobType」陣列,包含了「jobTypes」變數中的所有工作類型。

下一步修改「EditEmployee.razor」程式碼如下:

@page "/editemployee"
@using HRApp.Services
@using Models
<PageTitle> New Employee </PageTitle>
<h3> New Employee </h3>

<div class = "row">
  <div class = "col-md-8 col-lg-12">
    <EditForm Model = "@employee" FormName = "editEmployee">
      <div class = "mb-3">
        <label for = "employeeName" class = "form-label"> Employee Name : </label>
        <InputText id = "employeeName" @bind-Value = "employee.EmployeeName" class = "form-control" />
      </div>
      <div class = "mb-3">
        <label for = "birthDay" class = "form-label"> Birth Day : </label>
        <InputDate id = "birthDay" @bind-Value = "employee.BirthDay" class = "form-control" />
      </div>
      <div class = "mb-3">
        <label for = "isMarried" class = "form-label"> Is Married : </label>
        <InputCheckbox id = "isMarried" @bind-Value = "employee.IsMarried" class = "form-check-input" />
      </div>
      <div class = "mb-3">
        <label for = "jobType" class = "form-label"> Job Type : </label>
        <InputSelect id = "jobType" @bind-Value = "employee.JobTypeId" class = "form-select">
          <option> Select Job Type </option>
          @foreach ( var jobType in jobTypes! ) {
            <option value = "@jobType.Id"> @jobType.Type </option>
          }
        </InputSelect>
      </div>
      <button type = "submit" class = "btn btn-primary"> Submit </button>
    </EditForm>
  </div>
</div>

@code {

  private EmployeeDetails employee { get; set; } = new EmployeeDetails( ) {
      EmployeeName = string.Empty ,
      BirthDay = new DateOnly( 2000 , 1 , 1 )
    };

  private JobTypeService jobTypeService = new( );
  private JobType[]? jobTypes;

  protected override void OnInitialized( ) {
    jobTypes = jobTypeService.GetJobTypes( );
  }

}
 



參考以下程式碼,「InputSelect」元件是一個下拉選單,「option」標籤用來加入一個預設選項,顯示「Select Job Type」提示字串。這個選項沒有設定值,當使用者沒有選擇工作類型時會顯示這個選項。下拉選單中其餘的「option」選項是利用「foreach」語法根據「jobTypes」陣列中的內容動態產生的。
<InputSelect id = "jobType" @bind-Value = "employee.JobTypeId" class = "form-select">
          <option> Select Job Type </option>
          @foreach ( var jobType in jobTypes! ) {
            <option value = "@jobType.Id"> @jobType.Type </option>
          }
        </InputSelect>


「@code」區塊中初始化和載入工作類型資料,以便在元件中使用。我們建立「JobTypeService」物件來獲取工作類型資料。
private JobTypeService jobTypeService = new( );



定義一個「jobTypes」變數,型別是「JobType[]?」,用來儲存工作類型資料。

private JobType[]? jobTypes;



最後在「OnInitialized」方法中,叫用「JobTypeService」物件的「GetJobTypes」方法,將獲取到的工作類型資料放到「jobTypes」變數:

protected override void OnInitialized( ) {
   jobTypes = jobTypeService.GetJobTypes( );
 }


這樣當「EditEmployee」元件初始化時,「jobTypes」變數就會包含所有的工作類型資料,這些資料將應用在下拉選單中使用。

在 Visual Studio 2022 開發工具中,按下 鍵盤CTRL+F5組合鍵執行網站。在瀏覽器直接輸入URL:「http://localhost:埠號/editemployee」,瀏覽器將顯示修改員工的畫面,執行結果請參考下圖所示:


圖 3:產生下拉式清單選項。

Tags:

.NET | .NET Magazine國際中文電子雜誌 | Blazor | 許薰尹Vivid Hsu

NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List