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。
本文原创,转载请注明出处。