Page Navigation using MVVM in Store App

wpf page navigation mvvm
how to navigate from one xaml page to another in wpf
wpf single page application
wpf navigation
wpf navigation view
navigation service wpf mvvm
wpf sidebar navigation
wpf ipageviewmodel

I'm having a serious headache with this problem. I really dislike store apps but am forced to use it in this case. I've only worked with XAML for a few weeks.

My question is: How can I call a RelayCommand in my ViewModel (from my View of course) that will change the page on my view? And even better, change it using URI, so that I can pass a command parameter to file.

I'm totally lost on this. Currently I'm using this.Frame.Navigate(type type) in the View Code behind to navigate through pages.

I would really and I mean REALLY appreciate a description from a to z on what to do in this case.

I presume i could do something like building a framecontainer on my View and send it to my ViewModel and from there navigate the current frame to another. But I'm not sure how that works in Store apps.

I am really sorry for the lack of good questions, but I'm on a deadline and i need to get my View connected to my ViewModel in a proper way.. I don't like having both view codebehind as well as ViewModel code.

There are 2 ways to do this, a simple way is to pass a relay command action from the view to the view model.

public MainPage()
{
  var vm = new MyViewModel();
  vm.GotoPage2Command = new RelayCommand(()=>{ Frame.Navigate(typeof(Page2)) });
  this.DataContext = vm;
}

<Button Command={Binding GoToPage2Command}>Go to Page 2</Button>

Another way is by using an IocContainer and DependencyInjection. This one is a more losely coupled approach.

We will need an interface for navigation page so that we don't need to reference or Know anything about PageX or any UI element assuming that your viewmodel is in a separate project that doesn't know anything about the UI.

ViewModel Project:

  public interface INavigationPage
  {
    Type PageType { get; set; }
  }

  public interface INavigationService
  {
    void Navigate(INavigationPage page) { get; set; }
  }



public class MyViewModel : ViewModelBase
  {
    public MyViewModel(INavigationService navigationService, INavigationPage page)
    {
      GotoPage2Command = new RelayCommand(() => { navigationService.Navigate(page.PageType); })
    }

    private ICommand GotoPage2Command { get; private set; }
  }

UI Project:

  public class NavigationService : INavigationService
    {
       //Assuming that you only navigate in the root frame
       Frame navigationFrame = Window.Current.Content as Frame;
       public void Navigate(INavigationPage page)
       {
          navigationFrame.Navigate(page.PageType);
       }
    }

public abstract class NavigationPage<T> : INavigationPage
{
   public NavigationPage()
   {
      this.PageType = typeof(T);
   }
}

public class NavigationPage1 : NavigationPage<Page1> { }


public class MainPage : Page
{
   public MainPage()
   {
      //I'll just place the container logic here, but you can place it in a bootstrapper or in app.xaml.cs if you want. 
      var container = new UnityContainer();
      container.RegisterType<INavigationPage, NavigationPage1>();
      container.RegisterType<INavigationService, NavigationService>();
      container.RegisterType<MyViewModel>();

      this.DataContext = container.Resolve<MyViewModel>();       
   }
}

How to Navigate to next page from ViewModel of MVVM design in , How to Navigate to next page from ViewModel of MVVM design in Metro Application Building Windows Store apps with C# or VB (archived). Xamarin.Forms includes support for page navigation, which typically results from the user's interaction with the UI or from the app itself as a result of internal logic-driven state changes. However, navigation can be complex to implement in apps that use the Model-View-ViewModel (MVVM) pattern, as the following challenges must be met:

As Scott says you could use a NavigationService. I would firstly create an interface this is not needed in this example but will be useful if you use Dependency Injection (good solution with viewmodels and services) in the future :)

INavigationService:

public interface INavigationService
{
    void Navigate(Type sourcePage);
    void Navigate(Type sourcePage, object parameter);
    void GoBack();
}

NavigationService.cs will inherit INavigationService you will need the following namespaces

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;


