|
| 1 | +# WPF Binding stops working after an item container leaves the visual tree |
| 2 | + |
| 3 | +## Symptoms |
| 4 | +This issue affects bindings whose path contains an explicit use of the `DataContext` |
| 5 | +property of an element that belongs to the subtree generated for an item within an |
| 6 | +`System.Windows.Controls.ItemsControl`. When the element leaves the visual tree, |
| 7 | +the binding stops working; any subsequent changes to other properties mentioned in |
| 8 | +the path are ignored. |
| 9 | + |
| 10 | +The visible symptoms depend on how the binding is used. For example, an app |
| 11 | +may want to share a `System.Windows.Controls.ContextMenu` among the |
| 12 | +item containers within an `System.Windows.Controls.ItemsControl`, and have the |
| 13 | +content and behavior of the menu depend on the item container for which it is |
| 14 | +displayed. This can be implemented by declaring the menu as a resource and binding its |
| 15 | +`DataContext` to that of its `PlacementTarget`: |
| 16 | + |
| 17 | +```xml |
| 18 | +<UserControl.Resources> |
| 19 | + <ContextMenu x:Key="SharedContextMenu" |
| 20 | + DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}"> |
| 21 | + ... other content ... |
| 22 | + </ContextMenu> |
| 23 | +</UserControl.Resources> |
| 24 | +``` |
| 25 | + |
| 26 | +Then refer to the resource in the appropriate data template: |
| 27 | + |
| 28 | +```xml |
| 29 | +<DataTemplate> |
| 30 | + <StackPanel ContextMenu="{StaticResource SharedContextMenu}"> |
| 31 | + ... other content .... |
| 32 | + </StackPanel> |
| 33 | +</DataTemplate> |
| 34 | +``` |
| 35 | + |
| 36 | +When the user right-clicks the `StackPanel` for a particular data item, the shared context menu |
| 37 | +is displayed, its `PlacementTarget` is changed to be the `StackPanel`, the binding sets its |
| 38 | +`DataContext` to the data item, and the menu's content and behavior can depend on the data item. |
| 39 | + |
| 40 | +The issue arises if the app removes the item container from the visual tree while the menu |
| 41 | +is visible. (There are many ways this can happen: removing the data item from the underlying |
| 42 | +collection, replacing the `ItemsSource`, scrolling enough to re-virtualize the data item, etc.) |
| 43 | +When this happens, the binding stops working, and any subsequent changes to the `PlacementTarget` |
| 44 | +property are ignored. The visible symptom is that right-clicking a different data item |
| 45 | +will bring up the menu and reset its `PlacementTarget`, but its content and behavior are |
| 46 | +still attached to the original item rather than to the newly-chosen one. |
| 47 | + |
| 48 | +## Cause |
| 49 | +When an item container leaves the visual tree, its `DataContext` is changed to `{DisconnectedItem}`. |
| 50 | +The binding recognizes this sentinel value and suppresses the normal data transfer, but |
| 51 | +mistakenly leaves itself in a state where it ignores subsequent changes to other properties |
| 52 | +along the path (such as `PlacementTarget` in the example). |
| 53 | + |
| 54 | +## Resolution |
| 55 | +A hotfix for this issue is planned for .Net Framework 4.8. This page will be updated with a link to the hotfix when it becomes available. |
0 commit comments