Home > .NET, C#, MVVM, Universal Windows Platform > How to handle navigation events in MVVM using Windows Template Studio

How to handle navigation events in MVVM using Windows Template Studio

17/10/2017

Windows Template Studio is a Visual Studio 2017 Extension that accelerates the creation of new Universal Windows Platform (UWP) apps using a wizard-based experience.
Among the other things, it allows to use the MVVM pattern with a simple selection in the wizard, by providing a basic implementation rather than using MVVM Light. This approach avoids writing a lot of boilerplate code, but if we choose it, we’ll discover that an important feature is currently missing: the ability to automatically calls methods on ViewModels when we navigate to/from a Page.
However, adding this behavior is quite simple. We just need to add an INavigable interface to the project:

public interface INavigable
{
    Task OnNavigatedToAsync(object parameter, NavigationMode mode);

    void OnNavigatingFrom(NavigatingCancelEventArgs e);

    void OnNavigatedFrom();
}

Then, we have to edit the NavigationServices.Ex class, that is placed in the Services folder. First of all, we need to add the registration/deregistration methods for the Frame.Navigating event in the RegisterFrameEvents and UnregisterFrameEvents methods:

private void RegisterFrameEvents()
{
    if (_frame != null)
    {
        _frame.Navigating += Frame_Navigating;
        _frame.Navigated += Frame_Navigated;
        _frame.NavigationFailed += Frame_NavigationFailed;
    }
}

private void UnregisterFrameEvents()
{
    if (_frame != null)
    {
        _frame.Navigating -= Frame_Navigating;
        _frame.Navigated -= Frame_Navigated;
        _frame.NavigationFailed -= Frame_NavigationFailed;
    }
}

Then, let’s add the Frame_Navigating event handler and modify the existing Frame_Navigated as follows:

private void Frame_Navigating(object sender, NavigatingCancelEventArgs e)
{
    var dataContext = ResolveForPage(Frame.Content as Page);
    if (dataContext != null)
    {
        dataContext.OnNavigatingFrom(e);
        if (!e.Cancel)
        {
            dataContext.OnNavigatedFrom();
        }
    }
}

private async void Frame_Navigated(object sender, NavigationEventArgs e)
{
    Navigated?.Invoke(sender, e);

    var dataContext = ResolveForPage(e.Content as Page);
    if (dataContext != null)
    {
        await dataContext.OnNavigatedToAsync(e.Parameter, e.NavigationMode)
            .ConfigureAwait(false);
    }
}

private INavigable ResolveForPage(Page page)
    => (page?.DataContext as INavigable);

In the first event, if the DataContext (i.e., the ViewModel) of the Page implements the INavigable interface, we call its OnNavigatingFrom method, passing the NavigatingCancelEventArgs to it. So, if we set its Cancel property to true, we can cancel the navigation back. Otherwise, we then call the OnNavigatedFrom method.
On the other hand, when we navigate to a page, the Frame_Navigated event handler is invoked. In this case, we try to call the OnNavigateToAsync method, passing parameters and NavigationMode to it.

Now everything is ready. We can for example write something like this:

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

    public Task OnNavigatedToAsync(object parameter, NavigationMode mode)
    {
        return Task.CompletedTask;
    }

    public void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
    }

    public void OnNavigatedFrom()
    {
    }
}

We don’t need anything else. We can simply set breakpoints on these methods and see that they are invoked when we navigate to/from the corresponding page. Of course, we can define our own ViewModelBase class that already implements the INavigable interface, so we have to override only the navigation methods we really need.

Advertisements
  1. No comments yet.
  1. 17/10/2017 at 12:05
Comments are closed.
%d bloggers like this: