Donnerstag, 17. Juni 2010

A great MVVM view model base class for SL4 - Part II

In my previous post I mentioned the view model base class of Brian Genisio. It uses a dictinary as a value storage for your view models properties. In your view model you write the following:

public class MyViewModel : ViewModelBase
{
  public string Name
  {
    get { return Get(() => Name); }
    set { Set(() => Name, value); }
  }
}

The expression "() => Name" is used instead of the string "Name" to identify the property in a strong typed manner (that means you could have also written Get("Name") instead).

All this works fine as long as your view model orignially provides all the values you need. In my case I have view models that use model classes as data storage like so:

public class MyViewModel : ViewModelBase
{
  private Person m_Person;
  public string Name
  {
    get { return m_Person.Name; }
    set
    {
      if (m_Person.Name != value)
      {
        m_Person.Name = value;
        OnPropertyChanged("Name");
      }
    }
  }
}

That forces me to write all the set-code myself again. My idea to be able to use all the base class goodies again was to add an additional but optional business object to the base class as well as some new overloads to the Get / Set methods:

public class ViewModelBase : INotifyPropertyChanged
{
  private Object m_BusinessObject;

  public ViewModelBase() : this(null)
  { }

  public ViewModelBase(Object BusinessObject)
  {
  m_BusinessObject = BusinessObject;
  ...
  }

  protected T Get<TBusniessObject, T>(Expression<Func<T>> expression, T DefaultValue)
  {
    if (m_BusinessObject == null)
      return DefaultValue;

    String propName = GetPropertyName(expression);
    return (T)m_BusinessObject.GetType().GetProperty(propName).GetValue(m_BusinessObject, new object[] { });
  }

  protected void Set<TBusinessObject, T>(Expression<Func<T>> expression, T value)
  {
    if (m_BusinessObject == null)
      return;

    if (Get<TBusinessObject, T>(expression).Equals(value))
      return;

    String propName = GetPropertyName(expression);
    m_BusinessObject.GetType().GetProperty(propName).SetValue(m_BusinessObject, value, new object[] { });
    Set(propName, value);
  }

}


The idea is simple: as long as the business object is not null we get / set the value out of it via reflection. In the setter we first compare the current value with the acutal one to leave if nothing has changed. After having set the value to the business object, I pass the value through to the normal Set method in order to get all the other gadgets like dependent methods working.

With that code in place I am able to write the Property from my above example like so:

public class MyViewModel : ViewModelBase
{
  private Person m_Person;
  public string Name
  {
    get { Get<Person, string>(() => Name); }
    set { Set<Person, string>(() => Name, value); }
  }
}

Brians code is at codeplex. My suggestions can easily be incorporated.

Have fun.

1 Kommentar: