Hi,
I'm Building a demo App with the XamDataChart, I have 32 LineSeries linked to observablecollections and refreshing data each 100 ms with 15 new DataPoints per Serie, with the databiding, the updates are so fast and the chart do not render properly, I read an XamChart post with a RefreshEnabled property, the XamDataChart have a property similar/equivalent to perform refresh of the chart manually.
Thank you in advance.
Could you define how the chart is not rendering correctly? Also, if you could provide a sample illustrating the problem that would help greatly.
-Graham
Hi Graham,
I also have the same question from you. Actually earlier i was using xamcharts and now I am planing to switch to xamdatachart. In xamchart theres a property RefreshEnable to control redrawing all points on the surface of chart on any updates. Lets suppose if your chart is binded with a live data collection. suppose you are getting updates in miliseconds instead of immidiately updating the graph you can put some mechanism to hold refreshenable say after 15 seconds wait and then redraw all points in xamchart. Now my question is in xamdatachart is there any such thing to hold your chart from being update immidiately on getting updates ?
Thanks.
The xamDataChart is designed to gracefully bind to live updating data with millisecond refresh rates, but depending your your requirements you may want to throttle the chart refreshes even so. Below is a sample that shows the experience of the xamDataChart when updating the data every 20 milliseconds. You can change the itemsource bindings in the Xaml to point at the property Throttled to see how things look if you throttle the chart refreshes to occur only every half second, while the data source continues to refresch every 20 milliseconds.
The xamDataChart doesnt attempt to internalize the notion of when it should be updating and when not, it just responds to the datasource events provided and tries to keep the chart visual updated in as efficient as possible a way.
The Xaml:
<Grid x:Name="LayoutRoot" Background="White"> <igChart:XamDataChart x:Name="theChart"> <igChart:XamDataChart.Axes> <igChart:CategoryXAxis x:Name="xAxis" ItemsSource="{Binding Data}" Label="{}{Label:hh:mm:ss}"/> <igChart:NumericYAxis x:Name="yAxis" /> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:LineSeries x:Name="line" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ValueMemberPath="Value" ItemsSource="{Binding Data}" /> </igChart:XamDataChart.Series> </igChart:XamDataChart> </Grid>
And the code behind:
public partial class MainPage : UserControl, INotifyPropertyChanged { public MainPage() { InitializeComponent(); DataContext = this; Data = new ObservableCollection<TestDataItem>(); Throttled = new EventThrottlingCollection<TestDataItem>( Data, TimeSpan.FromSeconds(.5)); _timer.Interval = TimeSpan.FromMilliseconds( _millisecondRefreshInterval); _timer.Tick += Timer_Tick; _timer.Start(); } private int _millisecondRefreshInterval = 20; private Random _rand = new Random(); private double _currVal = 10.0; void Timer_Tick(object sender, EventArgs e) { if (_rand.NextDouble() > .5) { _currVal += _rand.NextDouble() * 1.0; } else { _currVal -= _rand.NextDouble() * 1.0; } DateTime now = DateTime.Now; Data.Add( new TestDataItem() { Label = now, Value = _currVal }); if (Data.Count > (TimeSpan.FromSeconds(30).TotalMilliseconds / _millisecondRefreshInterval)) { Data.RemoveAt(0); } } private DispatcherTimer _timer = new DispatcherTimer(); private ObservableCollection<TestDataItem> _data; public ObservableCollection<TestDataItem> Data { get { return _data; } set { _data = value; RaisePropertyChanged("Data"); } } private EventThrottlingCollection<TestDataItem> _dataView; public EventThrottlingCollection<TestDataItem> Throttled { get { return _dataView; } set { _dataView = value; RaisePropertyChanged("Throttled"); } } private void RaisePropertyChanged(string p) { if (PropertyChanged != null) { PropertyChanged( this, new PropertyChangedEventArgs(p)); } } public event PropertyChangedEventHandler PropertyChanged; } public class EventThrottlingCollection<T> : IEnumerable<T>, INotifyCollectionChanged { private IEnumerable<T> _inner; private DateTime _lastEvent; TimeSpan _batchInterval; public EventThrottlingCollection( IEnumerable<T> inner, TimeSpan batchInterval) { _inner = inner; INotifyCollectionChanged _coll = _inner as INotifyCollectionChanged; _lastEvent = DateTime.Now; _batchInterval = batchInterval; if (_coll != null) { _coll.CollectionChanged += Coll_CollectionChanged; } } void Coll_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e) { if (DateTime.Now - _lastEvent > _batchInterval) { _lastEvent = DateTime.Now; if (CollectionChanged != null) { CollectionChanged(this, new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset)); } } } public IEnumerator<T> GetEnumerator() { return _inner.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _inner.GetEnumerator(); } public event NotifyCollectionChangedEventHandler CollectionChanged; } public class TestDataItem { public DateTime Label { get; set; } public double Value { get; set; } }
Hope this helps! Let me know if you have any questions.
HI Graham,
Thanks for your reply. I already have found a work arround for this problem. I turned of Notifiactions and make a class derived from obserbable collection. And this class is containing explicite rest for my collection Bellow is the method in which I am resting my collection after updating all the point and its working fine now.
public
CollectionUpdated()
{
.Reset));
Yes,
If you turn off the markers you will see the performance improve further, so it definitely seems as if we have an issue in WPF in that regard. I will get back to you with a bug number.
If you run the program in debug mode and have verbose binding errors on in Visual Studio, then the performance will seem much worse than it actually is due to the amount of binding errors being logged into the console adding a lot of overhead. Compare to if you run the program with Ctrl-F5, and then compare to when you run the program with the markers disabled.
Because your items implement INotifyPropertyChanged, if you update them all every tick, then the chart will have to refresh that many times every tick. We are working to support that use case better in the future, but for now if your usage is to update the value of every item like that you are better disabling the notification events while you do the mass update, or detaching the collection while you change the items and then reattaching.
Unfortunately even if you do the latter, it seems like there is still a small hang each time the chart refreshes. I see a lot of binding errors being spit into the log that are not generated in similiar situations in Silverlight having to do with the markers. So I think there may be a bug for us to track down that is affecting the WPF performance in this scenario.
Please find attached a sample application of my senario. Thanks
Thanks for your reply and for the example as well. Can you please provide me a sample application. Actually I am using MVVM pattern and my collections are getting update through wcf call backs. Can you please provide me a running sample using MVVM updating collections in background worker thread? Currently I am doing in the same way and getting this GUI hang problem.