9

While watching a video about MVVM on Pluralsight there was a situation where the MVVM pattern got violated but no correct way of doing it was shown:

  • The view had a button that uses ICommand to trigger a handler in the ViewModel.
  • The handler correctly relayed the execution to a repository implementation.
  • The concrete implementation of the repository called a web service method.

However: if the webservice call failed, the ViewModel would bring up a message box that informs the user about the error. As the ViewModel is an abstraction of the View, it should not directly create UI, but what is the 100% clean way to get that message box presented to the user?

Krumelur
  • 32,180
  • 27
  • 124
  • 263

2 Answers2

12

Create a service:

interface IDialogService
{
    void ShowMessageBox(string message);
}

Implement it:

class DialogService : IDialogService
{
    public void ShowMessageBox(string message)
    {
        MessageBox.Show(); // ...
    }
}

Use dependency injection:

class ViewModel
{
    [Import] // This is MEF-specific sample
    private readonly IDialogService dialogService;
}

or service location:

class ViewModel
{
    private AnyCommandExecute()
    {   
        // This is MEF-specific sample
        var dialogService = container.GetExportedValue<IDialogService>();
    }
}

to obtain a concrete IDialogService in your view model, then call the obtained implementation from ViewModel.

The same approach is applicable for any other similar cases: show open/save dialog, show your custom view model in dialog.

Shannon Cook
  • 737
  • 1
  • 7
  • 16
Dennis
  • 37,026
  • 10
  • 82
  • 150
  • Looks simple and makes sense. But if I made the ViewModel abstract by not implementing the ShowMessageBox() and have one implementation for unit tests and one for productive use, I'd end up with the same effect without dependency injection. Any comments or criticism on such an approach? – Krumelur Jun 02 '13 at 09:21
  • 1
    1) This violates SRP. You're making view model responsible for everything. 2) Instead of 2 service implementations (one for production, one for testing), you should keep 2 implementations of each view model, which requires this functional. 3) Consider this: `SomeViewModel` needs to display message boxes, and it has abstract `ShowMessageBox`; `SomeDerivedViewModel : SomeViewModel` doesn't need to display it, but you already have this method. – Dennis Jun 03 '13 at 05:56
5

There are several ways to do this that adhere to the MVVM pattern, such as Interaction Service and Interaction Request.

Interaction Service

... a service that can be used by the view model to initiate interaction with the user, thereby preserving its independence on the view's implementation

enter image description here

Interaction Request

... uses events raised by the view model to express the intent to interact with the user, along with components in the view that are bound to these events and that manage the visual aspects of the interaction.

enter image description here

Source

Both quotes above are from this source (which also contains more detailed information about the patterns): http://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx#sec10

Community
  • 1
  • 1
lightbricko
  • 2,649
  • 15
  • 21