I have a Silverlight 4 project which displays a chart and some buttons to allow the user to change the chart's date range. The date range can also be passed in via a query string parameter - something like http://myserver/MySilverlightPage/#?DateRange=OneMonth - and when the user clicks a button I'd like to update the Url as well.
I understand that the way to do this is to call this.NavigationService.Navigate(new Uri(...))
, but as far as I can tell this can only be done from the Silverlight page code behind. And since I'm using MVVM, all processing of the command takes place in the ViewModel class. Is there a way to call Navigate
or otherwise change the Url from within the ViewModel?
To clarify, the xaml includes the following Button
:
<Button Content="1 Month View"
Command="{Binding OneMonthCommand}" />
And the ViewModel class contains a OneMonthCommand
property:
public ICommand OneMonthCommand { get; set; }
When the button is clicked my ICommand implementation's Execute
method is called. The question is - how can I change the Url from within that method?
I have found this to be a common problem in Silverlight applications I write using the MVVM pattern. I use a NavigationHelper class to centralize logic around navigation. It looks something like this:
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));
}
}
Then, I have the ViewModel have a NavigationHelper property, which is set by the page when the ViewModel is constructed.
BTW, it seems like it would be simpler to have the NavigationHelper passed in the ViewModel's constructor. But having non-default constructors for the ViewModel makes it harder to get things working at design-time in Blend, in my experience.
If you're just doing regular navigation, you should use regular HyperlinkButtons. If you're trying to navigate in response to other events though, then you could use messaging.
An alternative is to have the View pass the NavigationService class in to your ViewModel, and if you use a base page and base viewmodel you will be able to have it happen in those without the requirement of each viewmodel and view knowing about the hand-off taking place.
Using MVVM does not exclude the use of Hyperlink buttons if they will do the job you require.
The problem, as you found, with NavigationService.Navigate is that it requires knowledge of the a page for its context.
I don't think it is considered "too evil" to inject your current view back into it's view model when you set the datacontext in codebehind. It is generally worse for the View to know too much about its ViewModel.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With