2024年6月12日 星期三

在Blazor使用Fluent UI元件-5

作 者:恆逸資深講師 許薰尹

在本站《在Blazor使用Fluent UI元件 - 4》一文介紹如何在現有的Blazor專案中,手動加入Fluent UI元件 ,並使用「FluentDialog」元件設計確認刪除的對話盒。在這一篇文章中,我們將介紹延續這系列文章的情境,介紹該如何自訂對話盒,以便讓其它元件能夠重複使用這個對話盒。



設計MyDialog


首先讓我們使用元件來自訂對話盒,元件的程式碼可放在專案根目錄下的「Shared」資料夾。從「Solution Explorer」視窗 - 專案名稱上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Folder」選項,將新建立的資料夾命名為「Shared」。

在「Shared」資料夾中加入Razor元件,從「Solution Explorer」視窗 -「Shared」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Razro Component」項目,將元件名稱命為「MyDialog.razor」,然後在檔案中加入以下程式碼:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@using Microsoft.FluentUI.AspNetCore.Components
@implements IDialogContentComponent<FluentUIDataGrid.Models.Customer>
 
@* Header *@
<FluentDialogHeader ShowDismiss = "true">
  <FluentStack VerticalAlignment = "VerticalAlignment.Center">
    <FluentIcon Value = "@(new Icons.Regular.Size24.WindowApps())" />
    <FluentLabel Typo = "Typography.PaneHeader">
        @Dialog.Instance.Parameters.Title
    </FluentLabel>
  </FluentStack>
</FluentDialogHeader>
 
@* Footer *@
<FluentDialogFooter>
  <FluentButton Appearance = "Appearance.Accent" OnClick = "@DeleteAsync"> Delete </FluentButton>
  <FluentButton Appearance = "Appearance.Neutral" OnClick = "@CancelAsync"> Cancel </FluentButton>
</FluentDialogFooter>
 
@* Body *@
<FluentDialogBody>
  <FluentTextField @bind-Value = "@Content.CustomerId"> CustomerId: </FluentTextField>
  <FluentTextField @bind-Value = "@Content.CompanyName"> CompanyName: </FluentTextField>
  <FluentTextField @bind-Value = "@Content.ContactName"> ContactName: </FluentTextField>
</FluentDialogBody>
 
@code {
  [Parameter]
  public FluentUIDataGrid.Models.Customer Content { get; set; } = default!;
 
  [CascadingParameter]
  public FluentDialog Dialog { get; set; } = default!;
 
  private async Task DeleteAsync() {
    await Dialog.CloseAsync( Content );
  }
 
  private async Task CancelAsync() {
    await Dialog.CancelAsync( );
  }
}




分別說明如下,以下這兩行程式碼是在引入了必要的命名空間,並且實作了「IDialogContentComponent」介面,該介面的泛型參數是「FluentUIDataGrid.Models.Customer」:

1
2
@using Microsoft.FluentUI.AspNetCore.Components
@implements IDialogContentComponent<FluentUIDataGrid.Models.Customer>



以下程式碼建立了自訂對話盒的標題部分。「FluentDialogHeader」是對話盒的標題,「ShowDismiss」屬性設為「true」表示可以關閉對話盒。「FluentStack」是一個容器類型的元件,裡面包含了一個圖示(FluentIcon)和一個標籤(FluentLabel),這個標籤顯示的是對話盒的標題:

1
2
3
4
5
6
7
8
9
@* Header *@
<FluentDialogHeader ShowDismiss = "true">
  <FluentStack VerticalAlignment = "VerticalAlignment.Center">
    <FluentIcon Value = "@(new Icons.Regular.Size24.WindowApps())" />
    <FluentLabel Typo = "Typography.PaneHeader">
        @Dialog.Instance.Parameters.Title
    </FluentLabel>
  </FluentStack>
</FluentDialogHeader>



以下程式碼建立對話盒的尾部部分。「FluentDialogFooter」是對話盒的底部,裡面包含了兩個按鈕,一個是刪除按鈕,點擊後會執行「DeleteAsync」方法,另一個是取消按鈕,點擊後會執行「CancelAsync」方法。

1
2
3
4
5
@* Footer *@
<FluentDialogFooter>
  <FluentButton Appearance = "Appearance.Accent" OnClick = "@DeleteAsync"> Delete </FluentButton>
  <FluentButton Appearance = "Appearance.Neutral" OnClick = "@CancelAsync"> Cancel </FluentButton>
</FluentDialogFooter>


以下程式碼建立對話盒的主體部分。「FluentDialogBody」是對話盒的主體,裡面包含了三個文字欄位,分別繫結到「Content」物件的「CustomerId」、「CompanyName」和「ContactName」屬性。

 

 

1
2
3
4
5
6
@* Body *@
<FluentDialogBody>
  <FluentTextField @bind-Value = "@Content.CustomerId"> Id: </FluentTextField>
  <FluentTextField @bind-Value = "@Content.CompanyName"> CompanyName: </FluentTextField>
  <FluentTextField @bind-Value = "@Content.ContactName"> ContactName: </FluentTextField>
</FluentDialogBody>

 

 


