Tuesday, April 07, 2009

MVVM Infrastructure: ViewModel

This post is part of a short series I am doing on MVVM infrastructure. In this series, I will share some thinking and code that has helped to produce cleaner, simpler MVVM code in my applications.

Related posts:

  1. POCOs versus DependencyObjects
  2. ViewModel
  3. DelegateCommand
  4. ActiveAwareCommand

In this post, I'm going to show you a base class for view models I have imaginatively named ViewModel. This is by no means a complex class, but it's a fantastic time-saver when doing MVVM.

I had a few concerns at the fore-front of my mind when designing this class. Firstly, I wanted it to be extremely simple to use. When inheriting from it, I didn't want to have to worry about implementing specific constructors in my subclass or providing implementations of abstract members. It should be brain-dead simple to extend the ViewModel class.

Secondly, I was concerned about having too many members on the base class. Doing so could make it harder to discern those members of interest when working on subclasses. Essentially, I didn't want a lot of noise in the APIs, because that adds just that little bit of friction that can accumulate into a ball of pain.

Thirdly, I didn't want the class to impose too much on subclasses. They should be granted as much freedom of implementation as possible whilst still providing them with value. For example, subclasses should have the ability to provide their own implementation of equality.

Finally, I wanted to minimize the performance impact of leveraging this base class. I didn't want consumers to have to choose between a good view model design and performance. Ideally, they could have their cake and eat it, too. Of course, I'm not saying you can design your view models as fine-grained as you like without a thought for performance. I'm just saying I wanted to mitigate the risk.

As you'll see from the code, I think it's fair to say these goals have all been satisfied. The attached file includes API documentation, but the small size of the class means I can include it here, sans documentation:

public abstract class ViewModel : INotifyPropertyChanged 
{ 
    private readonly Dispatcher _dispatcher; 
    
    protected ViewModel() 
    { 
        if (Application.Current != null) 
        { 
            _dispatcher = Application.Current.Dispatcher; 
        } 
        else 
        { 
            //this is useful for unit tests where there is no application running 
            _dispatcher = Dispatcher.CurrentDispatcher; 
        } 

    } 

    [field:NonSerialized]
    public event PropertyChangedEventHandler PropertyChanged; 

    protected Dispatcher Dispatcher 
    { 
        get { return _dispatcher; } 
    } 

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
        PropertyChanged.Raise(this, e); 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
    } 
} 

There are really only two responsibilities taken on by this class:

  1. Implement INotifyPropertyChanged.
  2. Provide access to a Dispatcher.

The OnPropertyChanged overrides allow subclasses to easily raise the PropertyChanged event (incidentally, that call to PropertyChanged.Raise is by virtue of my library The Helper Trinity). For example, a subclass might do so like this:

public string Name 
{ 
    get { return _name; } 
    set 
    { 
        if (_name != value) 
        { 
            _name = value; 
            OnPropertyChanged("Name"); 
        } 
    } 
}

The Dispatcher property allows subclasses to gain access to the current Dispatcher, which makes it much easier to perform work to a background thread and then synchronize the results with the UI. Importantly, a new Dispatcher for the current thread is assigned if no WPF application is running. This makes unit testing much easier as there will always be a Dispatcher available via this property.

So that's it really. Nothing much to it, and that's the way I like it. Next up in this series, we'll start looking at the infrastructure I have around commanding.

12 comments:

blorq said...

From a testability perspective, using the dispatcher that way is not ideal. Personally, I wrap any actions that need the dispatcher in a Runner class that is injected into the viewmodels. That way, in testing you inject a "dont realy do this in the background" runner but in the real app you have one that runs stuff on the dispatcher. (My runner also has methods for running things on separate threads for heavy weight stuff as well as methods for threadpool)

Kent Boogaart said...

@blorg: sounds like design for testability to me, which I am not a fan of. Why not just have separate methods - one async and most sync? If you don't want to test the async behavior, just call the sync method from your test.

blorq said...

The fact that its async or not shouldnt really matter for testing that method. Moving that responsibility outward keeps the same flow and methods for both testing and "real world"

Kent Boogaart said...

But from your first post:

> That way, in testing you inject a "dont realy do this in the background" runner

From that, I'd assume your Runner class exists precisely so your unit tests run on a single thread. So there *will* be a different flow in a real world execution versus unit test.

