Quantcast
Channel: Windows Presentation Foundation (WPF) forum
Viewing all articles
Browse latest Browse all 18858

Let's talk about MVVM

$
0
0

As a side project I am currently learning MVVM pattern. And MVVM and WPF beling togehter, so I put this here. I found a usefull example (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx). I think I understand most of it by now, but am not certain.

So I made this discussion to fullfill multiple objectives:

First, show what I understand so you can tell me if I missunderstand something.

Secondly, to ask questions.

Third, have a introduction to MVVM for others who are new to it (because honestly the examples I found all jump pretty deep into the mater and imho omit important information).

1. It's all in the order:

MVVM stands for Model-View-ViewModel. While this order of terms is historically grown, it's totally misleading. To properly understand it you have to look at it as View-ViewModel-Model.
The View is at one and, the model at the other and the ViewModel has to bring both together. (or rather express the model in a way that the View can get the information it needs itself).

1a. Model:

The model are classes not designed for MVVM. Very often it is simply because they are Legacy Libraries. Most of the time it are ones you cannot alter without breaking code. Hence you need the ViewModel to "present" them to the View.
But even when writing code intentionally for a MVVM scenario, you might want to create a Model first. Simply because some applications that (have to) redraw after each (bigger) User interaction anyway (Console and APS.Net) don't need a ViewModel. They don't need the same flavor of binding WinForms or WPF Views need. For them even the check if there is a ChangeEventListener is wastefull overhead.
Logically that means the Model is totally oblivious to the fact that there is a VM model, much less that there is a View.

1b View:

Most often the View is the UserInterface. And with that I mean a WindowsForms or WPF user Interface. While you the View can be Console or ASP.NET page they don't benefit from this MVVM-Pattern nearly as much as WinForms or WPF. They might even loose preformance by using it.
The view is arbitrary. Wich means it is totally interchangeable. Despite it being arbitrary the library you use for the Model and ViewModel will propably contain one - because without view you could not debug or write code in the first place.
The view can just as easily be a Unit Test (the example linked has such a "view", in a seperate Project). As View and business logic are seperate, you can test your code without having to even touch a View.
The View has no idea of the model. It's only concern and source of information is the ViewModel. On the other hand nobody knows the View exists. Neither ViewModel nor Model have any references to the View (and not even calls for MessageBoxes or Showing Dialogs). Communication has to be done via Binding to the ViewModel or with Events in the ViewModel (that the View has to register).
A perfectly written View for a perfectly written ViewModel comes out with next to no Code behind and no event handlers. In fact the example above has exactly 0 lines of code behind and 0 event handlers defiend in the code of the View - it runs 100% on binding, templates and Commands in the ViewModel and XAML.
In the most ideal situation you don't even create the View. Some Coworker (the UI designer) does this work. You two just need to be aware how the ViewModel looks.

2c ViewModel:

The ViewModel is the man in the middle. It's job is to "upgrade" the Model with functionalities like ChangeNotification. Every part of the Business logic happens here. Be it validation of input, navigation along lists or executing operations like saving and openign files (by exposing Commands). It's the job of the View to show the user all the Data/Actions he needs to know, from all those the ViewModel provides.
There should be only one instance of the ViewModel and the most ideal place for it is the Resource tag of the App.xaml.
A perfectly written ViewModel does not require any reference in the Codebehind of the View.
The view Model usually consists of derived version of the model classes (hiding thier properties behind ones with ChangeNotification), a group of own properties with ChangeNotification and one or more lists (and especially OberservableCollection's).

3. Old friends:

A lot of the work regarding MVVM requires the use of a few Interfaces. And those aren't even new ones - they have been around since between .NET 1.1 too 3.0!
So naturally you can use them when not writing for MVVM.

INotifyPropertyChanged - The core for making your Properties suiteable for Binding. (see more about it there). When you derive or write your classes for your ViewModel, they usually also implement it. Otherwise the View had no way to know when values changed in the ViewModel!

IDataErrorInfo - When data is entered, is it valid? And how can we express it is invalid to the View? Simply drop an error message ito it's list and let the view look for it. You can drop and bind to one message per property comfortably. Also usefull: if you only want to save/write "valid" data, just check if the number or errors is 0.

ICommand - You know how difficulty it is to enable/disable buttons based on the current Status of the Data? It is not when using this little thing. It puts both the code to be executed and the check if it should be executed in one short code Block. Also check out RoutedCommand and (especially) RoutedUICommand, two class implementign it. You'll never want to go back to setting .enabeled on buttons afterwards. If you even use buttons/menu items anymore.

4. Flavors of Binding:

Binding in ASP.NET and Binding in WPF are two totally different things.

Binding in ASP is little more then saying "every time you are created, querry that Data Source". Objects in ASP have a very short lived duration. In fact when the html-page completed loading at your end, they stop being referenced before the html-connection closes. That pice of HTML that looks like a UI is nothing but a standart 1995 HTML-Form with a few images to look nice.
Everytime you click a Button or similar UI-element a HTML Form is send, the page is created completely from scratch, the values aquired from the HTML-Form are applied (inlcuding some coded variables for things that work automagically). Then the event is executed.
Then the entire page is finish and the server loads it again from scratch (to give you the "after" state of your "UI"), this second load is send to you.

In WPF and WinForms Bindings work on ChangeNotification. When either the Value in the View or the ViewModel change the other side mustimmediately be informed of this change, so it can get itself the new value. The UI already has anything in place to write changes to other Properties (so target to source works usually). You only have to make certain your ViewModel Propeties do the same (if needed) so the UI elements can get themself the new values (source to target updates).

5. Binding is in the properties:

To use the flavor of binding used in MVVM, properties have to notify everyone who is interested of changes to thier values. There are two ways to do it: being a DependecyProperty or using INotifyPropetyChanged.

DependencyProperty is the more complex one. However it is also the method used by virtually every Property in WPF Elements, so you can't do any binding without running into one. It does notify of changes just as well as INotifyProeprtyChanged, but it also has some important features that you need to be aware when using binding. When a DependecyProperty is not set (I mean it was never given a value, not even null) and anybody ask it for it's value it doesn't say "I am not set". It starts looking up the ElementTree if anyone there has a value for it! Only if it finds none it uses it's default value (wich is realised as a single instance in memory, regardless how many hundred labels/textboxes/GridViewRows you have).
So if you have a bunch of labels, textboxes and other UI Elements that need access the same DataContext (just different Properties), just give the dataContext to their container. If they don't have a value in DataContext but need one, they will start looking up and find the one in thier container. On the other hand you sometimes may need to prevent this by actively initialising some DataContext with x:null in XAML. After all null is a valid entry, thus stopping the search for a value.

Using INotifyPropetyChanged. This is the kind you will make most often. It is also really simple:
1. Let the class with the property implement INotifyPropertyChanged

2. Raise PropertyChanged whenever the value of the property Changes in the setter.

Cogratulations, your property will now inform the Binding system of changes (the Binding system simply puts a fitting Event into PropertyChanged). You might want to do some other considerations - for example you should put the Raising into a protected void RaisePropertyChange(string) method and really check if the new value is different before you set it & raise the event.

Questions:

Anything wrong so far with my understanding? Anything wrong with what I describe?


Viewing all articles
Browse latest Browse all 18858

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>