Wednesday, April 7, 2010

How to handle WPF events with MVVM on the cheap (without a framework).

In my experience, developers starting out with WPF and MVVM need (and want) to slowly wade in.   WPF is already a significant mind set shift and adding the overhead of learning MVVM and an MVVM framework is often just too much.

This blog entry assumes you have a basic understanding of WPF and MVVM and are just starting to ask the question – how do I handle WPF events in an MVVM architecture?   Normally you would handle WPF events in the code behind.   Of course this is anathema in MVVM (kidding – but code behind in MVVM is controversial as of now).   MVVM is all about continuing the concept of separation of UI and business logic and, in my humble opinion, adding any significant business logic functionality in the code behind is not a best practice (note I am a strong believer in unit tests which require separation of UI and business functionality).

Back to the original question – since adding significant functionality for events in code behind is not desired for MVVM the only other place for this code to go is in the View Model – but how does the code in the View Model get triggered.   There are many MVVM frameworks and all of them have their extensions to handle this.   But for many small to medium size applications, incorporating an MVVM framework isn’t required - a few simple base classes are all that is needed.   So if you want something simple to handle WPF events with MVVM for smaller programs or to just to continue getting your feet wet without having to incorporate an MVVM framework, read on.

One of the first things we learn in WPF/MVVM is that clicks on buttons are a type of event that is translated to Commands which we can handle on our View Model.   Unfortunately nearly all other events do not have this convenience. However, we can easily create this behavior cheaply!   The concept is to handle the event and then translate that event to a button command.   The questions are:  Where will the intermediate buttons be loacted and how to do the translation from event to button command?

Let’s answer the button location first.   Simple, the button is anywhere in the XAML markup but with visibility set to hidden!   Hidden buttons can still fire commands and are perfect for our needs.

In the sample code for this blog we will be handling the Closing Window and Close Window events.   Applications often ask “Do you want to save?” during shutdown. This sample code shows how this can be implemented.   Note however that the method described here can be used with any event!

Here are the obligatory screen shots of the sample application.

User clicked X on window - closing window event command fired:


User answered yes to shutdown - close window event command fired:


The following two hidden buttons will handle our closing window event and our close window event. Note the command bindings which will fire the command handler code in our View Model.

<!-- Hidden buttons to help us convert events to commands -->
<Button Visibility="Hidden" Name="ClosingMainViewModel" Command="{Binding Path=ClosingMainViewModelCommand}"/>
<Button Visibility="Hidden" Name="CloseMainViewModel" Command="{Binding Path=CloseMainViewModelCommand}"/>

Now to answer the second question – how to translate the event to a command handler.   Here is where simple code behind comes to the rescue.  We handle the event in the code behind and execute the command on the hidden button for that event.

private void MainView_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    ClosingMainViewModel.Command.Execute(e);
}

private void MainView_Closed(object sender, System.EventArgs e)
{
    CloseMainViewModel.Command.Execute(null);
}

In my opinion we don’t violate any MVVM rules since there is no significant business logic in the code behind – we are simply translating our event to a command.

The full code is available here. 

Enjoy!
Todd Stephan

No comments:

Post a Comment