WPF MVVM:如何从VIEW MODEL中获取父级?

22
在一个MVVM WPF应用程序中,如何从ViewModel设置第二个窗口的父窗口?
例如: view1 - viewModel1
viewModel1的命令调用:
var view2 = new view2

view2.Owner = <----这里是问题所在。我该如何从viewModel中获取view1作为拥有者?

view2.Show()

编辑:

请先查看下面被接受的回答,然后阅读以下编辑内容。

我正在使用MVVM light -> http://mvvmlight.codeplex.com/(非常好用)。

内置的消息系统非常棒。我现在正向视图模型发送一条消息,告诉它显示另一个窗口。

对于消息,我目前正在使用一个字符串,并在主视图中使用switch语句来确定要打开哪个视图;但是我可能会调整MVVM light工具包中也包含的令牌。

谢谢!


嗨dnndeveloper,当你说你正在从viewmodel发送消息到view告诉它显示另一个窗口时,你是指你正在接收该消息并在view1代码后台创建/显示另一个窗口吗? - nabeelfarid
nabeelfarid - 是的,在代码后台收到消息,然后在消息被解析后,将显示适当的窗口。 - dnndeveloper
5个回答

26

在我看来,打开一个新窗口是 View 的责任,而不是 ViewModel 的责任。个人而言,我会使用与显示对话框相同的方法(这已经在本论坛上讨论过):

让 ViewModel 发送一条消息到 View,请求它打开一个新窗口。 (或者)使用 IDialogService 或其他你想称之为的服务,将其传递给 ViewModel 的构造函数。这个服务将负责打开窗口(或委托该任务给 View)。 这样,你可以保持良好的关注点分离,并且您的 ViewModel 仍然可测试(您可以单元测试发送打开新窗口的请求,但无法测试窗口是否确实已经打开)。

这样说清楚了吗?

祝好,

Laurent


嗨Laurent,我应该如何从ViewModel1向View1发送消息以打开新的View2?您是指消息将在View 1的代码后台中接收到吗?因为我认为在mvvm中消息传递应该发生在viewmodels之间。或者我完全错了。抱歉,我是mvvm和wpf的新手,我正在使用您的mvvm light工具包。 - nabeelfarid
6
当使用IDialogService打开新窗口时,如何为新窗口/View2设置所有者属性?因为需要引用Window1/View1,而ViewModel1不包含对View1的引用。所以我认为DialogService将通过消息将任务委托给View1,但我仍然不确定View1如何接收消息并处理它,除非在View1的代码后台完成。 - nabeelfarid
嗨Laurent,您能否澄清一下ViewModel1发送消息(将创建一个新的view2)的代码应该放在哪里处理?是View1的代码后台吗? - nabeelfarid
在LBugnion's MVVM Light中,有Messenger.Default.Send方法。 - Lei Yang
1
小问题,如果您创建了一个服务,并且该服务仅接收ViewModel,那么该服务如何能够将所有者设置为新窗口? - J4N

8

从你的视图模型中调用

Messenger.Default.Send<NotificationMessage>(new NotificationMessage("Open Window"));

如果您的视图代码使用了代码后台(调用第二个视图的视图),您可以在构造函数中轻松编写以下内容:

Messenger.Default.Register<NotificationMessage>(this, ReplyToMessage);

同时在视图的代码后台也需要编写这个方法:
private void ReplyToMessage(NotificationMessage msg)
{
   if (msg.Notification == "Open Window")
   {
      SecondWindow win = new SecondWindow();
      win.ShowDialog();
   }
}

1

0
你可以这样做,就像你需要创建一些事件并在视图中注册这些事件,并在视图模型中调用它们,然后打开弹出窗口。

就像这个例子

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();

在这里注册事件,例如mn.POpUpEvent +=,然后双击选项卡按钮,在注册弹出方法中编写打开弹出窗口的代码。


0

Prism-Event Aggregator是一种很好的方法,我们可以创建独立的模块而不需要依赖。首先,ViewModel将发布事件,然后另一个View或ViewModel可以从事件聚合器中订阅该事件。

在这种情况下,Unity容器也可以使用依赖注入将一个ViewModel注入到另一个ViewModel中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接