using RealTimeGraphEx.DataSeries; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; namespace RealTimeGraphEx.Controllers { public class GraphMultiController : GraphControllerBase { private readonly object _lock = new object(); #region Cross Thread Fields internal ObservableCollection dataSeriesCollection; #endregion public int TotalPoints { get { return dataSeriesCollection.Count > 0 ? dataSeriesCollection[0].Points.Count : 0; } } internal bool IsAllSeriesEqual { get { return dataSeriesCollection.All(x => x.Points.Count == dataSeriesCollection[0].Points.Count); } } internal void TrimToLast() { lock (dataSeriesCollection) { if (dataSeriesCollection.Count > 1) { var min = dataSeriesCollection.FirstOrDefault(x => x.Points.Count == dataSeriesCollection.Min(y => y.Points.Count)); if (min != null) { lock (min.Points) { foreach (var series in dataSeriesCollection) { lock (series.Points) { if (series.Points.Count > min.Points.Count) { series.Points.RemoveRange(min.Points.Count, series.Points.Count - min.Points.Count); } } } } } } } } public ObservableCollection DataSeriesCollection { get { return (ObservableCollection)GetValue(DataSeriesCollectionProperty); } set { SetValue(DataSeriesCollectionProperty, value); } } public static readonly DependencyProperty DataSeriesCollectionProperty = DependencyProperty.Register("Controller", typeof(ObservableCollection), typeof(GraphMultiController), new PropertyMetadata(null, new PropertyChangedCallback(SetCrossThreadFields))); private static void SetCrossThreadFields(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphMultiController).OnSetCrossModelFields(); } protected virtual void OnSetCrossModelFields() { this.Dispatcher.Invoke(() => { dataSeriesCollection = DataSeriesCollection; }, System.Windows.Threading.DispatcherPriority.Send); } public GraphMultiController() : base() { DataSeriesCollection = new ObservableCollection(); } public override void Clear() { if (clearMethod != null) { clearMethod(); } dataSeriesCollection.ToList().ForEach(x => x.ClearPoints()); } internal override void ClearPoints() { dataSeriesCollection.ToList().ForEach(x => x.ClearPoints()); } public virtual void PushData(List values) { lock (_lock) { if (startThreadMethod != null) { startThreadMethod(); } dataSeriesCollection.ToList().ForEach(x => x.PushData(values)); } } public virtual void PushData(double[] values) { lock (_lock) { if (startThreadMethod != null) { startThreadMethod(); } dataSeriesCollection.ToList().ForEach(x => x.PushData(values)); } } public virtual void PushData(params List[] arrays) { PushData(arrays.ToList()); } public virtual void PushData(List> arrays) { lock (_lock) { if (startThreadMethod != null) { startThreadMethod(); } for (int i = 0; i < arrays.Count; i++) { dataSeriesCollection[i].PushData(arrays[i]); } } } public virtual void PushData(List array, int dataSeriesIndex) { lock (_lock) { if (startThreadMethod != null) { startThreadMethod(); } dataSeriesCollection[dataSeriesIndex].PushData(array); } } public virtual void PushDataSingles(List values) { lock (_lock) { if (startThreadMethod != null) { startThreadMethod(); } for (int i = 0; i < values.Count; i++) { dataSeriesCollection[i].PushData(values[i]); } } } internal virtual List> GetAndClearAllPoints() { List> pointsCollection = new List>(); lock (_lock) { foreach (var series in dataSeriesCollection) { pointsCollection.Add(series.Points.GetAndClearAllPoints()); } } return pointsCollection; } public void AddSeries(DataYSeries dataSeries) { DataSeriesCollection.Add(dataSeries); } } }