MVVM and Dialogs
For those familiar with the MVVM (Model, View, View-Model) pattern in .NET development, one conundrum that you’ve probably pondered, or at least read about, is what to do about showing a dialog. For a bit of background, MVVM is centered around the concept of binding from the View (XAML markup) to the “ViewModel”, which essentially acts as a staging platform for UI binding.
The ViewModel exposes the “Model” in such a way that the XAML can passively bind to it. It does this by exposing bindable properties (using INotifyPropertyChanged) and bindable commands (by using ICommand). Properties represent data, and commands represent actions.
The Problem
So, let’s say that you want a clean MVVM implementation which generally aspires to have no code-behind. Some people are more purist about this than others, but the concept has merit. Code-behind represents an active way of binding. That is, you have code that knows about the declarative markup and manipulates it. The problem here is that you have a dependency bugaboo. In a layered application, the layers should know about the one (or ones) underneath them and care nothing about the ones above them. This allows a different presentation layer to be plopped on a service tier or a different view to be skinned on a presentation tier. In the case of code-behind, what you have is a presentation tier that knows about its view and a view that knows about its presentation tier. You cannot simply skin another view on top because the presentation tier (read: code-behind) expects named elements in the declarative markup.
So, in a quest to eliminate all things code behind, you adopt MVVM and do fine when it comes to data binding and basic commands. But inevitably you want to open a window, and the WPF framework is extremely clunky and win-forms-like when it comes to this. Your choices, out of the box, are to have a named element in the XAML and manipulate it to show a dialog or else to have an event handler in the code behind.
What Others Have Suggested
The following are suggestions I’ve seen to address this problem and the reasons that I didn’t particularly care for them, in regards to my own situation. I did a fair amount of research before rolling my own.
- Just use the code behind (second response to post (3), though I’ve seen the sentiment elsewhere). I don’t really like this because I think that, when it comes to design guidelines, slippery slopes are a problem. If you’re creating a design where you’d like to be able to arbitrarily swap out groups of XAML files above a presentation layer, making this exception is the gateway to your skinnable plans going out the window. Why make exceptions to your guidelines if it isn’t necessary?
- Mediator Pattern. Well, this particular implementation lost me at “singleton,” but I’m not really a fan of this pattern in general for opening windows. The idea behind all of these is to create a situation where the View and ViewModel communicate through a mediator so as to have no direct dependencies. That is, ViewModel doesn’t depend on View–it depends on Mediator, as does the View. Generally speaking, this sort of mediation is effective at allowing tests and promoting some degree of flexibility, but you still have the same dependency in concept, and then you have the mediator code to maintain and manage.
- Behaviors. This is a solution I haven’t looked at too much and might come around to liking. However, at first blush, I didn’t like the looks of that extra XAML and the overriding of the Behavior class. I’m generally leery of .NET events and try to avoid them as much as possible. (I may create a post on that in and of itself, but suffice it to say I think the syntax and the forced, weakly typed parameters leave a lot to be desired.)
- Some kind of toolkit Blech. Nothing against the people that make these, and this one looks pretty good and somewhat in line with my eventual situation, but it seems like complete overkill to download, install, and maintain some third party application to open a window.
- IOC Container. I’ve seen some of these advertised, but the same principle applies here as the last one. It’s overkill for what I want to do.
I’ve seen plenty of other solutions and discussion as well, but none of them really appealed to me.
What I Did
I’ll just put the code and example usage in XAML here and talk about it:
public class OpenWindowCommand : SimpleCommand where T : Window, new()
{
#region Fields
/// Stores the function that evaluates whether or not the command can be executed
private readonly Func _canExecute;
/// View model that will serve as data context of the command in question
private readonly IViewModel _viewModel;
/// Used to verify method preconditions and object invariants
private readonly ArgumentValidator _validator = new ArgumentValidator();
#endregion
#region Constructor
/// For window open command,
///
public OpenWindowCommand(IViewModel viewModel, Func canExecute = null) : base(canExecute, null)
{
_validator.VerifyNonNull(viewModel);
_viewModel = viewModel;
}
#endregion
#region ICommand stuff
/// Ignores the command parameter, creates the window, sets its datacontext, and shows
public override void Execute(object parameter)
{
var myWindow = new T();
myWindow.DataContext = _viewModel;
myWindow.ShowDialog();
}
#endregion
}
That’s it. The things that are referenced here that you won’t have are worth mentioning but not vital to the implementation. SimpleCommand, from which “OpenWindowCommand” inherits, is a class that allows easier command declaration and use. It implements ICommand. It takes a delegate or a boolean for CanExecute() and a delegate for execution (that we override in OpenWindowCommand since we have a concrete implementation). Simple command is not generic–the generic is in OpenWindowCommand to allow strongly typed window opening (the presumption here being that you want to use this for windows that you’ve created and want to show modally).
The binding in the XAML to commands is to an object that represents a collection of commands. I actually have a CommandCollection object that I’ve created and exposed as a property on the ViewModel for that XAML, but you could use a Dictionary
So, basically, when the view model from which you want to open a window is being setup, you create an instance of OpenWindowCommand
Why I Like This
First of all, this implementation creates no code-behind. No named windows/dialogs certainly, but also no event handlers. I also like that this doesn’t have the attendant complexity of most of the other solutions that I’ve seen. There’s no IMediator/Mediator, there’s no ServiceLocator, no CommandManager.Instance–none of it. Just one small class that implements one framework interface.
Naturally, I like this because this keeps the ViewModel/presentation layer View agnostic. This isn’t true out of the box here, but it is true in my implementation. I don’t declare commands anywhere in my ViewModels (they’re all wired in configurably by my home-rolled IOC implementation at startup). So the ViewModel layer only knows about the generic Window, not what windows I have in my view.
Room for Improvement
I think it would be better if the presentation tier, in theory, didn’t actually know about Window at all. I’m keeping my eyes peeled for a way to remove the generic parameter from the class and stick it on the Execute() method to be invoked from XAML. XAML appears to be very finicky when it comes to generics, but I have some hope that this may be doable in the latest release. I’ll re-post when I find that, because I’d love to have a situation in which the XAML itself could specify what kind of window to open as a command parameter. (I’m not in love with command parameters, but I’d make an exception for this flexibility.)
I’m also aware that this doesn’t address non-modal windows, and that there is currently no mechanism for obtaining the result from ShowDialog. The former I will address as I grow the application that I’m working on. I already have a solution for the latter in my code, and perhaps I’ll detail that more in a subsequent post.
Hi there,
This post is a little old, but it was helpful for me. I like the idea, i’m having the same problem almost every developer that is new to WPF MVVM. I would like to ask you where do you give de Window in the OpenWindowCommand ? .. Thanks for the article.
Hi Alfonso — glad you found the post helpful. The window is instantiated in the Execute() method, as new T();
[…] I have seen this:https://daedtech.com/mvvm-and-dialogs […]
Hi,
Can you post a small example. I am new to MVVM and finding it difficult.
Unfortunately, I haven’t really touched WPF in the last 2+ years, so it’s not fresh in my mind. I’ve been doing ASP MVC and, most recently, Java. It’s not that I’d mind digging up some old stuff, but I’m sure there are several newer iterations of the WPF framework that might make anything I have obsolete at this point.