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 ...
随机推荐
- js json简介(json的本质也是字符串)(用于服务器和客户端通信)
js json简介(json的本质也是字符串)(用于服务器和客户端通信) 一.总结 1.json的语法和js的语法非常像,只是json的键和值都是双引号,因为json的本质也是字符串 2.json是一 ...
- [array] leetCode-15. 3Sum-Medium
leetCode-15. 3Sum-Medium descrition Given an array S of n integers, are there elements a, b, c in S ...
- 关于stm32的启动模式
1)用户闪存 = 芯片内置的Flash,这个应该就是在Keil中选择那个,每个芯片的flash不一样,具体可以在建立工程时查看内置flash的大小. 2)SRAM = 芯片内置的RAM区,就是内存啦. ...
- Linux下搭建Memcached缓存系统
首先说下抱歉,博主近期单位经常加班.博客更新有点慢.希望大家理解,草稿箱里存了不少内容,等不忙时候一点点填坑~ 在一般的站点开发学习时候.都会把数据存放在RDBMS(关系型数据库系统(Relation ...
- Win7的ftp功能
ftp作为文件传输协议,在一些特殊情况下用这种文件传输是比较方便的,并且win7本身也支持这个功能,在控制面板--->程序-->打开或关闭Windows功能,安装即可: 然后在管理控制台中 ...
- ng-cli搭建angular项目框架
原文地址 https://www.jianshu.com/p/0a8f4b0f29b3 环境准备 以下步骤都不需要事先创建文件夹,只是环境的准备过程,只有到需要搭建项目的时候才需要创建文件夹用来存放项 ...
- Uploadify404无效链接
Uploadify404无效链接 在使用Jquery Uploadify插件的時候.会发如今请求中有个返回值为404的请求. 假如如今的location为www.aa.com/bugs/more. h ...
- The DOT Language
CSDN新首页上线啦,邀请你来立即体验! 立即体验 博客 学院 下载 更多 登录注册 The DOT Language 翻译 2014年04月15日 11:27:07 标签: EBNF / 语言 / ...
- ArcEngine 图层标注 (根据字段、角度)
转自chanyinhelv原文 ArcEngine 图层标注 (根据字段.角度) 今天做了一个用AE来控制图层是否显示标注,以及已哪一个字段作为标注的字段,以哪一个字段作为标注的角度,现将代码写下来, ...
- VS2013 Qt5显示中文字符
VS2013上建立的Qt5project中显示中文字符的两种方式: 1. QStringLiteral("開始") 2. QString::fromLocal8Bit(" ...