1. 程式人生 > >WPF MVVM模式中,通過命令實現窗體拖動、跳轉以及顯隱控制

WPF 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

本文原創,轉載請註明出處。