public sealed class NavigationService : INavigationService
{
    public void Navigate(Type sourcePage)
    {
        var frame = (Frame)Window.Current.Content;
        frame.Navigate(sourcePage);
    }

    public void Navigate(Type sourcePage, object parameter)
    {
        var frame = (Frame)Window.Current.Content;
        frame.Navigate(sourcePage, parameter);
    }

    public void GoBack()
    {
        var frame = (Frame)Window.Current.Content;
        frame.GoBack();
    }
}

Simple ViewModel to show RelayCommand example. NB I Navigate to another Page (Page2.xaml) using the DoSomething RelayCommand.

MyViewModel.cs

public class MyViewModel : INotifyPropertyChanged
{
    private INavigationService _navigationService;

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public MyViewModel(INavigationService navigationService)
    {
        _navigationService = navigationService;
    }

    private ICommand _doSomething;

    public ICommand DoSomething
    {
        get
        {
            return _doSomething ??
                new RelayCommand(() =>
                    {
                        _navigationService.Navigate(typeof(Page2));
                    });
        }
    }}

In simple example Ive created the viewmodel in MainPage.cs and added the NavigationService but you can do this elsewhere depending on what your MVVM setup is like.

MainPage.cs

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();

        var vm = new MyViewModel(new NavigationService());
        this.DataContext = vm;
    }
}

MainPage.xaml (binds to the command DoSomething)

 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button Width="200" Height="50" Content="Go to Page 2"
             Command="{Binding DoSomething}"/>
</Grid>

Hope that helps.

Enterprise App Navigation, With view-first navigation, the page to navigate to refers to the name of the view type. The MVVM pattern provides a separation between the app's UI and The ViewModelBase class stores the NavigationService instance in� Xamarin.Forms includes support for page navigation, which typically results from the user's interaction with the UI, or from the app itself, as a result of internal logic-driven state changes. However, navigation can be complex to implement in apps that use the MVVM pattern.

I don't really like when a ViewModel references Views to navigate to. So I prefer to a ViewModel-first approach. By using ContentControls, DataTemplates for ViewModel types & some kind of navigation pattern in my ViewModels.

My navigation looks like this:

[ImplementPropertyChanged]
public class MainNavigatableViewModel : NavigatableViewModel
{
    public ICommand LoadProfileCommand { get; private set; }

    public ICommand OpenPostCommand { get; private set; }

    public MainNavigatableViewModel ()
    {
        LoadProfileCommand = new RelayCommand(() => Navigator.Navigate(new ProfileNavigatableViewModel()));
        OpenPostCommand = new RelayCommand(() => Navigator.Navigate(new PostEditViewModel { Post = SelectedPost }), () => SelectedPost != null);
    }
}

My NavigatableViewModel looks like:

[ImplementPropertyChanged]
public class NavigatableViewModel
{
    public NavigatorViewModel Navigator { get; set; }

    public NavigatableViewModel PreviousViewModel { get; set; }

    public NavigatableViewModel NextViewModel { get; set; }

}

And my Navigator:

[ImplementPropertyChanged]
public class NavigatorViewModel
{
    public NavigatableViewModel CurrentViewModel { get; set; }

    public ICommand BackCommand { get; private set; }

    public ICommand ForwardCommand { get; private set; }

    public NavigatorViewModel()
    {
        BackCommand = new RelayCommand(() =>
        {
            // Set current control to previous control
            CurrentViewModel = CurrentViewModel.PreviousViewModel;
        }, () => CurrentViewModel != null && CurrentViewModel.PreviousViewModel != null);

        ForwardCommand = new RelayCommand(() =>
        {
            // Set current control to next control
            CurrentViewModel = CurrentViewModel.NextViewModel;
        }, () => CurrentViewModel != null && CurrentViewModel.NextViewModel != null);
    }

