原文: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模式中,通过命令实现窗体拖动、跳转以及显隐控制的更多相关文章

  1. WPF自学入门(十一)WPF MVVM模式Command命令 WPF自学入门(十)WPF MVVM简单介绍

    WPF自学入门(十一)WPF MVVM模式Command命令   在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式 ...

  2. WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参

    原文:WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参 ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataC ...

  3. WPF MVVM模式的一些理解

    /*本文转自 http://www.cnblogs.com/sirkevin/archive/2012/11/28/2793471.html */ 使用WPF+Mvvm开发一年多,期间由于对Mvvm模 ...

  4. WPF 在事件中绑定命令(不可以在模版中绑定命令)

    其实这也不属于MVVMLight系列中的东东了,没兴趣的朋友可以跳过这篇文章,本文主要介绍如何在WPF中实现将命令绑定到事件中. 上一篇中我们介绍了MVVMLight中的命令的用法,那么仅仅知道命令是 ...

  5. WPF 在事件中绑定命令

    导航:MVVMLight系列文章目录:<关于 MVVMLight 设计模式系列> 其实这也不属于MVVMLight系列中的东东了,没兴趣的朋友可以跳过这篇文章,本文主要介绍如何在WPF中实 ...

  6. 在MVVM模式中,按钮Click事件的绑定方法

    在MVVM模式中,我们将Button的方法写到ViewModel中,然后绑定到前端界面.通常的做法是写一个类,继承ICommand接口,然而如果按钮比较多的话,就需要写很多的类,对于后期维护造成很大的 ...

  7. silverlighter下MVVM模式中利用Behavior和TargetedTriggerAction实现文本框的一些特效

    在silverlight一般开发模式中,给文本框添加一些事件是轻而易举的,然而MVVM开发模式中,想要给文本框添加一些事件并非那么容易,因为MVVM模式中,只有ICommand接口,而且也只有Butt ...

  8. “Win10 UAP 开发系列”之 在MVVM模式中控制ListView滚动位置

    这个扩展属性从WP8.1就开始用了,主要是为了解决MVVM模式中无法直接控制ListView滚动位置的问题.比如在VM中刷新了数据,需要将View中的ListView滚动到顶部,ListView只有一 ...

  9. windows下命令行模式中cd命令无效的原因

    当我们执行cmd 想切换当前工作目录时,会发现windows下命令行模式中cd命令没有生效,到底是什么原因呢? 例如: 当我们想切换到 D:\MySql\mysql-5.7.19-winx64\bin ...

随机推荐

  1. [Maven实战](6)仓库(本地仓库,远程仓库,镜像)

    1. 简单介绍 maven能够在某个位置统一存储全部maven项目共享的构件,这个统一的位置就是仓库.实际的Maven项目将不会各自存储其依赖文件,它们仅仅须要声明这些依赖的坐标,在须要的时候(比如. ...

  2. Java性能优化技巧集锦

    一.通用篇 "通用篇"讨论的问题适合于大多数Java应用. 1.1 不用new关键词创建类的实例 用new关键词创建类的实例时,构造函数链中的全部构造函数都会被自己主动调用.但假设 ...

  3. RDA安装

    解压到/home/oracle下面     $ cp /home/oracle/rda $ perl rda.pl -cv   运行上面的命令,如果最后一行出现下面所示,说明没问题       No ...

  4. android 应用内部获取本应用或者相应包名的应用的SHA1签名的办法

    我这个人比較懒.每次做的都是心血来潮,所以打算改掉这个坏毛病.昨晚非常晚才睡,躺在床上一直在回忆.这两年来,我以前的目标是什么,我放弃了什么,我完毕了什么. 结果目标非常多,也放弃了一些. 完毕的差点 ...

  5. angular自定义指令相关知识及代码

    原文地址 https://www.jianshu.com/p/0c015862156d 大纲 1.自定义指令之——属性指令 2.自定义属性指令的运行原理 3.自定义属性指令代码实践 4.自定义结构指令 ...

  6. [乐意黎原创] eclipse Kepler Selected SVN connector library is not available or cannot be loaded

    问题描写叙述:已经安装了subversive,可是在从SCM导入maven项目时.还是提示报错(如标题),依据报错原因发如今Team>SVN中确实没有svn连接器. 折腾了半天, 硬是没有结果. ...

  7. ios开发runtime学习四:动态添加属性

    #import "ViewController.h" #import "Person.h" #import "NSObject+Property.h& ...

  8. Android自定义组件系列【3】——自定义ViewGroup实现侧滑

    有关自定义ViewGroup的文章已经很多了,我为什么写这篇文章,对于初学者或者对自定义组件比较生疏的朋友虽然可以拿来主义的用了,但是要一步一步的实现和了解其中的过程和原理才能真真脱离别人的代码,举一 ...

  9. php 获取提交来源,判断从哪里提交的

    echo $_SERVER['HTTP_REFERER'];这个获取上个页面的url例如获得的是 $url = http://www.weisuyun.com/nihao.html其他页面提交过来的不 ...

  10. RFC chinese

    rfc专业性强,现实中不可能有好的全的rfc的翻译 尝试上在github上搜索 https://github.com/tidyjiang8/6lowpan-rfcs-chinese 诚如作者所说: 在 ...