Displaying user Messages, Errors and Dialogs from a ViewModel using a Service – Part 1

December 17, 2012

4 comments

Displaying user Messages, Errors and Dialogs from a ViewModel using a Service – Part 2 

Years after the invention of the MVVM pattern and people are still asking many questions about how to do this and how to do that, and specifically, how to display a Message, Error or even opening a Dialog from a View Model without accessing the view layer or visual tree.

If we go straight with the MVVM pattern concept, the view-model must not directly access or manipulate the View/Visual Tree or part of it in any circumstances. As many of you may already familiar with the basics, this serves one purpose: Separated Presentation. With all the benefits of separated presentation, this restriction is the origin of the complexity of this pattern and the source of many questions.

 

If we keep in mind the separation rule, there are several patterns out there we can use to target this problem. For example, we can use a Service.

var userInteraction = container.Resolve<IUserInteraction>();
var result = userInteraction.ShowMessage(
    "Allow camera access?", UserMessageOptions.YesNo);
if (result == UserMessageResult.Yes)
{
    // ...
}

What we’re doing here is actually using a service to separate the presentation related logic from the view-model, placing it inside a presentation-service, in our case: IUserInteraction.

Given that the IUserInteraction service is implemented as part of the view layer, and this layer is restricted from within the view-model, we are using a DI container to resolve this service implementation. This way we’re having a real separation, yet we are able to interact with the user.

Same concept for displaying errors, using a different method or interface for handling exceptions and error codes.

Now, looking inside the implementation of such a service, located in the view-layer, we may see something like this:

UserMessageResult ShowMessage(string message, UserMessageOptions options);
        
void ShowError(Exception e);

The service is part of the view-layer, so it’s reasonable that it may access any presentation element and run presentation code. In our case accessing WPF MessageBox. Of course you may want to use your own WPF/SL specific implementation of a message box, but then you only need to replace the native MessageBox with your own implementation, later when it will be alive and kicking.

 

Now the tricky part here is displaying dialogs.

First, depends on the type of application we are developing: Desktop, Tablet, Phone, etc. We should ask if Dialogs/Popups are the right mechanism to use. Of course there are alternatives: Navigation for example.

Whatever mechanism we’ll use, it will be part of the view-layer (For example, in Windows 8 Store Apps it’s part of the Frame or Page), so we better separate that from the view-model using the same service concept I’ve presented above.

Here’s a simple usage:

var saveImageDialogParameters = new SaveImageDialogParameters
{
    ImageFilePath = @"c:\images"
};

_userInteraction.ShowDialog<ISaveImageDialog, SaveImageDialogParameters>(
    "Save Image", saveImageDialogParameters);

A dialog is a bit complex than a simple message box, hence it may have view logic and we may want to develop it using the MVVM pattern, so we have a dialog view and a dialog view-model.

Now we’re dealing with two parts, and additional option to pass parameters to the dialog view-model. In our case ImageFilePath. Since we really don’t want to interact directly with the dialog view-model not the view from the actual view-model, we need to find a generic way to combine all together.

Let’s take a look at possible method signatures for opening dialogs from the view-model:

bool? ShowDialog<TConductor>(string title)
    where TConductor : IDialogConductor;

bool? ShowDialog<TConductor, TParameters>(string title, TParameters parameters)
    where TConductor : IDialogConductor<TParameters>; 

The concept here is using what I’m calling: a dialog conductor. A conductor is responsible for creating dialog view, view-model and initializing the view-model with the dialog parameters if any.

In our case, the ISaveImageDialog interface represents the conductor. Since the implementation is internal to the dialog, we resolve it from the container.

The first signature can be used for displaying a dialog without any parameters, and the second can be used in case that we want to provide both conductor and parameters.

 

In my next post about this topic I’ll provide the implementation details for the ShowDialog and complete code for the rest.

Stay tuned!

Displaying user Messages, Errors and Dialogs from a ViewModel using a Service – Part 2

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

4 comments

  1. RobDecember 17, 2012 ב 12:43

    You might consider looking into Caliburn.Micro. It has a window manager service for showing modals, popups, messages, etc. I also leverages the screen conductor pattern internally.

    Reply
  2. Tomer ShamamDecember 17, 2012 ב 13:54

    Hi Rob,
    I believe you did a great job with Caliburn.Micro, though not everyone is using it or familiar with, and I think writing about why we need it and providing pointers for how to develop such a solution will help many to better understand MVVM and the concept of separated presentation. Thinking this way is the core concept of MVVM and it’s arise again and again in many situations. Having this in mind, we can solve many other problems related to this pattern.

    Reply
  3. RobDecember 18, 2012 ב 15:18

    I agree. I wasn’t criticizing your article. I just wanted to make sure you knew of the similarities to Caliburn.Micro. It’s almost always good for people to understand the why and how.

    Reply
  4. Tomer ShamamDecember 19, 2012 ב 14:08

    Never thought you did, but really, I’m not so familiar with Caliburn.Micro. In that case, if we thought about the same ideas it seems like we’re in the right direction 🙂

    Reply