WPF Charting Toolkit - LineSeries Points not clearing when chart ItemsSource updated

Answered WPF Charting Toolkit - LineSeries Points not clearing when chart ItemsSource updated

  • Sunday, August 14, 2011 6:39 AM
     
     

    I have a user control that contains a line chart bound to an observable collection in an object:

    <chartingToolkit:Chart  Grid.Row="5" Name="chart" Padding="2" Grid.Column="0" Grid.ColumnSpan="4" BorderBrush="{x:Null}">

                <!-- Tempurature Curve -->

                <chartingToolkit:LineSeries

                                Title="Temperature"

                                Name="TemperatureSeries"

                                ItemsSource="{Binding Path=Entries}"

                                IndependentValueBinding="{Binding ProcessTime}"

                                DependentValueBinding="{Binding Temperature}">

                    <!-- Vertical axis for power curve -->

                    <chartingToolkit:LineSeries.DependentRangeAxis>

                        <chartingToolkit:LinearAxis

                                        Orientation="Y"

                                        Title="Temperature (&#176;F)"

                                        Minimum="0"

                                        Maximum="500"

                                        Interval="100"

                                        ShowGridLines="True"/>

                    </chartingToolkit:LineSeries.DependentRangeAxis>

                </chartingToolkit:LineSeries>

                <!-- Torque curve -->

                <chartingToolkit:LineSeries

                                Title="Pressure"

                                Name="PressureSeries"

                                ItemsSource="{Binding Path=Entries}"

                                IndependentValueBinding="{Binding ProcessTime}"

                                DependentValueBinding="{Binding Pressure}">

                    <!-- Vertical axis for torque curve -->

                    <chartingToolkit:LineSeries.DependentRangeAxis>

                        <chartingToolkit:LinearAxis

                                        Orientation="Y"

                                        Title="Pressure (psi)"

                                        Minimum="0"

                                        Maximum="700"

                                        Interval="100"/>

                    </chartingToolkit:LineSeries.DependentRangeAxis>

                </chartingToolkit:LineSeries>

                <chartingToolkit:Chart.Axes>

                    <!-- Shared horizontal axis -->

                    <chartingToolkit:LinearAxis

                                    Orientation="X"

                                    Title="Time (s)"

                                    Interval="{Binding Path=IdealChartXAxisDivision}"

                                    ShowGridLines="True"/>

                </chartingToolkit:Chart.Axes>

            </chartingToolkit:Chart>

     

    The data source is set in a grid that contains the cart and is updated via a dispatch timer.

    At a certain point I need to clear the chart data and start fresh but at least 50% of the time the chart lines clear but the points remain.

    I have tried the following:

     - Calling .Clear on the observable collection in the data source object.

     - Individually removing the entries in the observable collection in the data source object.

     - Setting the data source of the grid to null and then setting it to a new instance of the object.

     - Calling .Clear of the Points collection for each line series

     - Individually removing each point from each line series point collection.

     Each of these methods have had mixed results, often clearing the first time but not the second,.. but sometimes not clearing the first time.

    Any suggestions would be appreciated.

    The DataVisualization.Toolkit version I am using is: 3.5.40128.1

    Thank You.

