In WPF, a Binding’s source can be any .NET object;
the target of the Binding will be updated when the specified property on that
source changes. This works best when the source property is a
DependencyProperty, or when the source object
implements INotifyPropertyChanged; these objects
have built-in support for property value changed notifications. In other
cases, the ComponentModel infrastructure (as exposed by the
PropertyDescriptor class) stores the
source object in a global table in order to track clients who wish to be
notified when a property value changes.
Binding to a regular property of a regular .NET object (that doesn’t implement
INotifyPropertyChanged) has two drawbacks:
It may be needlessly inefficient. If, for example, the source object is not implementing INotifyPropertyChanged because it’s immutable, creating and attaching value changed handlers is unnecessary overhead.
Both these problems can be eliminated by setting the
Mode of the Binding to
OneTime, but in a large
application, determining all the bindings that could be OneTime is not an easy
task. Some spelunking (with .NET Memory Profiler
and .NET Reflector) showed that
the (internal) ReflectTypeDescriptionProvider class has a static Hashtable
containing all objects that have had value changed handlers added. A common
reason for objects to end up in that Hashtable is their participation in a WPF
binding, so enumerating this Hashtable at runtime can help track down bindings
that may need to be changed. (And if an object is never removed from this
hashtable, that may be a sign of a memory leak.)
This method uses reflection to dump the contents of the
ReflectTypeDescriptionProvider._propertyCache hashtable for diagnostic
purposes (the definition of the ReflectPropertyDescriptorInfo class is given
later):
The following code implements a window that displays all the properties that
were found. It can be used by adding it to a WPF application and creating a
special diagnostic button or keystroke that opens the window. You can open two
windows and compare the lists side-by-side, or use the Refresh button to
regenerate the list (after interacting with your application’s UI) to see if
any properties have been added or removed.
ReflectPropertyDescriptorWindow.xaml:
ReflectPropertyDescriptorWindow.xaml.cs:
And finally, the definition of the immutable ReflectPropertyDescriptorInfo
object, which is used as the source of a OneTime binding in the UI: