MVVM探索:从ViewModel关闭Window的最佳实践
在WPF里使用MVVM开发的时候,似乎总是不可避免的会遇到这样一个问题:ViewModel在处理完业务之后需要关闭这个Window,这时候要怎么处理?
网上有很多解决方案:有的在ViewModel抛出一个事件,在View端使用(XXXViewModel)this.DataContext的方式去响应事件;有的通过Trigger、Behavior、Action之类的方式曲线救国;还有的使用了其他的第三方框架。
这些操作从某个层面上来说确实能实现这个功能,但是有的操作起来过于麻烦,有的实现功能了但是大大的违反了MVVM的原则,有的则有很多局限性(比如只能针对关闭了Window之后什么都不做,或者必须要求Window有无参的构造函数)。直到我发现了还可以有这样一种操作之后,我觉得这应该处理这个问题的最佳实践了:优雅,简洁,符合MVVM的思想还没有局限性。
在MVVM里,View和ViewModel之间通过绑定完成了大部分的操作,这也是MVVM最为推荐的做法。那么,为什么View的关闭这个事情不能通过绑定来实现呢?是因为Window没有控制关闭这个操作的属性么?不,在没有使用MVVM,直接在后台写代码创建了一个Window的时候,我们只需要将这个Window的DialogResult属性赋值(不管是true还是false)就可以将这个窗口关闭。那么我们为什么不直接将Window的DialogResult属性在ViewModel绑定呢?
秉着这样的思想我去做了这个实验,编译通过,运行的时候得到了这样的异常提示:
“不能在“ChildWindow”类型的“DialogResult”属性上设置“Binding”。只能在 DependencyObject 的 DependencyProperty 上设置“Binding”。
这个提示已经很明显了:为什么不能直接对Window的DialogResult做绑定,因为DialogResult这个属性不是依赖属性,WPF里面所有的绑定都必须只能绑定依赖属性,而WPF里绝大部分的属性都是依赖属性,但是DialogResult恰恰不是依赖属性,所以不能绑定。
此路不通之后就有了上面的各种解决方法,但是为什么不这样想:DialogResult不是依赖属性,那我注册一个依赖属性不就完了么?WPF又不是不让注册。
注册依赖属性代码如下:
public static class DialogCloser
{
public static readonly DependencyProperty DialogResultProperty =
DependencyProperty.RegisterAttached(
"DialogResult",
typeof(bool?),
typeof(DialogCloser),
new PropertyMetadata(DialogResultChanged)); private static void DialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var window = d as Window;
if (window != null)
{
window.DialogResult = e.NewValue as bool?;
}
} public static void SetDialogResult(Window target, bool? value)
{
target.SetValue(DialogResultProperty, value);
}
}
然后在View端绑定这个依赖属性DialogResult:
<Window x:Class="mvvm_demo_close_window.ChildWindow"
...
xmlns:xc="clr-namespace:mvvm_demo_close_window"
xc:DialogCloser.DialogResult="{Binding DialogResult}">
然后在ViewModel端将这个当做正常的依赖属性去操作就行了,当this.DialogResult=true的时候就自动在ViewModel关闭了子窗口:
public class ChildWindowViewModel : ViewModelBase
{
private bool? dialogResult;
public bool? DialogResult
{
get { return this.dialogResult; }
set
{
this.dialogResult = value;
RaisePropertyChanged("DialogResult");
}
} //用来接收关闭按钮的Command
public ICommand CloseCmd
{
get
{
return new DelegateCommand((obj) =>
{
this.DialogResult = true;
});
}
}
}
这是我目前发现的最优雅的解决方案,DialogCloser也完全可以复用,如果大家还有更好的方案,欢迎提出来一起讨论。源代码已在下方给出,需要的自行下载。
MVVM探索:从ViewModel关闭Window的最佳实践的更多相关文章
- 腾讯优测优分享 | 探索react native首屏渲染最佳实践
腾讯优测是专业的移动云测试平台,旗下的优分享不定时提供大量移动研发及测试相关的干货~ 此文主要与以下内容相关,希望对大家有帮助. react native给了我们使用javascript开发原生app ...
- 探索react native首屏渲染最佳实践
文 / 腾讯 龚麒 0.前言 react native给了我们使用javascript开发原生app的能力,在使用react native完成兴趣部落安卓端发现tab改造后,我们开始对由react n ...
- WPF:MVVM模式下ViewModel关闭View
不外乎两种基本方法. 消息通知和参数传递. 一.消息通知 利用View里的IsEnable属性 原理是这样的: 1.UI中的IsEnabled绑定VM中的属性 2.UI的后台代码中,注册IsEnabl ...
- WPF - ViewModle中关闭Window
在Binding close event时候,需要从ViewModel关闭Window. 一个很简洁的解决方案就是,将Window 当做CommandParameter传过去. Command=&qu ...
- easyUI的window包含一个iframe,在iframe中如何关闭window?
easyUI的window包含一个iframe,在iframe中如何关闭window? parent.$('#win').window('close');
- 通过钩子程序跨程序关闭Window
需求: 在实际场景中会有自身程序在调用第三方的动态库过程中,因为第三方的动态库弹框导致线程阻塞,必须手动将弹窗关闭后才能回到自身程序的主线程中. 最简单的场景就是很多自助设备,本身是没有固定操作员的, ...
- 【C#】关闭 Window 之后,无法设置 Visibility,也无法调用 Show、ShowDialogor 或 WindowInteropHelper.EnsureHandle
问题: 在做WPF项目时,点击一个按钮弹出一个自定义的窗体,然后点击X关闭该窗体,然后再点击按钮想弹出该窗体时,报错:关闭 Window 之后,无法设置 Visibility,也无法调用 Show.S ...
- EasyUI-window包含一个iframe,在iframe中如何关闭window
我试过类似$('#win').window('close');报$.data...options无效的错误,我已经引入了js文件,路径没问题,而且在同一个页面,不用iframe是可以关闭的 在ifra ...
- Window下使用Xshell连接VirtualBox中CentOS SSH最佳实践
网上已经有非常多讲怎样连接VMware的文章.可是针对一些可能遇到的细节没有讲全. 这里会有一个非常 实际的样例,附带全部软件的链接,保证成功. 最佳实践什么的都是骗人的. 1.安装VirtualBo ...
随机推荐
- BASIC-3 字母图形 循环 字符串
基础练习 字母图形 时间限制:1.0s 内存限制:256.0MB 问题描述 利用字母可以组成一些美丽的图形,下面给出了一个例子: ABCDEFG BABCDEF CBABCD ...
- gitlab勾住rocket chat
出于协作的要求, 需要在把gitlab的push event勾到rocket chat上面, 通知协作的其他人. BUT rocket chat提供的脚本没有具体的文件diff, so, 只好修改一下 ...
- Windows下搭建Redis服务器
Redis服务器是当下比较流行的缓存服务器,Redis通常被人拿来和Memcached进行对比.在我看来,应当是各具优势吧,虽然应用场景基本类似,但总会根据项目的不同来进行不通的选用. 我们今天主要讲 ...
- boltdb的实现
整个代码不是很复杂,可以从代码中理解如何实现. 特点:btree,很小巧,但实现了完整事务机制,稳定,即使丢电也不会导致数据库错误. 整个结构如下: meta page (前两页) --- > ...
- Python进阶内容(四)--- 迭代器(Iterator)与生成器(Generator)
迭代器 我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器和带yield的ge ...
- 【三分模板】洛谷P3382三分模板
题目描述 如题,给出一个N次函数,保证在范围[l,r]内存在一点x,使得[l,x]上单调增,[x,r]上单调减.试求出x的值. 输入输出格式 输入格式: 第一行一次包含一个正整数N和两个实数l.r,含 ...
- ReSharper 全教程
Resharper系列 更多关于Resharper的介绍 参考我之前的文章: Resharper 详细教程 提升ReSharper和Visual Studio的性能 Visual Studio中使用R ...
- 【整理】REACT一些自己感觉需要记的东西
REACT生命周期: 组件的生命周期可分成三个状态: Mounting:已插入真实 DOM Updating:正在被重新渲染 Unmounting:已移出真实 DOM 生命周期的方法有: compon ...
- 手把手教你用Vue造轮子(3):开发可排序的表格组件
前言 最近闰土大叔跟Vue干上了,没办法,公司业务驱动,不用Vue没招啊,leader尝到了前后端分离带来的好处,除非你离职,哈哈哈,当然,那是不可能的,对于我这种要攒钱买房子的人来说.那还说什么呢, ...
- ThinkPHP3.2中英文切换!
小伙伴们好久不见!!! 最近公司项目版本升级,小梦已经忙成了狗,无暇顾及文章,今天抽时间写一篇助助兴! 用Thinkphp这个国产框架已经2年多了,现在有一个小功能:网站中英文切换功能,当然这 ...