本文将介绍如何在. NET Core3 环境下使用 MVVM 框架 Prism 的对话框服务, 这也是 prism 系列的最后一篇完结文章, 下面是 Prism 系列文章的索引:
.NET Core 3 WPF MVVM 框架 Prism 系列之文章索引
一. 对话框服务
在 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 为关闭事件, 可由此控制窗体的关闭
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. 注册对话框
- App.cs:
- protected override void RegisterTypes(IContainerRegistry containerRegistry)
- {
- containerRegistry.RegisterDialog<AlertDialog, AlertDialogViewModel>();
- }
还可以注册时起名字:
containerRegistry.RegisterDialog<AlertDialog, AlertDialogViewModel>("alertDialog");
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: 用于传入无返回值回调函数
二. 自定义对话框窗体
我们在上述可以看到, 对话框的窗体时一个 WPF 自带的窗体, 但是当我们要用自己自定义窗体, 例如, 去掉 Windows 的 Icon, 保留最大化, 最小化和关闭, 或者使用一些第三方的窗体控件, prism 支持通过注册一个对话框窗体, 然后通过再不同对话框的 View 指定其对话框窗体的 style, 则可以很灵活的实现不一样的对话框, 下面让我们来看看如何操作:
1. 注册自定义对话框窗体
新建一个窗体, DialogWindow.xaml:
- <Windows 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>
- </Windows>
- DialogWindow.xaml.cs:
- public partial class DialogWindow : Windows, IDialogWindow
- {
- public DialogWindow()
- {
- InitializeComponent();
- }
- protected override void OnSourceInitialized(EventArgs e)
- {
- WindowHelp.RemoveIcon(this);// 使用 win32 函数去除 Windows 的 Icon 部分
- }
- public IDialogResult Result { get; set; }
- }
- App.cs:
- protected override void RegisterTypes(IContainerRegistry containerRegistry)
- {
- containerRegistry.RegisterDialogWindow<DialogWindow>();// 注册自定义对话框窗体
- }
2. 自定义对话框窗体 Style
- 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>
那么就变成了下面这样:
最终, 我们的最后效果为这样:
三. 小结
通过 Prism 的对话框服务, 我们可以很好的通过一个 IDialogService 接口来统一管理对话框的弹出逻辑, 而且可以使用依赖注入的模式, 如果换成之前要定义一些自定义的对话框, 那么也要强依赖 View 部分, 而且可以通过自定义不同对话框的窗体样式, 达到一定的灵活性 (例如最终效果演示, 用了两个不同的对话框样式), 至此, .NET Core3.x Prism 系列文章已经全部写完
四. 源码
最后, 附上整个 demo 的源代码: PrismDemo 源码 https://github.com/ZhengDaoWang/PrismMetroSample
来源: https://www.cnblogs.com/ryzen/p/12771986.html