WPF: WpfWindowToolkit 一个窗口操作库的介绍
在 XAML 应用的开发过程中,使用 MVVM 框架能够极大地提高软件的可测试性、可维护性。MVVM 的核心思想是关注点分离,使得业务逻辑从 View 中分离出来到 ViewModel 以及 Model 中,从逻辑上来讲,这也是业务逻辑应该处的位置。
具体来说,借助于数据绑定 (Data Binding) 以及命令 (Command) 等这些XAML 平台自身所提供的机制,使得 MVVM 在 XAML 平台上很容易实现。但是,如果你对 XAML 应用开发以及 MVVM 的使用有一定的经验,你会发现,单纯 MVVM 本身并不能解决所有问题,比如页面导航、弹出对话框、窗口操作等,这时就需要结合一些与它相关的技术,如消息、行为、服务以及依赖注入等。这个原因是 MVVM 主要针对的是 View 的内容,而不是 View 本身的操作或其它别的东西,所以像弹出窗口或者页面导航之类的操作就需要上述技术的配合。
更具体一点,在 WPF 应用的开发过程中,很多时候我们需要打开和关闭窗口。要以“MVVM方式”来实现,就不容易。当然,我们可以使用消息来解决这个问题。不过,如果过多地使用消息,也会使代码难以维护并且增加调试的难度。
本文主要通过分享一个类库来解决这一问题:WpfWindowToolkit,就如名称所示,它是针对窗口的一些操作类的集合。

