I am trying to figure out a way for my ViewModel to handle saving or restore the page's state when the page is navigated From or To.
The first thing I tried was to add an EventToCommand behavior to the page, but the events (OnNavigatedFrom and OnNavigatedTo) are declared protected and the EventToCommand does not see the events to bind to.
Next I thought I would try using the Messenger class to pass a message to the ViewModel using code in the View's code behind:
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
Messenger.Default.Send<PhoneApplicationPage>(this);
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
Messenger.Default.Send<PhoneApplicationPage>(this);
base.OnNavigatedTo(e);
}
But this seems to have two issues, first is having this code in the code behind page. Second, the ViewModel cannot tell the difference between the OnNavigatedFrom and the OnNavigatedTo events without having to create a set a wrapper classes for the PhoneApplicationPage object (see UPDATE below).
What is the most MVVM-Light friendly way to handle these events?
UPDATE: I was able to resolve the second issue by Sending the Messages like this:
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
Messenger.Default.Send<PhoneApplicationPage>(this,"NavigatedFrom");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo");
base.OnNavigatedTo(e);
}
and Registering them like this:
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedFrom", false, (action) => SaveState(action));
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, (action) => RestoreState(action));
Executing a command from code behind is far cleaner than going through the whole messaging mess. After all there's nothing wrong with the view knowing about its DataContext.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
viewModel.NavigatedToCommand.Execute(e.Uri);
}
ProfileViewModel viewModel
{
get
{
return this.DataContext as ProfileViewModel;
}
}
Update: Passing in NavigationContext.QueryString is probably more useful, since it already parses out the parameters and value.
Sorry for being three years late to this question. Yes, I'm still using Silverlight. Okay I want to write it in Page
code-behind like this:
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.HandleOnNavigatedTo(e);
}
I am using an extension method like this:
public static void HandleOnNavigatedTo(this Page page, NavigationEventArgs e)
{
var vm = page.DataContext as IPageNavigationViewModel;
if (vm == null) return;
vm.HandleOnNavigatedTo(e);
}
The extension method implies that the Page
must have a View Model that implements IPageNavigationViewModel in DataContext
. For me, this is a separation-of-concerns compromise where the Page knows only about the most general-purpose data types in the Domain. This the interface:
using System.Windows.Navigation;
namespace Fox.Silverlight.ViewModels
{
/// <summary>
/// Defines View Model members for frame-navigation pages.
/// </summary>
public interface IPageNavigationViewModel
{
/// <summary>
/// Handles the <see cref="Page.OnNavigatedTo"/> method in the View Model.
/// </summary>
/// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
void HandleOnNavigatedTo(NavigationEventArgs e);
/// <summary>
/// Handles the <see cref="Page.OnNavigatedFrom"/> method in the View Model.
/// </summary>
/// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
void HandleOnNavigatedFrom(NavigationEventArgs e);
}
}
Looks like you have a solution to your problem already. I would also suggest the following:
Look at using one of the message values provided in the mvvm-toolkit, such as:
NotificationMessage<T>
Like this:
Messenger.Default.Send<NotificationMessage<PhoneApplicationPage>>(
new NotificationMessage<PhoneApplicationPage>(this, "Message"));
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