WPF工具包图表 - Series.Clear()后出现NullReferenceException

3

这个错误发生在一个更复杂的环境中,但可以在这个简单的例子中复现:

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);
    }
}

点击清除,然后点击修改。清除将从图表中删除该系列并创建一个新系列。修改将修改系列绑定的源。已删除的系列调用UpdateDataPoint,其中我遇到了空引用异常:ActualDependentRangeAxis为空:

protected override void UpdateDataPoint(DataPoint dataPoint)
{
  double maximum = ActualDependentRangeAxis.GetPlotAreaCoordinate(
    ActualDependentRangeAxis.Range.Maximum).Value;

我使用的是数据可视化开发版本4.0,具体内容请参考此链接


我已经尝试了您的代码,使用3.5版本一切正常。但是我找不到4.0版本,在CodePlex上最新的版本是3.5。 - vortexwolf
这是开发版本,可以从这里下载:http://blogs.msdn.com/b/delay/archive/2010/04/20/phone-y-charts-silverlight-wpf-data-visualization-development-release-4-and-windows-phone-7-charting-sample.aspx - hansmaad
1个回答

2

我认为我已经找到了这个错误的原因。在删除每个系列之前,您应该从每个系列中移除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,事件将按照应有的方式取消订阅。 编辑 如果您快速点击修改按钮,然后立即点击清除按钮,它将在某些情况下崩溃。这是因为图表需要一些时间来取消订阅数据点并隐藏它们。
无论如何,您都可以手动取消订阅,但必须使用反射,因为必要的方法(DetachEventHandlersFromDataPointsPlotArea)是内部或私有的。
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类中,而无需使用反射,这样就可以避免额外开销。


我已经尝试过这个了。情况正在变得更好,但如果我快速点击“修改”按钮,同样的错误会再次发生。 - hansmaad
@hansmaad 我更新了答案。你应该使用清除图表数据点事件的私有方法。 - vortexwolf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接