2012-01-15 97 views
4

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

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

视图控件事件 - >视图模型命令 - >引发事件 - >查看 已处理的事件 - >导航

视图控件事件 - >查看已处理的事件 - >导航

+0

其实它是你的选择你如何实现模式以及如何解决这样的问题。也许最好的做法是使用像MVVM Ligh Messenger之类的消息传递,因此从ViewModel发送一条消息,使得View应该导航,并且有一个资源类或者可以在你的Views之间导航的东西。 :) – BigL 2012-01-15 10:31:55

回答

6

对此问题有两种记录方法

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

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

  2. 实现处理导航的ViewService

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

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

杰西的方法更容易在SL中使用,因为它不需要访问根视觉。但是,导航代码分布在几个地方,需要使用代码来完成实际的导航。

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

所以总结 - 虽然Jesse的方法更容易实现,但个人而言,我更喜欢Laurent的方法,因为它是更清洁的架构 - 没有需要的代码,功能封装在单独的组件中,因此位于单个点。

+0

优秀的回应和链接! – 2012-01-18 16:00:07

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接口和依赖于NavigationFrame适当MainPage.xaml.cs获取对导航框架的引用:

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