I'm trying to get a binding to work on a child object of a user control. The Xaml looks like this:
<MyGrid>
<MyColumn ExtendedColumnData="{Binding ColumnToolTipDescriptions}"/>
</MyGrid>
Here is how the classes are defined:
[ContentProperty("Columns")]
public class MyGrid : UserControl
{
private MyColumnCollection _columns;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Category("Data")]
public MyColumnCollection Columns
{
get
{
if (_columns == null)
_columns = new MyColumnCollection();
return _columns;
}
}
}
public class MyColumnCollection : ObservableCollection<MyGridColumn>
{
}
public class MyGridColumn : DependencyObject
{
public object ExtendedColumnData
{
get { return (object)GetValue(ExtendedColumnDataProperty); }
set { SetValue(ExtendedColumnDataProperty, value); }
}
public static readonly DependencyProperty ExtendedColumnDataProperty =
DependencyProperty.Register("ExtendedColumnData", typeof(object), typeof(MyGridColumn), new UIPropertyMetadata(null));
}
From what I can tell, the binding is not even attempting to get the data as I've tried putting a converter against the binding, and the breakpoint on the Convert method never gets hit.
I'm using the MVVM pattern so the window's DataContext
property is set to a view model.
I've read some other questions on here and tried various permutations of the binding such as:
<MyColumn ExtendedColumnData="{Binding DataContext.ColumnToolTipDescriptions, ElementName=MyViewName}" />
<MyColumn ExtendedColumnData="{Binding DataContext.ColumnToolTipDescriptions, RelativeSource={RelativeSource AncestorType={x:Type local:MyView}}" />
But still no luck, the binding doesn't fire! The annoying thing is, this seems to work fine (if I add the property to the grid):
<MyGrid ExtendedColumnData="{Binding ColumnToolTipDescriptions}">
<MyColumn />
</MyGrid>
I'm not that experienced with WPF so I'm sure I'm missing something?
The problem is that
MyColumnCollection
is not inheriting data context (usual properties of a control are not part of inheritance context). If you don't have a data context bindings will not work.To fix that, try inheriting
MyColumnCollection
not fromObservableCollection
, but fromFreezableCollection
(freezable properties are part of inheritance context).The problem is logical tree. The direct solution should be (adapted to your example):
to maintain the logical tree of controls in order for dataContext to be propagated to children. When you call AddLogicalChild, it marks MyGrid as containing logical children, then LogicalChildren will be read and the dataContext of those children will be set (you can listen to DataContextChanged event in them). Overriding LogicalChildren is essential because FrameworkElement doesn't keep the list of children through AddLogicalChild and RemoveLogicalChild calls, oddly.