本文來自轉載
原文作者: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);
}
可以發現 Show 和 ShowDialog 函式的形參都是一樣的,只是使用場景不同:
name:所要呼叫的對話框 View 的名稱,若註冊時有取別名,則只能使用別名來呼叫parameters:IDialogParameters介面類型參數,傳入的提示訊息,通常是$"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 原始碼