WPF MVVM模式中,通过命令实现窗体拖动、跳转以及显隐控制
原文:WPF MVVM模式中,通过命令实现窗体拖动、跳转以及显隐控制
在WPF中使用MVVM模式,可以让我们的程序实现界面与功能的分离,方便开发,易于维护。但是,很多初学者会在使用MVVM的过程中遇到一个显而易见且无法回避的问题,那就是不同的窗体之间如何跳转?很多人在介绍MVVM的使用时,都没有明显提到该如何解决这一问题,不知是因为觉得太简单了还是其他原因。
博主根据自己的开发经验,写了一个简单的示例程序,介绍MVVM模式中,如何通过命令来控制窗体的跳转、拖动与显隐控制。
先看效果:

主窗体中只有一个按钮,点击该按钮后,可以打开新的窗。

新窗体可以为自定义样式窗体,鼠标拖动标题框,可以拖动整个窗体,点击关闭按钮,窗体隐藏。
下面是实现操作:
1.定义命令类ActionCommand.
使用MVVM模式的第一步,就是要实现自己的命令类。
public class ActionCommand<T> : ICommand where T : class
{
private Predicate<T> _canExecuteMethod;
private Action<T> _executeMethod; public ActionCommand(Action<T> executeMethod)
{
_canExecuteMethod = null;
_executeMethod = executeMethod;
} public ActionCommand(Action<T> executeMethod, Predicate<T> canExecuteMethod)
{
_canExecuteMethod = canExecuteMethod;
_executeMethod = executeMethod;
} public bool CanExecute(object parameter)
{
return _canExecuteMethod == null ? true : _canExecuteMethod(parameter as T);
} public event EventHandler CanExecuteChanged; public void Execute(object parameter)
{
if (_executeMethod != null)
{
_executeMethod(parameter as T);
}
UpdateCanExecute();
} public void UpdateCanExecute()
{
var handls = CanExecuteChanged;
if (handls != null)
{
handls(this, new EventArgs());
}
}
}
2.在App.xaml中定义窗体导航实现代码以及窗体操作命令
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
private static bool _bDebug = true;
public static void MessageBox(string text, string caption)
{
if (_bDebug)
{
System.Windows.MessageBox.Show(text, caption);
} } private static Dictionary<string, Window> _cacheWindow = new Dictionary<string, Window>();
public static Window NavigationToWindow(string wndUri, bool createNew = false, bool cache = true, string cacheKey = null)
{
Window window = null;
string key = string.IsNullOrWhiteSpace(cacheKey) ? wndUri : cacheKey;
if (createNew)
{
window = App.Current.GetType().Assembly.CreateInstance(wndUri) as Window;
if (cache && window != null)
{
if (!_cacheWindow.ContainsKey(key))
{
_cacheWindow.Add(key, window);
}
}
}
else
{
if (_cacheWindow.ContainsKey(key))
{
window = _cacheWindow[key];
}
else
{
window = App.Current.GetType().Assembly.CreateInstance(wndUri) as Window;
if (cache && window != null)
{
_cacheWindow.Add(key, window);
}
}
}
return window;
} /// <summary>
/// 显示窗体命令
/// </summary>
public static ICommand ShowWindowCommand
{
get
{
return new ActionCommand<string>(p =>
{
if (string.IsNullOrWhiteSpace(p))
{
App.MessageBox("参数不能为空!", "[App][ShowWindowCommand]");
return;
}
string[] arrs = p.Split(','); string wndUri = null, cacheKey = null;
bool createNewWnd = false, cacheWnd = true;
try
{
if (arrs.Length > 3)
{
wndUri = arrs[0];
createNewWnd = Convert.ToBoolean(arrs[1]);
cacheWnd = Convert.ToBoolean(arrs[2]);
cacheKey = arrs[3];
}
else if (arrs.Length > 2)
{
wndUri = arrs[0];
createNewWnd = Convert.ToBoolean(arrs[1]);
cacheWnd = Convert.ToBoolean(arrs[2]);
}
else if (arrs.Length > 1)
{
wndUri = arrs[0];
createNewWnd = Convert.ToBoolean(arrs[1]);
}
else
{
wndUri = arrs[0];
}
Window window = NavigationToWindow(wndUri, createNewWnd, cacheWnd, cacheKey);
if (window == null)
{
App.MessageBox("未找到导航窗体" + "[" + wndUri + "]", "[App][ShowWindowCommand]");
return;
}
window.Owner = App.Current.MainWindow;
if (!window.IsVisible)
{
window.Show();
}
else
{
window.Hide();
}
}
catch (Exception ex)
{
App.MessageBox(ex.Message, "[App][ShowWindowCommand]");
} }
);
}
} /// <summary>
/// 隐藏窗体命令
/// </summary>
public static ICommand HideWindowCommand
{
get
{
return new ActionCommand<string>(p =>
{
if (string.IsNullOrWhiteSpace(p))
{
App.MessageBox("参数不能为空!", "[App][HideWindowCommand]");
return;
} Window window = App.NavigationToWindow(p);
if (window != null)
{
window.Hide();
}
}
);
}
} /// <summary>
/// 拖动窗体命令
/// </summary>
public static ICommand DragMoveWindowCommand
{
get
{
return new ActionCommand<string>(p =>
{
if (string.IsNullOrWhiteSpace(p))
{
App.MessageBox("参数不能为空!", "[App][DrawMoveWindowCommand]");
return;
} Window window = App.NavigationToWindow(p);
if (window != null)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
window.DragMove();
}
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
}
}
}
);
}
}
}
3.在主窗体中使用ShowCommand命令来实现窗体导航。
<Window x:Class="WpfMVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfMVVM"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Width="100" Height="40" Content="打开新窗体" Command="{x:Static local:App.ShowWindowCommand}"
CommandParameter="WpfMVVM.View.CustomWindow"/>
</Grid>
</Window>
4.在自定义窗体CustomWindow.xaml中使用命令来实现窗体拖动和显隐控制。
为了使得Grid中的MouseMove事件能够响应命令绑定操作,导入blend中的类库:System.Windows.Interactivity.dll。并在页面中导入xml命名空间:xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"。这样就可以实现WPF中任意事件的命令响应。
<Window x:Class="WpfMVVM.View.CustomWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfMVVM"
Title="CustomWindow" Height="300" Width="300"
WindowStyle="None" AllowsTransparency="True"
ShowInTaskbar="False"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions> <Grid Grid.Row="0" Background="{StaticResource BoardHead}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="标题" Style="{StaticResource BoardTitle}"/>
<Button Grid.Column="1" Style="{StaticResource CloseBtn}"
Command="{x:Static local:App.HideWindowCommand}"
CommandParameter="WpfMVVM.View.CustomWindow"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseMove">
<i:InvokeCommandAction Command="{x:Static local:App.DragMoveWindowCommand}"
CommandParameter="WpfMVVM.View.CustomWindow"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid> <Grid Grid.Row="1" Background="{StaticResource BoardBody}">
<Image Source="/Resource/sun.png" Stretch="Uniform"/>
</Grid> </Grid>
</Window>
通过以上步骤操作,我们便可以实现窗体之间的导航以及自定义窗体的拖动控制以及显隐控制。
完整代码下载:http://download.csdn.net/detail/tianwenxue/9078205。
本文原创,转载请注明出处。
WPF MVVM模式中,通过命令实现窗体拖动、跳转以及显隐控制的更多相关文章
- WPF自学入门(十一)WPF MVVM模式Command命令 WPF自学入门(十)WPF MVVM简单介绍
WPF自学入门(十一)WPF MVVM模式Command命令 在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式 ...
- WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参
原文:WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参 ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataC ...
- WPF MVVM模式的一些理解
/*本文转自 http://www.cnblogs.com/sirkevin/archive/2012/11/28/2793471.html */ 使用WPF+Mvvm开发一年多,期间由于对Mvvm模 ...
- WPF 在事件中绑定命令(不可以在模版中绑定命令)
其实这也不属于MVVMLight系列中的东东了,没兴趣的朋友可以跳过这篇文章,本文主要介绍如何在WPF中实现将命令绑定到事件中. 上一篇中我们介绍了MVVMLight中的命令的用法,那么仅仅知道命令是 ...
- WPF 在事件中绑定命令
导航:MVVMLight系列文章目录:<关于 MVVMLight 设计模式系列> 其实这也不属于MVVMLight系列中的东东了,没兴趣的朋友可以跳过这篇文章,本文主要介绍如何在WPF中实 ...
- 在MVVM模式中,按钮Click事件的绑定方法
在MVVM模式中,我们将Button的方法写到ViewModel中,然后绑定到前端界面.通常的做法是写一个类,继承ICommand接口,然而如果按钮比较多的话,就需要写很多的类,对于后期维护造成很大的 ...
- silverlighter下MVVM模式中利用Behavior和TargetedTriggerAction实现文本框的一些特效
在silverlight一般开发模式中,给文本框添加一些事件是轻而易举的,然而MVVM开发模式中,想要给文本框添加一些事件并非那么容易,因为MVVM模式中,只有ICommand接口,而且也只有Butt ...
- “Win10 UAP 开发系列”之 在MVVM模式中控制ListView滚动位置
这个扩展属性从WP8.1就开始用了,主要是为了解决MVVM模式中无法直接控制ListView滚动位置的问题.比如在VM中刷新了数据,需要将View中的ListView滚动到顶部,ListView只有一 ...
- windows下命令行模式中cd命令无效的原因
当我们执行cmd 想切换当前工作目录时,会发现windows下命令行模式中cd命令没有生效,到底是什么原因呢? 例如: 当我们想切换到 D:\MySql\mysql-5.7.19-winx64\bin ...
随机推荐
- Codeforces Round #Pi (Div. 2) B Berland National Library
B. Berland National Library time limit per test1 second memory limit per test256 megabytes inputstan ...
- widow下svn上传项目时的文件可执行权限问题
还是项目上发现的问题,要上传Android的源码项目.这里客户端是windows的机器, 测试后发现俩个问题. 1. 文件后缀是.so的文件默认上传不了. 2. 文件后缀是.sh的文件,上传后, ...
- HDU4911-Inversion
题意:依据题目要求交换相邻的两个元素k次,使得最后剩下的逆序对数最少 思路:假设逆序数大于0,存在0 <= i < n使得交换Ai,Ai+1后逆序数降低1,所求答案就为max(invers ...
- 小白学开发(iOS)OC_ 使用继承来扩充类(2015-08-07)
// // main.m // 使用继承来扩充类 // // Created by admin on 15/8/12. // Copyright (c) 2015年 admin. All ri ...
- jquery ajax实现省市二级联动
今天给大家带来使用jQuery ajax实现的省市联动效果.我们直奔主题,先说下实现思路: 准备数据 这里数据库我使用的是mysql,先看下表格: provience表 city表 这里使用provi ...
- 使用LAMP创建基于wordpress的个从博客网站 分类: B3_LINUX 2014-07-15 16:45 800人阅读 评论(0) 收藏
参考: http://blog.csdn.net/ck_boss/article/details/27866117 一.mysql配置 1.安装mysql yum install mysql-serv ...
- 【搜索引擎Jediael开发笔记】v0.1完整代码 2014-05-26 15:17 463人阅读 评论(0) 收藏
详细代码请见 E:\Project\[重要]归档代码\SearchEngine归档代码 或 https://code.csdn.net/jediael_lu/jediael/tree/10991c83 ...
- 数组filter方法对数组元素进行过滤
Array.prototype.filter对数组中元素进行过滤 /** * @method reduce * @param {number} item 当前迭代的数组元素 * @param {num ...
- 搭建微信小程序开发环境
1.下载开发工具 点击进入下载地址选择和自己电脑匹配的安装包,并安装: image.png 安装完成后出现应用icon: image.png 2.创建项目 能够扫码登录的前提是微信号已经注册了小程序, ...
- [Angular] Create a custom pipe
For example we want to create a pipe, to tranform byte to Mb. We using it in html like: <div> ...