I'm in some sort of confusion: at one hand Microsoft architects and surrounding web community promote MVVM pattern for building WPF apps, but from the other hand in Prism patterns and practices they uses absolutely other design patterns – MVP, Presentation Model and Supervising Controller! And not a single example of use pure MVVM! They even say nothing about using MVVM in their PRISM documentation! So, what should one do in this situation? Is it possible to use MVVM pattern in PRISM applications with the same level of freedom as with patterns listed above? I mean would it be more complex or not because of (probably) kind a native architectural optimization for these patterns?
R – Design Patterns in PRISM
mvvmprism
Related Solutions
Unfortunately there is no one great MVVM example app that does everything, and there are a lot of different approaches to doing things. First, you might want to get familiar with one of the app frameworks out there (Prism is a decent choice), because they provide you with convenient tools like dependency injection, commanding, event aggregation, etc to easily try out different patterns that suit you.
The prism release:
http://www.codeplex.com/CompositeWPF
It includes a pretty decent example app (the stock trader) along with a lot of smaller examples and how to's. At the very least it's a good demonstration of several common sub-patterns people use to make MVVM actually work. They have examples for both CRUD and dialogs, I believe.
Prism isn't necessarily for every project, but it's a good thing to get familiar with.
CRUD:
This part is pretty easy, WPF two way bindings make it really easy to edit most data. The real trick is to provide a model that makes it easy to set up the UI. At the very least you want to make sure that your ViewModel (or business object) implements INotifyPropertyChanged
to support binding and you can bind properties straight to UI controls, but you may also want to implement IDataErrorInfo
for validation. Typically, if you use some sort of an ORM solution setting up CRUD is a snap.
This article demonstrates simple crud operations: http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx
It is built on LinqToSql, but that is irrelevant to the example - all that is important is that your business objects implement INotifyPropertyChanged
(which classes generated by LinqToSql do). MVVM is not the point of that example, but I don't think it matters in this case.
This article demonstrates data validation
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx
Again, most ORM solutions generate classes that already implement IDataErrorInfo
and typically provide a mechanism to make it easy to add custom validation rules.
Most of the time you can take an object(model) created by some ORM and wrap it in a ViewModel that holds it and commands for save/delete - and you're ready to bind UI straight to the model's properties.
The view would look like something like this (ViewModel has a property Item
that holds the model, like a class created in the ORM):
<StackPanel>
<StackPanel DataContext=Item>
<TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
<TextBox Text="{Binding LastName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
</StackPanel>
<Button Command="{Binding SaveCommand}" />
<Button Command="{Binding CancelCommand}" />
</StackPanel>
Dialogs:
Dialogs and MVVM are a bit tricky. I prefer to use a flavor of the Mediator approach with dialogs, you can read a little more about it in this StackOverflow question:
WPF MVVM dialog example
My usual approach, which is not quite classic MVVM, can be summarized as follows:
A base class for a dialog ViewModel that exposes commands for commit and cancel actions, an event to lets the view know that a dialog is ready to be closed, and whatever else you will need in all of your dialogs.
A generic view for your dialog - this can be a window, or a custom "modal" overlay type control. At its heart it is a content presenter that we dump the viewmodel into, and it handles the wiring for closing the window - for example on data context change you can check if the new ViewModel is inherited from your base class, and if it is, subscribe to the relevant close event (the handler will assign the dialog result). If you provide alternative universal close functionality (the X button, for instance), you should make sure to run the relevant close command on the ViewModel as well.
Somewhere you need to provide data templates for your ViewModels, they can be very simple especially since you probably have a view for each dialog encapsulated in a separate control. The default data template for a ViewModel would then look something like this:
<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}">
<views:AddressEditView DataContext="{Binding}" />
</DataTemplate>
The dialog view needs to have access to these, because otherwise it won't know how to show the ViewModel, aside from the shared dialog UI its contents are basically this:
<ContentControl Content="{Binding}" />
The implicit data template will map the view to the model, but who launches it?
This is the not-so-mvvm part. One way to do it is to use a global event. What I think is a better thing to do is to use an event aggregator type setup, provided through dependency injection - this way the event is global to a container, not the whole app. Prism uses the unity framework for container semantics and dependency injection, and overall I like Unity quite a bit.
Usually, it makes sense for the root window to subscribe to this event - it can open the dialog and set its data context to the ViewModel that gets passed in with a raised event.
Setting this up in this way lets ViewModels ask the application to open a dialog and respond to user actions there without knowing anything about the UI so for the most part the MVVM-ness remains complete.
There are times, however, where the UI has to raise the dialogs, which can make things a bit trickier. Consider for example, if the dialog position depends on the location of the button that opens it. In this case you need to have some UI specific info when you request a dialog open. I generally create a separate class that holds a ViewModel and some relevant UI info. Unfortunately some coupling seems unavoidable there.
Pseudo code of a button handler that raises a dialog which needs element position data:
ButtonClickHandler(sender, args){
var vm = DataContext as ISomeDialogProvider; // check for null
var ui_vm = new ViewModelContainer();
// assign margin, width, or anything else that your custom dialog might require
...
ui_vm.ViewModel = vm.SomeDialogViewModel; // or .GetSomeDialogViewModel()
// raise the dialog show event
}
The dialog view will bind to position data, and pass the contained ViewModel to the inner ContentControl
. The ViewModel itself still doesn't know anything about the UI.
In general I don't make use of the DialogResult
return property of the ShowDialog()
method or expect the thread to block until the dialog is closed. A non-standard modal dialog doesn't always work like that, and in a composite environment you often don't really want an event handler to block like that anyhow. I prefer to let the ViewModels deal with this - the creator of a ViewModel can subscribe to its relevant events, set commit/cancel methods, etc, so there is no need to rely on this UI mechanism.
So instead of this flow:
// in code behind
var result = somedialog.ShowDialog();
if (result == ...
I use:
// in view model
var vm = new SomeDialogViewModel(); // child view model
vm.CommitAction = delegate { this.DoSomething(vm); } // what happens on commit
vm.CancelAction = delegate { this.DoNothing(vm); } // what happens on cancel/close (optional)
// raise dialog request event on the container
I prefer it this way because most of my dialogs are non-blocking pseudo-modal controls and doing it this way seems more straightforward than working around it. Easy to unit test as well.
According to the included documentation in MVVM for WPF (page 2 of the general introduction)
The origins of this pattern are obscure, but it probably derives from the Smalltalk ApplicationModel pattern, as does the PresentationModel pattern described by Martin Fowler. It was adapted for WPF use by the Expression team as they developed version 1 of Blend. Without the WPF-specific aspects, the Model-View-ViewModel pattern is identical with PresentationModel.
Going to Martin's Fowler's website and looking up Presentation Model we have this
Compared to Passive View and Supervising Controller, Presentation Model allows you to write logic that is completely independent of the views used for display. You also do not need to rely on the view to store state. The downside is that you need a synchronization mechanism between the presentation model and the view. This synchronization can be very simple, but it is required. Separated Presentation requires much less synchronization and Passive View doesn't need any at all.
For my own metal cutting CAD-CAM application I use Passive View. The reasons for this are
- To making testing easier by having mock objects implementing the view thus allow the vast majority of my software's functionality to be automatically tested
- To reuse not only the core model but the different views for related types of metal cutting software.
- To clearly document the interaction between the views and the model.
- To destroy any dependency on the GUI toolkit as this software has been continuous development since 1985 and seen several major changes in the underlying tools, APIs, and even the language itself.
The the concerns of first three can be handled by the MVVM, Presentation Model, Supervising Controller pattern. But only the Passive View addressed #4.
As stated by Martin Fowler only the Passive View doesn't require any synchronization method. MVVM is a implementation of Presentation Model for WPF. You are dependent on the XAML interface to tie the view state located in the View Model with the View itself. So if at a later time you change the UI or it's APIs then your View Model will be changed as well.
In contrast Passive View only requires that the new UI elements implement the View Interface. It doesn't matter what they are actually connected to also as the form or controls implementing responds correctly.
But the price is that you have an extra step when implementing new elements of a view. You have to decide how they are to be presented to the presenter and at what level of abstraction. It is enough that it over kill on some projects or for some types of UI like dialog boxes.
The short answer to your question about MVVM being THE way for WPF, the answer is no it is not. It is a tool that need to be considered in light of the other issues surrounding the development of your application.
Best Answer
Absolutely. PRISM glues the parts of your composite application together, but those parts may use MVVM or whatever pattern you prefer (as can your Shell).