    public void Navigate(NavigatableViewModel newViewModel)
    {
        if (newViewModel.Navigator != null && newViewModel.Navigator != this)
            throw new Exception("Viewmodel can't be added to two different navigators");

        newViewModel.Navigator = this;

        if (CurrentViewModel != null)
        {
            CurrentViewModel.NextViewModel = newViewModel;
        }

        newViewModel.PreviousViewModel = CurrentViewModel;
        CurrentViewModel = newViewModel;
    }
}

My MainWindows.xaml:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewmodels="clr-namespace:MyApp.ViewModels"
        x:Class="MyApp.Windows.MainWindow"
        mc:Ignorable="d"
        Title="MainWindow" Height="389" Width="573" 
        d:DataContext="{d:DesignInstance {x:Type viewmodels:MyAppViewModel}, IsDesignTimeCreatable=True}">
    <Grid>
        <!-- Show data according to data templates as defined in App.xaml -->
        <ContentControl Content="{Binding Navigator.CurrentViewModel}"  Margin="0,32,0,0" />

        <Button Content="Previous" Command="{Binding Navigator.BackCommand}" Style="{DynamicResource ButtonStyle}" HorizontalAlignment="Left" Margin="10,5,0,0" VerticalAlignment="Top" Width="75" />
        <Button Content="Next" Command="{Binding Navigator.ForwardCommand}" Style="{DynamicResource ButtonStyle}" HorizontalAlignment="Left" Margin="90,5,0,0" VerticalAlignment="Top" Width="75" />
    </Grid>
</Window>

App.xaml.cs:

public partial class App
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        new MainWindow {DataContext = new MyAppViewModel()}.Show();
    }
}

MyAppViewModel:

[ImplementPropertyChanged]
public class MyAppViewModel
{
    public NavigatorViewModel Navigator { get; set; }

    public MyAppViewModel()
    {
        Navigator = new NavigatorViewModel();
        Navigator.Navigate(new MainNavigatableViewModel());
    }
}

App.xaml:

        <DataTemplate DataType="{x:Type viewmodels:MainNavigatableViewModel}">
            <controls:MainControl/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type viewmodels:PostEditViewModel}">
            <controls:PostEditControl/>
        </DataTemplate>

The downside is that you have more ViewModel-code which manages the state of what you are looking at. But obviously that is also a huge advantage in terms of Testability. And of course your ViewModels do not need to depend on your Views.

Plus I use Fody/PropertyChanged, that's what the [ImplementPropertyChanged] is about. Keeps me from writing OnPropertyChanged code.

Navigation with MVVM, When I first started out with MVVM, I was lost about how you should navigate between pages. I did not want to create a button on a page that… Very good article on the MVVM design pattern and navigation within a WPF app. control which stores the ContentPresenter of each TabItem when you switch� MVVM is meant to separate presentation logic into ViewModels and have ViewModels decoupled and reusable amongst different platforms (i.e. have the same ViewModel work in Windows Store Apps, Silverlight, WPF and even a console application) and be easily testable.

Here is another way to implement the NavigationService, without using an abstract class and without referencing view types in your view model.

Assuming that the view model of the destination page is something like this:

public interface IDestinationViewModel { /* Interface of destination vm here */ }
class MyDestinationViewModel : IDestinationViewModel { /* Implementation of vm here */ }

Then your NavigationService can simply implement the following interface:

public interface IPageNavigationService
{
    void NavigateToDestinationPage(IDestinationViewModel dataContext);
}

In your main window ViewModel you need to inject the navigator and the view model of the destination page:

class MyViewModel1 : IMyViewModel
{
    public MyViewModel1(IPageNavigationService navigator, IDestinationViewModel destination)
    {
        GoToPageCommand = new RelayCommand(() => 
                navigator.NavigateToDestinationPage(destination));
    }

    public ICommand GoToPageCommand { get; }
}

The implementation of the NavigationService encapsulates the view type (Page2) and the reference to the frame which is injected through the constructor:

class PageNavigationService : IPageNavigationService
{
    private readonly Frame _navigationFrame;

