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

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

在WPF中使用MVVM模式,可以让我们的程序实现界面与功能的分离,方便开发,易于维护。但是,很多初学者会在使用MVVM的过程中遇到一个显而易见且无法回避的问题,那就是不同的窗体之间如何跳转?很多人在介绍MVVM的使用时,都没有明显提到该如何解决这一问题,不知是因为觉得太简单了还是其他原因。

博主根据自己的开发经验,写了一个简单的示例程序,介绍MVVM模式中,如何通过命令来控制窗体的跳转、拖动与显隐控制。

先看效果:

搜狗截图20150904171343

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

搜狗截图20150904171406

新窗体可以为自定义样式窗体,鼠标拖动标题框,可以拖动整个窗体,点击关闭按钮,窗体隐藏。

下面是实现操作:

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

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

目录
相关文章
|
2月前
|
设计模式 前端开发 C#
WPF 项目中 MVVM模式 的简单例子说明
本文通过WPF项目中的加法操作示例,讲解了MVVM模式的结构和实现方法,包括数据模型、视图、视图模型的创建和数据绑定,以及命令的实现和事件通知机制。
|
3月前
|
C# 微服务 Windows
模块化革命:揭秘WPF与微服务架构的完美融合——从单一职责原则到事件聚合器模式,构建高度解耦与可扩展的应用程序
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中借鉴微服务架构思想,实现模块化设计。通过将WPF应用分解为独立的功能模块,并利用事件聚合器实现模块间解耦通信,可以有效提升开发效率和系统可维护性。文中还提供了具体示例代码,展示了如何使用事件聚合器进行模块间通信,以及如何利用依赖注入进一步提高模块解耦程度。此方法不仅有助于简化复杂度,还能使应用更加灵活易扩展。
99 0
|
3月前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
96 0
|
3月前
|
前端开发 开发者 C#
WPF开发者必读:MVVM模式实战,轻松实现现代桌面应用架构,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离应用程序的逻辑和界面,提高了代码的可维护性和可扩展性。本文介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定和逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种方式,开发者可以构建更加高效和可扩展的桌面应用程序。
159 0
|
3月前
|
前端开发 C# 开发者
WPF开发者必读:MVVM模式实战,轻松构建可维护的应用程序,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离关注点,提高了代码的可维护性和可扩展性。本文详细介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定与逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种模式,开发者可以更高效地构建桌面应用程序。希望本文能帮助你在WPF开发中更好地应用MVVM模式。
179 0
|
3月前
|
C#
WPF 自定义可拖动标题栏
WPF 自定义可拖动标题栏
50 0
|
3月前
|
C#
WPF/C#:程序关闭的三种模式
WPF/C#:程序关闭的三种模式
61 0
|
3月前
|
设计模式 前端开发 C#
WPF/C#:理解与实现WPF中的MVVM模式
WPF/C#:理解与实现WPF中的MVVM模式
181 0
|
6月前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
384 0
|
3月前
|
开发框架 缓存 前端开发
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件