Bindings on child dependency object of usercontrol not working

拈花ヽ惹草 提交于 2019-12-30 10:00:24

问题


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?


回答1:


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 from ObservableCollection, but from FreezableCollection (freezable properties are part of inheritance context).




回答2:


The problem is logical tree. The direct solution should be (adapted to your example):

public MyColumnCollection Columns
{
    get
    {
        if (_columns == null)
        {
            _columns = new MyColumnCollection();
            _columns.CollectionChanged += Columns_CollectionChanged;
        }
        return _columns;
    }
}

private void Columns_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.NewItems != null)
    {
        foreach (var item in e.NewItems)
        {
            AddLogicalChild(item);
        }
    }
    if (e.OldItems != null)
    {
        foreach (var item in e.OldItems)
        {
            RemoveLogicalChild(item);
        }
    }
    // not sure about Action == reset
}

protected override IEnumerator LogicalChildren
{
    get
    {
        return _columns == null ? null : _columns.GetEnumerator();
    }
}

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.



来源:https://stackoverflow.com/questions/4956041/bindings-on-child-dependency-object-of-usercontrol-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!