Вы находитесь на странице: 1из 20

Chapter 14

MVVM Made Simple


TableofContents
Chapter 14 ................................................................................................................... 14-1
MVVM Made Simple .................................................................................................... 14-1
Overview .......................................................................................................... 14-1
Why MVVM? .................................................................................................... 14-2
The Sample ...................................................................................................... 14-2
The Product Class ................................................................................ 14-3
The ProductManager Class .................................................................. 14-5
The Brute Force Approach ............................................................................... 14-6
Data Binding Basics in XAML .......................................................................... 14-7
Eliminate More Code........................................................................................ 14-9
Binding Other Properties .................................................................................. 14-9
A Simple ViewModel ...................................................................................... 14-12
DataCollection and DetailData Properties .......................................... 14-13
Populating the Data in the View Model Class .................................... 14-15
Hooking Into the View Model Class in the Code-Behind .................... 14-16
Event Procedures in the Window Class ......................................................... 14-17
Chapter Index................................................................................................. 14-20

Overview
Do you find yourself struggling to grasp the concepts of the Model-View-ViewModel (MVVM) design pattern? Have you found that you can understand the

MVVM Made Simple


basics of data binding in WPF and Silverlight, but when you start to read about
MVVM you find that you have been dropped off a cliff? Have you looked at some of
the XAML frameworks like PRISM only to find that it is just way too complicated for
what you need? If this sounds familiar, then dont worry, you are not alone. Many
great programmers struggle with this every day. In my humble opinion I say dont
try to implement a pure MVVM model, just Keep It Simple! Many times the simplest
approach is the best.
In this article I will present MVVM step-by-step but not drop you off a cliff. I am not
going to take the purist approach to MVVM, but I am going to use the familiar event
model in code-behind that you are used to. Yes, you will be using MVVM, but you
will do it using a programming model that you are very familiar with.

Why MVVM?
The whole point behind MVVM is to separate UI logic from your business and data
logic. You want to be able to test your business and data logic without having to
run your user interface. You can use MVVM to do this and still code your user
interface layer just like you are used to.
Before diving into MVVM it will be helpful to understand data binding in XAML.
Once you understand data binding in XAML you have the foundation you need to
apply a MVVM architecture to your WPF or Silverlight applications. Lets start our
discussion by taking a look at a sample WPF window that will be used to illustrate
the various concepts.

The Sample
Figure 1 shows a sample screen used to display product data, and also allow the
user to add and modify that product data. This is a WPF application, but the basic
data-binding concepts apply equally to Silverlight applications as well. This screen
will be used throughout this article to illustrate the various concepts of data binding
and ultimately an MVVM model.

14-2

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

The Sample

Figure 1: A simple add, edit, delete screen for Product data

The sample application uses an XML file for the product data, but could just as
easily go against a database. This sample uses a class called ProductManager
for all data access routines. There is a Product entity class that contains one
property for each data field in your data store.

The Product Class


The Product entity class implements the INotifyPropertyChanged interface so each
property can raise the PropertyChanged event. The data binding in XAML relies on
this interface to stay informed of changes to properties in your code. Listing 1
shows the Product entity class:

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

14-3

MVVM Made Simple


C#
public class Product : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Private Variables
private int _ProductId = 0;
private string _ProductName = string.Empty;
private decimal _Price = 0;
private bool _IsActive = true;
#endregion
#region Public Properties
public int ProductId
{
get { return _ProductId; }
set
{
if (_ProductId != value)
{
_ProductId = value;
RaisePropertyChanged("ProductId");
}
}
}
public string ProductName
{
get { return _ProductName; }
set
{
if (_ProductName != value)
{
_ProductName = value;
RaisePropertyChanged("ProductName");
}
}
}
... // More properties here
}
VB.NET
Public Class Product
Implements INotifyPropertyChanged
#Region "INotifyPropertyChanged"
Public Event PropertyChanged As PropertyChangedEventHandler
Implements INotifyPropertyChanged.PropertyChanged
Protected Sub RaisePropertyChanged(ByVal propertyName As String)

14-4

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

