前言

上节介绍的事件聚合器其实就可以实现MVVM模式下的弹窗过程,不过Prism非常贴心的有封装了专门实现子窗口的全套逻辑。

IDialogAware

既然要打开子窗口,那我们需要准备内容,但是窗口本身是prism准备好的,我们需要的准备是窗口内容,所以这里我新建一个用户控件,最终这个用户控件会被安排在一个prism为我们准备好的窗口里。我们为这个用户控件(view), 准备一个ViewModel,注意这个ViewModel需要实现接口IDialogAware。

1 新建用户控件

新建一个用户控件,命名一个类名就叫 “MyDialog” 吧,记住这个名字后续注册时用到:

<UserControl x:Class="WpfTest.Control.MyDialog"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:WpfTest.Control"mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"><StackPanel><TextBlock Text="我是个子窗口" FontSize="30"/><Button Command="{Binding BtnCloseCommand}" Content="Close" Width="200"/></StackPanel>
</UserControl>

2 新建一个ViewModel

给 “MyDialog”配套一个 “MyDialogViewModel.cs” ,注意该类需要实现接口IDialogAware。

internal class MyDialogViewModel: BindableBase, IDialogAware{#region IDialogAware的接口实现// 窗口标题public string Title => "弹窗";// 关闭弹窗操作public event Action<IDialogResult> RequestClose;// 是否允许关闭弹窗public bool CanCloseDialog(){return true;}// 当窗口关闭的调用public void OnDialogClosed(){MessageBox.Show("窗口关闭了!");}// 当窗口打开的时候调public void OnDialogOpened(IDialogParameters parameters){MessageBox.Show($"窗口打开了!" + "\n" +$"{parameters.GetValue<MainWindowViewModel>("123")}" + "\n" +$"{parameters.GetValue<string>("456")}");}#endregionprivate string name = "bean";public string Name{get { return name; }set { SetProperty(ref name, value); }}private string key = "321mima";public string Key{get { return key; }set { SetProperty(ref key, value); }}public DelegateCommand BtnCloseCommand { get => new DelegateCommand(() =>{// 关闭当前窗口RequestClose?.Invoke(new DialogResult(ButtonResult.OK));});}}

3 窗口内容注册

将我们刚刚新建的用户控件,在App的回调函数RegisterTypes中通过RegisterDialog方法注册到Prism的容器中,确保后期容器知道打开什么内容。

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{// 注册一个Dialog的内容containerRegistry.RegisterDialog<MyDialog>();
}

准备工作差不多了,接下来就看看,如何打开这个窗口了。

4 确保MyDialog和MyDialogViewModel是关联上

我们可以通过Prism的默认匹配规则(Views => ViewModels)。

也可以通过手动进行匹配:

ViewModelLocationProvider.Register<MyDialog, MyDialogViewModel>();

如果没匹配,则会报错如下:告诉你Dialog的ViewModel没有实现接口IDialogAware

IDialogService

Prism框架在初始化的时候,就会向容器中注册17项内容,事件聚合器是其一,IDialogService就是其二。它规定了窗口的打开方式。我们之前准备好的窗口内容就由它打开。

1 注入IDialogService

由于IDialogService是prism框架预先注册好的,所以,我们直接在MainWindowViewModel注入(MainWindowViewModel,对应的是主窗口):

[Dependency]
public IDialogService dialogService { get; set; }

2 ShowDialog打开窗口

这里ShowDialog和之前的实现了IDialogAware接口的MyDialogViewModel息息相关。

public DelegateCommand BtnCommand { get; }[Dependency]
public IDialogService dialogService { get; set; }public Prism子窗口实现ViewModel()
{BtnCommand = new DelegateCommand(() => {DialogParameters dialogParameters = new DialogParameters();dialogParameters.Add("123", this);dialogParameters.Add("456", "asdf");dialogService?.ShowDialog("MyDialog", dialogParameters, DoDialogResult);});
}private void DoDialogResult(IDialogResult dialogResult)
{// 委托   被动执行     被子窗口执行// dialogResult  第一方面可以拿到任意参数   第二方面   可判断关闭状态MessageBox.Show("返回值:" + dialogResult.Result.ToString());
}

ShowDialog的时候,我们传入的三个参数。

第一个参数,“MyDialog” ,这个就是我们之前新建的用户控件的类名称,也是我们往容器注册过的类:

containerRegistry.RegisterDialog<MyDialog>();

这里传入字符串“MyDialog” ,Prism就找到之前通过RegisterDialog注册的MyDialog。

第二个参数,dialogParameters 打开窗口可以传入的参数,以键值对的方式,键必须是字符串,值可以是任何内容。

DialogParameters dialogParameters = new DialogParameters();
dialogParameters.Add("123", this);
dialogParameters.Add("456", "asdf");

之前和MyDialog关联实现了IDialogAware的的MyDialogViewModel,就有个实现了一个OnDialogOpened,ShowDialog传入的参数就会在窗口打开时,传入这个函数。

第三个参数,DoDialogResult,是一个回调函数,当窗口关闭之后被调用

private void DoDialogResult(IDialogResult dialogResult)
{// 委托   被动执行     被子窗口执行// dialogResult  第一方面可以拿到任意参数   第二方面   可判断关闭状态MessageBox.Show("返回参数:" + dialogResult.Parameters.ToString());MessageBox.Show("返回值:" + dialogResult.Result.ToString());
}

这里函数里还有个参数,是对话框返回的结果,如果直接点击关闭按钮关闭的窗口,dialogResult参数里面就没啥内容。

那如何,在关闭之后得到对话框的一些信息呢?

这又要看:实现了IDialogAware的的MyDialogViewModel里面的事件:

public event Action<IDialogResult> RequestClose;

通过触发该事件,就可以关闭窗口并传入参数:

public DelegateCommand BtnCloseCommand { get => new DelegateCommand(() =>
{// 关闭当前窗口//RequestClose?.Invoke(new DialogResult(ButtonResult.OK));DialogParameters dialogParameters = new DialogParameters();dialogParameters.Add("123", 123);dialogParameters.Add("456", "456");RequestClose?.Invoke(new DialogResult(ButtonResult.Retry, dialogParameters));
});
}

这里有个地方,需注意:RequestClose?.Invoke 不能写到 接口方法 OnDialogClosed() 里面。

程序执行到这里时,你会发现 RequestClose 已经为 NULL 了, RequestClose 是Prsim框架赋值的

当事件触发时,窗口会关闭,此时DoDialogResult就会被框架调用,此时dialogResult得到了,触发事件时传入的参数ButtonResult.Retry,以及相应的dialogParameters 。

总结

为了实现MvvM整个实现过程,有亿点绕,这里从头梳理一遍。

1 需要建立一个用户控件(MyDialog)充当窗口内容,Prism框架提供默认窗口包含此用户控件。

2 需要为用户控件,配置一个ViewModel(MyDialogViewModel),此 ViewModel必须实现接口IDialogAware

3 MyDialog与MyDialogViewModel需要关联起来

4 需要通过RegisterDialog注册MyDialog

5 在主窗口中注入IDialogService对象,dialogService 。主窗口中dialogService调用ShowDialog

打开子窗口,通过ShowDialog参数以及实现了IDialogAware的MyDialogViewModel实现窗口调用前的参数输入,以及窗口关闭后的结果输出。


内容扩充

窗口样式设计

方式一:

因为,这里我们使用的是用户控件,而窗口其实是Prism提供的,那如何设置窗口的样式呢?

我们,可以添加如下代码,进行窗口设置。

<prism:Dialog.WindowStyle><Style TargetType="Window"><Setter Property="Width" Value="500"/><Setter Property="Height" Value="400"/><Setter Property="WindowStyle" Value="None"/><Setter Property="AllowsTransparency" Value="True"/><Setter Property="WindowChrome.WindowChrome"><Setter.Value><WindowChrome GlassFrameThickness="-1"/></Setter.Value></Setter></Style>
</prism:Dialog.WindowStyle>

方式二:

不使用prism提供的窗口,而是自己窗口:

首先我们新建一个窗口DialogWindowBase,然后让该窗口实现接口IDialogWindow:

