Jaco Karsten’s Blog

About WPF (and more)

MVVM Intercommunication between View and ViewModel

Posted by Jaco Karsten on 27 March 2009

I have found that the MVVM pattern significantly simplifies the development of a WPF application, especially as the complexity of an application increases. The simplicity is brought about by introducing separation of concerns to your project. The UI logic sits inside the View and the business logic sits inside the ViewModel. And databinding (which is a first class citizen in WPF) is the glue between the two. It also really simplifies things to have only one DataContext being bound to the View; and then binding the controls inside the View is as simple as:

• Exposing data to bind to as a property in your ViewModel (whether it is a collection or single value)
• Binding the appropriate control to this property.

RelayCommand

The RelayCommand that Josh Smith introduced was great since it allows you to bind a Command property of a button straight to a ICommand Property defined in your ViewModel. This removed the need for you to write code in the View’s code behind. I really started to enjoy using this pattern and it felt natural and intuitive to develop in this matter.

Interacting with the user from the ViewModel

As I made some progress in my project, it became apparent that there is no easy way of back and forth communication between the View and the ViewModel.

Say for example you click on a item in a DataGrid and then on a Delete button to delete the item. This fires off the ICommand’s Execute event handler inside your ViewModel, right?  But now you want to get confirmation from the user before you really delete this item. This means you somehow have to go back to the UI layer (View) to display a MessageBox with an appropriate message that comes from the ViewModel and then get the answer from the View back to the ViewModel to continue with the deletion. What I have found frustrating is that there is no easy way to accomplish this as yet.

So I have come up with a way of simplifying this intercommunication between the View and the ViewModel.

MVVMIntercom

The basic idea behind it is farely simple and an analogy would be playing tennis or ping pong between the View and ViewModel:

The tennis ball (or ping pong ball) would be something that I call a CommsUnit.
My definition of a CommsUnit is: A contained unit of information for triggering code execution on both the View and ViewModel in turn (also providing any data each side would need) in a sequential or workflow manner. This sequence is driven by a CommsState enum property inside the CommsUnit. The different states drive the sequence of triggering code execution.

Let’s make it practical. In my example of confirming an item deletion mentioned above: I would declare a ConfirmedDeleteCommsUnit like this:

public enum ConfirmedDeleteState
{
RequestingMessagePrompt,
ReturningDialogResult
}

public class ConfirmedDeleteCommsUnit : BaseCommsUnit
{
public ConfirmedDeleteState CommsState
{
get;
set;
}
public int RecordID
{
get;
set;
}
public string MsgBoxTitle
{
get;
set;
}
public string MsgBoxMessage
{
get;
set;
}
public MessageBoxResult MsgBoxResult
{
get;
set;
}
}

The View would contain 2 DependencyProperties that are TwoWay-bound to 2 INotifyPropertyChanged enabled properties on the ViewModel. The one is named “ToViewCommsUnit” and the other “ToViewModelCommsUnit”. As the names imply: ToViewCommsUnit is used to send information from the ViewModel to the View and ToViewModelCommsUnit is used to send information back.

The ViewModel would initiate the intercommunication process by creating a new ConfirmedDeleteCommsUnit and assigning it to it’s ToViewCommsUnit property. Because of the twoway binding applied to this property, the View’s ToViewCommsUnit would detect a change and raise an event which lets the View know that the ball is in its court. The View will assess the state of the CommsUnit and discover it is in “RequestingMessagePrompt” state which it knows how to handle. The state would trigger a messagebox and get the title and message from the CommsUnit that is needed to display the messagebox. The result is stored back inside the CommsUnit and the CommsState is changed to “ReturningDialogResult”, to be send back to the ViewModel. The View takes the same CommsUnit (which now contains the MessageBox result and new state) and assigns it to its ToViewModelCommsUnit property which, because of twoway binding, changes the ToViewModelCommsUnit property of the ViewModel. This in effect lets the ViewModel know that the ball is back in its court. The ViewModel discovers that the CommsUnit is in the “ReturningDialogResult” state which it knows how to handle. This will trigger the actual deletion to continue.

The Demo solution that I have written has a BaseView and BaseViewModel class that impliment this pattern or behaviour or what ever you want to call it. These base classes make this pattern easy to use inside all the Views and ViewModels of your project. Declaring base classes for your Views and ViewModels is really standard practice for WPF applications that would benefit from the MVVM pattern anyway.

Things to note about the Demo solution is: I am using Sql CE 3.5 as the datasource and apparently Expression Blend doesn’t support running applications with a sdf database file. VS 2008 works fine with it though. The only thing you need to change for the app to run in VS 2008 is the connection string defined under Settings of the project. SQL CE 3.5 in VS 2008 needs a hard coded path to work properly so update it according to where you have extracted the solution. That’s it.

Please let me know if you have any suggestions on how to improve this intercommunication process or if there is a better way that you have discovered.

Databinding in Dot Net 4.0 works a bit different from Dot Net 3.5, so I have created a Dot Net 4.0 compatible version of my Demo application for those of you who are using this approach. I, however have since moved on to use the Messaging Service approach which I think is a bit more elegant and flexible. I will try to post something on that in the near future.

About these ads

5 Responses to “MVVM Intercommunication between View and ViewModel”

  1. Joy said

    Thanks,
    It helped me lot…
    What about the Microsoft.Expression.Interactivity.dll??? can I include it in my project? Will there be any copyright issues if I include?

    • jacokarsten said

      Hi Joy,

      That’s a good question and I wish that someone inside Microsoft can give us an answer to that. All I know is that the library clearly isn’t finished, so expect changes to be made to it. My suggestion is (if possible) wait until a version is released on CodePlex before deploying it with your project.

      Jaco

  2. Vladisld said

    Thanks for the new idea.

    I was stumbled by the same problem several months ago and solved it by inheriting the DataGrid and adding the routed event for this particular purpose. Clearly not as generic solution as your idea.

    The benefit of routed event is that you may handle it anywhere in your visual tree. So for example it may be handled in your main window. Also, IMHO, it’s more clear to let the view to decide what need to be presented to the user ( message box or anything else and what text to present – probably localized )


    public class DataGridEx: DataGrid
    {
    #region DeleteConfirmation Routed Event
    ///
    /// Raised just before the selected item(s) are about to be deleted
    ///
    public static readonly RoutedEvent DeleteConfirmationEvent = EventManager.RegisterRoutedEvent("DeleteConfirmation", RoutingStrategy.Bubble, typeof(DataGridDeleteConfirmationHandler), typeof(DataGridEx));

    public event DataGridDeleteConfirmationHandler DeleteConfirmation
    {
    add { AddHandler(DeleteConfirmationEvent, value); }
    remove { RemoveHandler(DeleteConfirmationEvent, value);}
    }
    #endregion

    #region Command Handler(s)

    protected override void OnExecutedDelete(System.Windows.Input.ExecutedRoutedEventArgs e)
    {
    DataGridDeleteConfirmationArgs args = new DataGridDeleteConfirmationArgs(DeleteConfirmationEvent)
    {
    Confirmed = false,
    SelectedItems = this.SelectedItems
    };
    RaiseEvent(args);

    if (args.Handled && !args.Confirmed)
    {
    return;
    }
    base.OnExecutedDelete(e);
    }
    #endregion
    }

  3. Toby said

    Hi,

    I have been using this for a while but after upgrading to .NET 4 it’s broken and I can’t seem to find the cause. Did you come across this and find a fix?

    Regards

    Toby

    • Jaco Karsten said

      Hi Toby,

      I have created an updated version of the demo application that works with Dot NET 4.0. The main thing I have done was to move the binding code to the BaseView constructor as opposed to the DataContextChanged event handler.

      If you like this method of intercommunication, feel free to continue to use it. I just found that using a Messaging Service allows a lot more flexibility since you can send messages between any View and ViewModel; not just the 2 being bound to each other.

      You can find the link to the updated demo application in my original post.

      Regards
      Jaco

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: