MVVM和NavigationService

时间:2012-01-15 00:58:21

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

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

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

  

查看控制事件 - > ViewModel命令 - >举起活动 - >视图   处理事件 - >导航

     

     

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

2 个答案:

答案 0 :(得分:6)

此问题有两种记录方法

  1. 使用MVVM Light的消息传递功能实现导航
    这种方法是由Jesse Liberty在Part 3他的 MVVM Ligtht汤到坚果系列中提出的。他的方法是从命令发送消息到视图,指示应该进行导航操作。

  2. 实现处理导航的ViewService
    这种方法是Laurent Bugnion's response给Jesse的帖子。这实现了一个处理视图模型触发的所有导航操作的服务。
  3. 这两种方法仅涉及WP7应用程序中的导航。但是,它们也可以适用于Silverligt应用程序。

    Jesse的方法在SL中更容易使用,因为它不需要访问根视觉。但是,导航代码会分布在多个位置,并且需要后面的代码才能进行实际导航。

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

    总结 - 虽然,Jesse的方法更容易实现,但我个人更喜欢Laurent的方法,它更清晰的架构 - 不需要代码,并且功能被封装到一个单独的组件中,因此位于一个点上。

答案 1 :(得分:0)

这个问题有点晚了,但它是相关的,并希望对某人有益。我不得不使用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;
    }
}