The Sample
RaiseEvent PropertyChanged(Me, New
PropertyChangedEventArgs(propertyName))
End Sub
#End Region
#Region "Private Variables"
Private mProductId As Integer = 0
Private mProductName As String = String.Empty
Private mPrice As Decimal = 0
Private mIsActive As Boolean = True
#End Region
#Region "Public Properties"
Public Property ProductId() As Integer
Get
Return mProductId
End Get
Set(ByVal value As Integer)
If mProductId <> value Then
mProductId = value
RaisePropertyChanged("ProductId")
End If
End Set
End Property
Public Property ProductName() As String
Get
Return mProductName
End Get
Set(ByVal value As String)
If mProductName <> value Then
mProductName = value
RaisePropertyChanged("ProductName")
End If
End Set
End Property
...
More properties here
#End Region
End Class
Listing 1: The Product Entity Class

The ProductManager Class


The ProductManager class has methods that work with the Product entity class.
For example, there is a GetProducts method that returns an ObservableCollection
of Product objects. There are also stubs for Insert, Update and Delete. I did not
write any code in these methods as I was trying to just illustrate MVVM and not
data access.

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

14-5

MVVM Made Simple

The Brute Force Approach


To start out our discussion of data binding, lets just look at how you might use the
brute force approach to populating the ListView and the various text boxes on this
screen. First off, you create a ListView with XAML shown in Listing 2.
<ListView Grid.Row="0"
x:Name="lstData"
SelectedIndex="0"
SelectionChanged="lstData_SelectionChanged"
ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="Product Id"
Width="Auto"
DisplayMemberBinding="{Binding Path=ProductId}" />
<GridViewColumn Header="Product Name"
Width="Auto"
DisplayMemberBinding="{Binding Path=ProductName}" />
<GridViewColumn Header="Price"
Width="Auto"
DisplayMemberBinding="{Binding Path=Price}" />
</GridView>
</ListView.View>
</ListView>
Listing 2: The ListView XAML

You will use the Loaded event procedure of the WPF window to populate the list
view using the code shown in Listing 3. When you set the DataContext property
with the ObservableCollection of Product objects, the {Binding} in each
GridViewColumn shown in Listing 2 grabs the data from the Product objects
property to display in the appropriate column in the ListView.
C#
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ProductManager mgr = new ProductManager();
lstData.DataContext = mgr.GetProducts();
}
VB.NET
Private Sub Window_Loaded(ByVal sender As Object, _
ByVal e As RoutedEventArgs)
Dim mgr As New ProductManager()
lstData.DataContext = mgr.GetProducts()
End Sub
Listing 3: Calling GetProducts to load the ListView

14-6

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

Data Binding Basics in XAML


When you click on a row in the ListView control the SelectionChanged event fires.
In this event you will retrieve the Product object from the selected row and use that
to populate the text boxes and other controls with the data from that Product object
as shown in Listing 4.
C#
private void lstData_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
Product entity;
entity = (Product)lstData.SelectedItem;
txtProductId.Text = entity.ProductId.ToString();
txtProductName.Text = entity.ProductName;
txtPrice.Text = entity.Price.ToString();
chkIsActive.IsChecked = entity.IsActive;
}
VB.NET
Private Sub lstData_SelectionChanged(ByVal sender As Object, _
ByVal e As SelectionChangedEventArgs)
Dim entity As Product
entity = DirectCast(lstData.SelectedItem, Product)
txtProductId.Text = entity.ProductId.ToString()
txtProductName.Text = entity.ProductName
txtPrice.Text = entity.Price.ToString()
chkIsActive.IsChecked = entity.IsActive
End Sub
Listing 4: Populating Controls Manually

The code in Listing 4 should be fairly standard code that you are used to writing if
you have ever coded Windows Forms or ASP.NET. You also know that you need
to write code to take the data from the forms and move it back into the Product
object prior to passing this object to the Insert or Update methods on your data
class. You end up with a lot of code just to move data back and forth between your
UI and your entity class. When you use XAML data binding, you can completely
eliminate this code! Lets take a look at how to do that.