以下程式碼定義一些屬性和方法。「Content」屬性是一個參數,它的類型是「FluentUIDataGrid.Models.Customer」。「Dialog」性是一個「CascadingParameter」參數,它的類型是「FluentDialog」。「DeleteAsync」方法是在刪除按鈕被按下時執行,它會關閉對話盒並傳遞「Content」物件。「CancelAsync」方法是在取消按鈕被按下時執行,它會取消對話盒。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@code {
  [Parameter]
  public FluentUIDataGrid.Models.Customer Content { get; set; } = default!;
 
  [CascadingParameter]
  public FluentDialog Dialog { get; set; } = default!;
 
  private async Task DeleteAsync() {
    await Dialog.CloseAsync( Content );
  }
 
  private async Task CancelAsync() {
    await Dialog.CancelAsync( );
  }
}

 

 


下一步在「MyDataGridComponent.razor」元件中使用「MyDialog」對話盒。參考以下程式碼,當按下「FluentDataGrid 」任一筆資料右方的刪除按鈕時,便叫用「DialogService.ShowDialogAsync()」方法顯示自訂對話盒:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
@using FluentUIDataGrid.Models
@using Microsoft.EntityFrameworkCore
@inject NorthwindContext DbContext
@inject IDialogService DialogService
<h3>MyDataGridComponent</h3>
<FluentDataGrid  TGridItem = "Customer" Items = "Customers" GridTemplateColumns = "1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr">
  <PropertyColumn Property = "@(c => c.CustomerId)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.CompanyName)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.ContactName)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.ContactTitle)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.Address)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.City)" Sortable = "true" />
  <PropertyColumn Property = "@(c => c.Country)" Sortable = "true" />
  <TemplateColumn Title = "Actions">
    <FluentButton IconStart = "@(new Icons.Regular.Size20.Delete())" OnClick = "@( () => DeleteClicked(context) )">
      Delete
    </FluentButton>
  </TemplateColumn>
</FluentDataGrid>
 
 
@code {
 
  public async Task DeleteClicked( Customer customer ) {
    var dialog = await DialogService.ShowDialogAsync<FluentUIDataGrid.Shared.MyDialog>(
      customer, new DialogParameters {
          Height = "240px",
          Title = $"Delete Customer : { customer.CustomerId }",
          PreventDismissOnOverlayClick = true,
          PreventScroll = true
        } );
 
    var result = await dialog.Result;
    if ( !result.Cancelled && result.Data != null ) {
      var c = await DbContext.Customers.FirstOrDefaultAsync( c => c.CustomerId == customer.CustomerId );
      DbContext.Customers.Remove( c );
      if ( c is not null ) {
        await DbContext.SaveChangesAsync( );
      }
    }
  }
 
 
  public IQueryable<Customer> Customers { get; set; } = null!;
  protected override async Task OnInitializedAsync() {
 
    await Task.Run( () => {
      Customers = DbContext.Customers.AsQueryable( );
    } );
  }
}
 
<style>
  .dialog-box {
    background-color: #f2f2f2;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 10px;
    margin-bottom: 10px;
  }
 
  .dialog-title {
    font-size: 18px;
    font-weight: bold;
    margin-bottom: 10px;
  }
 
  .dialog-buttons {
    margin-top: 10px;
  }
 
    .dialog-buttons button {
      margin-right: 10px;
    }
</style>

 

 

 

分別說明如下,以下這段程式碼,叫用「DialogService.ShowDialogAsync()」方法顯示對話盒,傳入了一個「customer」物件和一個「DialogParameters」物件來設定對話盒的參數,「Height」設定高度、「Title」設定標題、「PreventDismissOnOverlayClick」是否防止點選背景來關閉對話盒,「PreventDismissOnOverlayClick」設定為「true」時不可以點選背景來關閉對話盒;「PreventDismissOnOverlayClick」設為「false」則可以點選背景來關閉對話盒、「PreventScroll」用來設定是否防止滾動。

 

 

1
2
3
4
5
6
7
var dialog = await DialogService.ShowDialogAsync<FluentUIDataGrid.Shared.MyDialog>(
      customer, new DialogParameters {
          Height = "240px",
          Title = $"Delete Customer : { customer.CustomerId }",
          PreventDismissOnOverlayClick = true,
          PreventScroll = true
        } );

 


以下這行程式碼是在等待對話盒關閉並獲取結果,如果對話盒沒有被取消且返回的資料不為空,則進行以下操作:首先,從資料庫中找尋與當前「customer」的「CustomerId」相符的「Customer」物件。然後,從「DbContext.Customers」移除該筆資料。最後,如果「CustomerId」相符的資料存在於資料庫,則刪除資料庫的資料:

 

 

1
2
3
4
5
6
7
8
var result = await dialog.Result;
if ( !result.Cancelled && result.Data != null ) {
  var c = await DbContext.Customers.FirstOrDefaultAsync( c => c.CustomerId == customer.CustomerId );
  DbContext.Customers.Remove( c );
  if ( c is not null ) {
    await DbContext.SaveChangesAsync( );
  }
}

 

這個範例的執行結果請參考下圖所示:


圖 1:自訂對話盒。







👉👉👉索取微軟網站開發技術系列 優惠訊息與課程資料

0 意見:

張貼留言