【问题标题】:DependencyProperty of type ObservableCollection doesn't bindObservableCollection 类型的 DependencyProperty 不绑定
【发布时间】:2015-06-11 12:29:21
【问题描述】:

我正在尝试使用DependencyProperty 制作自定义控件。 但我无法将我的ObservableCollection 绑定到控件。 当我使用Enumerable 时,我没有问题。但我需要将项目添加到集合中,所以我唯一的选择是 ObservableCollection

创建授权:

AuthorizationsDest = new ObservableCollection<Authorization>();
        AuthorizationsDest.Add(new Authorization() { Key = "Test1", Description = "Test1", ObjectState = ObjectState.UnModified });
    }

xaml 中的自定义控件

<customControls:ListBoxEditLookup ItemsSource="{Binding Authorizations}" DisplayMember="Description" DestinationList="{Binding AuthorizationsDest}" />

DependencyProperty

[Description("Binded destination list"), Category("Data")]
    public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register("DestinationList", typeof(ObservableCollection<HrdEntity>), typeof(ListBoxEditLookup), new UIPropertyMetadata(null));
    public ObservableCollection<HrdEntity> DestinationList
    {
        get
        {
            return GetValue(ItemsProperty) as ObservableCollection<HrdEntity>;
        }
        set { SetValue(ItemsProperty, value); }
    }

【问题讨论】:

  • “不绑定”是什么意思?你有错误吗?是否记录了任何绑定警告?
  • 您为什么希望它能够工作? DestinationListObservableCollection&lt;HrdEntity&gt; 类型,而 AuthorizationsDestObservableCollection&lt;Authorization&gt; 类型。换句话说,它们有两种不兼容的类型。
  • @Ghost:这无关紧要; SO上有几十个问题可以解释为什么GenericClass&lt;Supertype&gt;GenericClass&lt;Subtype&gt;不同且不兼容,并且两者都不能分配给另一个。例如,查看thisthisthis
  • @Ghost: ItemsSource in ItemsControl 的类型为 IEnumerable(几乎所有与集合相关的类型都实现了该类型)。控件在内部检查是否可以将可枚举对象转换为更专业的集合。
  • @Ghost 假设控件中的类型是IEnumerable,您可以检查它实现了哪些接口并有条件地启用控件的某些功能。例如,if (value is INotifyCollectionChanged) 将告诉您是否可以侦听集合更改事件,if (value is IList) 将告诉您是否可以使用索引运算符对集合进行索引。将其专门输入为 ObservableCollection&lt;T&gt; 严重限制了它的使用方式(例如,我在我的项目中使用自己的 ObservableList&lt;T&gt; 类,因为 ObservableCollection&lt;T&gt; 的 API 非常有限。)

标签: c# wpf observablecollection dependency-properties


【解决方案1】:

根据对您问题的评论回复,我认为我们已经意识到在您的依赖属性上使用特定的具体集合类型会导致问题,您应该考虑使用诸如IEnumerable 之类的接口。继续阅读以获得更详细的说明。


在自定义控件中使用IEnumerable 接口作为集合依赖属性的类型通常是一个好主意。它是每个集合实现的基本接口,因为它允许在它们上运行foreach 循环。设置依赖属性后,您可以检查该值以查看它是否在您的控件中实现了您关心的其他接口。

例如,如果您的控件想要在集合中添加、删除和插入项目和/或索引等操作,请检查它是否实现了IList。如果你想观察集合的变化,检查它是否实现了INotifyCollectionChanged

考虑维护对集合的私有引用,这些引用被键入为您需要访问的接口。例如:

private IList mItemsAsList;
private INotifyCollectionChanged mItemsAsObservable;

// Call when the value of ItemsProperty changes
private void OnItemsChanged(IEnumerable newValue)
{
    if (mItemsAsObservable != null)
    {
        mItemsAsObservable.CollectionChanged -= Items_CollectionChanged;
    }

    mItemsAsList = newValue as IList;
    mItemsAsObservable = newValue as INotifyCollectionChanged;

    if (mItemsAsObservable != null)
    {
        mItemsAsObservable.CollectionChanged += Items_CollectionChanged;
    }
}

private void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // Do stuff in response to collection being changed
}

如果您的控件需要某些东西(不是可选的),如果这些要求未满足,您始终可以在属性更改回调中抛出ArgumentException。例如,如果您必须能够向集合中添加新项目:

mItemsAsList = newValue as IList;
if (newValue != null && (mItemsAsList == null || mItemsAsList.IsReadOnly || mItemsAsList.IsFixedSize))
{
    throw new ArgumentException("The supplied collection must implement IList, not be readonly, and have a variable size.", "newValue");
}

一旦您对集合有专门的引用,您就可以根据实现的接口来限制您的功能。例如,假设您要添加一个新项目:

private void AddItem(object item)
{
    // Make sure to check IsFixedSize because some collections, such as Array,
    // implement IList but throw an exception if you try to call Add on them.
    if (mItemsAsList != null && !mItemsAsList.IsReadOnly && !mItemsAsList.IsFixedSize)
    {
        mItemsAsList.Add(item);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-03
    • 1970-01-01
    • 2012-01-17
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多