Click here to Skip to main content
Click here to Skip to main content

Dialogs the MVVM Way

, 9 Jan 2014
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

JP van Mackelenbergh
Architect NSpyre
Netherlands Netherlands
I am a relaxed guy, born in '73, who likes to develop software professionally in both my work and in my spare time.
 
Keywords are C#, WCF, WPF.

Comments and Discussions

 
Questionviewmodel interprets Yes No which is a UI class [modified] Pinmemberyalenap10-Feb-14 8:20 
AnswerRe: viewmodel interprets Yes No which is a UI class PinmemberJP van Mackelenbergh24-Feb-14 0:12 
GeneralRe: viewmodel interprets Yes No which is a UI class [modified] Pinmemberyalenap24-Feb-14 9:33 
GeneralMy vote of 5 PinmemberJoachim_797172013-Jan-14 20:46 
GeneralRe: My vote of 5 PinmemberJP van Mackelenbergh14-Jan-14 3:11 
QuestionExpanding this? Pinmembercjb1109-Jan-14 23:52 
AnswerRe: Expanding this? PinmemberJP van Mackelenbergh10-Jan-14 9:45 
SuggestionRe: Expanding this? PinmemberMember 460088713-Jan-14 20:11 
QuestionLooks like the way its done in PRISM PinmvpSacha Barber9-Jan-14 5:37 
AnswerRe: Looks like the way its done in PRISM PinmemberJP van Mackelenbergh10-Jan-14 9:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 9 Jan 2014
Article Copyright 2014 by JP van Mackelenbergh
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid