Mvvm 导航逻辑属于哪里,视图、视图模型还是其他地方?

Mvvm 导航逻辑属于哪里,视图、视图模型还是其他地方?,mvvm,silverlight-4.0,mvvm-light,wcf-ria-services,Mvvm,Silverlight 4.0,Mvvm Light,Wcf Ria Services,I视图中的一个按钮,绑定到ViewModel的ICommand属性(实际上它是mvvv灯光的RelayCommand) 如果用户单击按钮,我希望导航到新视图。当然,NavigationService是视图的一部分,而不是ViewModel。这意味着导航是视图的责任?但是在我的例子中,当点击按钮时我将看到的视图取决于很多因素,包括登录用户是谁,数据库处于什么状态等等。。。当然,视图不需要所有这些信息 执行NavigationService.Navigate调用的首选选项是什么?警告:固执己见的MV

I视图中的一个按钮,绑定到ViewModel的ICommand属性(实际上它是mvvv灯光的RelayCommand)

如果用户单击按钮,我希望导航到新视图。当然,NavigationService是视图的一部分,而不是ViewModel。这意味着导航是视图的责任?但是在我的例子中,当点击按钮时我将看到的视图取决于很多因素,包括登录用户是谁,数据库处于什么状态等等。。。当然,视图不需要所有这些信息


执行NavigationService.Navigate调用的首选选项是什么?

警告:固执己见的MVVM新手提醒:)(我对MVVM非常陌生,但到目前为止非常喜欢。)

好问题。我发现模仿
NavigationService
并将
INavigationService
传递给ViewModel是完全可行的(如果有些地方有点难看的话)。事实上,您甚至可以使用泛型使接口稍微好一点,以传入类型(作为类型参数)而不是字符串URI

然而,我发现当你把导航所涉及的额外数据放在哪里时,我有点不对劲。。。我还没有找到一个好的地方来进行所有的编码/取消编码,以便整齐地传播状态。我怀疑ViewModelFactory很可能就是这个等式的一部分


因此,这还不是一个完美的解决方案-但至少ViewModel可以负责“立即导航”(或“返回”)的操作。

如果您已经在使用MVVM Light,一个选项是使用它包含的消息总线。因此,您可以将按钮绑定到视图模型上的RelayCommand,正如您所说的那样。在RelayCommand的处理程序中,您可以决定导航到哪个视图。这将在视图模型中保留所有逻辑

一旦命令处理程序决定导航到哪个视图,它就可以在消息总线上发布消息。您的视图将侦听该消息,然后使用NavigationService实际执行导航。所以,它除了等待别人告诉它去某个地方导航,然后在别人告诉它的地方导航之外,什么都不做

为此,我定义了一个视图模型可以发布的NavigationMessage类,以及一个视图继承的视图基类,其中包含侦听器。NavigationMessage如下所示:

公共类导航消息:NotificationMessage
{
公共字符串页面名
{
获取{return base.Notification;}
}
公共字典QueryStringParams{get;private set;}
公共导航消息(字符串pageName):基本(pageName){}
公共导航消息(字符串pageName,字典查询字符串Params):此(pageName)
{
QueryStringParams=QueryStringParams;
}
}
这允许只传递页面名称,或者还可以选择包含任何必要的查询字符串参数。RelayCommand处理程序将按如下方式发布此消息:

private void RelayCommandHandler()
{
//确定下一个视图的逻辑,然后。。。
sender.Default.Send(新导航消息(“ViewToNavigate”);
}
最后,视图基类如下所示:

公共类基页:PhoneApplicationPage
{
公共基页()
{
Messenger.Default.Register(此页为NavigateToPage);
}
受保护的无效NavigateToPage(NavigationMessage消息)
{
//未显示GetQueryString,但它只是一个用于格式化字典中查询字符串的辅助方法
字符串queryStringParams=message.queryStringParams==null?”:GetQueryString(message);
字符串uri=string.Format(“/Views/{0}.xaml{1}”,message.PageName,queryStringParams);
NavigationService.Navigate(新Uri(Uri,UriKind.Relative));
}
}

这是假设所有视图都位于应用程序根目录下的“视图”文件夹中的约定。这对我们的应用程序来说很好,但当然,这可以扩展到支持不同的场景来组织视图。

我也很喜欢MVVM,但是似乎有些Silverlight模板并不特别适合MVVM;导航是其中之一。感谢您提出将类型而不是字符串作为“uri”传递的想法。在这种情况下,这是非常有意义的。我承认我对MVVM Light提供的Messenger系统不太熟悉。进一步思考,这是否意味着所有的视图都会注册并听到这个导航消息?我想这可能是个问题。我在WindowsPhone7应用程序中使用了这项技术,我一次只有一个视图处于活动状态,因此它工作得非常好。如果您在桌面版Silverlight或WPF中工作,并且同时有多个视图处于活动状态,我可以看出这可能是一个问题。您可能还想查看Caliburn Micro framework:。它包括一个INavigationService实现,您可以将它注入到视图模型中,类似于Jon在回答中所描述的。