- Understanding the Role of XAP Files
- The Windows Phone Capabilities Model
- The Threading Model for XAML-Based Graphics and Animation in Windows Phone
- Understanding the Frame Rate Counter
- The Windows Phone Application Analysis Tool
- Reading Device Information
- Applying the Model-View-ViewModel Pattern to a Windows Phone App
- Property Change Notification
- Using Commands
- Argument Validation
- A Platform-Agnostic Dialog Service
- Consuming Local Web Applications
- Summary
Property Change Notification
A key aspect of MVVM related to data binding is property change notification. Property change notification allows a source object (for example, a viewmodel) to signal to a target FrameworkElement that a value needs updating in the UI.
There are two ways to implement change notification in a source class: either using dependency properties or by implementing the INotifyPropertyChanged interface, which is often referred to as just INPC.
Implementing INotifyPropertyChanged: The Traditional Approach
The INotifyPropertyChanged interface has a single event called PropertyChanged. The implementation of INotifyPropertyChanged ordinarily includes the following construct:
public
event
PropertyChangedEventHandler
PropertyChanged;protected
virtual
void
OnPropertyChanged( [CallerMemberName
]string
propertyName =null
) {PropertyChangedEventHandler
tempEvent = PropertyChanged;if
(tempEvent !=null
) { tempEvent(this
,new
PropertyChangedEventArgs
(propertyName)); } }
The CallerMemberName attribute is used by a new compiler feature that automatically passes the name of the calling member to the target method. No longer is it necessary in most cases to pass the name of a property as a loosely typed string.
A property is then able to signal to a subscriber of the event that a property value needs updating, like so:
string
foo;public
string
Foo {get
{return
foo; }set
{if
(foo !=value
) { foo =value
; OnPropertyChanged(); } } }
When setting a property that is the source property of a data binding, the update must occur on the UI thread or an UnauthorizedAccessException will ensue. Source properties can be set from non-UI threads using the application’s Dispatcher as shown in the following excerpt:
Deployment
.Current.Dispatcher.BeginInvoke(delegate
{ Foo ="bah"
; });
There are a number of reasons why peppering your code with BeginInvoke calls is not a good idea. First, it imposes an unnecessary threading model on your viewmodel code. Second, it can lead to code that need not be executed on the UI thread, creeping in to the delegate. And, third, it is pretty ugly and decreases the readability of your code.
The next section looks at extracting INPC into a reusable and UI thread friendly class.
Implementing INotifyPropertyChanged: An Alternative Approach
Although there is nothing manifestly wrong with adding the OnPropertyChanged method to every class that implements INotifyPropertyChanged (apart from violating the DRY principle), it makes sense to extract the change notification code into a reusable class, because this allows you to not only reduce boilerplate code but also to add other features to the event-raising code, such as improving support for multithreaded apps and implementing INotifyPropertyChanging (as well as INotifyPropertyChanged).
The WPUnleashed project in the downloadable sample code includes such a class, named PropertyChangeNotifier. The ViewModelBase class delegates change notification to a PropertyChangeNotifier instance.
Throughout this book you frequently see viewmodel properties (with backing fields) resembling the following:
string
foo;public
string
Foo {get
{return
foo; }set
{ Assign(ref
foo,value
); } }
Here, the name of the property, the current value, and the new value are passed to the base class’s Assign method. The following excerpt shows the signature of the Assign method:
public
AssignmentResult
Assign<TField>(ref
TField field, TField newValue, [CallerMemberName
]string
propertyName =""
) { ... }
The Assign method updates the field value, while also offering the following advantages:
- The application’s Dispatcher automatically raises the PropertyChanged event on the UI thread if called from a non-UI thread. This eliminates the need to add Dispatcher.BeginInvoke calls to a viewmodel to avoid cross-thread errors.
- The Assign method also raises a PropertyChanging event. PropertyChangeNotifier implements INotifyPropertyChanging interface as well as INotifyPropertyChanged and allows a subscriber to cancel an update if desired.
- PropertyChangeNotifier assists the viewmodel in remaining UI technology agnostic. That is, retrieving an application’s Dispatcher in a Windows Phone app is done differently in a WPF application.
- PropertyChangeNotifier uses a weak reference to its owner, thereby preventing memory leaks from occurring when targets fail to unsubscribe from events.
- The single line Assign method reduces the amount of boilerplate code in properties.
The return value of the Assign method is an AssignmentResult enum value, whose values are described in the following list:
- Success—The assignment occurred and the field value now equals the new value.
- Cancelled—A subscriber to the PropertyChanging event cancelled the assignment. This relies on a custom extension to the INotifyPropertyChanging event.
- AlreadyAssigned—No assignment was made because the existing field value was already equal to the new value.
- OwnerDisposed—The PropertyChangeNotifier uses a weak reference to the object for which it is providing property changing monitoring. This value indicates that no assignment was performed because the owner object has been disposed.
Because property change notification is such a common requirement of model and viewmodel classes, for the sake of convenience a NotifyPropertyChangeBase class is also provided in the downloadable sample code. It leverages an instance of the PropertyChangeNotifier, and can be used as a base class for any class that needs INotifyPropertyChanged to be implemented.
In particular, the ViewModelBase class inherits from this class (see Figure 2.10).
FIGURE 2.10. ViewModelBase inherits from NotifyPropertyChangeBase, which has a PropertyChangeNotifier.
The implementation details of the PropertyChangeNotifier are lengthy and are not included in this section. However, you can find an article already covering the topic at http://danielvaughan.org/post/Property-Change-Notification-using-a-Weak-Referencing-Strategy.aspx.
Before moving on to commanding, be assured that you do not need to use the property notification system presented here in your own projects. If you are happy using the traditional approach to INPC, that is perfectly fine. Be mindful, however, that a lot of the phone SDK APIs have events that do not always return on the UI thread, and you may need to rely more heavily on the Dispatcher to prevent cross-thread errors.