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

本文原创,转载请注明出处。

时间: 2024-10-27 08:58:52

WPF MVVM模式中,通过命令实现窗体拖动、跳转以及显隐控制的相关文章

实战基础技能(08)--------MVVM模式中WPF数据的完全绑定

一:截图,描述:将后台代码的姓名.年龄绑定到文本框,单击”增加年龄“--年龄自+1,单击”显示年龄“--弹出年龄的显示对话框,实现了从文本框修改年龄和后台更改年龄并显示到文本框 运行结果和解决方案管理截图如下: 二:person类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; namespace 完全数据绑定 {

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

原文:WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参 ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataContext,所以如果要绑定父级的DataContext,直接DataContext=“{Binding}”是行不通的 不能绑父级,但是能绑资源 第一步:定义一个中间类用来做资源对象 1 public class BindingProxy : Freezable 2 { 3 #region Over

WPF MVVM模式的一些理解

/*本文转自 http://www.cnblogs.com/sirkevin/archive/2012/11/28/2793471.html */ 使用WPF+Mvvm开发一年多,期间由于对Mvvm模式的理解不足,遇到了很多问题,也绕了很多弯子:网上提供的Mvvm的示例比较简单,实际项目中的需求也各种各样.不过经过几个项目,也有了一些对Mvvm模式的理解: 1. Mvvm是什么,Mvvm是怎么来的?Mvvm模式广泛应用在WPF项目开发中,使用此模式可以把UI和业务逻辑分离开,使UI设计人员和业务

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

其实这也不属于MVVMLight系列中的东东了,没兴趣的朋友可以跳过这篇文章,本文主要介绍如何在WPF中实现将命令绑定到事件中. 上一篇中我们介绍了MVVMLight中的命令的用法,那么仅仅知道命令是如何构建使用的还不够,很多情况下我们都需要在某个事件触发的时候才去触发命令,所以将命令绑定到事件上是非常有效的做法,下面我们来接着实现将命令绑定到事件中. WPF实现命令绑定到事件 使用 System.Windows.Interactivity.dll 中的 Interaction 可以帮助我们实现

WPF 在事件中绑定命令

导航:MVVMLight系列文章目录:<关于 MVVMLight 设计模式系列> 其实这也不属于MVVMLight系列中的东东了,没兴趣的朋友可以跳过这篇文章,本文主要介绍如何在WPF中实现将命令绑定到事件中. 上一篇中我们介绍了MVVMLight中的命令的用法,那么仅仅知道命令是如何构建使用的还不够,很多情况下我们都需要在某个事件触发的时候才去触发命令,所以将命令绑定到事件上是非常有效的做法,下面我们来接着实现将命令绑定到事件中. WPF实现命令绑定到事件 使用 System.Windows

WPF MVVM模式

1. MVVM MVVM的设计模式最早于2005年由微软的WPF和Silverlight架构师John Gossman在他的博客中提到. WPF中采用MVVM的架构可以获得以下好处: 1. 将UI和业务的设计完全分开,View只是ViewModel的消费者 2. 有助于我们区别并哪些是UI操作,哪些是业务操作,而不是将他们混淆 3.层与层之间耦合度降低,这一点非常符合面向对象(OOP)的思想. 2.MVVM 用图来表示,这个是从网上找的图,简单明了,省去了自己画.   3.下面来一步一步写代码吧

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

原文:在MVVM模式中,按钮Click事件的绑定方法 在MVVM模式中,我们将Button的方法写到ViewModel中,然后绑定到前端界面.通常的做法是写一个类,继承ICommand接口,然而如果按钮比较多的话,就需要写很多的类,对于后期维护造成很大的不变,微软提供了一个DelegateCommand类,可以简化开发. 使用方法如下: 首先生命ViewModel属性,GetMsg函数, public DelegateCommand GetMsg { get { return new Deleg

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

这个扩展属性从WP8.1就开始用了,主要是为了解决MVVM模式中无法直接控制ListView滚动位置的问题.比如在VM中刷新了数据,需要将View中的ListView滚动到顶部,ListView只有一个ScrollIntoView()方法可以控制滚动的位置,但最好在VM中不要出现直接控制View的代码,需要通过其他的方式. 使用一个扩展属性即可实现: /// <summary> /// 将ListView滚动到顶部 使用方法:在ListView增加扩展属性 /// ext:ListViewSc

Messenger在MVVM模式中的应用

Messenger在MVVM模式中的应用 Messenger在MVVM中应用的前提 我们知道在MVVM架构中,系统平台的Silverlight客户端界面开发和业务逻辑已经被分开,XAML是SL的主要部分,界面设计者只需要绑定ViewModel里的数据即可.但是在ViewModel里有些时候是需要界面发出响应的,在这种情况下,Messenger显示出它的用处. Messenger的架构 Messager构件代码 定义Imessager接口 注册一个接收消息的类型,比如某一控件来接收消息 void