Closing View from ViewModel
Lightweight approach to close view from viewmodel command.
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 theRequestClose
event. The ViewModel should implement theICloseable
interface if it supports Closeable behavior. - Implement
ICloseable
in the view model. - Add a
CloseComm
to the view model.and
- Wire-up a
RequestClose
event in theLoaded
event of the View code behind, ifDataContext
implements theICloseable
interface. - View-viewmodel binding is done in the Application
Startup
. StartupURI
should be removed from MainWindow.xaml.
interface ICloseable
{
event EventHandler<EventArgs> RequestClose;
}
class MainWindowViewModel : ViewModelBase, ICloseable
public ICommand CloseCommand { get; private set; }
Loaded += (s, e) =>
{
if (DataContext is ICloseable)
{
(DataContext as ICloseable).RequestClose += (_, __) => this.Close();
}
};
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// Create Main Window instance
MainWindow window = new MainWindow();
// Create Main Window View Model
MainWindowViewModel viewModel = new MainWindowViewModel();
// Associate DataContext
window.DataContext = viewModel;
Application.Current.MainWindow = window;
window.Show();
}
Points of Interest
The following refinements are useful:
- View view-model binding can be moved from
OnStartup
toViewModelLocator
. 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.