Data Binding Basics in XAML


Just as you use the Binding syntax in the ListView you may also use this same
approach for your text boxes, check boxes and other controls. Each
GridViewColumn control has as its parent the ListView itself. This concept of a
parent is very important in XAML and we can use this to our advantage. Consider
the following XAML.
Haystack Code Generator for .NET
Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

14-7

MVVM Made Simple


<Grid Name="grdDetail">
<TextBox Text="{Binding Path=ProductName}" />
</Grid>

In the above XAML, the Grid named grdDetail contains one text box that has a
{Binding} in its Text property. If you set the DataContext of the Grid control to an
instance of a Product object, then the Text property of the TextBox will display the
ProductName property within that Product object as shown in the following code:
C#
Product entity = new Product();
entity.ProductName = "A New Product";
grdDetail.DataContext = entity;
VB.NET
Dim entity As New Product()
entity.ProductName = "A New Product"
grdDetail.DataContext = entity;

You can take advantage of this technique to eliminate the code shown in Listing 4
that moves the code from the Product object into the various controls. Replace the
code in the SelectionChanged event with the code shown in Listing 5.
C#
private void lstData_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
_Entity = (Product)lstData.SelectedItem;
grdDetail.DataContext = _Entity;
}
VB.NET
Private Sub lstData_SelectionChanged(ByVal sender As Object, _
ByVal e As SelectionChangedEventArgs)
mEntity = DirectCast(lstData.SelectedItem, Product)
grdDetail.DataContext = mEntity
End Sub
Listing 5: Wrap controls into containers to make data binding easier.

14-8

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

Eliminate More Code

Eliminate More Code


While you eliminated a lot of code in the last example, you still had to write code in
the SelectionChanged event. You can eliminate even more code by taking
advantage of the control-to-control data binding features in XAML. In the XAML
shown in Listing 6 you will set the DataContext property of the Grid to a Binding
that uses the ElementName attribute set to the name of the ListView. You set the
Path property to SelectedItem as that property of the ListView contains the
currently selected Product object. This syntax is all that is needed to automatically
bind the ListView control to the Grid where all your text box controls are located.
You can now remove the SelectionChanged event procedure completely!
<Grid DataContext="{Binding
ElementName=lstData, Path=SelectedItem}">
<TextBox Text="{Binding Path=ProductId}" />
<TextBox Text="{Binding Path=ProductName}" />
<TextBox Text="{Binding Path=Price}" />
<CheckBox IsChecked="{Binding Path=IsActive}" />
</Grid>
Listing 6: Use ElementName and Path to Bind the ListView to the Grid.

Binding Other Properties


All of the data binding you have done so far relates to data you retrieve from your
database. However, you can bind almost any property on any control to any
property on any class. To illustrate this concept consider the Add, Save and Cancel
buttons on the form shown in Figure 1. Notice how the Add button is enabled, but
the Save and Cancel buttons are disabled. The IsEnabled property on these
buttons can be controlled from properties on a class.
Lets assume you have XAML window named winMoreDataBinding. You can add
the appropriate properties to this window class and bind the IsEnabled properties
of your buttons to these properties. To do this you need to implement the
INotifyPropertyChanged interface on your window. Listing 7 shows the code that
you would add your Window class to implement properties that you bind to the
respective IsEnabled properties of your buttons.

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

14-9

MVVM Made Simple


C#
public partial class winMoreDataBinding : Window,
INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
private bool _IsSaveEnabled = false;
private bool _IsCancelEnabled = false;
private bool _IsAddEnabled = true;
public bool IsSaveEnabled
{
get { return _IsSaveEnabled; }
set
{
if (_IsSaveEnabled != value)
{
_IsSaveEnabled = value;
RaisePropertyChanged("IsSaveEnabled");
}
}
}
public bool IsCancelEnabled
{
get { return _IsCancelEnabled; }
set
{
if (_IsCancelEnabled != value)
{
_IsCancelEnabled = value;
RaisePropertyChanged("IsCancelEnabled");
}
}
}
public bool IsAddEnabled
{
get { return _IsAddEnabled; }
set
{
if (_IsAddEnabled != value)
{
_IsAddEnabled = value;
RaisePropertyChanged("IsAddEnabled");
}
}
}

}
VB.NET

