1. 程式人生 > WINDOWS開發 >.NET Core 3 WPF MVVM框架 Prism系列之對話方塊服務

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

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

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

一.對話方塊服務#

在Prism中,通過一個IDialogAware介面來實現對話方塊服務:

Copypublic 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為關閉事件,可由此控制窗體的關閉

1.建立對話方塊的View和ViewModel#

AlertDialog.xaml:

Copy<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,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:

Copypublic 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.註冊對話方塊#

App.cs:

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

還可以註冊時起名字:

CopycontainerRegistry.RegisterDialog<AlertDialog,AlertDialogViewModel>(“alertDialog”);

3.使用對話方塊服務#

CreateAccountViewModel.cs(修改部分):

Copypublic 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函式來呼叫,下面是該介面的定義:

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

我們可以發現show和ShowDialog函式都是一樣形參,無非就是使用場景不一樣

  • name:所要呼叫對話方塊view的名字,當註冊別名時,只能使用別名來呼叫
  • parameters:IDialogParameters介面型別引數,傳入的提示訊息,通常是$"message={xxxx}"格式,然後再ViewModel的OnDialogOpened函式通過IDialogParameters介面的GetValue函式來獲取
  • callback:用於傳入無返回值回撥函式

二.自定義對話方塊窗體#

?我們在上述可以看到,對話方塊的窗體時一個WPF自帶的窗體,但是當我們要用自己自定義窗體,例如,去掉window的Icon,保留最大化,最小化和關閉,或者使用一些第三方的窗體控制元件,prism支援通過註冊一個對話方塊窗體,然後通過再不同對話方塊的View指定其對話方塊窗體的style,則可以很靈活的實現不一樣的對話方塊,下面讓我們來看看如何操作:

1.註冊自定義對話方塊窗體#

新建一個窗體,DialogWindow.xaml:

Copy<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:

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

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

    public IDialogResult Result { get; set; }
}

App.cs:

Copyprotected override void RegisterTypes(IContainerRegistry containerRegistry)
{
     containerRegistry.RegisterDialogWindow<DialogWindow>();//註冊自定義對話方塊窗體
}

2.自定義對話方塊窗體Style#

AlertDialog.xaml:

Copy <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:

Copy <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>

那麼就變成了下面這樣:

技術分享圖片

最終,我們的最後效果為這樣:

技術分享圖片

三.小結#

?通過Prism的對話方塊服務,我們可以很好的通過一個IDialogService介面來統一管理對話方塊的彈出邏輯,而且可以使用依賴注入的模式,如果換成之前要定義一些自定義的對話方塊,那麼也要強依賴View部分,而且可以通過自定義不同對話方塊的窗體樣式,達到一定的靈活性(例如最終效果演示,用了兩個不同的對話方塊樣式),至此,.NET Core3.x Prism系列文章已經全部寫完

四.原始碼#

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