WPF MVVM從入門到精通7:關閉窗口和打開新窗口


若是登錄成功,我們一般會執行的操作是關閉當前窗口,然后打開一個新的窗口。但為了比較理想地實現MVVM,我們被禁止在ViewModel里面訪問View的元素。那我們該如何實現上面的功能呢?

首先是打開窗口的功能,我們使用的方法是:

(1)窗口初始化的時候即注冊需要訪問的新窗口。

(2)ViewModel在需要打開新窗口時,使用注冊過的窗口。

我們先定義一個WindowManager類:

    using System;
    using System.Collections;
    using System.Windows;
     
    namespace LoginDemo.ViewModel.Common
    {
        /// <summary>
        /// 窗口管理器
        /// </summary>
        public static class WindowManager
        {
            private static Hashtable _RegisterWindow = new Hashtable();
     
            public static void Register<T>(string key)
            {
                if (!_RegisterWindow.Contains(key))
                {
                    _RegisterWindow.Add(key, typeof(T));
                }
            }
     
            public static void Register(string key, Type t)
            {
                if (!_RegisterWindow.Contains(key))
                {
                    _RegisterWindow.Add(key, t);
                }
            }
     
            public static void Remove(string key)
            {
                if (_RegisterWindow.ContainsKey(key))
                {
                    _RegisterWindow.Remove(key);
                }
            }
     
            public static void Show(string key, object VM)
            {
                if (_RegisterWindow.ContainsKey(key))
                {
                    var win = (Window)Activator.CreateInstance((Type)_RegisterWindow[key]);
                    win.DataContext = VM;
                    win.Show();
                }
            }
        }
    }

代碼比較簡單,就不解釋了。然后我們在LoginWindow的構造函數里添加代碼,變成如下所示:

    using LoginDemo.ViewModel.Common;
    using LoginDemo.ViewModel.Login;
    using System.Windows;
     
    namespace LoginDemo
    {
        /// <summary>
        /// LoginWindow.xaml 的交互邏輯
        /// </summary>
        public partial class LoginWindow : Window
        {
            public LoginWindow()
            {
                InitializeComponent();
     
                this.DataContext = new LoginViewModel();
     
                WindowManager.Register<MainWindow>("MainWindow");
            }
        }
    }

是不是發現這里說好只加一行,現在又加一行代碼了?實在沒有辦法,打開窗口就是要這么做。

然后我們在ViewModel需要打開窗口的地方寫下面一行代碼:

WindowManager.Show("MainWindow", null);

這樣新的窗口就能在ViewModel里面被打開了。

 

我們接下來說關閉窗口。要做到這一功能,我們又要借助System.Windows.Interacivity里面的Behavior。它可以把ViewModel里面的一個屬性,關聯到View層的一個事件(我們這里當然是要關聯Window.Close())。

我們先來定義這個關閉行為:

    using System.Windows;
    using System.Windows.Interactivity;
     
    namespace LoginDemo.ViewModel.Common
    {
        /// <summary>
        /// 窗口行為
        /// </summary>
        public class WindowBehavior : Behavior<Window>
        {
            /// <summary>
            /// 關閉窗口
            /// </summary>
            public bool Close
            {
                get { return (bool)GetValue(CloseProperty); }
                set { SetValue(CloseProperty, value); }
            }
            public static readonly DependencyProperty CloseProperty =
                DependencyProperty.Register("Close", typeof(bool), typeof(WindowBehavior), new PropertyMetadata(false, OnCloseChanged));
            private static void OnCloseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                var window = ((WindowBehavior)d).AssociatedObject;
                var newValue = (bool)e.NewValue;
                if (newValue)
                {
                    window.Close();
                }
            }
     
        }
    }

然后我們在XAML文件里增加以下內容:

    <i:Interaction.Behaviors>
        <c:WindowBehavior Close="{Binding ToClose}"/>
    </i:Interaction.Behaviors>

這樣的話,窗口的關閉事件就綁定到了ViewModel里面的ToClose屬性了。但這個屬性還沒有呢,定義一個:

    private bool toClose = false;
    /// <summary>
    /// 是否要關閉窗口
    /// </summary>
    public bool ToClose
    {
        get
        {
            return toClose;
        }
        set
        {
            toClose = value;
            if (toClose)
            {
                this.RaisePropertyChanged("ToClose");
            }
        }
    }

如此,只要我們在ViewModel里面執行ToClose=true;,當前窗口就會關閉。這節的內容體現在點擊登錄按鈕上,大體如下:

    private BaseCommand loginClick;
    /// <summary>
    /// 登錄事件
    /// </summary>
    public BaseCommand LoginClick
    {
        get
        {
            if (loginClick == null)
            {
                loginClick = new BaseCommand(new Action<object>(o =>
                {
                    //執行登錄邏輯
                    WindowManager.Show("MainWindow", null);
                    ToClose = true;
                }));
            }
            return loginClick;
        }
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM