我一直在想这个问题......从另一个视图模型打开一个新窗口(view& viewmodel)的最佳做法是什么如果我们记住打开新窗口的viewmodel不知道该视图的存在(应该如此)。
感谢。
答案 0 :(得分:13)
我更喜欢使用通过ViewModel构造函数插入的动作委托。这也意味着我们可以在单元测试期间轻松验证:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new MainViewModel(() => (new Window()).Show()); // would be actual window
}
}
public class MainViewModel
{
private Action popupAction;
public MainViewModel(Action popupAction)
{
this.popupAction = popupAction;
}
public ICommand PopupCommand { get; set; }
public void PopupCommandAction()
{
popupAction();
}
}
public class SomeUnitTest
{
public void TestVM()
{
var vm = new MainViewModel(() => { });
}
}
答案 1 :(得分:5)
我不使用ViewModel打开另一个View / ViewModel。这由财务主任负责。 ViewModel可以通知Controller(例如,通过Event)用户期望看到下一个View。 Controller在IoC Container的帮助下创建View / ViewModel。
WPF Application Framework (WAF) 的ViewModel(EmailClient)示例应用程序中显示了它的工作原理。
答案 2 :(得分:3)
使用介体模式,例如mvvmlight的messenger类:
http://mvvmlight.codeplex.com/Thread/View.aspx?ThreadId=209338
基本思想是viewmodel向其视图发送消息。然后接收视图如下所示:
OnMsgRecived() {
Viewmodel vm = New Viewmodel() - Or use dependency injection to resolve
View v = new View()
v.DataContext = vm
v.Show()
}
这允许发送消息的视图模型显示另一个窗口,其中没有“知道”如何或谁进行了打开。
答案 3 :(得分:2)
我个人更喜欢在我的ViewModel中引发事件,以向视图发出信号,告知它需要执行类似打开窗口的操作。我尽量不直接这样做,所以我在ViewModel中看不到像OpenWindow这样的事件,因为在我看来,这似乎违反了View和ViewModel之间的区别。相反,我可能会做一个属性改变状态并相应地引发一个PropertyChanged事件,视图可以监听,然后决定打开一个窗口来响应这个信号。在某些情况下,窗口的打开根本与ViewModel中的某些内容无关,而只是View的一个功能。在这些情况下,我根本不害怕在View的代码隐藏部分中放置代码来打开另一个视图。
mediator pattern只是使它更加松散耦合,并允许主应用程序窗口View或高度嵌套的View可以在应用程序内全局侦听消息,而无需直接访问ViewModel以附加事件处理程序等等。要过滤掉不相关的消息,您可以查看某种消息源值或消息源自何处的其他指示。对于那些熟悉Windows消息的人以及在非托管和WinForms开发中如何在不同控件(Windows)之间工作的人来说,可能是一种理解系统的方法,可以在广播消息的中介之上构建。
答案 4 :(得分:0)
我同意类似中介的方法,但OnMsgReceived在视图的代码隐藏中清楚地处理,是否有一种避免这种情况的好方法?