As a starter in this all architecture of MVVM I'm having a few doubts regarding the navigation between one window to another. I'm using the Framework MVVM Light.
The behavior I expect is in WinForms like this:
GeneralWindow gw = new GeneralWindow(); this.Hide(); // or close
gw.Show();
I already lose a couple of hours trying to find some hints using the messenger, but the methods I found I have to use code-behind in the view and that is not very MVVMish.
Best regards and thank you in advance.
The behavior I expect is in WinForms like this:
GeneralWindow gw = new GeneralWindow(); this.Hide(); // or close gw.Show();
MVVM pattern divides View
from ViewModel
. So it is not eligible to create new View
from ViewModel
. Creating window instance and showing window from view model is violation of MVVM". So I suggest you to use the popular technique where you can change Views
using ContentControl
and DataTemplate
.
Let's dive in this technique:
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModelA}">
<localControls:ViewAUserControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModelB}">
<localControls:ViewBUserControl/>
</DataTemplate>
<Window.Resources>
<ContentPresenter Content="{Binding CurrentView}"/>
</Window>
If Window.DataContext
is an instance of ViewModelA
, then ViewA
will be displayed and Window.DataContext
is an instance of ViewModelB
, then ViewB
will be displayed.
Let me show an example where it can be seen where you should put DataTemplates
:
<Window x:Class="SimpleMVVMExample.ApplicationView"
...The code omitted for the brevity...
Title="Simple MVVM Example with Navigation" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModelA}">
<localControls:ViewAUserControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModelB}">
<localControls:ViewBUserControl/>
</DataTemplate>
</Window.Resources>
<DockPanel>
<Border DockPanel.Dock="Left" BorderBrush="Black" BorderThickness="0,0,1,0">
<ItemsControl ItemsSource="{Binding ListOfViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"
Margin="2,5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<ContentControl Content="{Binding CurrentDataTemplateViewModel}" />
</DockPanel>
</Window>
The best example I've ever seen and read it is made by Rachel Lim. See the example.
Update:
If you want really open new Window, then you should create an intermediate layer to make ViewModel not dependent on a concrete implementation of creating new window.
public class YourViewModel
{
private readonly IWindowFactory windowFactory;
private ICommand openNewWindow;
public YourViewModel(IWindowFactory _windowFactory)
{
windowFactory = windowFactory;
/**
* Would need to assign value to m_openNewWindow here, and
* associate the DoOpenWindow method
* to the execution of the command.
* */
openNewWindow = null;
}
public void DoOpenNewWindow()
{
windowFactory.CreateNewWindow();
}
public ICommand OpenNewWindow { get { return openNewWindow; } }
}
public interface IWindowFactory
{
void CreateNewWindow();
}
public class ProductionWindowFactory: IWindowFactory
{
#region Implementation of INewWindowFactory
public void CreateNewWindow()
{
NewWindow window = new NewWindow
{
DataContext = new NewWindowViewModel()
};
window.Show();
}
#endregion
}
How to close a Window?
There are a lot of approaches.. One of them is:
Application.Current.MainWindow.Close()