(7/7).NET Core 3 WPF MVVM框架 Prism系列之對話方塊服務

(7/7).NET Core 3 WPF MVVM框架 Prism系列之對話方塊服務

.NET Core3環境下使用MVVM框架Prism的對話方塊服務,這也是Prism系列的最後一篇完結文章

最後更新 2023/6/11 上午12:47
RyzenAdorer
預計閱讀 7 分鐘
分類
WPF
專題
WPF MVVM框架 Prism系列
標籤
.NET C# WPF Prism MVVM

本文來自轉載

原文作者:RyzenAdorer

原文標題:.NET Core 3 WPF MVVM 框架 Prism 系列之對話框服務

原文連結:https://www.cnblogs.com/ryzen/p/12771986.html

本文將介紹如何在 .NET Core 3 環境下使用 MVVM 框架 Prism 的對話框服務,這也是 Prism 系列的最後一篇完結文章。下面是 Prism 系列文章的索引:

.NET Core 3 WPF MVVM 框架 Prism 系列之文章索引

1. 對話框服務

在 Prism 中,透過一個 IDialogAware 介面來實現對話框服務:

public interface IDialogAware
{
    bool CanCloseDialog();
    void OnDialogClosed();
    void OnDialogOpened(IDialogParameters parameters);
    string Title { get; set; }
    event Action<IDialogResult> RequestClose;
}
  • CanCloseDialog() 函式決定表單是否關閉
  • OnDialogClosed() 函式在表單關閉時觸發,觸發條件取決於 CanCloseDialog() 函式
  • OnDialogOpened() 函式在表單打開時觸發,比表單的 Loaded 事件更早觸發
  • Title 為表單的標題
  • RequestClose 為關閉事件,可由此控制表單的關閉

2.1. 建立對話框的 View 和 ViewModel

AlertDialog.xaml:

<UserControl
  x:Class="PrismMetroSample.Shell.Views.Dialogs.AlertDialog"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:local="clr-namespace:PrismMetroSample.Shell.Views.Dialogs"
  mc:Ignorable="d"
  xmlns:prism="http://prismlibrary.com/"
  Width="350"
  Height="120"
  prism:ViewModelLocator.AutoWireViewModel="True"
>
  <Grid Margin="5">
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid Margin="0,0,0,10">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="70" />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <image
        Source="pack://application:,,,/PrismMetroSample.Infrastructure;Component/Assets/Photos/alter.png"
        Height="40"
        UseLayoutRounding="True"
        RenderOptions.BitmapScalingMode="HighQuality"
      />
      <TextBlock
        Grid.Column="1"
        Text="{Binding Message}"
        HorizontalAlignment="Left"
        VerticalAlignment="Center"
        Grid.Row="0"
        TextWrapping="Wrap"
        FontSize="15"
        FontFamily="Open Sans"
      />
    </Grid>
    <Grid Grid.Row="1">
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <button
        Margin="5"
        Foreground="White"
        FontSize="12"
        Background="#5cb85c"
        Command="{Binding CloseDialogCommand}"
        CommandParameter="true"
        Content="Yes"
        Width="64"
        Height="28"
        HorizontalAlignment="Right"
        Grid.Row="1"
      />
      <button
        Grid.Column="1"
        Margin="5"
        Foreground="White"
        FontSize="12"
        Background="#d9534f"
        Command="{Binding CloseDialogCommand}"
        CommandParameter="false"
        Content="No"
        Width="64"
        Height="28"
        HorizontalAlignment="Left"
        Grid.Row="1"
      />
    </Grid>
  </Grid>
</UserControl>

AlertDialogViewModel.cs:

public class AlertDialogViewModel : BindableBase, IDialogAware
{
    private DelegateCommand<string> _closeDialogCommand;
    public DelegateCommand<string> CloseDialogCommand =>
        _closeDialogCommand ?? (_closeDialogCommand = new DelegateCommand<string>(ExecuteCloseDialogCommand));

    void ExecuteCloseDialogCommand(string parameter)
    {
        ButtonResult result = ButtonResult.None;
        if (parameter?.ToLower() == "true")
            result = ButtonResult.Yes;
        else if (parameter?.ToLower() == "false")
            result = ButtonResult.No;
         RaiseRequestClose(new DialogResult(result));
     }

     // 觸發表單關閉事件
     public virtual void RaiseRequestClose(IDialogResult dialogResult)
     {
         RequestClose?.Invoke(dialogResult);
     }

     private string _message;
     public string Message
     {
         get { return _message; }
         set { SetProperty(ref _message, value); }
     }

     private string _title = "Notification";
     public string Title
     {
         get { return _title; }
         set { SetProperty(ref _title, value); }
     }

     public event Action<IDialogResult> RequestClose;

     public bool CanCloseDialog()
     {
         return true;
     }

