I’ve got an extension method that I use to fire PropertyChanged notifications that looks something like this:
public static TRet RaiseIfChanged<TObj, TRet>(this TObj target, Expression<Func<TObj, TRet>> property, TRet newValue)
where TObj : AlantaViewModelBase
{
var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo;
var propertyValue = propertyInfo.GetValue(target, null);
if (!EqualityComparer<TRet>.Default.Equals((TRet)propertyValue, (TRet)newValue))
{
// Marshal this to the dispatcher so that the RaisePropertyChanged() notification happens after
// the value is actually set.
Deployment.Current.Dispatcher.BeginInvoke(() => target.RaisePropertyChanged(propertyInfo.Name));
}
return newValue;
}
It gets used like this:
private bool isBusy;
public bool IsBusy
{
get { return isBusy; }
set { isBusy = this.RaiseIfChanged(p => p.IsBusy, value); }
}
My question is about the Dispatcher.BeginInvoke() that I use to actually call the target.RaisePropertyChanged(). Given that the property won’t actually change until the extension method completes, I need to be confident that the event won’t actually get raised until after the property’s value has been set. Can I be confident that this will always be the case? Or are there instances when the event will get fired before the property has changed? Or is there a better way to handle this?
You have no such guarantee. The exact time the RaisePropertyChanged() method runs greatly depends on the state of the UI thread. And if it just happens to be ready to look at the invoke queue for invoke targets to execute at the exact time your worker thread calls RaiseIfChanged and the worker thread loses it processor quantum then, yes, that call is going to be made before the worker can return and set the property value. Unlikely, but the road of good threading intentions is littered with roadkill like this.
You have to assign the property before raising the event. The un-dry test-and-set is pretty simple. Keep dry but ugly by using PropertyInfo.SetValue() or passing the backing variable by reference. Personally I wouldn’t, using reflection to read the property value is an easy three orders of magnitude slower than just coding this directly.