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.
Note
To determine whether the PropertyChanged
event field has any subscribers, it is copied to a temporary local variable, which allows you to then test whether it is null in a thread-safe manner. Without first obtaining a copy, another thread could potentially unsubscribe from the event after the null check but before the event is raised, which would inadvertently lead to a NullReferenceException
being thrown.
An alternative that avoids the null check is to assign the event to an empty handler, as shown:
public event PropertyChangingEventHandler PropertyChanging = delegate {};
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.
18.224.67.84