It has been a while since I have undertaken a large article, so I thought it was about time I corrected that, and wrote a fairly meaty article. This article and the subsequent series of articles represents this meat. This article represents the 1st in a saga of articles that I will be unleashing on how to do a good job of MVVM when working with WPF.
For those that do not know what on earth MVVM is, it is basically a UI design pattern that is particularly suited to working with WPF thanks to the binding options available with WPF. The idea is that the ViewModel is an abstraction of the View and you should be practically able to test the entire UI by running Unit tests against the ViewModels within the system. In fact I heard one very influential Microsoft employee once said that before they saw the UI they would like to see the unit tests to see how it all worked. If you can read the unit tests and understand how the UI works, you are doing MVVM right.
Here are some nice MVVM links in case you need them:
In my opinion MVVM is a superb pattern, but there are limitations that it just does not do that well, for example how does one show a MessageBox (a modal dialog) from what is essentially a non UI class. Having worked out how to show a MessageBox from a ViewModel, how can we ensure that the code that relies on a "Yes" or "No" being picked for the ViewModel to traverse a certain code path is fully tested in the Unit tests applied to the ViewModel. This sort of thing is non trivial. I have literally seen 100s of articles stating they are good MVVM examples, you know what, they are not. They showcase basic binding without a single thought about the sort of thing I just mentioned. There are probably 100 people on the planet doing MVVM correctly, and I know a fair few of them. It is not easy until the information gets blasted into your skull by getting it wrong enough. I now feel I have got it wrong often enough to speak with some authority on how, not only how not to do it, but also how to do it right. Experience by initiation of fire and all that.
I have personally been doing WPF/MVVM for a while now and have struggled with this supposedly great pattern for pretty much most of that time, and it is only now that I feel ah yes I get how to do that 100% right. This article and subsequent articles will now share that knowledge with you. Should you want that knowledge. I leave that up to you.
So what is this article and subsequent articles all about then. Well simply put it is a MVVM framework which I am called "Cinch", and a demo app and a bunch of unit tests, which granted doesn't sound that great, but what I am hoping is as we move through the series you will actually go, aha that is kinda nice/great whatever, and that addresses exactly the trouble we had and I see how we can fix that now. Even if you do not end up using Cinch, you may find that some of its code may help you in your own work. That's cool too.
One really great thing is that the entire demo apps code behind, consists of 1 line of code, which means I can test everything from unit tests, yes everything, threads, navigation, messages between Views/ViewModels, saving files, loading files the lot. That 1 line of code ain't bad when you consider there are 4 Views and a popup all interacting together.
I hope you will see the benefit of Cinch in all of this, and the subsequent articles content.
That's the plan anyway.
Before I start, I would specifically like to say a massive thanks to the following people, without whom this article and the subsequent series of articles would never have been possible. Basically what I have done with Cinch is studied most of these guys, seen what's hot, what's not, and come up with Cinch which I hope addresses some new ground not covered in other frameworks.
Mark Smith (Julmar Technology), for his excellent MVVM Helper Library, which has helped me enormously. Mark I know I asked your permission to use some of your code, which you most kindly gave, but I just wanted to say a massive thanks for your cool ideas, some of which I genuinely had not thought of. I take my hat off to you mate.
Josh Smith / Marlon Grech (as an atomic pair) for their excellent Mediator Implementation. You boys rock, always a pleasure.
Karl Shifflett / Jaime Rodriguez (Microsoft boys) for their excellent MVVM Lob tour, which I attended, well done lads.
Bill Kempf, for just being Bill and being a crazy wizard like programmer, who also has a great MVVM framework called Onyx, which I wrote an article about some time ago. Bill always has the answers, to tough questions, cheers Bill.
ALL of the WPF Disciples, for being the best online group to belong to IMHO.
Thanks guys/girl, you know who you are.
In a lot of ways, this article is an absolute crock of sh*t, as there will be no code and no explanations of anything in this article, but it will serve as a kind of road map of what is coming up in the series of articles... And that is about all this article really does, but I just felt it was needed to explain the other articles, somehow.
I have really struggled with how best to present this content, as there is a lot (a real lot) to get through, but finally I arrived at this decision, release a primer article that has full source code for all those that feel they can navigate the road themselves, with no explanation. The primer article (this one) will simply be used as a stepping stone on to the real meat, AKA the next articles.
This way if anyone wants to look at the code they can, all that I ask is that if people dive into the code, now, could they maybe keep complicated questions until later on in the series, as I will be going through EVERYTHING in future articles in this series. So you will get all the knowledge/content just not in this article, not yet. I will be trying my best to get the content out there quickly. I should be able to get another one up by next weekend I hope.
The demo app makes use of:
- VS2008 SP1
- .NET 3.5 SP1
- SQL server (see the README.txt in the
MVVM.DataAccess project to learn what you have to setup for the demo app database)
Not much actually, what I can say is what Cinch does, and that is the following:
- Allows view to communicate LifeCycle events to a ViewModel without any hard reference links being maintained, and no IView interface requirements. There is no link at all between the View and the ViewModel.
- Has several attached behaviours for common tasks such as:
- Numeric text entry
- Run an
ICommand in a ViewModel based on a
RoutedEvent from an XAML FrameworkElement
- Have a group of such
RoutedEvent Events for a single XAML FrameworkElement
- Allows the ViewModel to determine if a Models data should be editable, the UI simply updates via bindings, based on the ViewModel driven editability state. This is available at individual Model field level, so it's very flexible.
- Delegate validation rules which allows validation rules to be as granular as necessary
IDataErrorInfo support using the Delegate rules approach
IEditableObject usage to store/restore object state on edit / cancel edit
- Weak event creation, to allow the creation of
- Weak event subscription, which also allows auto unsubscriptions
- Mediator messaging with
WeakReference support out of the box
- DI/IOC using Unity DI Container, to allow alternative Test/actual app service implementations
- Service implementations which include (where Cinch has defaults for WPF/UnitTest for most of these, with the exception of the Popup window service which will be covered in a subsequent article and shall still be available within the attached demo code at any rate)
- Advanced logging using Log4Net
- MessageBox service (which can be 100% emulated within unit tests, as if the user actually clicked a
MessageBox button), thus enabling the ViewModel code to be traversed down the correct path
- Open file service (which can be 100% emulated within unit tests, as if the user actually chose a file to open in the model
OpenFileDialog), thus enabling the ViewModel code to be traversed down the correct path
- Save file service (which can be 100% emulated within unit tests, as if the user actually chose a file to save in the model
SaveFileDialog), thus enabling the ViewModel code to be traversed down the correct path
- Popup window service, to control the showing/hiding and setup of Popup Window in WPF (which is a nightmare)
- Threading helpers
- Dispatcher extension methods to allow quick marshalling of a
Action<T> to the correct UI Dispatcher
Application.DoEvents (for a certain Dispatcher Priority)
BackgroundTaskManager with callback to alert waiting Unit tests of completion, to allow test to complete or timeout
ObservableCollection, which notifies
CollectionChanged on correct Dispatcher thread
ObservableCollection, which allows a range of items to be added
MenuItem ICommand ViewModel implementation made easy
- Closeable ViewModels (when working in Tabbed UI environment, which is what one should really be doing with MVVM)
In the subsequent articles, I will be showcasing it roughly like this:
- A walkthrough of Cinch, and its internals - Part I
- A walkthrough of Cinch, and its internals - Part II
- How to develop ViewModels using Cinch
- How to Unit test ViewModels using Cinch app, including how to test Background work threads which may run within Cinch ViewModels
- A Demo app using Cinch
That is actually all I wanted to say right now, but I can promise you the subsequent articles WILL have a LOT of meat and examples about how to get started with Cinch.
Till then I guess, if you want you can try out/explore that attached code. If you have a specific query, could you maybe wait till all 4 parts are available and then if I have not covered what you wanted to ask, feel free to ask me.
As always, votes / comments are welcome.