05-21-2014 06:29 AM
Hello,
first at all im using Meassurement Studio 2013.
i have a lot of Timers in my Application. The Timers refresh some Values in my UI.
That works all like a Charme.My BIG Problem is now the GRaph from MEassurement Studio.
With following Code i load the aktual Values and refresh the Graph. If i do this with the Dispatchertimer oder with a normal Threading.Timer the Ui freezes and the Graph too. That caused that the Plots are wrong.
For example a GRaph Screenshot with two Plots. That are calculated Sinus-Curves. But they didn't look like.
So, thats awfull 🙂
Here is my Code
private System.Windows.Threading.DispatcherTimer _timer = new System.Windows.Threading.DispatcherTimer(System.Windows.Threading.DispatcherPriority.Render) { Interval = TimeSpan.FromMilliseconds(100) }; private void _timer_Tick(object sender, EventArgs e) { int j = 0; foreach (var item in this.ConfigurationViewModel.PlotConfigurations) { int numberOfPoints = 1; double[] data = new double[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { try { var val = this.realTimeSystem.GetSingleValue(item.SelectedVariable.Identifier); if (val == null) break; double valD = double.Parse(val.ToString()); data[i] = valD; } catch { this.logger.Log("Plot Exception for {0}", item.SelectedVariable); } } if (data.Count() > 0) { chartCollection[j].Append(data); } j++; } }
this is my chartcollection
private CustomChartCollection[] _chartCollection; public CustomChartCollection[] chartCollection { get { return _chartCollection; } set { _chartCollection = value; RaisePropertyChanged("chartCollection"); } } chartCollection = new[] { new CustomChartCollection(), new CustomChartCollection(), new CustomChartCollection(), new CustomChartCollection(), new CustomChartCollection(), new CustomChartCollection(), new CustomChartCollection(), new CustomChartCollection(), };
and here the class of the customchartcollection
#region CustomChartCollection-Class [DataTypeDescriptor(typeof(GraphDataCollectionDescriptor<>))] public class CustomChartCollection : ChartCollection<double> { public CustomChartCollection() : base(100000) { } protected override void OnDataChanged(GraphCollectionChangedEventArgs e) { base.OnDataChanged(new GraphCollectionChangedEventArgs(0)); } } #endregion
and here is the XAML of my Graph
<ni:Graph x:Name="graph" DataSource="{Binding chartCollection}" RenderMode="Raster" PreferIndexData="True" SuppressScaleLayout="True" PlotAreaBackground="{Binding GraphBackgroundBrush}" nix:GraphExtensions.PlotsSource="{Binding Plots2}" nix:GraphExtensions.AxesSource="{Binding GraphAxes}"> </ni:Graph>
So what i'm doing wrong ? Is the Dispatchertimer with 100 ms to slow ?
Or is it better to work with to Timers and make it with addRange ?
Thanks in advance
Nice Wishes
05-21-2014 10:38 AM
I am trying to reproduce your issue locally: how are your axes configured (range, adjuster, etc)? It would be very helpful if you could attach a stand-alone project that reproduces the problem using simulated data.
05-22-2014 01:13 AM
Hi Paul,
i tried to generate a Application that is like my real Application.
In my real Application i have an own Thread that fills some Variables with the current Values. In my Graph-thread i pick the Currentvalues everey 100 ms (i think this is to slow).
I dont know how to make the Graph smoother to scroll. In our Winforms Application we have a buffer and we write every 100ms abou 500 Values into the Graph. I don't know how to do this with WPF.
Hope you can help me.
Manuel
05-22-2014 02:26 PM
So your concern is with updating a WPF graph with one sample every 100 ms, as opposed to updating a Windows Forms graph with 500 samples every 100 ms? From your earlier code, in the _timer_Tick
handler you set numberOfPoints = 1
, retrieve the one value with realTimeSystem.GetSingleValue
, and then append the data
array containing that one value to the corresponding chart collection. If you increase the size of the data
array, you can append multiple points at once to the chart collection.
If that is not your issue, please let me know what I should be looking for in the test application you provided. The only "pause" I saw was when the data went past the default size of the window. Otherwise, with the whole graph in view, it appeared to update continuously as values were appended.
05-23-2014 12:46 AM
Hi Paul,
sure you can help me. I agree with you that 100 ms one Point is not the same as 500 Points.
I need a possibility to load more Values in a List with Datetime and the Value. i hahve two x-Axis in my Graph. One for example has the Range 0 - 60 ( this means 0seconds to 60 seconds). This Axis is visible. And i have one invisible Axis that is coninious.
Actually i append every 100 ms a Point. So the Graph set the x-Axis automaticly.
I need now a possibility so set more Points to the Graph with an x,y Point. So the Graph didn't set the X-Axis automaticly.
In Winforms it was very easy. I need to port this to WPF.
Can you build me an Example wich has two threads. One thread fills an Array with Points (x,y) and the Other thread Appends the Array to the GRaph. The Graph shoul have a fixed x-Axis with 0-60 (this where my seconds) and also should be continous chart.
Do you know what i mean. Its very tricky i think
Thanks
Manuel
05-23-2014 01:01 PM
Without knowing the Windows Forms API you used, it is difficult to recommend a WPF equivalent.
That said, here is a simple producer/consumer example in WPF, based on your requirements for x,y time/sample values, two threads, limiting UI updates to 100 ms, and a fixed horizontal reference axis:
XAML:
<ni:Graph x:Name="graph" RenderMode="Raster">
<ni:Graph.Axes>
<ni:AxisDouble Orientation="Horizontal" Range="0,60" Adjuster="ContinuousChart" Visibility="Collapsed" />
<ni:AxisDouble Orientation="Horizontal" Range="0,60" Adjuster="None" InteractionMode="None" />
</ni:Graph.Axes>
</ni:Graph>
Code:
public partial class MainWindow : Window {
private readonly BlockingCollection<Point> _simulatedData;
private readonly ChartCollection<double, double> _graphData;
private readonly DispatcherTimer _consumerTimer;
public MainWindow( ) {
InitializeComponent( );
// Start producer.
_simulatedData = new BlockingCollection<Point>( );
Task.Factory.StartNew( this.SimulateData );
// Start consumer.
_graphData = new ChartCollection<double, double>( 100000 );
graph.DataSource = _graphData;
_consumerTimer = new DispatcherTimer(
TimeSpan.FromMilliseconds( 100 ),
DispatcherPriority.Normal,
this.ConsumeData,
this.Dispatcher );
}
private void SimulateData( ) {
Random random = new Random( );
DateTime start = DateTime.UtcNow;
while( true ) {
TimeSpan time = DateTime.UtcNow - start;
double value = random.NextDouble( );
_simulatedData.Add( new Point( time.TotalSeconds, value ) );
Thread.Sleep( 25 );
}
}
private void ConsumeData( object sender, EventArgs e ) {
// Pull all the currently available data from the simulated data source.
int count = _simulatedData.Count;
double[] times = new double[count];
double[] values = new double[count];
for( int i = 0; i < count; ++i ) {
Point sample = _simulatedData.Take( );
times[i] = sample.X;
values[i] = sample.Y;
}
// Append all the accumulated values to the graph's data collection at once.
_graphData.Append( times, values );
}
}
05-26-2014 01:43 AM
Hi Paul,
thanks for you help, but this doesnt work in my Application 😞
Please see the Atachment.
05-26-2014 04:50 AM
hi Paul,
i got it working now. My Demo-Application works very well. But when i tried it in my real-Application i got an Exception
"Index values must be strictly increasing.
Parametername: index"
and this where my index-Values
{ChartCollection<Double,Double>: Capacity=10000, Count=69}
[0]: {Sample<Double,Double>: Index=0,4605921, Value=0,108677158764633}
[1]: {Sample<Double,Double>: Index=0,6341268, Value=0,108677158764633}
[2]: {Sample<Double,Double>: Index=0,7841568, Value=0,108677158764633}
[3]: {Sample<Double,Double>: Index=0,9341868, Value=0,108677158764633}
[4]: {Sample<Double,Double>: Index=1,0842168, Value=0,108677158764633}
[5]: {Sample<Double,Double>: Index=1,2912582, Value=0,108677158764633}
[6]: {Sample<Double,Double>: Index=1,4487897, Value=0,108677158764633}
[7]: {Sample<Double,Double>: Index=1,6493298, Value=0,108677158764633}
[8]: {Sample<Double,Double>: Index=1,7998599, Value=0,108677158764633}
[9]: {Sample<Double,Double>: Index=1,9498899, Value=0,108677158764633}
[10]: {Sample<Double,Double>: Index=2,0999199, Value=0,108677158764633}
[11]: {Sample<Double,Double>: Index=2,2499499, Value=0,108677158764633}
[12]: {Sample<Double,Double>: Index=2,3999799, Value=0,108677158764633}
[13]: {Sample<Double,Double>: Index=2,5500099, Value=0,108677158764633}
[14]: {Sample<Double,Double>: Index=2,7000399, Value=0,108677158764633}
[15]: {Sample<Double,Double>: Index=2,8500699, Value=0,108677158764633}
[16]: {Sample<Double,Double>: Index=3,0000999, Value=0,108677158764633}
[17]: {Sample<Double,Double>: Index=3,1501299, Value=0,108677158764633}
[18]: {Sample<Double,Double>: Index=3,3566712, Value=0,108677158764633}
[19]: {Sample<Double,Double>: Index=3,5587116, Value=0,108677158764633}
[20]: {Sample<Double,Double>: Index=3,770754, Value=0,108677158764633}
[21]: {Sample<Double,Double>: Index=3,9402879, Value=0,108677158764633}
[22]: {Sample<Double,Double>: Index=4,1153229, Value=0,108677158764633}
[23]: {Sample<Double,Double>: Index=4,2823563, Value=0,108677158764633}
[24]: {Sample<Double,Double>: Index=4,4598918, Value=0,108677158764633}
[25]: {Sample<Double,Double>: Index=4,6184235, Value=0,108677158764633}
[26]: {Sample<Double,Double>: Index=4,7949588, Value=0,108677158764633}
[27]: {Sample<Double,Double>: Index=4,9724943, Value=0,108677158764633}
[28]: {Sample<Double,Double>: Index=5,1535305, Value=0,108677158764633}
[29]: {Sample<Double,Double>: Index=5,3095617, Value=0,108677158764633}
[30]: {Sample<Double,Double>: Index=5,4665931, Value=0,108677158764633}
[31]: {Sample<Double,Double>: Index=5,6196237, Value=0,108677158764633}
[32]: {Sample<Double,Double>: Index=5,8636725, Value=0,108677158764633}
[33]: {Sample<Double,Double>: Index=6,0202038, Value=0,108677158764633}
[34]: {Sample<Double,Double>: Index=6,1992396, Value=0,108677158764633}
[35]: {Sample<Double,Double>: Index=6,3497697, Value=0,108677158764633}
[36]: {Sample<Double,Double>: Index=6,4997997, Value=0,108677158764633}
[37]: {Sample<Double,Double>: Index=6,6498297, Value=0,108677158764633}
[38]: {Sample<Double,Double>: Index=6,7998597, Value=0,108677158764633}
[39]: {Sample<Double,Double>: Index=6,9498897, Value=0,108677158764633}
[40]: {Sample<Double,Double>: Index=7,1044206, Value=0,108677158764633}
[41]: {Sample<Double,Double>: Index=7,2589515, Value=0,108677158764633}
[42]: {Sample<Double,Double>: Index=7,4089815, Value=0,108677158764633}
[43]: {Sample<Double,Double>: Index=7,5590115, Value=0,108677158764633}
[44]: {Sample<Double,Double>: Index=7,7235444, Value=0,108677158764633}
[45]: {Sample<Double,Double>: Index=7,8735744, Value=0,108677158764633}
[46]: {Sample<Double,Double>: Index=8,0236044, Value=0,108677158764633}
[47]: {Sample<Double,Double>: Index=8,2221441, Value=0,108677158764633}
[48]: {Sample<Double,Double>: Index=8,3721741, Value=0,108677158764633}
[49]: {Sample<Double,Double>: Index=8,5222041, Value=0,108677158764633}
[50]: {Sample<Double,Double>: Index=8,6722341, Value=0,108677158764633}
[51]: {Sample<Double,Double>: Index=8,8222641, Value=0,108677158764633}
[52]: {Sample<Double,Double>: Index=8,9722941, Value=0,108677158764633}
[53]: {Sample<Double,Double>: Index=9,1228242, Value=0,108677158764633}
[54]: {Sample<Double,Double>: Index=9,2728542, Value=0,108677158764633}
[55]: {Sample<Double,Double>: Index=9,4228842, Value=0,108677158764633}
[56]: {Sample<Double,Double>: Index=9,5729142, Value=0,108677158764633}
[57]: {Sample<Double,Double>: Index=9,7324461, Value=0,108677158764633}
[58]: {Sample<Double,Double>: Index=9,8824761, Value=0,108677158764633}
[59]: {Sample<Double,Double>: Index=10,0325061, Value=0,108677158764633}
[60]: {Sample<Double,Double>: Index=10,1825361, Value=0,108677158764633}
[61]: {Sample<Double,Double>: Index=10,3330662, Value=0,108677158764633}
[62]: {Sample<Double,Double>: Index=10,4830962, Value=0,108677158764633}
[63]: {Sample<Double,Double>: Index=10,6331262, Value=0,108677158764633}
[64]: {Sample<Double,Double>: Index=10,7941584, Value=0,108677158764633}
[65]: {Sample<Double,Double>: Index=10,9446885, Value=0,108677158764633}
[66]: {Sample<Double,Double>: Index=11,0947185, Value=0,108677158764633}
[67]: {Sample<Double,Double>: Index=11,2447485, Value=0,108677158764633}
[68]: {Sample<Double,Double>: Index=11,3947785, Value=0,108677158764633}
So the index is increasing. Don't know what this error means 😕
05-26-2014 05:58 AM
Sorry, it was my mistake.
Now it works.
I will make some tests ang give you feedback as soon as possible.
Manuel