问题
I have the following set up:
- Custom WPF Control (Base class), deriving from
Canvas
- Implementation of that base class
- An
ObservableCollection<T>
dependency property on that implementation
I have a test app that displays three unique instances of my custom control (e.g. <custom:MyControl x:Name="Test1" />
, Test2, Test3, and so on). When I run and debug the app, the contents of the ObservableCollection<T>
are the same for all three instances of the control. Why is this?
Chart:
[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();
}
ChartData:
[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>()));
}
One way I modify the chart data is (assuming multiple data groups), for example:
MyChart.DataGroups[index].Points.Add(new Point() { Y = someNumber });
MyChart.Refresh();
But every instance inside DataGroups[]
is identical.
The same thing is happening if I define my collection(s) via XAML, like so:
<c:Chart x:Name="ChartA">
<c:ChartData x:Name="DataGroup1" />
<c:ChartData x:Name="DataGroup2" />
</c:Chart>
Then, in code, I would access the defined collections:
ChartA.DataGroups[0].Points.Add(new Point() { Y = someNumber });
ChartA.Refresh();
回答1:
You havent done anything wrong. It is by design. It shall work that way. Just set your value in constructor instead and you will not have a singleton.
http://msdn.microsoft.com/en-us/library/aa970563.aspx
Initializing the Collection Beyond the Default Value
When you create a dependency property, you do not specify the property default value as the initial field value. Instead, you specify the default value through the dependency property metadata. If your property is a reference type, the default value specified in dependency property metadata is not a default value per instance; instead it is a default value that applies to all instances of the type. Therefore you must be careful to not use the singular static collection defined by the collection property metadata as the working default value for newly created instances of your type. Instead, you must make sure that you deliberately set the collection value to a unique (instance) collection as part of your class constructor logic. Otherwise you will have created an unintentional singleton class.
回答2:
PointsProperty
is a static value that you initialize with a default value of new ObservableCollection<Point>()
. This static initializer creates a single ObservableCollection
and uses that as the default value for Points
on any object of type ChartData
that you create. It is not a factory that creates new ObservableCollection
s for every instance that needs a default value; it simply uses the same ObservableCollection
for each.
I'm guessing that you never explicitly assign a value to Points
, thus always relying on the default value, which is shared across all instances. That's why each instance has the same collection of points.
来源:https://stackoverflow.com/questions/19217208/dependency-property-in-custom-control-is-sharing-memory-values-unexpectedly