Opening a new window on button click WPF MVVM
I am learning WPF MVVM and want to open a new window on a button click from a main window.
I know each View has to have an equivalent ViewModel and one of the basic principles of MVVM is that the ViewModel must not know anything about the View.
So please can anybody provide me a simple clean example that does not violate any MVVM principles on how to create two Views and two ViewModels that have the following functionality:
Show a new view by clicking a button from a main View.
You can create a separate service for launching views as dialog, so that it can be used in a generic way across the application. And will inject this service to the ViewModel via Constructor which wants to launch any dialog.
public interface IDialogWindowService<T>
{
void Show();
void ShowDialog();
}
public class DialogWindowService<T> : IDialogWindowService<T> where T : Window
{
public void Show()
{
container.Resolve<T>().Show();
}
public void ShowDialog()
{
container.Resolve<T>().ShowDialog();
}
}
You can create a separate service for launching views as dialog, so that it can be used in a generic way across the application. And will inject this service to the ViewModel via Constructor which wants to launch any dialog.
public interface IDialogWindowService<T>
{
void Show();
void ShowDialog();
}
public class DialogWindowService<T> : IDialogWindowService<T> where T : Window
{
public void Show()
{
container.Resolve<T>().Show();
}
public void ShowDialog()
{
container.Resolve<T>().ShowDialog();
}
}
Now just inject this service to the respective viewmodel.
public class YourViewModel
{
//commands
public ICommand someCommand { get; set; }
private IDialogWindowService<BookingView> _dialogService;
public YourViewModel(IDialogWindowService<YourView > dialogService)
{
_dialogService = dialogService
someCommand = new RelayCommand(someCommandDoJob, () => true);
}
public void someCommandDoJob(object obj)
{
//Since you want to launch this view as dialog you can set its datacontext in its own constructor.
_dialogService.ShowDialog();
}
}
OR
you can use DataTemplates
to change view. It allows to dynamically switch Views
depending on the ViewModel
:
<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.
The best example I've ever seen and read it is made by Rachel Lim. See the example.
What I've done with some success in the past is to create what is basically a View Factory, that constructs a view and assigns it a viewmodel. This gives me a one-stop shop to do the stiching for the views, much like you would to using IoC.
There may be advantages and disadvantages to this, so I'd be curious to learn if there are other/better ways, but so far, this is the practice I've found least painful.
Depending on your usage, there isn't anything wrong with opening a view from the view's code-behind. It's still view code after all.
MyView view = new MyView();
view.Show();
Otherwise, if you need to open a window from the ViewModel
or using a ICommand
, then you can look at the "Open Windows and Dialogs in MVVM" library I wrote on GitHub. This will demonstrate how to open a Window
by clicking on a button using the MVVM design pattern.
上一篇: 如何以MVVM的方式打开模式窗口