 public partial class DialogWindowBase : Window, IDialogWindow{public IDialogResult Result{get; set;}public DialogWindowBase(){InitializeComponent();}}

最后在APP类中注册,该窗口:

containerRegistry.RegisterDialogWindow<DialogWindowBase>();

那么prism就会使用这个窗口而不是默认的,那么我们设置这个窗口就OK了。

2022年12月7日  更新内容:

RequestClose?.Invoke 不能写到 接口方法 OnDialogClosed() 里面。

【Prism系列】Prism子窗口实现相关推荐

  1. 【Prism系列】Module实现程序的插件化

    前言 首先区分Module和model这两个单词.model是之前MVVM提到很多的模型部分.而今天讲的是Module:模块/单元.Module有助于我们将程序分成一个个模块进行管理.借助Module ...

  2. .NET Core 3 WPF MVVM框架 Prism系列之事件聚合器

    本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 一.事件聚合器  在上一篇 .NET Core 3 WPF MVVM框架 Prism系列之模块化 ...

  3. c#事件的发布-订阅模型_NET Core 3 WPF MVVM框架 Prism系列之事件聚合器

    本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 一.事件聚合器#  在上一篇 .NET Core 3 WPF MVVM框架 Prism系列之模块化 ...

  4. 【Prism系列】Prism中的命令

