|
Oct
10
Written by:
Jeremiah Morrill
10/10/2009 7:36 PM
MVVM has been a trending topic lately. And why shouldn’t it be? People want to build great WPF/SL applications and want guidance on how to build them using the framework’s strengths. If you are anything like me, you started your WPF/SL career, learning the framework classes and hierarchy. You learned XAML, triggers, storyboards and animations. You even hobbled together something that looked mind blowing, but the code was a monstrosity. Where do you go from here? How do you leverage all this separation of UI and biz-code that was promised in WPF? I’m going to go out on a limb and make a wild assumption. I believe the majority of people that are trying to learn MVVM [and are having trouble] have never practiced any sort of UI application pattern. Maybe they dabbled in MVC/MVP. Maybe they studied the GoF patterns in school. Why do I assume this? Well because that describes myself and it describes lots of other developers I’ve interacted with. Not very scientific reasoning, but I’m going with it anyways. Because of this lack of general experience, MVVM tutorials and write-ups can be difficult for many developers. Some of these developers will no doubt take MVVM as a very strict pattern and do not deviate from what their perception of MVVM purity is as not to upset the MVVM gods. So that said, the rest of this write up I’m going to try to start from square one. As if I was talking to myself years ago. Layman as #%$@. Beginner’s MVVM Challenge #1 |or| Takin’ You Down to MVVM Town So we want to begin our journey into MVVM town by way of Bindingopolis. Our first web search brings us to a tutorial talking a bunch of mumbo jumbo about models, views and view-models. Usually you get a good description of what each is in concept, which is cool, but we also want to know what is it in CODE? -
A model is a class that has your data. No magic here. class Model { public string Name { get; set; } public string Address { get; set; } } -
A view is, for the sake of explanation, is a UserControl. It’s a kind of like a mullet. Except its a party in the front, code in the back. /// /// Interaction logic for View.xaml /// public partial class View : UserControl { public View() { InitializeComponent(); } } -
A View-Model is, again, just another class. This is where your View (aka UserControl) will get it’s data. It’s a data abstraction of your View. So if you view needs some data, this is where it gets it. If values need to be converted/formatted, this would be a good place to do it. Take special notice of the INotifyPropertyChanged interface. class ViewModel : INotifyPropertyChanged { private Model m_model; public ViewModel() { m_model = new Model(); } public string Name { get { return m_model.Name; } set { if (m_model.Name != value) { m_model.Name = value; InvokePropertyChanged("Name"); } } } public event PropertyChangedEventHandler PropertyChanged; private void InvokePropertyChanged(string propertyName) { var e = new PropertyChangedEventArgs(propertyName); PropertyChangedEventHandler changed = PropertyChanged; if (changed != null) changed(this, e); } } The ViewModel class is really up to you how you want to design it. The INotifyPropertyChanged interface allows us to update bindings (more later). It’s accepted practice to make a base class for the ViewModel. Some folks inherit from DependencyObject and make dependency properties for things in their view model. Don’t do this. Those people are sadists. Beginner’s MVVM Challenge #2 |or| A Menage a Trois That Won’t Get You in Trouble So how do our three players, the Model, View and ViewModel, work together? What sort of witchcraft must we implement? DataContext (again, for the sake of simplicity). Take a look at your View’s (UserControl) class hierarchy. You’ll see FrameworkElement in there. This has a property called DataContext of type object. When you set the DataContext, it will propagate down the tree. So to answer the question of how these all fit…Your model is loaded from where-ever, a data base, a file, etc. Your ViewModel gets your Model and exposes it’s data to your View. Your View gets access to your ViewModel from, wait for it…the DataContext. Consider this from our code snippets above: myView.DataContext = new ViewModel(); And the XAML for the “View” class. <UserControl x:Class="WpfApplication3.View" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="300"> <Grid> <TextBlock Text="{Binding Name}" /> Grid> UserControl> So you see, we explicitly set the DataContext. We also setup a binding in our View’s XAML. WPF/SL will automatically look at the DataContext via reflection and pull out value for the “Name” property. If we write code in our ViewModel to change the value of the “Name” property, it will automatically be updated in our UI via the binding. This is the purpose for INotifyPropertyChanged. If we want to update the value in the view model from the UI we’d do something like this: <TextBox Text="{Binding Name, Mode=TwoWay}" /> Now when we run this, the the value of the “Name” property will be in a TextBox. When you edit the value (and the TextBox loses focus), the view model’s Name property will be updated. I would like to mention that getting the View and ViewModel together is a topic in itself. Some people explicitly set the ViewModel to the DataContext. Some people set it in the XAML. Some people just include the ViewModel as a and do StaticResource bindings to it. Some people use dependency injection and some use a service locator pattern (or both DI and ServiceLocator). All of these have it’s pro’s and cons. It all depends what is important to you. So now all this raises another question: Why even bother? I can just load my model from code-behind and fill in the properties myself. We have successfully partitioned our application. A designer can edit the Views XAML in Blend without too much fear of breaking any business logic. They can design without Blend crashing on them. Your code now has a separation of concerns, making extensibility, testing and maintenance much less involved than stepping through thousands of lines of interconnected, circular dependant spaghetti. Don’t get me wrong, you can still write shit code in MVVM, but MVVM is a good start in avoiding shit code. Beginner’s MVVM Challenge #3 |or| MVVM is a Mole-hill, Not a Mountain. In my opinion, the last couple pages, this is all MVVM is. It’s NOTHING more. “But Jer”, you say, “How do I make my View do X with the ViewModel? How do I make my ViewModel do Y to the View? This can’t be IT. There’s gotta be more to MVVM.” Yes there is more, but not to MVVM. There are other patterns you should be aware of to assist you in MVVM. Patterns like commanding (baked into WPF, solutions for SL), mediator and *gasp* dependency injection. There’s other facilities baked into WPF and Silverlight that can further assist, such as the ItemsControl and data templates. I will, in a later post, talk more deeply on these subjects in an article named “Anatomy of an MVVM Application *or* How Tards Like Me Make MVVM Apps”.
Tags:
24 comment(s) so far...
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Very nice article!
My special thanks for having model without INotifyPropertyChanged (and other UI related staff). While it's supposed to be obvious in fact it's surprisingly rare. I saw a lot of frameworks where mantra "don't put business loging in UI" were interpreted as "let's then put UI logic to business layer".
By Oleg on
10/10/2009 8:45 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Thanks Oleg!
Yeah I wanted to show a model in the barest form. That MVVM doesn't restrict model infrastructure.
LOL!! @ "let's then put UI logic to business layer"...
By Jeremiah Morrill on
10/10/2009 8:53 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Could you please explain why inheriting ViewModel from DependencyObject is sadistic?
By Daniel on
10/11/2009 3:10 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Daniel,
Yeah I should have been more clear about that point. It's not that inheriting from DependencyObject that is "bad" (A valid case can sometimes be easy access to the Dispatcher for threaded operations), but it's the use of Dependency Properties instead of INotifyPropertyChange that is evil. I can cite slower binding performance, but my real issue with DPs are they are so much more code, more maintenance, harder to refactor. Converting data within the VM is also much easier with just a POCO and INPC. I cannot see any advantage to dependency properties in a VM...but I am open to new ideas ;)
By Jeremiah Morrill on
10/11/2009 4:06 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Jer
Great article, and it's good to see a nice straightforward no bull explanation of MVVM. Of course, I have to maintain my mystique, so I'm going to stick to the mumbo-jumbo and make people think that MVVM is harder than it is (not!!!).
By Pete O'Hanlon on
10/13/2009 1:16 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Thanks Pete!
Maybe this article was a bad idea... If everyone can do MVVM, then our collective pay goes lower!
By Jeremiah Morrill on
10/13/2009 1:19 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
That's awesome, thanks for that. Nice to have a clean example without the DI getting in the way.
By Jarrod N on
10/13/2009 3:08 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Excellent!
By Mark Wisecarver on
10/13/2009 4:05 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Definitely the funniest introduction to MVVM I've ever read, made my day.
By Disore on
10/13/2009 9:55 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Thanks Jeremiah, as an antique developer I've always been afraid of moderne technique's like MVVM. Leaving jokes apart, I found your article very concise, clean and easy to follow. After all of this I still have one minor question: since almost all the tutorials and examples I've seen are web-based, I wonder weher this pattern is meant to be used for web-based applications or it can be effective even for Windows forms ones?
By Marco Turrini on
10/14/2009 6:39 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
This is an awesome article. I'm thinking you totally need todo a Tard framework for WPF etc. ;) assuming the architecture astronauts don't have you knocked off if all samples were straight forward like this... we would be much better off.
By David J Kelley on
10/15/2009 3:01 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
"I cannot see any advantage to dependency properties in a VM" - true enough, unless you want your properties to be animated - only DPs can be animated.
By Joan Miro on
10/15/2009 7:25 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
You are taking all thq Mystique out of MVVM ;). Love your article. I had to develop my first ever GUI application this year. I choose WPF and MVVM. I was impressed by Josh's article at that time I think. Now that I am into 3 months of development, frankly I am scared by the number of views/models/viewmodels running around in my code. I love MVVM but I think there should be more to MVVM than this simple naive models hmm? Or may be I could be looking for something that is not there. Thanks for clearing this up.
By Srikanth Kotagiri on
10/15/2009 9:44 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Many thanks!!! I've been trying to wrap my head around this for a while now and this really brought it down to earth in which to move forward. Thanks! I'm looking forward to future entries!
By Sean Patterson on
10/15/2009 9:46 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Srikanth,
MVVM doesn't or shouldn't care about how naive your models are. You certainly can design your models to assist you in your MVVM usage, but the idea is your model can be anything, coming from anywhere. It's up to your best judgement for your solution on how to implement your model. I showed a very simple solution just so we don't convolute what MVVM, at its core, really is.
By Jeremiah MOrrill on
10/15/2009 9:50 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
So if i try to use it where should i implement validation in Model or in ViewModel.
By Florim Maxhuni on
10/20/2009 1:13 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
Really I am happy to read such a clear explanation about MVVM pattern in WPF. Thanks a lot for your article and also request know more about this. Where can I get your other details blog about MVVM. Thanks once again
By Rajesh Kumar Jena on
10/22/2009 8:32 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
I'm not really a GUI developer. WPF and GUI design patterns are completly new to me. I've searched around and found many MVVM articles that are totaly bloated and gave me the impression that MVVM is very complicated topic. Your article proved the otherwise - thank you! But for me there is still some things that I do not understand: Which class does the access to my business logic? The Model or the ViewModel? Say we have a simple application. One window where you can enter a path to a directory. You push a button "Get files from directory". The business logic obtains all existing files in the directory. All files are displayed in a list box or something like that. When you select a single file from the list additional information (creation date whatever) is displayed in a text box. Can you us a little sketch how this will be done with WPF/MVVM?
Greetings and thanks!
By justanotherdeveloper on
10/30/2009 1:04 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
justanotherdeveloper,
I don't like giving concrete answers in some cases because I believe there shouldn't be many concrete rules in development...which might be a concrete rule in it self ;)
I do see querying the filesystem as something that could go in either the VM or the model. Generally speaking, if the querying the filesystem is complex or needs reuse, I'd put it into a model class and expose the data via the VM. In the case you described, where you want extra meta-data (not just a string[] of files), you may want to create an ObservableCollection that is exposed on your VM. Bind this to a listbox or ItemsControl w/ a custom template and you can show the data in some very interesting ways, using XAML alone.
I will say, I have built in some business logic into the VM itself in some cases, in other cases used a model(s). I do believe that if you keep the UI and _other_code_ separate, most stuff will come naturally (eventually). There's no _right_ way to do it...but people naturally will love to tell you that you are doing it wrong :)
By Jeremiah Morrill on
10/30/2009 1:57 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
justanotherdeveloper,
I don't like giving concrete answers in some cases because I believe there shouldn't be many concrete rules in development...which might be a concrete rule in it self ;)
I do see querying the filesystem as something that could go in either the VM or the model. Generally speaking, if the querying the filesystem is complex or needs reuse, I'd put it into a model class and expose the data via the VM. In the case you described, where you want extra meta-data (not just a string[] of files), you may want to create an ObservableCollection that is exposed on your VM. Bind this to a listbox or ItemsControl w/ a custom template and you can show the data in some very interesting ways, using XAML alone.
I will say, I have built in some business logic into the VM itself in some cases, in other cases used a model(s). I do believe that if you keep the UI and _other_code_ separate, most stuff will come naturally (eventually). There's no _right_ way to do it...but people naturally will love to tell you that you are doing it wrong :)
By Jeremiah Morrill on
10/30/2009 1:58 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
this is something i have been very interested in lately. thanks.
By Replica FENDI Handbag on
1/5/2010 10:57 PM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
dude, i luv u!
i m pretty new to programming and application design. i did just understand MVC nearly a month ago, and trying to get through MVVM was a pretty brainfuck the last days. its hard to get what a pattern is about, if there are only examples with bloated code out there, that look very alien to you. hard to figure out than, if that is part of the design pattern or just some crazy stuff you'd never even think about.
thank you for this funny and well made article!
By egi on
1/29/2010 7:11 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
I would hesitate (but not be completely against) calling MVVM a buffet. If you pick and choose then its not MVVM anymore :) I believe the biggest struggle is determining what your definition is of each layer and following it to the letter…or redefining it. We could add more layers and extend MVVM to MVVMVMV, etc, or we could simply know that VM includes VMV. The code could be the same but oh how you could argue one way or the other.
By Rapid Share on
2/2/2010 1:35 AM
|
Re: MVVM for Tarded Folks Like Me *or* MVVM and What it Means to Me
You state:
"Consider this from our code snippets above: myView.DataContext = new ViewModel();"
but where is this code? I dont see it. Does it go in the view's code-behind, or in the view's xaml?
Z-tarded
By Z on
2/8/2010 10:07 AM
|
|
|
|