WPF:通用集合依赖项属性

问题描述

我用通用集合依赖属性创建了自定义控件。 但是,只要从xaml更改了此属性,setter的视图模型中的值就为空。

CustomControl:

   public IList A       
   {
            get { return (IList)GetValue(AProperty); }
            set { SetValue(AProperty,value); }
   }

   public static readonly DependencyProperty AProperty =
            DependencyProperty.Register(nameof(A),typeof(IList),typeof(CustomControl),new PropertyMetadata(new List<object>()));

viewmodel:

  List<B> collectionB;
  public List<B> CollectionB
        {
            get { return collectionB; }
            set
            {
                if (collectionB == value) return;
                collectionB = value;
            }
        }
        

如果我将CollectionB的类型更改为List ,它将正常工作。

解决方法

集合属性的最通用类型是IEnumerable-例如,参见ItemsControl.ItemsSource属性。

还要注意,为集合类型依赖项属性设置非空默认值是有问题的,因为拥有类的所有实例默认情况下都将在同一集合实例上运行。将一个元素添加到一个控件的A属性将更改所有其他控件实例的集合。

您应该这样声明属性:

public IEnumerable A       
{
    get { return (IEnumerable)GetValue(AProperty); }
    set { SetValue(AProperty,value); }
}

public static readonly DependencyProperty AProperty =
    DependencyProperty.Register(
        nameof(A),typeof(IEnumerable),typeof(CustomControl));

如果您确实需要一个非空的默认值,请将其添加到控件的构造函数中:

SetCurrentValue(AProperty,new List<object>());

更新:对集合类型属性使用OneWayToSource绑定

<local:CustomControl A="{Binding CollectionB,Mode=OneWayToSource}" />

仅在A的默认值与绑定的source属性赋值兼容时有效,该属性不适用于List<object>List<B>

您应该根本不设置默认值,而应使用TwoWay绑定

<local:CustomControl A="{Binding CollectionB,Mode=TwoWay}" />

使用

private List<B> collectionB = new List<B>();

public List<B> CollectionB
{
    get { return collectionB; }
    set { collectionB = value; }
}

或者只是

public List<B> CollectionB { get; set; } = new List<B>();
,

这是因为IList<T>没有实现IList,所以从一种类型转换为另一种类型将失败。

如果您想与A绑定,则必须将其绑定到也正在实现IList的东西上