INotifyPropertyChanged is an interface which is very important to do proper databinding and is heavily used in the MVVM pattern.
However, to implement it you have to raise the PropertyChanged event whenever a data-bound property changes value, and you have to pass the name of the property to it. This results in string based programming and this generally is not good for maintenance. Some people create a RaisePropertyChanged method in the base class and then invoke this method in each property setter. Again this is not ideal because you cannot always derive from this base class, especially if you already have a base class. In this post I want to show you an alternative way of implementing INotifyPropertyChanged that doesn’t require a base class (you simple implement the INotifyPropertyChanged on each class) with a nice, string-less way of raising the PropertyChanged event. For example, look at this class:
1: public class Customer : INotifyPropertyChanged
2: {
3: private string firstName;
4:
5: public string FirstName
6: {
7: get { return firstName; }
8: set
9: {
10: if (!object.Equals(value, firstName))
11: {
12: firstName = value;
13: PropertyChanged.Raise(this, o => o.FirstName);
14: }
15: }
16: }
17: }
As you can see, the PropertyChanged.Raise does all the work, and you pass in the sender and the property using a Lambda expression. Simple and no strings. To make things even simpler, I use a code snippet that implements the property directly for me:
1: <?xml version="1.0" encoding="utf-8" ?>
2: <CodeSnippet Format="1.0.0"
3: xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
4: <Header>
5: <Title>NPC</Title>
6: <Author>Peter</Author>
7: <Shortcut>npc</Shortcut>
8: <Description>NotifyPropertyChangedProperty</Description>
9: <SnippetTypes>
10: <SnippetType>SurroundsWith</SnippetType>
11: <SnippetType>Expansion</SnippetType>
12: </SnippetTypes>
13: </Header>
14: <Snippet>
15: <Declarations>
16: <Literal>
17: <ID>type</ID>
18: <Default>int</Default>
19: </Literal>
20: <Literal>
21: <ID>field</ID>
22: <Default>prop</Default>
23: </Literal>
24: <Literal>
25: <ID>name</ID>
26: <Default>Prop</Default>
27: </Literal>
28: </Declarations>
29: <Code Language="CSharp">
30: <![CDATA[
31: [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
32: private $type$ $field$;
33:
34: public $type$ $name$ {
35: get { return $field$; }
36: set {
37: if( ! object.Equals( value, $field$ ) )
38: {
39: $field$ = value;
40: PropertyChanged.Raise( this, o => o.$name$ );
41: }
42: }
43: }
44: ]]>
45: </Code>
46: </Snippet>
47: </CodeSnippet>
So how does it work? Here is the definition of the Raise Extension method:
1: public static void Raise<T, P>(
2: this PropertyChangedEventHandler pc
3: , T source
4: , Expression<Func<T, P>> pe)
5: {
6: if (pc != null)
7: {
8: pc.Invoke(source,
9: new PropertyChangedEventArgs(((MemberExpression)pe.Body).Member.Name));
10: }
11: }
This extension method has three arguments, the first two should be clear. The last is a LINQ expression.
When you invoke it the compiler converts this into a tree of objects, which represents the lambda expression o => o.FirstName, and passes it as an argument. This tree of objects is then traversed to find the MemberExpression which contains the name of the property. So the overhead is the creation and traversal of this small tree of objects. So it is a little less fast then passing a string, but the code is compile-time safe and supported by Visual Studio refactoring. This technique is generally known as static reflection.