我正在尝试使用绑定来处理用户控件的子对象。 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没有经验,所以我确定我错过了什么?
答案 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 调用保留子项列表。