Using the latest version (11.1) of the datachart I need to add roughly ~300 points 10 times a second so that the chart looks like it is flowing smoothly. Currently I have a observable collection that I simply add values to in a for loop every 1/10th second. What I want to make sure of is that the chart does not try to redraw in between each add or even group of adds. I would want it to redraw only after all 300 points are added. Is there I way I can tell how often the graph is redrawing itself? Also, is there a better way of minimizing redraws? Should I disconnect the observable collection, add the values and then reconnect it?
Any optimization advice would be appreciated.
Mike,
The chart will defer most of the work it has to do until you relinquish the UI thread. So, for example, when you add the points in a handler from a DispatcherTimer when that handler finishes executing, the UI thread is free again, and the chart reconciles your data changes with its internal model and schedules a rerender.
That being said, some tracking work it being done as you make each data change, so there may be some differences based on how you add the points to the collection. But the chart wont attempt to rerender until you yield up the UI thread.
This is not how the chart behaved in earlier versions, so if you were seeing a marked difference between various updating mechanisms in earlier versions, then thats why.
I wouldn't necessarily recommend doing anything like detaching the observable collection and reattaching. The work done during the attach can be much more overhead than modifications of the attached collection.
One thing to consider is that unless you plan on updating properties on an item bound to the chart, you may want to consider NOT implementing INotifyPropertyChanged. You don't need this interface if you are only ever adding and removing points to the series, rather than updating the values of existing points. And there is some overhead involved in the chart adding and removing all the event handlers it needs to deal with INotifyPropertyChanged. So, if you don't need it, I would recommend leaving it out.
I believe we have a recent blog post with some other recommendations for chart performance. I'll try to find it for you.
-Graham
This blog post from Kiril captures some of the other performance recommendations I would recommend. http://blogs.infragistics.com/blogs/kiril_matev/archive/2011/04/07/tuning-the-xamdatachart-for-blazing-fast-charting.aspx
Please note about the Label DataTemplates item. In 11.1 and later the recommendation is reversed. You are better of NOT using DataTemplates in the axis labels unless you need to. There were some inefficiencies in the non templated case prior to 11.1
Furthermore, if you don't need an axis's labels, its more efficient if you collapse the label panel. The resolution property can also help quite a bit in certain scenarios, just be aware that the greater you raise the value, the less faithfully the line will represent the underlying data, but more and more efficient to render geometry will be produced.
Graham,
I am using an observablecollection but the objects that the collection contains do not implement INotifyPropertyChanged. Is that what you are saying or should I also be able to use a regular collection rather than an observablecollection?
In this particular example I create a list of lets say 4000 items and I just replace each item via index with a new object. The only piece I need the chart to respond to is when the collection changes. The objects themselves will never change. Given that what is the most efficient list type?
No you have to use an ObservableCollection or something else that implements INotifyCollectionChanged. What I was saying is that in your scenario you may not need to implement INotifyPropertyChanged on the individual items, and not doing so will make it more efficient. But it sounds like you are already avoiding this overhead.
If you are replacing all the items in the collection at once at each update (do you need to update all at once or only some?) then you might want to experiment with using a collection that only fires the reset event of INotifyCollectionChanged, when you are done doing each frames update. This avoids an event being sent for each individual index being updated.
However, there is more overhead involved in a reset event than single item updates. So whether its better to send a reset event or all the individual item update events depends largely on how many items you have. I would experiment with both and see which gives you more performance. There will be a tipping point number of items where the aggregated overhead of all the individual events being sent will begin to outweigh the overhead of proccessing the reset event which is more expensive than some number of individual item events. But I can't tell you what this tipping point will be.
I can tell you that the chart doesn't try to do anything too expensive for each individual item update event. So you may not get much additional performance for sending the one reset event, even if it is faster. The charts performance is bound more to the expensiveness of the reconciliation after all your updates are done, and the actual Silverlight rendering overhead.
Ok, that does fit then with what I was reading.
In this scenario I add ~500 points/sec into a queue and then have a worker process pull ~100 points out and update the collection roughly 5 times a second. So the goal is to have the chart reconsile 5 times per second. This is specifically done to try to get a smooth motion scrolling yet still get good performance. I will try the reset event but I doubt that 100 points changes will add up the the single reset event in cost.