MVVM UnPlugged

In Part 1 of the MVVM series “MVVM Unplugged – Definition, Benefits, Classes and its interactions“, we saw that the MVVM pattern provides a clean separation between your application’s user interface, its presentation logic, and its business logic and data by separating each into separate classes. In this blog, we are going to focus on the Data Binding aspect of implementing the MVVM pattern esp. Databinding of properties using INotifyPropertyChanged interface.

Data Binding

Data binding is one of the very important mechanism through which the various classes under the MVVM pattern interact with each other.WPF and Silverlight both provide powerful data binding capabilities. Silverlight and WPF data binding supports multiple data binding modes. There are various modes of data binding, with one-way data binding, UI controls can be bound to a view model so that they reflect the value of the underlying data when the display is rendered. Two-way data binding will also automatically update the underlying data when the user modifies it in the UI. To achieve data binding and to make ensure that the UI is kept up to date when the data changes in the view model, it should implement the appropriate change notification interfaces.  If there are properties in the ViewModel that needs to be data bound with the view then the view model should implement the INotifyPropertyChanged interface. If the view model represents a collection, it should implement the INotifyCollectionChanged interface or derive from the ObservableCollection class that provides an implementation of this interface. The INotifyPropertyChanged interface and INotifyCollectionChanged interface both define an event that is raised whenever the underlying data is changed. Any data bound controls will be automatically updated when these events are raised. WPF and Silverlight data binding supports binding to nested properties via the Path property. Thumb rule for achieving data binding in WPF or Silverlight is that any view model or model that is accessible to the view should implement either the INotifyPropertyChanged or INotifyCollectionChanged interfaces, as per the need.

In this blog, we are going to focus on the implementation of the INotifyPropertyChanged interface. If we look in the object browser of the INotifyPropertyChanged, we see that it’s a very simple interface and it is just asking the concrete classes to expose an event which takes in a delegate PropertyChangedEventHandler delegate.

namespace System.ComponentModel
{
       // Summary: Notifies clients that a property value has changed.
       public interface INotifyPropertyChanged
       {
           // Summary: Occurs when a property value changes.
           event PropertyChangedEventHandler PropertyChanged;
       }
}

The PropertyChangedEventHandler is defined as a method that will handle the INotifyPropertyChanged. PropertyChanged event is raised when a property is changed on a component. It takes in two parameters:

  •  sender – The source of the event.
  •  e – A System.ComponentModel.PropertyChangedEventArgs that contains the event data.

If we look into the PropertyChangedEventArgs, it has a constructor which takes in a parameter PropertyName as string now this parameter is basically is the property which has changed.

public PropertyChangedEventArgs(string propertyName);

Now since we have a basic understanding of how the INotifyPropertyChanged interface works and what constitutes the PropertyChangedEventHandler and PropertyChangedEventArgs. Lets take a look at an example of how we are going to implement this interface.

View

In our view, We have created a simple window which is depicting a user and has three properties defined on it – First Name , Last Name and Age. Let’s go ahead and create a view model for our simple view.

ViewModel

 Lets create a view model for our User View and name it as UserViewModel. To implement the databinding, lets implement the INotifyPropertyChanged interface. As seen in the code below, we see that for implementing the INotifyPropertyChanged, we have declared a public event PropertyChanged which takes in a delegate method PropertyChangedEventHandler. Now for all the properties which we want to have databinding capabilities, we have gone ahead and provided the event trigger by calling the delegate PropertyChanged.

class UserViewModel : INotifyPropertyChanged
{
    private int _age;
    private string _firstName;
    private string _lastName;
    public event PropertyChangedEventHandler PropertyChanged;
    public UserViewModel(){}
    public string LastName
    {
       get { return _lastName; }
       set
       {
          if (value != _lastName)
          {
             _lastName = value;
             if (PropertyChanged != null)
             {
               this.PropertyChanged(this, new propertyChangedEventArgs("LastName"));
             }
          }
       }
    }
    public string FirstName
    {
        get { return _firstName; }
        set
        {
           if (value != _firstName)
           {
             _firstName = value;
             if (PropertyChanged != null)
             {
                this.PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
             }
           }
        }
    }
    public int Age
    {
        get { return _age; }
        set
        {
           if (value != _age)
           {
              _age = value;
              if (PropertyChanged != null)
              {
                 this.PropertyChanged(this, new PropertyChangedEventArgs("Age"));
              }
           }
        }
    }
}

