【问题标题】:MVVM and NavigationServiceMVVM 和 NavigationService
【发布时间】:2012-02-10 14:40:38
【问题描述】:

实现任何模式的众多好处之一是在应用程序的不同层之间分离关注点。对于 Silverlight 和 MVVM,我认为 NavigationService 属于 UI。

如果 NavigationService 属于 UI,那么它应该在后面的 XAML 代码中使用,但命令发生在 ViewModel 上。我是否应该在 ViewModel 中的 Command 上引发事件并让 View 处理事件并调用 Navigation?如果我所做的只是导航到另一个页面,这听起来有点荒谬。我不应该直接处理 UI 事件并从那里导航吗?

视图控制事件 -> ViewModel 命令 -> 引发事件 -> 视图 已处理的事件 -> 导航

查看控制事件 -> 查看处理的事件 -> 导航

【问题讨论】:

  • 实际上,如何实现该模式以及如何解决此类问题是您的选择。也许最好的做法是使用像 MVVM Ligh Messenger 这样的消息传递,然后从您的 ViewModel 发送一条消息,让 View 导航,并有一个资源类或在您的 View 之间导航的东西。 :)

标签: silverlight-4.0 mvvm mvvm-light windows-phone-7.1


【解决方案1】:

这个问题有两种记录方法

  1. 使用 MVVM Light 的消息传递功能实现导航

    Jesse Liberty 在Part 3 他的MVVM Lighttht 坚果系列中提出了这种方法。他的方法是从命令向视图发送一条消息,指示应该进行导航操作。

  2. 实现处理导航的 ViewService

    这种方法是 Laurent Bugnion's response 到 Jesse 的帖子。这实现了一个服务来处理由视图模型触发的所有导航操作。

这两种方法都只处理 WP7 应用程序中的导航。但是,它们也可以适应 Silverligt 应用程序。

Jesse 的方法在 SL 中更易于使用,因为它不需要访问根视觉对象。但是,导航代码分布在多个地方,需要后面的代码来执行实际导航。

Laurent 的方法需要访问根视觉 - 用于访问内置导航功能。如 Laurent 的代码所示,访问它在 WP7 应用程序中没什么大不了的。然而,在 SL 应用中,它稍微复杂一些,因为没有环绕框架。然而,我已经在我的一个项目中使用附加属性实现了 SL 模式,确实做了所需的布线 - 所以虽然需要更多的工作,但它也可用于 SL。

因此得出结论——虽然 Jesse 的方法更容易实现,但我个人更喜欢 Laurent 的方法,因为它的架构更简洁——不需要背后的代码,并且功能被封装到一个单独的组件中,因此位于一个点上。

【讨论】:

  • 优秀的响应和链接!
【解决方案2】:

这个问题有点晚了,但它是相关的,希望对某人有所帮助。我必须使用 MvvmLight 创建一个 SL4 应用程序,并且想使用一个可以模拟并且可以注入到 ViewModel 中的导航服务包装器。我在这里找到了一个很好的起点:来自 Mix11 的 Laurent Bugnion 的 SL4 示例代码示例,其中包括一个导航服务演示:Deep Dive MVVM Mix11

以下是实现可与 Silverlight 4 一起使用的可模拟导航服务的基本部分。关键问题是获取对要在自定义 NavigationService 类中使用的主导航框架的引用。

1) 在 MainPage.xaml 中,导航框架被赋予一个唯一的名称,在本示例中,它将是 ContentFrame

<navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}"
    Source="/Home" Navigated="ContentFrame_Navigated"  
    NavigationFailed="ContentFrame_NavigationFailed">
    <!-- UriMappers here -->
</navigation:Frame>

2) 在 MainPage.xaml.cs 中,导航框架作为属性公开:

public Frame NavigationFrame
{
    get { return ContentFrame; }
}

3)导航服务类实现了INavigationService接口,依赖MainPage.xaml.cs的NavigationFrame属性获取导航框架的引用:

public interface INavigationService
{
    event NavigatingCancelEventHandler Navigating;
    void NavigateTo(Uri uri);
    void GoBack();
}

public class NavigationService : INavigationService
{
    private Frame _mainFrame;
    public event NavigatingCancelEventHandler Navigating;
    public void NavigateTo(Uri pageUri)
    {
        if (EnsureMainFrame())
            _mainFrame.Navigate(pageUri);
    }
    public void GoBack()
    {
        if (EnsureMainFrame() && _mainFrame.CanGoBack)
            _mainFrame.GoBack();
    }
    private bool EnsureMainFrame()
    {
        if (_mainFrame != null)
            return true;
        var mainPage = (Application.Current.RootVisual as MainPage);
        if (mainPage != null)
        {
            // **** Here is the reference to the navigation frame exposed earlier in steps 1,2 
            _mainFrame = mainPage.NavigationFrame;
            if (_mainFrame != null)
            {
                // Could be null if the app runs inside a design tool
                _mainFrame.Navigating += (s, e) =>
                {
                    if (Navigating != null)
                    {
                        Navigating(s, e);
                    }
                };
                return true;
            }
        }
        return false;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    相关资源
    最近更新 更多