    public PageNavigationService(Frame navigationFrame)
    {
        _navigationFrame = navigationFrame;
    }

    void Navigate(Type type, object dataContext)
    {
        _navigationFrame.Navigate(type);
        _navigationFrame.DataContext = dataContext;
    }

    public void NavigateToDestinationPage(IDestinationViewModel dataContext)
    {
        // Page2 is the corresponding view of the destination view model
        Navigate(typeof(Page2), dataContext);
    }
}

To get the frame simply name it in your MainPage xaml:

<Frame x:Name="RootFrame"/>

In the code behind of the MainPage initialize your bootstrapper by passing the root frame:

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        var bootstrapper = new Bootstrapper(RootFrame);
        DataContext = bootstrapper.GetMainScreenViewModel();
    }
}

Finally here is the bootstrapper implementation for completeness ;)

class Bootstrapper
{
    private Container _container = new Container();

    public Bootstrapper(Frame frame)
    {
        _container.RegisterSingleton(frame);
        _container.RegisterSingleton<IPageNavigationService, PageNavigationService>();
        _container.Register<IMyViewModel, MyViewModel1>();
        _container.Register<IDestinationViewModel, IDestinationViewModel>();

#if DEBUG
        _container.Verify();
#endif
    }

    public IMyViewModel GetMainScreenViewModel()
    {
        return _container.GetInstance<IMyViewModel>();
    }
}

MVVM Navigation with Xamarin.Forms Shell, One of the topics that I find a bit contentious amongst app developers is how This meant you could navigate between views/pages by simply� In order to use the Navigation in MVVM Light you will have to register and Configure INavigationService in ViewModelLocator.cs, for this you will have to register each Page with a PageKey. First declare page key variable for each page in the App as a Public constant string before initializing instance of ViewModelLocator Class

This simply bothers me that no one has solved this at the architectural level. So this is the code for complete decoupling the views, viewmodels and the mapping between them with using the built-in Frame based navigation. The implementation uses Autofact as DI container, but can be easily ported to other IoC solutions.

Core VM logic (these should be in the same assembly):

// I would not get into how the ViewModel or property change notification is implemented
public abstract class PageViewModel : ViewModel
{
    protected internal INavigationService Navigation { get; internal set; }

    internal void NavigationCompleted()
    {
        OnNavigationCompleted();
    }

    protected virtual void OnNavigationCompleted()
    {

    }
}

public interface INavigationService
{
    void Navigate<TModel>() where TModel : PageViewModel;
}

public abstract class NavigationServiceBase : INavigationService
{
    public abstract void Navigate<TModel>() where TModel : PageViewModel;
    protected void CompleteNavigation(PageViewModel model)
    {
        model.Navigation = this;
        model.NavigationCompleted();
    }
}

This code should be in a UWP class library or executable:

public interface INavigationMap<TModel>
    where TModel: PageViewModel
{
    Type ViewType { get; }
}

internal class NavigationMap<TModel, TView> : INavigationMap<TModel>
    where TModel: PageViewModel
    where TView: Page
{
    public Type ViewType => typeof(TView);
}

public class NavigationService : NavigationServiceBase
{
    private readonly Frame NavigationFrame;
    private readonly ILifetimeScope Resolver;

    public NavigationService(ILifetimeScope scope)
    {
        Resolver = scope;
        NavigationFrame = Window.Current.Content as Frame;
        NavigationFrame.Navigated += NavigationFrame_Navigated;
    }

    private void NavigationFrame_Navigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
    {
        if(e.Content is FrameworkElement element)
        {
            element.DataContext = e.Parameter;

            if(e.Parameter is PageViewModel page)
            {
                CompleteNavigation(page);
            }
        }
    }

    public override void Navigate<TModel>()
    {
        var model = Resolver.Resolve<TModel>();
        var map = Resolver.Resolve<INavigationMap<TModel>>();

        NavigationFrame.Navigate(map.ViewType, model);
    }
}