Maybe you could do a blog post on this to provide a more complete picture?

Philipp said...

When it comes to raising property change events, I sometimes prefer (strongly typed) lambdas over strings, especially if I want to raise a property change for a property from somewhere else than the property's setter (e.g. because there is none as the getter calculates the value).

In case somebody wants to use the snippet (hope formatting doesn't get completely screwed up...):


/// <summary>
/// Allows triggering the <see cref="PropertyChanged"/> event using
/// a lambda expression, thus avoiding strings. Keep in mind that
/// using this method comes with a performance penalty, so don't use
/// it for frequently updated properties that cause a lot of events
/// to be fired.
/// </summary>
/// <typeparam name="T">Type of the property.</typeparam>
/// <param name="propertyExpression">Expression pointing to a given
/// property.</param>
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
//the cast will always succeed if properly used
MemberExpression memberExpression = (MemberExpression)propertyExpression.Body;
string propertyName = memberExpression.Member.Name;
OnPropertyChanged(propertyName);
}


/// <summary>
/// Raises the <see cref="PropertyChanged"/> event for
/// a given property.
/// </summary>
/// <param name="propertyName">The name of the changed property.</param>
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged.Raise(this, new PropertyChangedEventArgs(propertyName));
}


/// <summary>
/// Raises the <see cref="PropertyChanged"/> event for
/// a set of properties.
/// </summary>
/// <param name="propertyNames">Provides the names of the changed properties.</param>
protected void OnPropertyChanged(params string[] propertyNames)
{
foreach (string propertyName in propertyNames)
{
OnPropertyChanged(propertyName);
}
}



I also like Josh Smith's base class that performs a conditional verification of property strings in Debug builds:
http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/

Brian said...

Also a great post. I have come up with a very similar class, but I have added a few more methods to the base class:

protected void Set<T>(string propertyName, T value);
protected T Get<T>(string propertyName);
protected T Get<T>(string propertyName, T defaultValue);

The values are stored in a dictionary, and the changed event is fired if the value changed.

Then, in the view model, I can get rid of all the private field backing store:

public int Foo
{
get { return Get("Foo", 0); }
set { Set("Foo", value); }
}

Doing this cleans up my ViewModel code tremendously.

Thanks again for helping me feel like what I am doing is not crazy.

Brian Genisio
http://HouseOfBilz.com

Diego said...

Hi Kent, i see in your post that when you want to call the dispatcher you do a check to know if the Application.Current is diferent to null in order to get the Application.Current.Dispatcher or Dispatcher.CurrentDispatcher if it is null.

What is the diference between both forms to obtain the dispatcher in a application?

I know that, for unit test, the application object is null... but is the same works always with Dispatcher.CurrentDispatcher?

I mean, what is the correct form or more elegant to obtain the dispatcher in a application and for unit test. If i get always the dispatcher throw Dispatcher.CurrentDispatcher the problem with unit test is solved or not?

Thanks for your posts...

Kent Boogaart said...

@Diego: Application.Current.Dispatcher is a singleton and is guaranteed to be the dispatcher associated with your UI's thread.

Dispatcher.Current will return a dispatcher for the *current* thread, creating one if necessary.

Thus, if you get in the habit of using Dispatcher.Current in an application context, you may find yourself with a reference to a new Dispatcher without realizing it.

Consider this really simple example:

ThreadPool.QueueUserWorkItem(delegate
{
// do some heavy work

// marshal results back to UI
Application.Current.Dispatcher.Invoke(...);

// this won't work because it will create a new Dispatcher associated with the background thread
//Dispatcher.Current.Invoke(...);
});

The whole point of the Dispatcher property on the base view model is you can do this:

base.Dispatcher.Invoke(...);

and it will work in your application context, and your unit test context.

mike said...

I'm stuck with .Net 3.5, do you have a ViewModel class that will work with this?
Dispatcher object and Application.Current are not available

thanks,

Mike

Kent Boogaart said...

@Mike: both of those exist in 3.5, so not sure what you mean...?

Unknown said...

Hi,
what is the [field:NonSerialized] Meta used for?

thanks & regards

Mike

Kent Boogaart said...

@Mike: that's to ensure that any event handlers are not serialized when the VM is. If you don't serialize your VMs (I tend not to, so not sure why I included this at the time), then you needn't worry include this.