Introduction
This short article presents a walk-through of
how to close a WPF application from the View Model.
Background
Closing/starting a window is UI interaction (owned by the view) and should be decoupled from
the view model. The view model should contain Commands and Properties (as needed for the view).
View model can also contain events to which the view can respond. In the approach presented in this article,
a view model event is used to trigger an action owned by the view.
There are already multiple approaches to this problem:
- Using
Attached Behavior
- Using Application level service/controller to manage application life cycle
- Using Message Bus (like MVVM Light Messenger/Prism Event Aggregator)
The approach mentioned in this article is a trimmed down version of the above approaches for a small WPF application (where
an Attached Behavior or Application service are overkill).
Approach
In this approach, a RequestClose event will be added to the ViewModel.
The view model will raise a RequestClose event and the view will respond
to it by invoking the Close method.
The event wire up and
the view-viewmodel binding is done in the Application startup override.
Using the Code
The code is written in VS2012 RTM. It should be opened in VS2010/VS2012RTM/VS2012 as
Visual Studio projects / solutions are now backwards compatible.
The application uses MVVM Light (for
an MVVM based framework).
The demo application contains a single window with a button "Close Me". Clicking on this button invokes
a CloseCommand
on the view model that in turn raises a RequestClose event. The view handler then closes the instance (on listening
to the RequestClose event).
- Create an
ICloseable interface that defines the RequestClose event.
The ViewModel should implement the ICloseable interface if it supports Closeable behavior. interface ICloseable
{
event EventHandler<EventArgs> RequestClose;
}- Implement
ICloseable in the view model.
class MainWindowViewModel : ViewModelBase, ICloseable
- Add a
CloseCommand to the view model.
public ICommand CloseCommand { get; private set; }
- Wire-up a
RequestClose event in the Loaded event of
the View code behind, if DataContext implements the ICloseable interface. Loaded += (s, e) =>
{
if (DataContext is ICloseable)
{
(DataContext as ICloseable).RequestClose += (_, __) => this.Close();
}
}; - View-viewmodel binding is done in the Application
Startup.
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
MainWindowViewModel viewModel = new MainWindowViewModel();
window.DataContext = viewModel;
Application.Current.MainWindow = window;
window.Show();
}
StartupURI should be removed from MainWindow.xaml.
Points of Interest
The following refinements are useful:
- View view-model binding can be moved from
OnStartup to
ViewModelLocator. Refer to
this blog for View ViewModel binding approaches. - Event wire-up can be refreshed on
DataContext change notification.
History
This is the second version of the article. In this revision, the ICloseable interface is introduced and
event wire up for the RequestClose event has been moved to the View.