Home > C#, MVVM, WinRT > Calling ViewModel methods in response to Page navigation events using MVVM Light in WinRT

Calling ViewModel methods in response to Page navigation events using MVVM Light in WinRT

07/05/2013

The OnNavigatedTo and OnNavigatedFrom methods allow us to execute code when a Page of a Windows Store app is, respectively, loaded or unloaded. However, if we’re using the MVVM pattern, we shouldn’t use these methods directly.

A possible solution, using MVVM Light Toolkit, is to define an interface that must be implemented by every ViewModel that have to handle the load/unload events:

public interface INavigable
{
    void Activate(object parameter);
    void Deactivate(object parameter);
}

A ViewModel that uses this interface appears like the following:

public class MainViewModel : ViewModelBase, INavigable
{
    // ...

    public void Activate(object parameter)
    {
        
    }

    public void Deactivate(object parameter)
    {
        
    }
}

Then, we must create a class that inherits from Page and calls the methods defined in the INavigable interface:

public class BindablePage : Page
{
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        var navigableViewModel = this.DataContext as INavigable;
        if (navigableViewModel != null)
            navigableViewModel.Activate(e.Parameter);
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        base.OnNavigatedFrom(e);

        var navigableViewModel = this.DataContext as INavigable;
        if (navigableViewModel != null)
            navigableViewModel.Deactivate(e.Parameter);
    }
}

In the OnNavigatedTo and OnNavigatedFrom methods, we check if the DataContext implements the INavigable interface: in this case, we call its Activate or Deactivate methods, passing the corresponding parameter to them.

Finally, we need to modify our View in order to use BindablePage instead of the standard Page:

<common:BindablePage
    x:Class="App1.MainPage"
    xmlns:common="using:App1.Common"
    ...>

</common:BindablePage>

And, of course, we need to modify the code-behind too, changing the base class from which MainPage inherits.

If we’re using the LayoutAwarePage class, we can follow the same solution, but is this case we can override the LoadState and SaveState methods, so we can also save and restore state using the ViewModel:

public interface INavigable
{
    void Activate(object parameter, Dictionary<string, object> state);
    void Deactivate(Dictionary<string, object> state);
}

public class MainViewModel : ViewModelBase, INavigable
{
    // ...

    public void Activate(object parameter, Dictionary<string, object> state)
    {
        
    }

    public void Deactivate(Dictionary<string, object> state)
    {
        
    }
}

public class BindablePage : LayoutAwarePage
{
    protected override void LoadState(object navigationParameter, 
        Dictionary<string, object> pageState)
    {
        base.LoadState(navigationParameter, pageState);

        var navigableViewModel = this.DataContext as INavigable;
        if (navigableViewModel != null)
            navigableViewModel.Activate(navigationParameter, pageState);
    }

    protected override void SaveState(Dictionary<string, object> pageState)
    {
        base.SaveState(pageState);

        var navigableViewModel = this.DataContext as INavigable;
        if (navigableViewModel != null)
            navigableViewModel.Deactivate(pageState);
    }
}

Remember always to change the opening tag of every XAML Page, as described earlier, in order to use the new BindablePage and its support to activation/deactivation through ViewModel.

About these ads
Categories: C#, MVVM, WinRT
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: