2
votes

I have a test application to test the navigation on windows phone 8.1, and I can got to a second page from my main page to the second page.

The problem, is that when I click the back button, I return to the desktop screen and the application go to background, so I have to hold the back button to return to the application.

I have seen examples that override the backButtonKeyPressed event, but this is in the code behind of the page, so this is not suit in my case bacause I want to use MVVM.

In my application, the code that control the goBack event is in the NavigationSerive.

Really I am not be able to find a good example for solving this problem in MVVM. It is not mandatory to use MVVM Light, if there are any other way that use MVVM pattern, is good for me.

Thanks.

1

1 Answers

2
votes

Here's my implementation of a navigation service. Not going to claim it's perfect, but it works for me. This also pre-dates the built-in navigation service in MVVM Light 5, but you may be able to still make use of it, or parts of it.

Register it in ViewModelLocator using

SimpleIoc.Default.Register<INavigationService, NavigationService>();

and then inject it into your view models via the constructor. Use NavigateTo() to navigate to other pages; the back button pressed handler exits the application only when there is no more history, otherwise it navigates to the previous page.

public interface INavigationService
{
    void NavigateTo(Type pageType, object parameter = null);

    void NavigateTo(string pageName, object parameter = null);

    void GoBack();
}

.

public class NavigationService : INavigationService
{
    #region Public

    /// <summary>
    /// Navigates to a specified page.
    /// </summary>
    public void NavigateTo(string pageName, object parameter = null)
    {
        Type pageType = Type.GetType(string.Format("SendToSync.{0}", pageName));

        if (pageType == null)
            throw new Exception(string.Format("Unknown page type '{0}'", pageName));

        NavigateTo(pageType, parameter);
    }

    /// <summary>
    /// Navigates to a specified page.
    /// </summary>
    public void NavigateTo(Type pageType, object parameter = null)
    {
        var content = Window.Current.Content;
        var frame = content as Frame;

        if (frame != null)
        {
            var previousPageType = frame.Content.GetType();

            if (previousPageType != pageType)
                NavigationHistory.Add(previousPageType);

            //await frame.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => frame.Navigate(pageType));

            frame.Navigate(pageType, parameter);
        }

        Window.Current.Activate();
    }

    /// <summary>
    /// Goes back.
    /// </summary>
    public void GoBack()
    {
        var content = Window.Current.Content;
        var frame = content as Frame;

        if (frame != null)
        {
            var currentPageType = frame.Content.GetType();

            // remove the previous page from the history

            var previousPageType = NavigationHistory.Last();
            NavigationHistory.Remove(previousPageType);

            // navigate back

            frame.Navigate(previousPageType, null);
        }
    }

    #endregion

    #region Private

    /// <summary>
    /// The navigation history.
    /// </summary>
    private List<Type> NavigationHistory { get; set; }

    #endregion

    #region Initialization

    public NavigationService()
    {
        NavigationHistory = new List<Type>();

        HardwareButtons.BackPressed += HardwareButtons_BackPressed;
    }

    /// <summary>
    /// Called when the back button is pressed; either navigates to the previous page or exits the application.
    /// </summary>
    private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
    {
        if (NavigationHistory.Count == 0)
        {
            e.Handled = false;
        }
        else
        {
            e.Handled = true;
            GoBack();
        }
    }

    #endregion
}

EDIT: Here's parts of my ViewModelLocator

In the constructor:

SimpleIoc.Default.Register<MainViewModel>();

And the accompanying property:

public MainViewModel MainViewModel
{
    get { return ServiceLocator.Current.GetInstance<MainViewModel>();  }
}

This will always return the same single instance of MainViewModel (and the view model data will persist).