     public void OnDialogClosed()
     {

     }

     public void OnDialogOpened(IDialogParameters parameters)
     {
         Message = parameters.GetValue<string>("message");
     }
 }

2.2. 註冊對話框

App.cs:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
     containerRegistry.RegisterDialog<AlertDialog, AlertDialogViewModel>();
}

也可以註冊時取別名:

containerRegistry.RegisterDialog<AlertDialog, AlertDialogViewModel>("alertDialog");

2.3. 使用對話框服務

CreateAccountViewModel.cs(修改部分):

public CreateAccountViewModel(IRegionManager regionManager, IDialogService dialogService)
{
     _regionManager = regionManager;
     _dialogService = dialogService;
}

 public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
 {
     if (!string.IsNullOrEmpty(RegisteredLoginId) && this.IsUseRequest)
     {
          _dialogService.ShowDialog("AlertDialog", new DialogParameters($"message={"是否需要用當前註冊的用戶登入?"}"), r =>
           {
                 if (r.Result == ButtonResult.Yes)
                     navigationContext.Parameters.Add("loginId", RegisteredLoginId);
           });
      }
      continuationCallback(true);

 }

效果如下:

我們是透過呼叫 IDialogService 介面的 ShowDialog 函式來呼叫,下面是該介面的定義:

public interface IDialogService : Object
{
    void Show(String name, IDialogParameters parameters, Action<IDialogResult> callback);
    void ShowDialog(String name, IDialogParameters parameters, Action<IDialogResult> callback); 
}

可以發現 ShowShowDialog 函式的形參都是一樣的,只是使用場景不同:

  • name:所要呼叫的對話框 View 的名稱,若註冊時有取別名,則只能使用別名來呼叫
  • parametersIDialogParameters 介面類型參數,傳入的提示訊息,通常是 $"message={xxxx}" 格式,然後在 ViewModel 的 OnDialogOpened 函式中透過 IDialogParameters 介面的 GetValue 函式來取得
  • callback:用於傳入無回傳值的回呼函式

2. 自訂對話框表單

在上述範例中,對話框表單是 WPF 內建的表單。但如果我們想要使用自訂表單,例如去除 Window 的圖示、保留最大化、最小化和關閉按鈕,或使用第三方表單控制項,Prism 支援先註冊一個對話框表單,然後在各個對話框的 View 中指定其對話框表單的樣式,如此便能靈活地實現不同的對話框。以下說明如何實作:

2.1. 註冊自訂對話框表單

建立一個新的表單 DialogWindow.xaml

<Window
  x:Class="PrismMetroSample.Shell.Views.Dialogs.DialogWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:local="clr-namespace:PrismMetroSample.Shell.Views.Dialogs"
  mc:Ignorable="d"
  xmlns:prism="http://prismlibrary.com/"
>
  <Grid> </Grid>
</Window>

DialogWindow.xaml.cs:

public partial class DialogWindow : Window, IDialogWindow
{
    public DialogWindow()
    {
        InitializeComponent();
    }

    protected override void OnSourceInitialized(EventArgs e)
    {
        WindowHelp.RemoveIcon(this); // 使用 Win32 函式去除 Window 的圖示部分
    }

    public IDialogResult Result { get; set; }
}

App.cs:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
     containerRegistry.RegisterDialogWindow<DialogWindow>(); // 註冊自訂對話框表單
}

2.2. 自訂對話框表單樣式

AlertDialog.xaml:

<prism:Dialog.WindowStyle>
  <style TargetType="Window">
    <Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterScreen" />
    <Setter Property="ShowInTaskbar" Value="False"/>
    <Setter Property="SizeToContent" Value="WidthAndHeight"/>
  </style>
</prism:Dialog.WindowStyle>

效果如下:

如果我們要將表單樣式全部移除,修改 AlertDialog.xaml

<prism:Dialog.WindowStyle>
  <style TargetType="Window">
    <Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterScreen" />
    <Setter Property="ShowInTaskbar" Value="False"/>
    <Setter Property="SizeToContent" Value="WidthAndHeight"/>
    <Setter Property="WindowStyle" Value="None"/>
  </style>
</prism:Dialog.WindowStyle>

結果就變成下面這樣:

最終,我們的最後效果如下:

3. 小結

透過 Prism 的對話框服務,我們可以透過 IDialogService 介面統一管理對話框的彈出邏輯,並使用依賴注入模式。如果換成以往,要定義一些自訂對話框,就必須強依賴 View 的部分;而現在則可以透過自訂不同對話框的表單樣式,達到一定的靈活性(例如最終效果演示中使用了兩種不同的對話框樣式)。至此,.NET Core 3.x Prism 系列文章已全部撰寫完畢。

4. 原始碼

最後,附上整個 Demo 的原始碼:PrismDemo 原始碼

繼續探索

延伸閱讀

更多文章