自定义控件中的依赖项属性意外共享内存/值

本文关键字:共享 内存 意外 属性 依赖 自定义控件 | 更新日期: 2023-09-27 18:34:06

我有以下设置:

  • 自定义 WPF 控件(基类(,派生自Canvas
  • 该基类的实现
  • 该实现的ObservableCollection<T>依赖项属性

我有一个测试应用程序,它显示我的自定义控件的三个唯一实例(例如 <custom:MyControl x:Name="Test1" />、测试2、测试3等(。当我运行和调试应用程序时,ObservableCollection<T>的内容对于控件的所有三个实例都是相同的。这是为什么呢?


图表:

[ContentProperty("DataGroups")]
public abstract class Chart : Canvas
{
    static Chart()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(Chart), new FrameworkPropertyMetadata(typeof(Chart)));
    }
    public ObservableCollection<ChartData> DataGroups
    {
        get { return (ObservableCollection<ChartData>)GetValue(DataGroupsProperty); }
        set { SetValue(DataGroupsProperty, value); }
    }
    public static readonly DependencyProperty DataGroupsProperty =
        DependencyProperty.Register("DataGroups", typeof(ObservableCollection<ChartData>), typeof(Chart), new FrameworkPropertyMetadata(new ObservableCollection<ChartData>(), FrameworkPropertyMetadataOptions.AffectsArrange));
    public abstract void Refresh();
}

图表数据:

[ContentProperty("Points")]
public class ChartData : FrameworkElement
{
    public ObservableCollection<Point> Points
    {
        get { return (ObservableCollection<Point>)GetValue(PointsProperty); }
        set { SetValue(PointsProperty, value); }
    }
    public static readonly DependencyProperty PointsProperty =
        DependencyProperty.Register("Points", typeof(ObservableCollection<Point>), typeof(ChartData), new PropertyMetadata(new ObservableCollection<Point>()));
}

我修改图表数据的一种方法是(假设有多个数据组(,例如:

MyChart.DataGroups[index].Points.Add(new Point() { Y = someNumber });
MyChart.Refresh();

但是DataGroups[]中的每个实例都是相同的。


如果我通过 XAML 定义我的集合,也会发生同样的事情,如下所示:

<c:Chart x:Name="ChartA">
    <c:ChartData x:Name="DataGroup1" />
    <c:ChartData x:Name="DataGroup2" />
</c:Chart>

然后,在代码中,我将访问定义的集合:

ChartA.DataGroups[0].Points.Add(new Point() { Y = someNumber });
ChartA.Refresh();

自定义控件中的依赖项属性意外共享内存/值

你没有做错任何事。这是设计使然。它应该以这种方式工作。只需在构造函数中设置您的值,您将不会有单例。

http://msdn.microsoft.com/en-us/library/aa970563.aspx

初始化超出默认值的集合

创建依赖属性时,不要将属性默认值指定为初始字段值。而是通过依赖项属性元数据指定默认值。如果属性是引用类型,则依赖项属性元数据中指定的默认值不是每个实例的默认值;相反,它是应用于该类型的所有实例的默认值。因此,必须注意不要将集合属性元数据定义的单一静态集合用作新创建的类型实例的工作默认值。相反,必须确保有意将集合值设置为唯一(实例(集合,作为类构造函数逻辑的一部分。否则,您将创建一个无意的单例类。

PointsProperty是一个静态值,您可以使用默认值 new ObservableCollection<Point>() 初始化。此静态初始值设定项创建单个ObservableCollection,并将其用作您创建的任何类型为 ChartData 的对象Points的默认值。它不是为每个需要默认值的实例创建新ObservableCollection的工厂;它只是对每个使用相同的ObservableCollection

我猜你从来没有显式地为Points赋值,因此始终依赖于默认值,该值在所有实例之间共享。这就是为什么每个实例都有相同的点集合。