14-10

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

Binding Other Properties


Partial Public Class winMoreDataBinding
Inherits Window
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Protected Sub RaisePropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, _
New PropertyChangedEventArgs(propertyName))
End Sub
Private _IsSaveEnabled As Boolean = False
Private _IsCancelEnabled As Boolean = False
Private _IsAddEnabled As Boolean = True
Public Property IsSaveEnabled() As Boolean
Get
Return _IsSaveEnabled
End Get
Set(ByVal value As Boolean)
If _IsSaveEnabled <> value Then
_IsSaveEnabled = value
RaisePropertyChanged("IsSaveEnabled")
End If
End Set
End Property
Public Property IsCancelEnabled() As Boolean
Get
Return _IsCancelEnabled
End Get
Set(ByVal value As Boolean)
If _IsCancelEnabled <> value Then
_IsCancelEnabled = value
RaisePropertyChanged("IsCancelEnabled")
End If
End Set
End Property
Public Property IsAddEnabled() As Boolean
Get
Return _IsAddEnabled
End Get
Set(ByVal value As Boolean)
If _IsAddEnabled <> value Then
_IsAddEnabled = value
RaisePropertyChanged("IsAddEnabled")
End If
End Set
End Property

End Class
Listing 7: Add Properties to your Window to Control UI Elements

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

14-11

MVVM Made Simple


To bind each of these properties to your buttons IsEnabled properties you write the
following XAML:
<Button Content="Add"
IsEnabled="{Binding Path=IsAddEnabled}" />
<Button Content="Save"
IsEnabled="{Binding Path=IsSaveEnabled}" />
<Button Content="Cancel"
IsEnabled="{Binding Path=IsCancelEnabled}" />
Listing 8: Bind UI Properties to properties in a class

Now in the code-behind for your window if you set the IsAddEnabled property to
False, then the Add button will become disabled automatically. It is important that
you set the property IsAddEnabled, not the private variable that this property uses
as its backing data store. The Set procedure for the IsAddEnabled will raise the
property changed event which is how XAML is informed of the change in value and
then knows to refresh its controls UI state.

A Simple ViewModel
Now that you are familiar with data binding both in terms of data objects and UI
objects, you can now expand on your knowledge to create a simple ViewModel and
eliminate even more code-behind from your windows. If you download and look at
each of the samples illustrated in this article, you will find that each window has
about 200 lines of code-behind. When you start using a ViewModel you will cut this
amount by more than half!
Remember that a view model is just a class with code, there is no magic. In the
sample application that goes along with this article, there is a class called
ProductViewModel. You will create an instance of this class by creating it as a
resource in your XAML. First you will create an XML namespace and give that
namespace a name. In the XAML shown in Listing 9 the fourth line down creates a
namespace called local and assigns that namespace to the name of the assembly
where the ProductViewModel class is located. Next, in the <Window.Resources>
section of the XAML is where you create an instance of the ProductViewModel and
assign it a key called viewModel.

14-12

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

A Simple ViewModel
<Window x:Class="winSimpleMVVM"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMSample"
Title="Simple View Model Sample" >
<Window.Resources>
<local:ProductViewModel x:Key="viewModel" />
</Window.Resources>
...
</Window>
Listing 9: Use XAML to create an instance of a ViewModel class

DataCollection and DetailData Properties


In the ProductViewModel class there are two properties that you will use for data
binding to your window (see Listing 10). The DataCollection property is an
ObservableCollection of Product objects and DetailData is a single instance of a
Product object. The DataCollection property will be filled in with the data in the
constructor of the ProductViewModel class. The DetailData property will be filled in
when you click on a row in the ListView.

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

14-13

MVVM Made Simple


C#
private ObservableCollection<Product> mDataCollection;
public ObservableCollection<Product> DataCollection
{
get { return mDataCollection; }
set
{
mDataCollection = value;
RaisePropertyChanged("DataCollection");
}
}
private Product mDetailData;
public Product DetailData
{
get { return mDetailData; }
set
{
mDetailData = value;
RaisePropertyChanged("DetailData");
}
}
VB.NET
Public Property DataCollection As ObservableCollection(Of Product)
Get
Return mDataCollection
End Get
Set(ByVal value As ObservableCollection(Of Product))
mDataCollection = value
RaisePropertyChanged("DataCollection")
End Set
End Property
Public Property DetailData As Product
Get
Return mDetailData
End Get
Set(ByVal value As Product)
mDetailData = value
RaisePropertyChanged("DetailData")
End Set
End Property
Listing 10: DataCollection and DetailData are Dependency Properties

You use these two properties as the source of data for the ListView control (Listing
11) and as the source of data for the Grid that contains all of the detail text boxes
and the check box (Listing 12).
<ListView x:Name="lstData"
ItemsSource="{Binding Path=DataCollection}">
...
</ListView>
Listing 11: Bind the ListView to a property of the ViewModel class

14-14

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

A Simple ViewModel
<Grid DataContext="{Binding Path=DetailData}">
...
</Grid>
Listing 12: Bind the Detail Grid to a property of the ViewModel class

Populating the Data in the View Model Class


There is a method called InitializeComponent that is called in the constructor of a
WPF Window. The InitializeComponent method is where all controls on your page
are created. This includes the ProductViewModel. This means that the constructor
in your ProductViewModel will be called at this time. In Listing 13 you see the
constructor code in the ProductViewModel class. Notice that is calls the
GetProducts method in the ProductManager class which as you remember returns
a collection of Product objects.
C#
public class ProductViewModel : DependencyObject,
INotifyPropertyChanged
{
ProductManager _DataManager = new ProductManager();
public ProductViewModel()
{
DataCollection = _DataManager.GetProducts();
}
...
}
VB.NET
Public Class ProductViewModel
Inherits DependencyObject
Implements INotifyPropertyChanged
Private mDataManager As New ProductManager()
Public Sub New()
DataCollection = mDataManager.GetProducts()
End Sub
...
End Class
Listing 13: Initialize the DataCollection property in the constructor of your ViewModel

Since you are doing data access in the constructor it is very critical that you have
excellent exception handling in place when retrieving your data. The GetProducts
method contains all of the exception handling in this example.
Notice that the ProductViewModel class implements the INotifyPropertyChanged
interface. In the prior example, this interface was added to the Window class

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

14-15

MVVM Made Simple


because that is where the UI properties such as IsAddEnabled were created. Now
all those UI properties are in the view model class.

Hooking Into the View Model Class in the CodeBehind


Remember that you created an instance of the view model class in the XAML. You
will need to interact with this view model class in the code-behind of your window.
In the constructor of your Window class (Listing 14) you can grab the instance of
the view model class that was created by using the FindResource method on the
Window class. You pass in the key that you assigned to the view model class in the
XAML, in this case viewModel, you cast it to a ProductViewModel and assign it
into a private field variable in the Window class. You can now use this private
variable to call any method or get/set any properties in the view model.
C#
public partial class winSimpleMVVM : Window
{
ProductViewModel _ViewModel;
public winSimpleMVVM()
{
InitializeComponent();
// Initialize the Product View Model Object
_ViewModel = (ProductViewModel)this.FindResource("viewModel");
}
...
}

VB.NET
Partial Public Class winSimpleMVVM
Inherits Window
Private mViewModel As ProductViewModel
Public Sub New()
InitializeComponent()
' Initialize the Product View Model Object
mViewModel = DirectCast(Me.FindResource("viewModel"), _
ProductViewModel)
End Sub
...
End Class
Listing 14: Grab the instance of the ViewModel class in your code-behind.

14-16

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

Event Procedures in the Window Class

Event Procedures in the Window Class


In the product screen, there are still event procedures left in the Window class.
These event procedures are for when you click on the Add, Save and/or Cancel
buttons. There is very little code in each event procedure as all that is needed is to
make calls to the view model class, or maybe perform a little bit of UI logic. Listing
15 shows all the code that is left in the code-behind of this window. Notice that you
use the private view model variable to call methods in the view model.

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