The rest is just convenience code for registering in the DI and usage examples:

public static class NavigationMap
{
    public static void RegisterNavigation<TModel, TView>(this ContainerBuilder builder)
        where TModel : PageViewModel
        where TView : Page
    {
        builder.RegisterInstance(new NavigationMap<TModel, TView>())
            .As<INavigationMap<TModel>>()
            .SingleInstance();
    }
}

     builder.RegisterNavigation<MyViewModel, MyView>();


public class UserAuthenticationModel : PageViewModel
{
    protected override void OnNavigationCompleted()
    {
        // UI is visible and ready
        // navigate to somewhere else
        Navigation.Navigate<MyNextViewModel>();
    }
}

MVVM Light Navigation 5, This creates a Windows Store app project with a MainPage and the corresponding C# code behind file. Now we will add two more pages. In the Solution� A badly written code is a NIGHTMARE (when needed to maintain). For any developer there is nothing better than having a clean, structured code. And if you In android application development MVVM is the most popular design pattern. In this Android MVVM Tutorial we will learn building a simple app using MVVM.

Page Navigation using MVVM in Store App, 问题I\'m having a serious headache with this problem. I really dislike store apps but am forced to use it in this case. I\'ve only worked with XAML for a few weeks. Hi Andy, Thanks a lot for this post. This is my first project using WPF/MVVM, I have one doubt, as you mentioned we can pass the object from one view model to another ViewModel like this Mediator.Notify(“GoTo1Screen”, SelectedCustomer ); In my project, I am passing the selected (row) customer data from the grid to the edit view model, but I don’t know how I receive this data from edit

Converting multi-page WPF app to use MVVM. Can't figure out how , I've made a functioning single page MVVM application before in the form of my Rock by converting my Fuel Tracker to an MVVM app which can navigate between but I am using them for the first time to store the leaderboards for my game. @LucasSossai said: I want to implement hierarchical navigation in my App, and probably ViewModel to ViewModel instead of Page to Page navigation.

Model-View-ViewModel (MVVM) Explained, If your application isn't scaling, don't blame MVVM, blame how you are using MVVM. to Model/View/ViewModel pattern for building WPF Apps and generated quite a stir you use the navigation framework supplied by Silverlight, you use region The simple fact that you have a UI element with “current page” and “total� In WPF application navigation plays a vital role. Performing navigation using MVVM is little tricky. In this article we will see how to navigate different UserControls in a ContentControl. Scenario: Let us take typical application which talks about employees. Say for example it has two UserControls one for employee and the other one for

Comments
  • Have you looked up NavigationService?
  • are you using mvvm light for your app?
  • No i am not dellywheel.
  • Nice, but I have question: What if I have one container created in App.xaml.cs. This solution works great, but I have few NavigationPages which implements one interface. I can't create two register with the same interface. I can use RegisterCollection, but in ViewModel constructor I have to use indexes and it's not nice solution. I would like register few NavigationPages and use them in viewModels constructor. Is there any possibility to identity which NavigationPage from IEnumerable collecion i want to use without check the type (becouse these types are in UIProject and I haven't access.
  • Ioc has ways to register multiple instances and identify those instance during resolve. In unitycontainer and in ninject, I believe that you can give a name when you register. You can check this post stackoverflow.com/questions/16921008/…
  • What's the relevance of vm in MainPage.cs @dellywheel
  • @WD - I create a new instance of MyViewModel and then add it as MainPage's DataContext to enable databinding eg so that we can bind to the DoSomething command from the xaml.
  • @SWilko - This would mean that the VM will have an idea about Page2, I think it's ok but not recommended. I would rather pass something that's more abstract than passing the type page2 itself.
  • VIewModels should not know about views.
  • DataType is not supported in UWP templates The data type is computed. Template based navigation where the content control resolves the data template automagically is not supported (easily) in uwp as it is in wpf or silverlight.
  • Interesting (and sad). Wouldn't this be a solution? stackoverflow.com/questions/33252915/…