To make this code working, we now just need to define these bindings in the User View XAML code and we also need to provide the hook up code between the view and viewmodel.

<TextBox Height="23" HorizontalAlignment="Left" Margin="242,27,0,0" Name="firstNameTextBox" Text ="{Binding FirstName,Mode=TwoWay}" VerticalAlignment="Top" Width="120" Grid.Column="1" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="242,69,0,0" Name="lastNameTextBox" Text ="{Binding LastName,Mode=TwoWay}" VerticalAlignment="Top" Width="120" Grid.Column="1" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="242,115,0,0" Name="ageTextBox" Text ="{Binding Age,Mode=TwoWay}" VerticalAlignment="Top" Width="120" Grid.Column="1" />

As you can see from the code above, we have bound the textboxes with the Properties defined in our UserViewModel class.

Now as a final step , we just need to hook up the View and Model, one way in which we can do this is by creating an object of View Model in our constructor of the view and then setting up the data context of the view as the view model.

UserViewModel viewModel = new UserViewModel();
this.DataContext = viewModel;

Problems with this implementation of the INotifyPropertyChanged.

If we notice it closely, with the approach described above, we have to implement the INotifyPropertyChanged interface on all of our View Models and this would lead to errors as we have to repetitively specify the property name in the event argument which is an string. Let’s look at a better way of implementing the same thing.

 Better Approach : Using NotificationObject of Prism

The Prism Library provides a convenient base class from which you can derive your view model classes that implements the INotifyPropertyChanged interface in a type-safe manner. The base class it provides us is called NotificationObject. Let’s take a look at its implementation.

public abstract class NotificationObject : INotifyPropertyChanged
{
   protected NotificationObject();
   // Summary: Raised when a property on this object has a new value.
   public event PropertyChangedEventHandler PropertyChanged;
   // Summary: Raises this object's PropertyChanged event.
   // Parameters: 
   // propertyExpression:
   // A Lambda expression representing the property that has a new value.
   // Type parameters:
   // T: The type of the property that has a new value
   protected void RaisePropertyChanged(Expression propertyExpression);
   // Summary: Raises this object's PropertyChanged event for each of the properties.
   // Parameters:
   // propertyNames: The properties that have a new value.
   protected void RaisePropertyChanged(params string[] propertyNames);
   // Summary:
   // Raises this object's PropertyChanged event.
   // Parameters:
   // propertyName: The property that has a new value.
   protected virtual void RaisePropertyChanged(string propertyName);
}

In the code above, we see that Prism has defined a class NotificationObject which implements the INotificationPropertyChanged interface.  We also see that it has three overloaded methods defined for Raising the Property Changed , one method takes, the Lambda expression representing the property that has a new value, the second one takes an array of properties that has a new value and the third one is similar to the one which we explained above in our implementation of the INotifyPropertyChanged event which takes in the property name that has a new value.

 Lets implement a new View Model class for our user view , this one will derive from the NotificationObject provided by the Prism.

class UserBindingUsingPrismViewModel : NotificationObject
{
   private int _age;
   private string _firstName;
   private string _lastName;
   public string LastName
   {
      get { return _lastName; }
      set
      {
         if (value != _lastName)
         {
           _lastName = value;
           RaisePropertyChanged(() => this.LastName);
         }
      }
   }
   public string FirstName
   {
       get { return _firstName; }
       set
       {
          if (value != _firstName)
          {
            _firstName = value;
            RaisePropertyChanged(() => this.FirstName);
          }
       }
   }
   public int Age
   {
      get { return _age; }
      set
      {
         if (value != _age)
         {
           _age = value;
           RaisePropertyChanged(() => this.Age);
         }
      }
   }
}

As we can see from the above code, our inherited view model class is now raising the property change event by invoking RaisePropertyChanged using a lambda expression that refers to the property. Using a lambda expression in this way involves a small performance cost because the lambda expression has to be evaluated for each call. The benefit is that this approach provides compile-time type safety and refactoring support if you rename a property. Although the performance cost is small and would not normally impact your application, the costs can accrue if you have many change notifications. In this case, one should consider using the non-lambda method overload.

About Abhinav Ranjan

Technologist | Strategist
Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>