-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
In WPF you can bind to a control's DependencyProperty or a property on a view model (implementing INotifyPropertyChanged), which are fine, but if you bind to a property on an immutable model (not implementing INotifyPropertyChanged) it falls back to using a PropertyDescriptor.AddValueChanged listener, which causes a binding leak (reported by Snoop, documented here. As far as I can tell, this only makes some sense if it follows the WinForms pattern (a specific change event is present) or the property is writable (so multiple controls setting the value via the PropertyDescriptor will be notified about those changes, but not when changed directly in M/VM code).
Here's where the PropertyDescriptor accessor is chosen:
wpf/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPath.cs
Lines 619 to 627 in 42f7d5d
| // 4. PropertyDescriptor (obtain from item - this is reputedly | |
| // slower than obtaining from type, but the latter doesn't | |
| // discover properties obtained from TypeDescriptorProvider - | |
| // see bug 1713000). | |
| // This supports the WinForms ValueChanged pattern. | |
| if (accessor == null && item != null) | |
| { | |
| accessor = TypeDescriptor.GetProperties(item)[propertyName]; | |
| } |
I've only recently become aware of this issue, but clearly it's been around a long time, and I wonder if it can be mostly fixed just by adding some checks before choosing to use a PropertyDescriptor.AddValueChanged listener, firstly looking for the WinForms event, and secondly checking for a public setter on the PropertyInfo for the instance being accessed. If neither of these are present, then it seems better to fall through to the PropertyInfo option below, which hopefully makes it effectively a one-time binding, but that can still be re-evaluated if a parent property that does notify changes.
I'm sure there are people who know this part of the framework much better than I, so please let me know if there is a fundamental problem with my suggestion, or if there is a better solution for avoiding this problem without requiring everything to implement INotifyPropertyChanged.