若是登录成功,我们一般会执行的操作是关闭当前窗口,然后打开一个新的窗口。但为了比较理想地实现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;}}