一、基本介绍
从介绍里,我们可以看出,它可以解决窗口的打开与关闭,以及在窗口间传递参数和返回值等类的问题,而实现这一切都不需要我们在 View 的 CodeBehind 中写任何代码,也不需要借助于消息,所需要作的修改仅在 XAML 代码和 ViewModel 中,从而遵循了 MVVM 的原则并达到了其目的。
从 Github (http://github.com/imnbwd/WpfWindowToolkit)下载到源码后,其中有 Demo,通过这个 Demo 我们可以了解它是如何使用的。在以下的内容里,我们先简单对它有些了解,更为具体的内容则可以看它的源码和 Demo。
二、安装
要在项目中使用它,可以从 Nuget 上下载,或者直接使用命令:
InstallPackage WpfWindowToolkit
三、如何使用
1. 打开窗口
有两种方式:使用附加属性或行为。
在使用时,需要先添加命名空间:
xmlns:behaviors="clr-namespace:PraiseHim.Rejoice.WpfWindowToolkit.Behaviors;assembly=WpfWindowToolkit"
xmlns:helpers="clr-namespace:PraiseHim.Rejoice.WpfWindowToolkit.Helpers;assembly=WpfWindowToolk
附加属性:
<Button x:Name="btn1"
helpers:WindowHelper.OpenWindowType="{x:Type local:Window1}"
Content="Open window using Window Helper" />
行为:
<Button x:Name="btn5"
Margin="0,5,0,0"
Content="Open window with parameter using action">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<behaviors:OpenWindowAction Parameter="WPF (action)" WindowType="{x:Type local:Window1}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
可以看出,它们都是通过将要打开的窗口的类型(Type) 指定给 WindowType 属性。
2. 打开窗口时传递参数
要在打开窗口的同时,向其 ViewModel 传递参数,也很简单。同上面一样,只需要再为 Parameter 属性赋值即可,这个 Parameter 可以绑定到当前窗口的 ViewModel 的成员上,因此,可以将任何类型的数据传递给要打开的窗口。
接下来,则是需要注意的,要对被打开的窗口的 ViewModel 作一些修改:使它继承 ViewModelBaseData<T>,这里的 T 就是所传递参数的类型。然后,通过 InternalData 属性即可得到传递过来的参数。
<behaviors:OpenWindowAction Parameter="WPF (action)" WindowType="{x:Type local:Window1}" />
public class Window1ViewModel : ViewModelBaseData<string>
{
protected override string InternalData { get; set; }
...
}
在打开窗口时,还有一种复杂的方式,同时也会给使用者更灵活的控制。方法是,当前窗口继承 ViewModelBaseEx 类,然后调用它的 ShowWindow 方法。在此,再不详述,具体可以参考 Github 上的说明文档。
3. 从被打开的窗口中返回值
当关闭打开的窗口,要实现这个目的,也需要两步,首先,第一个窗口(要打开其它窗口的那个窗口)的 ViewModel 需要继承 ViewModelBaseEx,或 ViewModelBaseEx<T> 类,然后使用 ShowWindow(OpenWindowInfo, Action<TReturnValue>) 方法来打开窗口,其中第二个参数是一个带参数的 Action,这里的参数就是返回值,在这个 Action 中,我们就可以处理返回值 。
public class ReturnValueMainWindowViewModel : ViewModelBaseEx<Friend>
{
public void ShowFriendSelectionWindow()
{
this.ShowWindow(new OpenWindowInfo { WindowType = typeof(ReturnValueTestWindow) }, friend =>
{
if (friend != null)
{
MessageBox.Show($"You have selected this friend: {friend.Name}");
}
else
{
MessageBox.Show("No friend has been selected");
}
});
}
}
第二步,被打开的窗口的 ViewModel,需要实现 IWindowReturnValue<T> 接口,这个接口包含 ReturnValue 属性,我们只要为它赋值就可以了。
public class ReturnValueTestWindowViewModel : BindableBase, IWindowReturnValue<Friend>
{
...
public void SetReturnValue()
{
ReturnValue = SelectedFriend;
}
...
}
4. 关闭窗口
在 View 中关闭
要关闭窗口,可以使用 CloseWindowAction,如下:
<Button Content="Close the current window with confirmation">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<behaviors:CloseWindowAction ClosingCheckFunc="{Binding CheckBeforeCloseWindow}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
它提供一个属性 ClosingCheckFunc,可以绑定到一个返回布尔值的函数,如果此函数返回 true,则关闭,否则,则不关闭。
处理 Window.Closing 事件
除此以外,在窗口被关闭时,它也提供对 Window 的 Closing 事件的支持,通常我们可能会在这个事件处理中来询问是否关闭窗口。要这么做,只要为当前窗口添加一个行为即可,如下:
<i:Interaction.Behaviors>
<behaviors:ClosingWindowBehavior ClosingCheckFunc="{Binding CheckBeforeCloseWindow}" />
</i:Interaction.Behaviors>
而其中的 ClosingCheckFunc 属性所指向的方法则是我们在 ViewModel 中添加的判断逻辑。
在 ViewModel 中关闭窗口
此外,它也支持在 ViewModel 的中来关闭当前窗口,首先,为窗口添加行为:
<Window>
<i:Interaction.Behaviors>
<behavior:EnableWindowCloseBehavior />
</i:Interaction.Behaviors>
...
</Window>
然后,ViewModel 需要实现 IClosable 接口,它包含一个 Action,名为CloseAction 并在合适的位置调用 CloseAction 即可。
public class CloseTestViewModel : BindableBase, IClosable
{
public Action CloseWindow { get; set; }
...
}
CloseWindow?.Invoke(); // or just CloseWindow();
总结
本文主要介绍了 WPF 窗口操作库——WpfWindowToolkit 的使用,它完全支持 MVVM,能够解决窗口的打开、关闭、窗口间的传值与返回值等问题。如果你正在开发 WPF 应用,并且采用了 MVVM 模式,不妨试一个这个库。要想多了解,可以到 Github 上下载其源码。
如果什么问题或建议,欢迎随时交流。
WPF: WpfWindowToolkit 一个窗口操作库的介绍的更多相关文章
- Cookie 详解以及实现一个 cookie 操作库
Cookie 详解以及实现一个 cookie 操作库 cookie 在前端有着大量的应用,但有时我们对它还是一知半解.下面来看看它的一些具体的用法 Set-Cookie 服务器通过设置响应头来设置客户 ...
- C# WPF使一个窗口挡在最前面,且不处理此窗口就不能点击其他窗口
模态框弹出就可以了.窗口用ShowDialog调用. 可以在子窗体里把WindowStartupLocation设置为CenterOwner, 让子窗体在MainWindow的中心位置显示
- libxl库的介绍,对Excel操作封装得很好的一个库,兼容2007版和多字节字符(最后有破解版下载)
前段时间忙着毕业论文,终于有时间写博客了. 早些时候老大给我的一个任务需要对excel进行读表操作,研究了一下c++对excel的操作. 对Excel的操作基本有com,ODBC,AD等,其中ODBC ...
- WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口)
原文 WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口) WPF 的 UI 逻辑只在同一个线程中,这是学习 WPF 开发中大家几乎都会学习到的经验.如果希望做不同线程 ...
- WPF实现只打开一个窗口,并且重复打开时已经打开的窗口置顶
内容来自:https://codereview.stackexchange.com/questions/20871/single-instance-wpf-application 第一步:添加Syst ...
- javascript进行百度换肤 和显示隐藏一个窗口的操作
简单的运用javascript来进行百度换肤的操作 <!DOCTYPE html> <html lang="en"> <head> <me ...
- IOTutility 一个轻量级的 IOT 基础操作库
IOTutility 一个轻量级的 IOT 基础操作库 Base utility for IOT devices, networking, controls etc... IOTutility 的目的 ...
- 使用 WPF 开发一个 Windows 屏幕保护程序
最近有小伙伴问我如何可以让 Windows 静置一段时间不操作之后,显示一个特殊的界面.我想了想,屏幕保护程序可以做到这一点,而且,屏幕保护程序的开发也是非常简单的. 本文将介绍如何为 Windows ...
- Python常用的库简单介绍一下
Python常用的库简单介绍一下fuzzywuzzy ,字符串模糊匹配. esmre ,正则表达式的加速器. colorama 主要用来给文本添加各种颜色,并且非常简单易用. Prettytable ...
随机推荐
- Gulp 的简单使用(原创)
1.安装nodejs 安装省略 npm的全称是Node Package Manager,是随同NodeJS一起安装的包管理和分发工具,它很方便让JavaScript开发者下载.安装.上传以及管理已经安 ...
- IOS学习7——cocoapod安装与使用教程
参考: iOS开发-CocoaPods使用详细说明 iOS开发-CocoaPods使用详细说明 一.CocoaPods简述 iOS开发时,项目中经常会需要引用第三方框架库,如果每用到一个第三方框架哦 ...
- iOS 通知的变化ios9-10,新功能展示
二.新功能展示 1 使用 /iOS通知新功能玩法 2. 全面 iOS10里的通知与推送详情 一.变化 四.Notification(通知) 自从Notification被引入之后,苹果就不断的 ...
- iOS UIWebView 加载进度条的使用-WKWebView的使用,更新2017.6.26
1.由于项目中加载网络插件,直接使用了webview加载.使用了三方NJKWebViewProgress进度条的使用,近期在测试时发现,网络缓慢时出现白屏,有卡顿现象. 于是采用了WKWebView进 ...
- 538. Convert BST to Greater Tree
Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original B ...
- js 自定义html标签属性
<input type="text" id="txtBox" displayName="123456" /> 获取自定义属性值: ...
- ecshop 属性表(attribute)商品属性表(goods_attr)货品表(prduct) 商品数量的联系
ecshop 属性表(attribute)商品属性表(goods_attr)货品表(prduct) 商品数量的联系 一个商城的商品属性存放在属性表(attribute)里 ,每个商品对应的属性在goo ...
- php-迭代创建级联目录
方法一代码: path = './a/b/c/d/e/f'; $path_arr = explode('/',$path);//得到数组array('.','a','b','c','d','e','f ...
- js 深入理解原型模式
我们创建每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象.使用原型的好处是可以让所有对象共享它所包含的属性和方法. function Person(){ } Pers ...
- 浅谈JavaScript的面向对象程序设计(一)
面向对象的语言有一个标志,他们都有类的概念,通过类可以创建多个具有相同属性和方法的对象.但是JavaScript中没有类的概念,因此JavaScript与其他的面向对象语言还是有一定区别的.JavaS ...