All Replies

  • Sunday, August 14, 2011 12:55 PM
     
     

    Hello,

    can you post little code about your DispatcherTimer, how often it updates etc. Thank you.

  • Sunday, August 14, 2011 3:28 PM
     
      Has Code

    Not much to it really

    public delegate void CookCompleteEventHandler(object sender, EventArgs e);
    
      public class Cook : INotifyPropertyChanged, IDataErrorInfo
      {
    
        public ObservableCollection<CookEntry> Entries { get; set; }
    
    
     
        public event PropertyChangedEventHandler PropertyChanged;
        public event CookCompleteEventHandler CookComplete;
    
        public Cook()
        {
          LogInterval = Properties.Settings.Default.MinimumLogInterval;
          Entries = new ObservableCollection<CookEntry>();
          _logger = new CookLogger();
          OnPropertyChanged("Entries");
          
      
          _timer = new DispatcherTimer {IsEnabled = false};
          _timer.Tick += TimerTick;
        }
    
        
        
        public void Start()
        {
          if (!_device.Running)
          {
            //This is a new cook
            CookStartDate = DateTime.Now;
            _logger.SaveCook(this);
    
            _device.CookTime = CookTime;
            
            //log data at T=0
            var entry = ReadEntryFromDevice();
            _logger.SaveCookEntry(entry);
            Entries.Add(entry);
    
            //Tell the digester to start cooking
            _device.Start = true;
            //update the state
    
          }
          _timer.Interval = TimeSpan.FromSeconds(LogInterval);
          _timer.IsEnabled = true;
    
        }
    
        private void TimerTick(object sender, EventArgs e)
        {
            var entry = ReadEntryFromDevice();
            _logger.SaveCookEntry(entry);
            Entries.Add(entry);
    
            //Check to see if the cook is done
            if(!_device.Running)
            {
              State = CookState.Complete;
              _timer.IsEnabled = false;
              LogCookComplete();
              
            }
          }
        }
    
        private void LogCookComplete()
        {
          
          CookEndDate = DateTime.Now;
    
          _logger.SaveCook(this);
    
          State = CookState.Idle;
    
          if (CookComplete != null)
          {
            CookComplete(this, new EventArgs());
          }
        }
    
        private void OnPropertyChanged(string propertyName)
        {
          if (PropertyChanged != null)
          {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
          }
        }
    
      }
    


    The chart binding is set up like this:

     <chartingToolkit:Chart Grid.Row="5" Name="chart" Padding="2" Grid.Column="0" Grid.ColumnSpan="4" BorderBrush="{x:Null}">
          <!-- Tempurature Curve -->
          <chartingToolkit:LineSeries
                  Title="Temperature"
                  Name="TemperatureSeries"
                  ItemsSource="{Binding Path=Entries}"
                  IndependentValueBinding="{Binding ProcessTime}"
                  DependentValueBinding="{Binding Temperature}">
    


    The chart is in a grid that has its data source set to a cook object I am using the CookComplete event to try and clean up the chart:

        void CookCookComplete(object sender, EventArgs e)
        {
          //Tried removing points 1 by 1
          var pointCount = PressureSeries.Points.Count;
    
          for (var i = 0; i < pointCount; i++ )
          {
            PressureSeries.Points.RemoveAt(0);
    
            TemperatureSeries.Points.RemoveAt(0);
    
          }
          //Tried clearing the points collection
          PressureSeries.Points.Clear();
          TemperatureSeries.Points.Clear();
          //Tried resetting the data context
          mainGrid.DataContext = null;
          _cook = null;
    );
          _cook = new Cook(()
    
          mainGrid.DataContext = _cook;
          _cook.CookComplete += CookCookComplete;
    
          
        }
    


    I also tried:

    Clearing the Entries collection in the cook object.

    Removing Entries 1 by 1 in the cook object.

     


    scrock
  • Sunday, August 14, 2011 5:34 PM
     
     

    Hello again,

    whats the default interval for the timer you get the time form somewhere else? WPF and Silverlight work default with 60 frames per second, if the timer is too fast that might make a problem, calling the timer tick event before rerendering the timer So you must call the timer maximum 60 times per second, but i think the problems lies somewhere else.. Also you create each time a new timer by calling _cook = new Cook(), and this will cause creating multple instances of the timer. The DispatchTimer when started adds itself to a collection of timers and if you dont stop it, it will be never get to the garbagecollector. Also this way you root the object in which the timer is and _cook is also never going to the garbagecollector. I think you should modify the code, not creating everytime new timer. Good luck hope this info helps you.

  • Sunday, August 14, 2011 6:05 PM
     
     

    Hi Dimitar,

     

    Thanks for the advice but I don't believe the problem is with the the DispatchTimer.  I am running the timer at a 10 second interval.  I had started to create a new cook object as a work around to this very problem (with no success actually).

    I had the same issue with the chart when I was using the same instance of cook and clearing the collection. 

    Clearing the collection, and now creating a new instance of the cook happen only after the timer is disabled.


    scrock
  • Sunday, August 14, 2011 6:43 PM
     
     

    Xmm it might be than again some bug with the Chart control. Your collections are ObservableCollections so when you add and remove item the UI should refresh and as you said you are crated new instances of the object just to check if it will help. How often the but with the points occur? Everytime or the application needs some time working and than the bug appears?The chart control still have some bugs, before month i encounter very bad architecture when changing the date intevral to seconds.

  • Sunday, August 14, 2011 7:05 PM
     
     Answered

    Hi Dimitar,

    I think I have sorted it out and it does appear to be a bug in the chart control.  It seems that it was because I was adding the last entry to the list and then clearing the list immediately.  It seems like maybe this was causing the list to be emptied before the chart control had finished calculating the points and rendering from the last entry added.  By not clearing the entry until the next tick of the timer after the last entry has been added it seems like it gives the chart the delay it needs and now it cleans itself nicely.

    I guess my users are just going to have to wait a few extra seconds between runs.

    Thanks for you help.


    scrock
    • Marked As Answer by scrock Sunday, August 14, 2011 7:05 PM
    •  
  • Sunday, July 29, 2012 2:08 PM
     
     

     We also meet this kind of issue on "columnseries" chart. If we refresh the column chart for 2 times every second, the chart will stop updating after several times running.

    Is there are some solution or workaround?


    Guo

  • Monday, October 22, 2012 9:26 AM
     
     

    A) Add this class to your project (visual basic)

    Imports System.Windows.Threading

    Public Class ThreadHelper

        ''' <summary>
        ''' Force rendering
        ''' </summary>
        Public Shared Sub FlushWindowsMessageQueue()
            Application.Current.Dispatcher.Invoke( _
                New Action(AddressOf DummySub), _
                DispatcherPriority.Background, _
                New Object() {})
        End Sub

        Private Shared Sub DummySub()
        End Sub

    End Class

    B) Refresh chart :

    ChartSerie1.ItemsSource = Nothing     ' clear the datasource chart

    ThreadHelper.FlushWindowsMessageQueue()

    ChartSerie1.ItemsSource = mytable.AsDataView     ' bind the chart to your datasource

    ThreadHelper.FlushWindowsMessageQueue()