有没有办法从ViewModel中调用Navigate?

问题描述:

我有一个Silverlight 4项目,它显示一个图表和一些按钮,以允许用户更改图表的日期范围。日期范围也可以通过查询字符串参数传递 - 例如http://myserver/MySilverlightPage/#?DateRange=OneMonth - 并且当用户单击按钮时,我想更新Url。有没有办法从ViewModel中调用Navigate?

据我所知,做到这一点的方式是致电this.NavigationService.Navigate(new Uri(...)),但据我所知,这只能从后面的Silverlight页面代码完成。而且由于我使用的是MVVM,所以命令的所有处理都在ViewModel类中进行。有没有办法调用Navigate或以其他方式更改ViewModel中的Url?

为了澄清,该XAML包括以下Button

<Button Content="1 Month View" 
     Command="{Binding OneMonthCommand}" /> 

而且ViewModel类包含一个OneMonthCommand属性:

public ICommand OneMonthCommand { get; set; } 

当按钮被点击我的ICommand实现的Execute方法被调用。问题是 - 如何从该方法中更改Url?

我发现这是使用MVVM模式编写的Silverlight应用程序中的常见问题。我使用NavigationHelper类来集中导航的逻辑。它看起来是这样的:

public interface INavigationHelper 
{ 
    void Home(); 
    void SomeOtherPage(); 
} 

public class NavigationHelper : INavigationHelper 
{ 
    private NavigationService _navSvc; 

    public NavigationHelper(NavigationService navSvc) 
    { 
     _navSvc = navSvc; 
    } 

    public void Home() 
    { 
     _navSvc.Navigate(new Uri("/Home", UriKind.Relative)); 
    } 

    public void SomeOtherPage() 
    { 
     _navSvc.Navigate(new Uri("/SomeOtherPage", UriKind.Relative)); 
    } 
} 

然后,我有视图模型有NavigationHelper属性,它是由页面视图模型构造时设置。

顺便说一句,在ViewModel的构造函数中传递NavigationHelper会更简单。但是,根据我的经验,在ViewModel中使用非默认构造函数会让Blend中的设计工作变得更加困难。

+0

谁在你的情况下构建ViewModel?视图的代码隐藏?或者创建两个视图和视图模型的第三个类? – 2011-11-15 21:26:22

+0

一般而言,我通常会将ViewModel创建为页面XAML中的资源。但是,如果这不够强大,我会转向第三方创建者。不过,我认为这种模式在两种情况下都能起作用。 – RationalGeek 2011-11-16 15:02:14

使用MVVM并不排除使用超链接按钮,如果他们将完成您所需要的工作。

如您所见,使用NavigationService.Navigate的问题在于它需要关于其上下文的页面知识。

当你在代码隐藏中设置datacontext时,我认为将当前视图注入到视图模型中并不被认为是“太邪恶”了。 View对其ViewModel知之甚少。

如果您只是定期进行导航,您应该使用常规的HyperlinkBut​​tons。如果您尝试导航以响应其他事件,那么您可以使用消息传递。

另一种方法是让View将NavigationService类传递给您的ViewModel,并且如果您使用基本页面和基本视图模型,那么您将能够在没有每个视图模型和视图要求的情况下将它发生发生交接。