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.
HI Graham,
Thanks for your reply. Well it seems fine for one series what if I have to manage multiple series. Actually in my case I have to add remove and update multiple series in the chart. And by your example I belive its fine for one series but not sure for multiple and run time add and remove series senario. Let me try your proposed solution and ill let you know the result.
All you are doing in these examples is to manage how many change notifications events are sent by your data sources, which may not even be necessary, depending on your situation, as the chart is designed to process many updates in rapid sucession. The ideas here should generalize to multiple series, without problems.
Yeah, if you are updating all of your collections from different threads there is one additional thing to watch out for, in that you might want all the series to update in one threaded interection so it does not appear that one series advances before the others. The below shows one way of achieving that using the reactive extensions approach, but there are, of course, many other ways of going about it:
public partial class MainPage : UserControl, INotifyPropertyChanged { private ObservableCollection<TestDataItem> _liveData = new ObservableCollection<TestDataItem>(); private ObservableCollection<TestDataItem> _liveData2 = new ObservableCollection<TestDataItem>(); public MainPage() { InitializeComponent(); DataContext = this; Data = new ManualResetProxy<TestDataItem>(_liveData); Data2 = new ManualResetProxy<TestDataItem>(_liveData2); SynchronizeRefreshes(); GenerateRandomBufferedData(_liveData, Data); GenerateRandomBufferedData(_liveData2, Data2); } private void SynchronizeRefreshes() { var needsRefresh = Observable.FromEvent <NeedsRefreshEventHandler, NeedsRefreshEventArgs>( (h) => new NeedsRefreshEventHandler(h), (h) => NeedsRefresh += h, (h) => NeedsRefresh -= h); var data1NeedsRefresh = needsRefresh.Where( (ev) => ev.EventArgs.Proxy == Data); var data2NeedsRefresh = needsRefresh.Where( (ev) => ev.EventArgs.Proxy == Data2); var refreshAllData = data1NeedsRefresh.Zip( data2NeedsRefresh, (l, r) => new List<ManualResetProxy<TestDataItem>>() { l.EventArgs.Proxy, r.EventArgs.Proxy }); refreshAllData.ObserveOnDispatcher().Subscribe( (items) => { foreach (var item in items) { item.Reset(); } }); } public void GenerateRandomBufferedData( IList<TestDataItem> target, ManualResetProxy<TestDataItem> proxy) { Random rand = new Random(); var liveValues = Observable.GenerateWithTime( 5.0, (v) => true, (v) => new TestDataItem { Label = DateTime.Now, Value = v }, (v) => TimeSpan.FromMilliseconds(20), (v) => { if (rand.NextDouble() > .5) { return v + rand.NextDouble(); } return v - rand.NextDouble(); }); var chunks = liveValues.BufferWithTime( TimeSpan.FromSeconds(.5)); chunks.ObserveOnDispatcher() .Subscribe( (items) => { foreach (var item in items) { target.Add(item); if (target[target.Count - 1].Label - target[0].Label > TimeSpan.FromSeconds(30)) { target.RemoveAt(0); } } if (NeedsRefresh != null) { NeedsRefresh( this, new NeedsRefreshEventArgs { Proxy = proxy }); } }); } private class NeedsRefreshEventArgs : EventArgs { public ManualResetProxy<TestDataItem> Proxy { get; set; } } private delegate void NeedsRefreshEventHandler(object sender, NeedsRefreshEventArgs args); private event NeedsRefreshEventHandler NeedsRefresh; private ManualResetProxy<TestDataItem> _data; public ManualResetProxy<TestDataItem> Data { get { return _data; } set { _data = value; RaisePropertyChanged("Data"); } } private ManualResetProxy<TestDataItem> _data2; public ManualResetProxy<TestDataItem> Data2 { get { return _data2; } set { _data2 = value; RaisePropertyChanged("Data2"); } } private void RaisePropertyChanged(string p) { if (PropertyChanged != null) { PropertyChanged( this, new PropertyChangedEventArgs(p)); } } public event PropertyChangedEventHandler PropertyChanged; }
Let me know how else I can help out.-Graham
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.
Please find attached a sample application of my senario. Thanks
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.