导航逻辑在哪里,View,ViewModel或其他地方?

时间:2010-10-04 17:10:25

标签: mvvm silverlight-4.0 mvvm-light wcf-ria-services

我在视图中的一个按钮,绑定到ViewModel的ICommand属性(实际上它是来自mvvv-light的RelayCommand)

如果用户点击了我想导航到新视图的按钮。当然,NavigationService是View而不是ViewModel的一部分。这意味着导航是View的责任?但在我的情况下,单击按钮时我将要查看的视图取决于很多因素,包括登录用户是谁,数据库所处的状态等等......当然,视图不需要全部那个信息。

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

2 个答案:

答案 0 :(得分:12)

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

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

我一直在这样做,通过定义我的视图模型可以发布的NavigationMessage类,以及我的视图从中包含监听器的视图基类。 NavigationMessage看起来像这样:

public class NavigationMessage : NotificationMessage
{
    public string PageName
    {
        get { return base.Notification; }
    }

    public Dictionary<string, string> QueryStringParams { get; private set; }

    public NavigationMessage(string pageName) : base(pageName) { }

    public NavigationMessage(string pageName, Dictionary<string, string> queryStringParams) : this(pageName)
    {
        QueryStringParams = queryStringParams;
    }
}

这允许简单地传递页面名称,或者可选地还包括任何必要的查询字符串参数。 RelayCommand处理程序将发布此消息,如下所示:

private void RelayCommandHandler()
{
    //Logic for determining next view, then ...
    Messenger.Default.Send(new NavigationMessage("ViewToNavigate"));
}

最后,视图基类如下所示:

public class BasePage : PhoneApplicationPage
{
    public BasePage()
    {
        Messenger.Default.Register<NavigationMessage>(this, NavigateToPage);
    }

    protected void NavigateToPage(NavigationMessage message)
    {
        //GetQueryString isn't shown, but is simply a helper method for formatting the query string from the dictionary
        string queryStringParams = message.QueryStringParams == null ? "" : GetQueryString(message);

        string uri = string.Format("/Views/{0}.xaml{1}", message.PageName, queryStringParams);
        NavigationService.Navigate(new Uri(uri, UriKind.Relative));
    }
}

这假设一个约定,其中所有视图都位于应用程序根目录的“Views”文件夹中。这适用于我们的应用程序,但当然这可以扩展到支持不同的方案来组织您的视图。

答案 1 :(得分:6)

警告:自以为是的MVVM新手警报:)(我对MVVM很新,但到目前为止很享受它。)

好问题。我发现模拟NavigationService并将INavigationService传递给ViewModel是完全可行的(如果有点丑陋)。事实上,您甚至可以使用泛型使界面更好,传入类型(作为类型参数)而不是字符串URI。

然而,我发现当你把导航中涉及的额外数据放在哪里时,我已经有些不安了...我还没有找到一个好的单一地方来做所有的编码/解码来传播状态整齐。我怀疑ViewModelFactory可能是该等式的一部分...

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