2013-03-12 3 views
3

Ошибка возникает в гораздо более сложном контексте, но могут быть воспроизведены в этом простом примере:WPF Chart Toolkit - NullReferenceException после Series.Clear()

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

нажмите на Clear затем нажмите на Modify. Clear удаляет серию из диаграммы и создает новую. Modify изменяет источник привязок к ряду. Удаленные серии называют UpdateDataPoint где я получаю NullReferenceException: ActualDependentRangeAxis равно нулю:

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

Я использую Data Visualization Development Releases 4.0

+0

Я пробовал ваш код с версией 3.5, и все работало нормально. И я не могу найти версию 4, на codeplex последняя версия - 3.5. – vorrtex

+0

Это релиз разработки отсюда: 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

ответ

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 - события будут отписался, как это должно быть.

Редактировать

Это будет врезаться в одном случае, если вы нажмете быстро кнопку Изменить, а затем immideately кнопку Очистить. Это происходит потому, что диаграмме требуется некоторое время, чтобы отменить подписку на информационные точки из событий и скрыть их.

В любом случае вы можете отказаться от подписки вручную, но вам нужно использовать рефлексию, потому что необходимые методы (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 класса, то он будет выполнен без накладных расходов.

+0

Я уже пробовал это. Все становится лучше, но если я нажимаю кнопку «Модифицировать-щелкнуть» достаточно быстро, повторяется такая же ошибка. – hansmaad

+0

@ hansmaad Я обновил ответ. Вы должны использовать закрытый метод, который очищает события от точек данных диаграммы. – vorrtex