如何使用MVVM Light Toolkit打开一个新窗口

我在我的WPF应用程序中使用MVVM Light工具包。 我想知道从现有窗口打开新窗口的最佳方法是什么。 我有这个MainViewModel ,它负责我的应用程序的MainWindow 。 现在在MainView ,点击一个button,我想打开第二个窗口。 我有RelayCommmand绑定到ButtonCommand 。 在RelayCommand的方法中,我可以创build一个新的窗口对象,并简单地调用Show() ,如下所示:

 var view2 = new view2() view2.Show() 

但我不认为ViewModel应该负责创build新的view2对象。 我已经阅读这篇文章WPF MVVM从视图模型中获取父母,其中Bugnionbuild议从viewmodel1传递消息到view1 ,然后view1应该创build新的view2 。 但是我不确定把这个消息传递给view1是什么意思呢? view1如何处理消息? 在代码背后还是什么?

问候,Nabeel

将ViewModel1消息传递给View1意味着使用MVVM Light Toolkit中的消息传递function 。

例如,您的ViewModel1可以有一个名为ShowView2Command的命令,然后它会发送一条消息来显示视图。

 public class ViewModel1 : ViewModelBase { public RelayCommand ShowView2Command { private set; get; } public ViewModel1() : base() { ShowView2Command = new RelayCommand(ShowView2CommandExecute); } public void ShowView2CommandExecute() { Messenger.Default.Send(new NotificationMessage("ShowView2")); } } 

View1将在其后面的代码中注册接收消息,并在收到正确的消息时显示View2。

 public partial class View1 : UserControl { public View1() { InitializeComponent(); Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived); } private void NotificationMessageReceived(NotificationMessage msg) { if (msg.Notification == "ShowView2") { var view2 = new view2(); view2.Show(); } } } 

你为什么走这条路? 这很简单。 如果用toggleButton或超链接或任何其他数量的button式控件replacebutton,则不需要更新“后面的代码” – 它是MVVM模式的基本原理。 在你的新toggleButton(或其他),你仍然最终绑定到同一个确切的命令。

例如,我正在为一个想要有2个用户界面的客户创build一个项目 – 在演示方面,每个用户都会有根本的不同。 水平选项卡与垂直RadPanelBar(认为手风琴)进行导航。 这两个视图都可以指向相同的viewModel – 当用户单击视图1中的工作订单选项卡时,它会激发面板栏中工作订单标题中触发的相同“WorkOrderCommand”。

在一个代码隐藏模型中,你必须编写两个单独的事件。 在这里你只需要编码一个。

此外,它允许使用Blend的devise师创build他们想要的任何布局。 只要他们有hook(EventToCommand控件),我自己(作为开发人员)就不会在乎最终产品的外观。

松耦合是非常强大的。

你可以这样做,就像你需要创build一些事件,并在视图中注册这些事件,并在视图模型中调用这些事件并打开popup窗口。

喜欢这个例子

 public class Mainclass : MainView { public delegate abc RegisterPopUp(abc A); public RegisterPopUp POpUpEvent ; public RelayCommand ShowCommand { private set; get; } public void ShowCommand() { ShowCommand("Your parameter"); } } 

在视图内部MainView mn=new MainView();

在这里注册事件像thake mn.POpUpEvent +=比双击标签button时间

并在寄存器popup方法右边打开popup窗口的代码。

除非我在这里忽略了一点 – 如果我使用后面的代码,那么为什么不直接实现button_click事件并打开第二个视图?

Bugnion似乎暗示的是view1 – > button click – > relay命令 – > viewmodel1 – > message – > view1 – > view1.cs – >打开view 2。

无论如何,通过编写代码将会牺牲可testing性,那么为什么要采用这么长的路线呢?

您可以使用通用接口将视图特定的function抽象为服务。 在视图层中,您可以提供这些服务的具体实例,并使用IoC容器和dependency injection技术构build视图模型。

在你的情况下,你可以build立一个接口IWindowManager或类似的具有所需的方法。 这可以在你的视图层中实现。 我最近写了一篇小博客post,演示了如何将对话行为抽象出来的视图模型。 类似的apporach可以用于任何用户界面相关的服务,如导航,消息框等

此链接可能对您有所帮助http://nileshgule.blogspot.com/2011/05/silverlight-use-dialogservice-to.html

许多人也使用从view.cs文件中订阅的视图模型中触发事件的方法,并从那里执行MessageBox或任何其他UI相关的操作。 我个人喜欢注入服务的方法,因为那样你可以提供同一服务的多个实现。 一个简单的例子就是如何在Silverlight和Windows Phone 7应用程序中处理导航。 您可以使用相同的视图模型,但根据应用程序types注入不同的导航服务实现。

我find了解决这个问题的最好方法,就是从ViewModel打开和closures窗口。 正如这个链接build议的,

  1. 创build一个DialogCloser
    公共静态类DialogCloser
     {
         public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached(“DialogResult”,typeof(bool?),typeof(DialogCloser),new PropertyMetadata(DialogResultChanged));

         private static void DialogResultChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
         {
             var window = d作为Window;
             if(window!= null)window.Close();
         }

         public static void SetDialogResult(Window target,bool?value)
         {
             target.SetValue(DialogResultProperty,value);
         }
     }
  1. 创build一个从GalaSoft.MvvmLight.ViewModelBaseinheritance的基本ViewModel以及其他成员。 完成后,使用此视图模型作为其他视图模型的基础。
    布尔?  _closeWindowFlag;
    公共布尔?  CloseWindowFlag
     {
        得到{return _closeWindowFlag;  }
        组
         {
             _closeWindowFlag = value;
             RaisePropertyChanged( “CloseWindowFlag”);
         }
     }

     public virtual void CloseWindow(bool?result = true)
     {
         Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, 
        新行动(()=>
         {
             CloseWindowFlag = CloseWindowFlag == null?  true:!CloseWindowFlag;
         }));
     } 
  1. 在视图中,使用基本视图模型中的CloseWindowFlag属性绑定DialogCloser.DialogResult依赖项属性。

然后,您可以从视图模型中打开/closures/隐藏窗口。