14-17

MVVM Made Simple


C#
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
_ViewModel.AddRecord();
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
_ViewModel.CancelEdit();
// TODO: Write code to undo changes
lstData.SelectedIndex = 0;
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
_ViewModel.SaveData();
}
private void TextHasChanged(object sender, TextChangedEventArgs e)
{
// Only Change Mode if Element has Keyboard Focus
if (((UIElement)sender).IsKeyboardFocused)
_ViewModel.SetEditUIDisplay();
}
private void CheckedHasChanged(object sender, RoutedEventArgs e)
{
if (((UIElement)sender).IsKeyboardFocused ||
((UIElement)sender).IsMouseDirectlyOver)
_ViewModel.SetEditUIDisplay();
}
VB.NET
Private Sub btnAdd_Click(ByVal sender As Object, _
ByVal e As RoutedEventArgs)
mViewModel.AddRecord()
End Sub
Private Sub btnCancel_Click(ByVal sender As Object, _
ByVal e As RoutedEventArgs)
mViewModel.CancelEdit()
' TODO: Write code to undo changes
lstData.SelectedIndex = 0
End Sub
Private Sub btnSave_Click(ByVal sender As Object, _
ByVal e As RoutedEventArgs)
mViewModel.SaveData()
End Sub
Private Sub TextHasChanged(ByVal sender As Object, _
ByVal e As TextChangedEventArgs)
' Only Change Mode if Element has Keyboard Focus
If DirectCast(sender, UIElement).IsKeyboardFocused Then
mViewModel.SetEditUIDisplay()

14-18

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

Event Procedures in the Window Class


End If
End Sub
Private Sub CheckedHasChanged(ByVal sender As Object, _
ByVal e As RoutedEventArgs)
If DirectCast(sender, UIElement).IsKeyboardFocused _
OrElse DirectCast(sender, UIElement).IsMouseDirectlyOver Then
mViewModel.SetEditUIDisplay()
End If
End Sub
Listing 15: Very little code is left in the code-behind of your Window class

If you want, you can get rid of some of these events using the Commanding model
available in WPF. However, you end up writing a lot more code to support the
command model, and to me there is very little benefit. You have accomplished the
goal of moving all logic into the view model class so that you can unit test the view
model. There is no UI code at all in the view model class and thus can be tested
very easily using automated tools. Another problem with the command model is
that not all events can be hooked up to commands. So at some point you then
have to write some very complicated code to hook to all these events. I find the
simpler approach that I have laid out in this article a good compromise between
having everything in the code-behind and a pure view model approach. I have
accomplished the goals of MVVM but I have kept my programming model simple
and easy to understand.

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

14-19

MVVM Made Simple

Summary
Once you understand the basics of data binding in XAML, you can eliminate a lot
code that is otherwise needed to move data into controls and out of controls back
into an object. This forms the basis of a MVVM approach. You are used to writing
classes, you just need to get used to the idea of using properties on classes to
affect UI properties. In this article you saw a very simple and easy-to-use pattern
for MVVM. While the purists would disagree with this approach, those folks that like
things simple and easy to understand should be satisfied.

Chapter Index
A
An MVVM Sample, 14-2

B
Bind to UI Properties, 14-9
Binding using ElementName and Path, 149

D
Data Binding Basics in XAML, 14-7
DataCollection Property in MVVM Sample,
14-13
DetailData Property in MVVM Sample, 1413

I
INotifyPropertyChanged, 14-3

14-20

M
Model View View Model, 14-1
MVVM, 14-1
MVVM Made Simple, 14-1

P
Product Class in MVVM Sample, 14-3
ProductManager Class in MVVM Sample,
14-5
ProductViewModel Class in MVVM, 14-12

S
Simple View Model Class, 14-12

W
Why MVVM?, 14-2

Haystack Code Generator for .NET


Copyright 2010-2011 by PDSA, Inc.
All rights reserved. Reproduction is strictly prohibited.

Вам также может понравиться