导航逻辑属于哪里,View、ViewModel 还是其他地方?

发布于 2024-09-26 00:58:08 字数 288 浏览 1 评论 0原文

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

如果用户单击按钮,我想导航到新视图。当然,NavigationService 是 View 的一部分,而不是 ViewModel 的一部分。这意味着导航是视图的责任?但就我而言,单击按钮时我将进入的视图取决于很多因素,包括登录用户是谁、数据库所处的状态等......当然视图不应该需要所有该信息。

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

I a button in a view, bound to an ICommand property of the ViewModel (actually it's RelayCommand from mvvv-light)

If the user clicks on the button I want to navigate to a new view. Of course the NavigationService is part of the View not the ViewModel. That implies that the navigation is the responsibility of the View? But in my case, the view I will be going when the button is clicked depends on a great many factors, including who the logged in user is, the state the database is in, etc... Surely the View shouldn't need all that information.

What is the preferred option for executing a NavigationService.Navigate call?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无所的.畏惧 2024-10-03 00:58:08

如果您已经在使用 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”文件夹中的约定。这对于我们的应用程序来说效果很好,但当然这可以扩展以支持组织视图的不同场景。

If you're already using MVVM Light, one option is to make use of the message bus that it includes. So you bind your button to a RelayCommand on the view model, as you've said you're already doing. In the handler for your RelayCommand you can make the decision on which view to navigate to. This keeps all that logic in the view model.

Once your command handler has decided which view to navigate to, it can publish a message on the message bus. Your view will be listening for that message and then use the NavigationService to actually perform the navigation. So it's not doing anything other than waiting to be told to navigate somewhere and then navigating where it's told.

I've been doing this by defining a NavigationMessage class that my view models can publish, and a view base class that my views inherit from which contains the listener. The NavigationMessage looks like this:

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;
    }
}

This allows for simply passing the page name, or optionally also including any necessary query string parameters. A RelayCommand handler would publish this message like this:

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

Finally, the view base class looks like this:

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

This is assuming a convention where all the views are in a "Views" folder in the root of the app. This works fine for our app but of course this could be extended to support different scenarios for how you organize your views.

情何以堪。 2024-10-03 00:58:08

警告:固执己见的 MVVM 新手警报:)(我对 MVVM 很陌生,但到目前为止很喜欢它。)

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

然而,我发现当涉及到在导航中放置额外数据时,我有点陷入困境......我还没有找到一个好的单一位置来完成所有编码/取消编码以整齐地传播状态。我怀疑 ViewModelFactory 很可能是该等式的一部分......

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

Warning: opinionated MVVM newbie alert :) (I'm very new to MVVM, but enjoying it a lot so far.)

Good question. I've found that it's perfectly feasible (if a little ugly in places) to mock out NavigationService and pass an INavigationService to a ViewModel. In fact, you can even make the interface slightly nicer with generics, to pass in a type (as a type argument) rather than a string URI.

However, I've found I've come somewhat unstuck when it comes to where you put the extra data involved in navigation... I haven't found a good single place to do all the encoding/unencoding to propagate state neatly. I suspect the ViewModelFactory may well be part of that equation...

So, not a perfect solution yet - but at least ViewModel can be responsible for the action of "navigate now" (or "go back").

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文