Bit long for a comment but some further explanation seems advisable.
The article I linked to does simplistic instantiation of viewmodels.
You need something more sophisticated in a commercial app, but let's gloss over such huge subjects as dependency injection.
Something must instantiate your viewmodel and that is probably best handled by a factory which can be as simple as a lambda.
Most of this is air code so apologies for mis spelling. The intention is to give you a flavour of what you need to do. Which is fairly extensive.
In your app you would add a dictionary:
Dictionary<Type, Object> AllMyViewModels;
This will store the state of previously used viewmodels which will in turn allow you to store state of whatever the user was last doing in FooView because you bind everything you care about to FooViewModel.
Let's imagine this is mainwindow and a single window app.
That has mainwindowviewmodel and maybe that contains that ViewModels dictionary if this is a small app.
Here's a prototype window. The loginuc and useruc are usercontrols.
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:LoginViewModel}">
<local:LoginUC/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:UserViewModel}">
<local:UserUC/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ItemsControl ItemsSource="{Binding NavigationViewModelTypes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding VMType}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ContentPresenter Grid.Column="1"
Content="{Binding CurrentViewModel}"
/>
</Grid>
</Window>
Click one of those buttons in the itemscontrol and navigation will happen by switching out CurrentViewModel.
That will be templated out into a user control in the view.
This is some code I happen to have so it could easily be improved by using something like the community mvvm toolkit. This is just to give you ( or anyone ) the idea though.
MainWindowViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
public string MainWinVMString { get; set; } = "Hello from MainWindoViewModel";
public ObservableCollection<TypeAndDisplay> NavigationViewModelTypes { get; set; } = new ObservableCollection<TypeAndDisplay>
(
new List<TypeAndDisplay>
{
new TypeAndDisplay{ Name="Log In", VMType= typeof(LoginViewModel) },
new TypeAndDisplay{ Name="User", VMType= typeof(UserViewModel) }
}
);
private object currentViewModel;
public object CurrentViewModel
{
get { return currentViewModel; }
set { currentViewModel = value; RaisePropertyChanged(); }
}
private RelayCommand<Type> navigateCommand;
public RelayCommand<Type> NavigateCommand
{
get
{
return navigateCommand
?? (navigateCommand = new RelayCommand<Type>(
vmType =>
{
CurrentViewModel = null;
CurrentViewModel = Activator.CreateInstance(vmType);
}));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
As it is, type is used to instantiate a viewmodel without any parameters. That happens every time in the code above. We can extend that by using our dictionary though.
Add on
private Dictionary<Type, Object> viewModels = new Dictionary<Type, Object>();
And change the command
?? (navigateCommand = new RelayCommand<Type>(
vmType =>
{
CurrentViewModel = null;
if (viewModels.ContainsKey(vmType))
{
CurrentViewModel = viewModels[vmType];
return;
}
CurrentViewModel = Activator.CreateInstance(vmType);
viewModels.Add(vmType, CurrentViewModel);
}));
Now, we add any viewmodel to the dictionary if it isn't there or return what's in that dictionary if we have an appropriate viewmodel.
You could add a factory into this for each viewmodel which passes in parameters.
Other areas you could improve this include using dependency injection. Some viewmodels you probably don't want to retain state. You can differentiate in the dependency injection container when you register your viewmodels and specify whether they should be singleton or transient ( and a new instance ).
The DI container would replace the dictionary.
Usually, parameters you want for a viewmodel are services like repository which in turn have dependencies you'd want to use DI for.