private void UpdateViewerMovingAverages(MovingAverageWrapper wrapper, string average, string averageMax, string Ftp, string heartRate) { lock (this.lvViewer) { ViewerListViewItem listViewItem = wrapper.ViewerListViewItem; ViewerItem viewerItem = listViewItem.ViewerItem; if (average != null) { viewerItem.Average = average; } if (averageMax != null) { viewerItem.AverageMax = averageMax; } if (Ftp != null) { viewerItem.Ftp = Ftp; } if (heartRate != null) { viewerItem.HeartRate = heartRate; } } }
/// <summary> /// Occurs each time a collector's moving average changes. Allows for UI update by marshalling the call accordingly. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MovingAverageChangedEventHandler(object sender, MovingAverage.MovingAverageChangedEventArgs e) { //if (!m_dispatcher.CheckAccess()) // are we currently on the UI thread? //{ // // We're not in the UI thread, ask the dispatcher to call this same method in the UI thread, then exit // m_dispatcher.BeginInvoke(new MovingAverageChangedEventHandlerDelegate(MovingAverageChangedEventHandler), new object[] { sender, e }); // return; //} lock (lvViewer) { MovingAverageWrapper wrapper = m_maCollection[e.DurationType]; Collector collector = wrapper.Collector; ViewerListViewItem listViewItem = wrapper.ViewerListViewItem; ViewerItem viewerItem = listViewItem.ViewerItem; switch (collector.FieldAvgType) { case FieldUomType.Watts: viewerItem.Average = e.AveragePower.ToString(); break; case FieldUomType.Wkg: if (m_currentUser.WeightAsKgs > 0) { viewerItem.Average = Math.Round(e.AveragePower / m_currentUser.WeightAsKgs, 2).ToString("#.00"); } break; } viewerItem.HeartRate = e.AverageHR.ToString(); // The FTP column will track the AvgPower until the time duration is satisfied. // This enables the rider to see what his FTP would be real-time. // Once the time duration is satisfied, we no longer will update using the AvgPower. if (!wrapper.MaxDurationTriggered) { switch (collector.FieldFtpType) { case FieldUomType.Watts: viewerItem.Ftp = Math.Round(e.AveragePower * 0.95, 0).ToString(); break; case FieldUomType.Wkg: if (m_currentUser.WeightAsKgs > 0) { viewerItem.Ftp = Math.Round((e.AveragePower / m_currentUser.WeightAsKgs) * 0.95, 2).ToString("#.00"); } break; } } } }
/// <summary> /// Occurs each time a collector's moving average max value changes. Allows for UI update by marshalling the call accordingly. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MovingAverageMaxChangedEventHandler(object sender, MovingAverage.MovingAverageMaxChangedEventArgs e) { //if (!m_dispatcher.CheckAccess()) // are we currently on the UI thread? //{ // // We're not in the UI thread, ask the dispatcher to call this same method in the UI thread, then exit // m_dispatcher.BeginInvoke(new MovingAverageMaxChangedEventHandlerDelegate(MovingAverageMaxChangedEventHandler), new object[] { sender, e }); // return; //} lock (lvViewer) { MovingAverageWrapper wrapper = m_maCollection[e.DurationType]; Collector collector = wrapper.Collector; ViewerListViewItem listViewItem = wrapper.ViewerListViewItem; ViewerItem viewerItem = listViewItem.ViewerItem; switch (collector.FieldAvgMaxType) { case FieldUomType.Watts: viewerItem.AverageMax = e.MaxAvgPower.ToString(); break; case FieldUomType.Wkg: if (m_currentUser.WeightAsKgs > 0) { viewerItem.AverageMax = Math.Round(e.MaxAvgPower / m_currentUser.WeightAsKgs, 2).ToString("#.00"); } break; } // Save the fact that this moving average has fulfilled it's time duration wrapper.MaxDurationTriggered = true; // The FTP column will now track the MaxAvgPower now that the time duration is satisfied. switch (collector.FieldFtpType) { case FieldUomType.Watts: viewerItem.Ftp = Math.Round(e.MaxAvgPower * 0.95, 0).ToString(); break; case FieldUomType.Wkg: if (m_currentUser.WeightAsKgs > 0) { viewerItem.Ftp = Math.Round((e.MaxAvgPower / m_currentUser.WeightAsKgs) * 0.95, 2).ToString("#.00"); } break; } } }
public void AddViewerItem(DurationType durationType, string durationDesc) { MovingAverage ma = new MovingAverage(durationType, false); ma.MovingAverageChangedEvent += MovingAverageChangedEventHandler; ma.MovingAverageMaxChangedEvent += MovingAverageMaxChangedEventHandler; // Initialize and add item to ListView ViewerListViewItem lvi = new ViewerListViewItem(new ViewerItem(durationDesc)); this.lvViewer.Items.Add(lvi); Collector collector = ZAMsettings.Settings.Collectors[durationDesc]; m_maCollection.Add(durationType, new MovingAverageWrapper(ma, lvi, collector)); }
/// <summary> /// Load and initialize the moving average collection wrapper collection based upon the current menu item checked settings. /// /// This is called on form load and also when menu items change. /// </summary> private void LoadMovingAverageCollection() { // empty the MovingAverageWrapper dictionary m_maCollection.Clear(); // Clear the ListView lvViewer.Items.Clear(); //m_labelHelpers.ForEach(helper => helper.ClearLabels(true)); //tsslOverall.Text = ""; // Loop through the menu items within the Collect menu. // If an item is checked, we want to create a collector for it. // The collector duration is determined by a match between the menu item's tag and the DurationType Enum. // Up to 3 items can be shown. // The label on the UI gets the same text as the menu item. foreach (ToolStripItem mi in tsmiAnalyze.DropDownItems) { ToolStripMenuItem tsmi = mi as ToolStripMenuItem; if (tsmi == null) { continue; } if (tsmi.Checked) { if (m_maCollection.Count < 3) { DurationType result; if (Enum.TryParse <DurationType>(tsmi.Tag.ToString(), true, out result)) { MovingAverage ma = new MovingAverage(m_zpMonitorService, m_loggerFactory, result, false); ma.MovingAverageChangedEvent += MovingAverageChangedEventHandler; ma.MovingAverageMaxChangedEvent += MovingAverageMaxChangedEventHandler; // Initialize and add item to ListView ViewerListViewItem lvi = new ViewerListViewItem(new ViewerItem(tsmi.Text)); this.lvViewer.Items.Add(lvi); Collector collector = ZAMsettings.Settings.Collectors[tsmi.Text]; m_maCollection.Add(result, new MovingAverageWrapper(ma, lvi, collector)); // Here we assign the row's id text (5 sec, 1 min, etc) and associate the matching Collector. // All of this makes it easy to update the display as the MovingAverage events fire. //m_labelHelpers[labelSet].MovingAvg.Text = tsmi.Text; //m_labelHelpers[labelSet].Collector = ZAMsettings.Settings.Collectors[tsmi.Text]; if (m_maCollection.Count >= 3) // only allow up to 3 collectors { break; } } else { throw new ApplicationException($"Bug: The menuitem tag {tsmi.Tag} for menuitem {tsmi.Text} did not match any DurationType Enums."); } } else { tsmi.Checked = false; } } } }
public MovingAverageWrapper(MovingAverage movingAverage, ViewerListViewItem viewerListViewItem, Collector collector) { MovingAverage = movingAverage; ViewerListViewItem = viewerListViewItem; Collector = collector; }