In my opinion, if is using WPF or Silverlight you should is using the MVVM design pattern. It is perfectly suited to the technology and allows to keep your code clean and easy to maintain.
The problem is, there was a lot of online resources for MVVM, each with their own the "the" of implementing the design pattern a nd it can be overwhelming. I would like to present MVVM in the simplest the possible using just the basics.
So lets start at the beginning.
MVVM
MVVM is a short for model-view-viewmodel.
Models is simple class objects the hold data. They should only contain properties and property validation. They is not responsible for getting data, saving data, click events, complex calculations, business rules, or any of the Stuff.
Views is the UI used to display data. In very cases, they can be datatemplates which are simply a template that tells the application what to display a class. It is OK to put code behind your view IF that code is related to the view only, such as setting focus or running Animations.
ViewModels is where the magic happens. This is where the majority of your Code-behind goes:data access, click events, complex calculations, business rules valid ation, etc. They is typically built to reflect a View. For example, if a View contains a ListBox of objects, a Selected object, and a Save button, the ViewModel would has an Obs Ervablecollection obectlist, Model selectedobject, and ICommand Savecommand.
MVVM Example
I ' ve put together a small sample showing these 3 layers and how they relate to each other. You'll notice that other than property/method names and none of the objects need to know anything about the others. Once the interfaces has been designed, each layer can be built completely independent of the others.
Sample Model
For this example I ' ve used a Product Model. You'll notice the only thing this class contains are properties and change notification code.
Usually I would also implement IDataErrorInfo here for property validation, however I has left this out for now.
public class Productmodel:observableobject {#region The fields private int _productid; private string _productname; Private decimal _unitprice; #endregion//Fields #region Properties public int ProductId {get {return _productid;} set {if (value! = _productid) {_productid = Valu E OnPropertyChanged ("ProductId"); }}} public string ProductName {get {return _productname;} set {if (value! = _productname) {_productname = value; OnPropertyChanged ("ProductName"); }}} public decimal UnitPrice {get {return _unitprice;} set {if (value! = _unitprice) { _unitprice = value; OnPropertyChanged ("UnitPrice"); }}} #endregion//Properties}
The class inherits from Observableobject, which are a custom class I use to avoid have to rewrite the property ch Ange notification code repeatedly. I would actually recommend looking Into microsoft PRISM ' S NOTIFICATIONOBJECT  OR MVVM Light ' s viewmodelbase which does the same thing once is comfortable with MVVM, but for now I wanted to keep 3rd party libraries out of this and to show the code.
Public abstract class Observableobject:inotifypropertychanged {#region INotifyPropertyChanged members <summary>//Raised when a property is on this object has a new value. </summary> public event PropertyChangedEventHandler propertychanged; <summary>//Raises this object ' s PropertyChanged event. </summary>//<param name= "PropertyName" >the property, which has a new value.</param> p rotected virtual void onpropertychanged (String propertyname) {this. Verifypropertyname (PropertyName); if (this. PropertyChanged! = null) {var e = new PropertyChangedEventArgs (PropertyName); This. PropertyChanged (this, e); }} #endregion//INotifyPropertyChanged members #region Debugging aides//<summary> Warns the developer if this object does not has A public property with the specified name. This//method does not exist in a Release build. </summary> [Conditional ("DEBUG")] [DebuggerStepThrough] public virtual void Verifypropertyn Ame (String propertyname) {//Verify the property name matches a real,//public, Instan Ce property on the This object. if (typedescriptor.getproperties (this) [propertyname] = = null) {string msg = ' Invalid property n Ame: "+ propertyname; if (this. Throwoninvalidpropertyname) throw new Exception (msg); else Debug.fail (msg); }}///<summary>//Returns Whether an exception are thrown, or if a debug.fail () is used When a invalid property name was passed to the Verifypropertyname method. The default value is False, but subclasses used by unit tests might/Override this property's getter to return true. </summary> protected virtual bool Throwoninvalidpropertyname {get; private set;} #endregion//Debugging aides}
In addition to the INotifyPropertyChanged methods, there are also a debug method to validate the PropertyName. This was because the PropertyChange notification gets passed in as a String, and I has caught myself forgetting to change This string, when I, is the name of a property.
Note: The propertychanged notification exists to alert the View that a value have changed so it knows to update. I have seen suggestions-to-drop it from the model and to expose the model ' s properties to the View from the ViewModel inst EAD of the Model, however I find in most cases this complicates things and requires extra coding. Exposing the Model to the View via the ViewModel are much simpler, although either method is valid.
Sample ViewModel
I am doing the ViewModel next because I need it before I can create the View. This should contain everything the User would need to interact with the page. Right now it contains 4 properties:a ProductModel, a getproduct command, a saveproduct command, a ProductId used for L Ooking up a product.
public class Productviewmodel:observableobject {#region The fields private int _productid; Private ProductModel _currentproduct; Private ICommand _getproductcommand; Private ICommand _saveproductcommand; #endregion #region Public properties/commands public ProductModel currentproduct {get {R Eturn _currentproduct; } set {if (value! = _currentproduct) {_currentpro duct = value; OnPropertyChanged ("Currentproduct"); }}} public ICommand Saveproductcommand {get {if ( _saveproductcommand = = null) {_saveproductcommand = new Relaycommand ( param = saveproduct (), param = (currentproduct! = null)); } return _saveproductcommand; }} public ICommand Getproductcommand {get {if (_getproductcom Mand = = null) {_getproductcommand = new Relaycommand (param => ; GetProduct (), param = ProductId > 0); } return _getproductcommand; }} public int ProductId {get {return _productid;} set {if (value! = _productid) {_productid = value; OnPropertyChanged ("ProductId"); }}} #endregion #region private Helpers private void GetProduct () { You should get the product from the database/or but for now we ' ll just return a new object Pr Oductmodel p = new ProductModel (); P.productid = ProductId; P.productname = "Test Product"; P.unitprice = 10.00; Currentproduct = p; } private void Saveproduct () {//would implement your Product save here} #end Region}
There is another new class Here:the Relaycommand. This is the essential for MVVM. It is a command, which is the meant to being executed by and classes to run code in this class by invoking delegates. Once again, I ' d recommend checking out THE&NBSP;MVVM light Toolkit ' s version of the This command is more comfor Table with MVVM, but I wanted to keep this has included this code here.
<summary>//A command whose sole purpose are to relay their functionality to other//objects by Invok ING delegates. The default return value for the////CanExecute method is ' true '. </summary> public class Relaycommand:icommand {#region readonly ACTION<OBJECT&G T _execute; ReadOnly predicate<object> _canexecute; #endregion//Fields #region Constructors//<summary>//Creates a new command that can Alwa Ys execute. </summary>//<param name= "execute" >the execution logic.</param> public Relaycommand ( Action<object> execute): This (execute, NULL) {}//<summary>//Cre Ates a new command. </summary>//<param name= "execute" >the execution logic.</param>//<param name= " CanExecute ">the Execution status logic.</param> Public Relaycommand (action<object> Execute, predicate<object> canexecute) {if (execute = = NULL) throw new ArgumentNullException ("execute"); _execute = Execute; _canexecute = CanExecute; } #endregion//constructors #region ICommand members [DebuggerStepThrough] public bool Canexe Cute (object parameters) {return _canexecute = = null? True: _canexecute (parameters); } public Event EventHandler canexecutechanged {add {commandmanager.requerysuggested + = value;} Remove {commandmanager.requerysuggested-= value;} } public void Execute (object parameters) {_execute (parameters); } #endregion//ICommand members}Sample View
And now the views. These is datatemplates which define how a class should is displayed to the User. There is many ways to add these templates to your application, but the simplest-on-is-to-just add them to the startup WI Ndow ' s Resources.
<Window.Resources> <datatemplate datatype= "{x:type Local:productmodel}" > <border borderbrush= "Bla CK "borderthickness=" 1 "padding=" > <Grid> <Grid.ColumnDefinitions> <columndefinition/> <columndefinition/> </grid.columndefinition s> <Grid.RowDefinitions> <rowdefinition/> <rowdefi Nition/> <rowdefinition/> </Grid.RowDefinitions> <tex Tblock grid.column= "0" grid.row= "0" text= "ID" verticalalignment= "Center"/> <textbox grid.row= "0" Gr Id. column= "1" text= "{Binding ProductId}"/> <textblock grid.column= "0" grid.row= "1" text= "Name" vertic alalignment= "Center"/> <textbox grid.row= "1" grid.column= "1" text= "{Binding ProductName}"/> <textbLock grid.column= "0" grid.row= "2" text= "Unit price" verticalalignment= "Center"/> <textbox grid.row= "2" grid.column= "1" text= "{Binding UnitPrice}"/> </Grid> </Border> </datatemplate > <datatemplate datatype= "{x:type Local:productviewmodel}" > <dockpanel margin= "> &L" T;dockpanel dockpanel.dock= "Top" > <textblock margin= "10,2" dockpanel.dock= "left" text= "Enter Product Id "verticalalignment=" center "/> <textbox margin=" 10,2 "width=" "verticalalignment=" center "text=" {Binding Path=productid, updatesourcetrigger=propertychanged} "/> <button content=" Save Product "Dock Panel.dock= "Right" margin= "10,2" verticalalignment= "Center" command= "{Binding Path=saveproductcomma nd} "width="/> <button content= "Get Product" dockpanel.dock= "right" margin= "10,2" VERTICALALIGNM Ent= "Center" Command= "{Binding Path=getproductcommand}" isdefault= "True" width= "/>" </DockPanel> <contentcontrol margin= "20,10" content= "{Binding path=currentproduct}"/> </DockPanel> < /datatemplate></window.resources>
The View defines the datatemplates:one for the ProductModel, and one for the Productviewmodel. You'll need to add a namespace reference to the Window definition pointing to your views/viewmodels so you can define the Datatypes. Each DataTemplate-binds to properties belonging to the class it's made for.
In the ViewModel template, there are a ContentControl that's bound to productviewmodel.currentproduct. When this control tries to display the currentproduct, it'll use the ProductModel DataTemplate.
Starting the Sample
And finally, to start the application add the following on startup:
MainWindow app = new MainWindow (); Productviewmodel ViewModel = new Productviewmodel (); app. DataContext = Viewmodel;app. Show ();
This was found in the code behind the startup File–usually App.xaml.cs.
This creates your Window (the one with the datatemplates defined in window.resources), creates a ViewModel, and it sets th E Window ' s DataContext to the ViewModel.
And there you have it. A basic look at MVVM.
UPDATE
Sample code can is found here.
Notes
There is many other ways to does the things shown here, but I wanted to give you a good starting point before you start div ing into the confusing world of MVVM.
The important thing to remember on the using MVVM is your Forms, Pages, Buttons, textboxes, etc (the "views") is not your AP Plication. Your ViewModels is. The views is merely a user-friendly from interact with your ViewModels.
So if you want to change pages, you should not being changing pages in the View, but instead you should be setting something Like the Appviewmodel.currentpage = Yourpageviewmodel. If you want to run a Save method, you don't put that behind a button's Click event, but rather bind the button.command to A ViewModel ' s ICommand property.
I started with Josh Smith's article on MVVM, which is a good read but for a beginner like me, some of these concepts fle W right over my head.
I ' ve never do a blog or tutorial before, but I noticed there are a lot of the confusion about what "MVVM is" and "use it. Since I struggled through the maze of material online to figure out what MVVM was and how its used, I thought I ' D try and Write a simpler explanation. I Hope this clarifies things a bit and doesn ' t make it worse :)
>> next–navigation with MVVM
A Simple MVVM Example[forward]