WPF工具箱图-在Series.Clear()之后的NullReferenceException
本文关键字:之后 NullReferenceException Clear Series 工具箱 WPF | 更新日期: 2023-09-27 18:03:26
错误发生在更复杂的上下文中,但可以在这个简单的示例中重现:
MainWindow.xaml
<Window>
<StackPanel>
<Button Click="Button_Click_1">Clear</Button>
<Button Click="Button_Click_2">Modify</Button>
<charting:Chart x:Name="chart" />
</StackPanel>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
Random rand = new Random();
ObservableCollection<KeyValuePair<double, double>> values =
new ObservableCollection<KeyValuePair<double, double>>();
public MainWindow()
{
InitializeComponent();
values.Add(new KeyValuePair<double, double>(10, 10));
values.Add(new KeyValuePair<double, double>(20, 40));
values.Add(new KeyValuePair<double, double>(30, 90));
values.Add(new KeyValuePair<double, double>(40, 160));
values.Add(new KeyValuePair<double, double>(50, 250));
AddSeries();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
chart.Series.Clear();
AddSeries();
}
private void AddSeries()
{
var series = new LineSeries();
series.SetBinding(LineSeries.ItemsSourceProperty, new Binding());
series.DataContext = values;
series.DependentValueBinding = new Binding("Value");
series.IndependentValueBinding = new Binding("Key");
chart.Series.Add(series);
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
values[3] = new KeyValuePair<double,double>(40, rand.NextDouble() * 300);
}
}
点击清除,然后点击修改。清除从图表中删除该系列并创建一个新系列。Modify修改系列绑定的源。删除的系列调用UpdateDataPoint
,我得到一个NullReferenceException: ActualDependentRangeAxis
是空的:
protected override void UpdateDataPoint(DataPoint dataPoint)
{
double maximum = ActualDependentRangeAxis.GetPlotAreaCoordinate(
ActualDependentRangeAxis.Range.Maximum).Value;
我使用数据可视化开发版本4.0
我想我已经找到这个错误的原因了。在删除它们之前,您应该从每个系列中删除DataContext
:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
foreach (var series in chart.Series.OfType<Series>())
{
series.DataContext = null;
}
chart.Series.Clear();
AddSeries();
}
如果您清除DataContext
-事件将取消订阅,因为它应该。
编辑
在一种情况下,如果你快速点击修改按钮,然后立即点击清除按钮,它会崩溃。这是因为图表需要一些时间从事件中取消订阅数据点并隐藏它们。无论如何,你可以手动取消订阅,但你必须使用反射,因为必要的方法(DetachEventHandlersFromDataPoints
和PlotArea
)是内部的或私有的。
private void Button_Click_1(object sender, RoutedEventArgs e)
{
this.DetachAllEventsFromSeries();
chart.Series.Clear();
AddSeries();
}
private void DetachAllEventsFromSeries()
{
var plotAreaProperty = typeof(DataPointSeries).GetProperty("PlotArea", BindingFlags.Instance | BindingFlags.NonPublic);
var detachMethod = typeof(DataPointSeries).GetMethod("DetachEventHandlersFromDataPoints", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var series in chart.Series.OfType<DataPointSeries>().ToList())
{
var plotArea = (Panel)plotAreaProperty.GetValue(series, null);
if (plotArea == null)
{
continue;
}
var datapoints = plotArea.Children.OfType<DataPoint>().ToList();
detachMethod.Invoke(series, new[] { datapoints });
}
}
此外,如果您有可能重新编译工具包库,您可以将此方法添加到DataPointSeries
类中,而不需要反射,然后它将在没有开销的情况下执行。