This is old news, in fact it’s been known about since 2007 and it’s by design. However, it came up at work today and it’s a surprise to me. Since it’s by design however, it’s both easy to fall into and easy to work around.
Here’s the Microsoft support ticket.
https://support.microsoft.com/en-us/kb/938416
Note that it hasn’t been modified since 2007, and yet, this is the first I’ve heard of this. Maybe this makes me a bad developer, or someone who didn’t fully take on the technicalities of what’s actually happening under the hood. The latter, hopefully.
The ticket does a decent job of explaining the detail it in fairness so please go and read that.
Here’s the short, simplified version:
- Bindings are designed to work with Dependency Properties or classes that implement INotifyPropertyChanged.
- Bindings that are to properties that don’t fit that criteria bind via the PropertyDescriptor and create strong object references, which can stop these objects from being garbage collected.
So how should you avoid this
<Label Name="MyLabel"> <Stack Panel Name="MyStackPanel"> <TextBlock Text="{Binding ElementName=MyStackPanel, Path=Children.Count}" /> </StackPanel> </Label>
The good news is that the ways to avoid these things have long been seen as good practice. That said, it’s good to be reminded, and things like the sample above really are not that obvious.
- In general, don’t create data bindings to plain C# classes. Follow the MVVM pattern and implement INotifyPropertyChanged, and have the properties you bind to use it.
- When you want to bind to a collection in your view model and use the properties of the collection in your binding (rather then properties on the collection items, which should come under point 1), use ObservableCollection which does implement INotifyPropertyChanged, or CollectionViewSource to wrap a different collection type, rather than collections or interfaces like List or IEnumerable which don’t.
- Use OneTime binding. This is one way to not need to implement INotifyPropertyChanged. Of course, it’s only really useful if the view you are using is showing static information and not likely to be interacted with. TextBlock’s are often great candidates for OneTime binding (I think the default in WPF for the Text Property is OneWay, meaning they respond to ViewModel updates).
- Bind to dependency properties part 1. One place you might do this is binding to elements in a custom control to properties on an associated class.
- Watch out when binding to properties on other controls. As the example in the Microsoft explanation points out (and copied above), it’s easy to quickly bind to regular CLR properties. e.g StackPanel.Children.Count (Children is a UIElementCollection that doesn’t implement INotifyPropertyChanged or INotifyCollectionChanged).
If you do think you might have memory leaks created by this, there are some bits of info on solving these in the following (dated but still useful) posts:
Cory Plotts: WPF and Memory Leaks
Jossef Goldberg: Finding Memory Leaks in WPF-based applications