Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dialogs the MVVM Way

0.00/5 (No votes)
9 Jan 2014 1  
This article and the attached example will show how to show dialogs the MVVM way with databinding and no code-behind in the view.

Introduction

The Model-View-ViewModel pattern is really nice since it clearly defines the responsibility of the View, the ViewModel and the Model. There should be no direct contact between the View and the ViewModel and via the databinding mechanism, this is easily possible.

However, I ran into a problem when a confirmation was required from the user before removing an entity chosen by the user. The command responsible for the removal behavior was triggered from within the View and executed from within the ViewModel. In my opinion, the ViewModel should not directly use any presentation functionality (e.g. showing a MessageBox).

In my quest to find a reasonable solution on the web, I ran into the following solutions:

  1. Just show the messagebox from the ViewModel.  
  2. Use a solution that adds extra code to the View which reacts to a trigger from the ViewModel.
  3. Bind the View to a message property and have it show a messagebox when this changes.
  4. Use one of the available MVVM frameworks and use the solution they provide.

Solution 1 & 2 where directly discarded, solution 3 was getting close however I found it quite limiting to react to a change to a message. Solution 4 was not an option for me since I am not really fond of the MVVM frameworks I reviewed.

Because I was unable to find a solution matching my requirements, I came up with the solution mentioned in this article.

The Solution

Using the Behavior class located in the System.Windows.Interactivity assembly, it is possible to hook in between the View and ViewModel without requiring direct contact between the View and ViewModel.  

Extending this Behavior class with functionality that will register the behavior instance centrally based on a provided identifier will ensure that both the View and ViewModel can use it without any direct reference.

This resulted in the following design:

Using the Code

InteractionBehaviorCollection

To be able to register the behaviors centrally, the singleton InteractionBehaviorCollection is used. Based on the identifier of the behavior, it will store the instance of the behavior so that it can be retrieved when required.

InteractionBehaviorBase

To extend the Behavior class, a derived class is created, this is called InteractionBehaviorBase. When the interaction behavior is attached (used in a View), it will register itself with the InteractionBehaviorCollection. When the interaction behavior is detached, it will also unregister itself again.

MessageBoxInteractionBehavior

This class contains the required functionality to show a regular MessageBox when required. When a custom dialog is required, another specific InteractionBehavior can be created which will be responsible for showing the custom dialog when required by a ViewModel.

This class provides 3 properties which enables us to customize the message box. This includes the Caption, the Message and the possible buttons as they will be shown in the message box.

There is one method, the method Execute which will show the message box and which passes the result onto the custom code for processing. This processing will be done at the ViewModel so that the logic can react on the client action.

public override void Execute(  
   Action<Object> interactionFinished,  
   params object[] args)  
 {  
   if ((interactionFinished != null) &&   
     !string.IsNullOrEmpty(Caption) &&  
     !string.IsNullOrEmpty(Message))  
   {  
     string caption = string.Format(Caption, args);  
     string message = string.Format(Message, args);  
   
     interactionFinished(MessageBox.Show(message, caption, Buttons,  
         MessageBoxImage.Information));  
   }
} 

The View, MainWindow.xaml

In the XAML of the view, the behavior is defined, this also includes the properties. It is possible to include formatting characters so that custom information can be passed when the behavior is triggered from the ViewModel. The identifier is required so that the ViewModel can identify this specific behavior.

<i:Interaction.Behaviors>  
   <local:MessageBoxInteractionBehavior   
     Caption="This contains the caption"   
     Message="This contains the message, parameters can also be added (For example the current date/time: {0})"   
     Buttons="YesNo"   
     Identifier="ThisIdentifiesThisSpecificCombination"/>  
 </i:Interaction.Behaviors>   

ViewModelBase

This is the base for the specific view model as it is used in the attached example. It contains the method ExecuteInteraction which allows to trigger the interaction behavior with the corresponding identifier.

// Find the matching interaction behavior.  
IInteractionBehavior interactionBehavior =  
   InteractionBehaviorCollection.Instance.Get(identifier);  
if (interactionBehavior != null)  
{  
   try  
   {  
     interactionBehavior.Execute(interactionFinished, args);  
     result = true;  
   }  
   catch (Exception)  
   {  
   }  
} 

TestViewModel

The view model used for this test application. It provides a command to trigger the interaction behavior, it is used via the property TestInteractionBehaviorCommand. The actual triggering of the message box from within the view model is located in the method TestInteractionBehavior.

private void TestInteractionBehavior()  
{  
   ExecuteInteraction("ThisIdentifiesThisSpecificCombination", (result) =>  
   {  
       MessageBoxResult messageBoxResult = (MessageBoxResult)result;  
       if (messageBoxResult == System.Windows.MessageBoxResult.Yes)  
       {  
          // We know that the user selected the option Yes.  
       }  
    }, DateTime.Now);  
}

Calling ExecuteInteraction will trigger the interaction behavior which matches the identifier "ThisIdentifiesThisSpecificCombination". The result of the message box is received and can be used to handle the required client action. It is possible to pass parameters so that messages can be customized, e.g., display the name of the entity that is being removed. For this example, I stick with the current date/time.

The following message box is shown when ExecuteInteraction is called.

Points of Interest

This example uses the default message box to interact with the user. Based on the information in this example, it should be no problem to exchange this with a custom view which better suits your needs.

History

  • 9 Jan 2014: First version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here