usercontrol的子依赖项对象的绑定不起作用

时间:2011-02-10 10:39:21

标签: c# wpf binding user-controls wpf-controls

我正在尝试使用绑定来处理用户控件的子对象。 Xaml看起来像这样:

<MyGrid>
    <MyColumn ExtendedColumnData="{Binding ColumnToolTipDescriptions}"/>
</MyGrid>

以下是如何定义类:

[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));
}

据我所知,绑定甚至没有尝试获取数据,因为我尝试将转换器放在绑定上,并且Convert方法上的断点永远不会被命中。

我正在使用MVVM模式,因此窗口的DataContext属性设置为视图模型。

我已经在这里阅读了一些其他问题并尝试了各种绑定的排列,例如:

<MyColumn ExtendedColumnData="{Binding DataContext.ColumnToolTipDescriptions, ElementName=MyViewName}" />
<MyColumn ExtendedColumnData="{Binding DataContext.ColumnToolTipDescriptions, RelativeSource={RelativeSource AncestorType={x:Type local:MyView}}" />

但仍然没有运气,绑定不会开火!令人讨厌的是,这似乎工作正常(如果我将属性添加到网格):

<MyGrid ExtendedColumnData="{Binding ColumnToolTipDescriptions}">
    <MyColumn />
</MyGrid>

我对WPF没有经验,所以我确定我错过了什么?

2 个答案:

答案 0 :(得分:2)

问题是MyColumnCollection不继承数据上下文(控件的常用属性不是继承上下文的一部分)。如果您没有数据上下文绑定将无法正常工作。

要解决此问题,请尝试继承MyColumnCollection而不是ObservableCollection,而是FreezableCollection(freezable属性是继承上下文的一部分)。

答案 1 :(得分:0)

问题是逻辑树。直接解决方案应该(适合您的例子):

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();
    }
}

维护控件的逻辑树,以便将dataContext传播给子级。当您调用 AddLogicalChild 时,它会将MyGrid标记为包含逻辑子项,然后将读取 LogicalChildren 并设置这些子项的dataContext(您可以在其中侦听DataContextChanged事件) )。覆盖 LogicalChildren 是必不可少的,因为很奇怪,FrameworkElement不会通过 AddLogicalChild RemoveLogicalChild 调用保留子项列表。