    前言 在<[Prism系列] Prism实现依赖注入_code bean的博客-CSDN博客>中我们讲到了prism的搭建过程,以及如何容器的使用以及自动注入的过程. 在<[wpf] ...

  5. FineUI小技巧(5)向子窗口传值,向父窗口传值

    前言 FineUI中经常会用到启用IFrame的Window控件,这样有助于从物理上进行代码解耦和.IFrame的引入就会涉及传值问题,如何在父窗口和子窗口之间相互传值呢? 向子窗口传值 向子窗口传值 ...

  6. 代码赏析:子窗口对于键盘和鼠标的响应

    一.引言 首先声明,代码并不是我写的:其次,代码是我在小甲鱼的<Win32 SDK程序设计>系列教程的第41讲中看到的.因为本人一方面在学习这个教程,一方面也对于优美的代码有着自己的独特的 ...

  7. Python 的Tkinter包系列之一:窗口初步

    Python 的Tkinter包系列之一:窗口初步 图形用户界面(GUI.Graphical User Interface)是基于图形的界面,windows就是一个图形用户界面的操作系统,而DOS是基 ...

  8. python label textvariable_在子窗口中为标签的textvariable赋值失败时,有关,给,Label,问题...

    写了个母子窗体程序,当主窗口打开子窗口后,通过set textvariable 的发发对Label标题赋值失败,如果将子窗体程序单独运行,则正常.请教各位大神如果处理,多谢! from tkinter ...

  9. 请问,关闭子窗口提示错误,大家遇到这样的问题吗?

    请问,关闭子窗口提示错误,大家遇到这样的问题吗? Delphi / Windows SDK/API http://www.delphi2007.net/DelphiBase/html/delphi_2 ...

最新文章

  1. 像素钱包:一个可以把比特现金藏在图片里的APP
  2. eclipse里面M2_REPO引用(Maven2安装总结)
  3. Prima Cartoonizer中文版
  4. 简单形象又有趣地说说强大的神经网络
  5. 广东移动数据中心攻关“液/气双通道散热技术”
  6. linux——Shell脚本说明、创建、执行、调试
  7. Spark中Data skew(数据倾斜)Java+Python+Scala三种接口完整代码
  8. 程序设计入门-C语言基础知识-翁恺-第六周:数组-详细笔记(六)
  9. python中的运算符_Python 中的神秘运算符
  10. 人类一败涂地电脑版_《漫威复仇者联盟》帧数对比丨PS4《人类一败涂地》新地图上线...
  11. java如何获取本机IP
  12. 小波包分解、重构 matlab代码
  13. 学校机房计算机安全使用制度,学校机房安全管理制度
  14. 国内多少所高校开始博士生采用申请招生的方法了?
  15. 方差为什么用平方不用绝对值,为什么要对差值求平方而不是取标准偏差的绝对值?...
  16. 机器人理论简介—— 台湾交通大学机器人学公开课(一)
  17. win10无限重启_安装 Win10+Ubuntu双系统,让迷你掌上电脑更具生产力
  18. C# 读取outlook 本地签名
  19. 安装openKylin 开源操作系统 (ubuntukylin-22.04-pro-amd64.isowindows版)
  20. Windows桌面任务栏上面无线网显示不见了如何解决

热门文章

  1. 基于用户行为特征的推荐算法
  2. 推荐几款Python编程类游戏,妈妈再也不用担心我的学习了
  3. 流浪大师善始者众善终者寡_流浪者–适合每个开发人员的瑞士军刀
  4. Vue v-for循环中 key 属性的使用
  5. 致远a8-v5-6.0协同管理软件_易达酒吧管理软件下载-易达酒吧管理软件v10.0免费版...
  6. 如何搭建windows server服务器
  7. WhatsApp营销之群组(二):搜群
  8. AJAX教程@ajax
  9. 更改表格行tr的背景颜色
  10. net软件工程师求职简历