From 4b5ac96b7c64dcdd491f8925ab32a1ad7a5d2adf Mon Sep 17 00:00:00 2001 From: YONGYE Date: Tue, 14 Oct 2025 12:38:10 +0800 Subject: [PATCH] =?UTF-8?q?=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MainWindow.xaml.cs | 2 - Services/ChartManager.cs | 328 ++++++++++++------------ Services/SensorChartManager.cs | 157 ++++++------ src/public/Excel/Report_2025_10_13.xlsx | Bin 4101 -> 4102 bytes 4 files changed, 240 insertions(+), 247 deletions(-) diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 8b0e00b..60317f5 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -93,7 +93,6 @@ public partial class MainWindow : Window // 清空之前图表数据 chartManager.ClearAllCharts(); sensorManager.Start(); - //chartManager.Start(); // 启动图表刷新 BtnSensorControl.Content = "检测确定"; isDetecting = true; } @@ -101,7 +100,6 @@ public partial class MainWindow : Window { // 停止检测 sensorManager.Stop(); - //chartManager.Stop(); // 停止图表刷新 BtnSensorControl.Content = "检测开始"; isDetecting = false; } diff --git a/Services/ChartManager.cs b/Services/ChartManager.cs index 8769a4e..73b8209 100644 --- a/Services/ChartManager.cs +++ b/Services/ChartManager.cs @@ -1,199 +1,195 @@ using guoke; using LiveCharts; using LiveCharts.Wpf; -using System; -using System.Collections.Generic; using System.Windows.Threading; -using WpfApp.src.config; -namespace WpfApp.Services +namespace WpfApp.Services; + +public class ChartManager { - public class ChartManager + private readonly Dispatcher dispatcher; + private readonly LogService log; + private readonly DatabaseService db; + private readonly EventService even; + + private const string SENSOR_DATA_EVENT = "SensorDataUpdate"; + + // 最大保留点数 + private const int MAX_POINTS = 20; + + // 每个图表的数据封装 + private class ChartData { - private readonly Dispatcher dispatcher; - private readonly LogService log; - private readonly DatabaseService db; - private readonly EventService even; + public ColumnSeries ColumnSeries; + public ChartValues StandardMin = new ChartValues(); + public ChartValues StandardAvg = new ChartValues(); + public ChartValues StandardMax = new ChartValues(); + public List Labels = new List(); + } - private const string SENSOR_DATA_EVENT = "SensorDataUpdate"; + // 管理多个图表 + private Dictionary charts = new Dictionary(); - // 最大保留点数 - private const int MAX_POINTS = 20; + public ChartManager(Dispatcher uiDispatcher, + LogService logService, + DatabaseService databaseService, + EventService eventService) + { + dispatcher = uiDispatcher; + log = logService; + db = databaseService; + even = eventService; - // 每个图表的数据封装 - private class ChartData + SubscribeToSensorDataEvents(); + } + + /// + /// 初始化图表(一次性设置标准线和柱状图) + /// + public void InitChart(CartesianChart chart) + { + dispatcher.Invoke(() => { - public ColumnSeries ColumnSeries; - public ChartValues StandardMin = new ChartValues(); - public ChartValues StandardAvg = new ChartValues(); - public ChartValues StandardMax = new ChartValues(); - public List Labels = new List(); - } + if (chart == null) return; - // 管理多个图表 - private Dictionary charts = new Dictionary(); - - public ChartManager(Dispatcher uiDispatcher, - LogService logService, - DatabaseService databaseService, - EventService eventService) - { - dispatcher = uiDispatcher; - log = logService; - db = databaseService; - even = eventService; - - SubscribeToSensorDataEvents(); - } - - /// - /// 初始化图表(一次性设置标准线和柱状图) - /// - public void InitChart(CartesianChart chart) - { - dispatcher.Invoke(() => + // 如果已经初始化过,先清除 + if (charts.ContainsKey(chart)) { - if (chart == null) return; - - // 如果已经初始化过,先清除 - if (charts.ContainsKey(chart)) - { - charts.Remove(chart); - } - - var data = new ChartData(); - data.ColumnSeries = new ColumnSeries - { - Title = "实时值", - Values = new ChartValues() - }; - - var line1 = new LineSeries { Title = "标准下限", Values = data.StandardMin }; - var line2 = new LineSeries { Title = "标准均值", Values = data.StandardAvg }; - var line3 = new LineSeries { Title = "标准上限", Values = data.StandardMax }; - - chart.Series = new SeriesCollection { data.ColumnSeries, line1, line2, line3 }; - - chart.AxisX.Clear(); - chart.AxisY.Clear(); - - chart.AxisX.Add(new Axis - { - Title = "时间", - Labels = data.Labels - }); - - chart.AxisY.Add(new Axis - { - Title = "数值" - }); - - charts[chart] = data; - }); - } - - /// - /// 接收到传感器实时数据(单点更新) - /// - private void OnSensorDataReceived(object sender, GeneralEventArgs e) - { - if (e is SensorDataEventArgs sensorArgs) - { - string chartTitle = sensorArgs.ChartTitle; // 例如 "myChart1" - double value = sensorArgs.SensorValue; - string timeLabel = DateTime.Now.ToString("HH:mm:ss"); - - // 找到对应图表并更新 - foreach (var chart in charts.Keys) - { - if (chart.Name == chartTitle) - { - UpdateChartPoint(chart, timeLabel, value); - break; - } - } + charts.Remove(chart); } - } - - /// - /// 更新单个图表的数据点(柱状图 + 标准线 + X轴标签) - /// - public void UpdateChartPoint(CartesianChart chart, string label, double value) - { - if (chart == null || !charts.TryGetValue(chart, out var data)) - return; - - dispatcher.Invoke(() => + var data = new ChartData(); + data.ColumnSeries = new ColumnSeries { - // 保留四位小数 - double roundedValue = Math.Round(value, 4); - data.ColumnSeries.Values.Add(roundedValue); - // 对标准线固定值,强制 double - data.StandardMin.Add(Math.Round((double)5, 4)); - data.StandardAvg.Add(Math.Round((double)10, 4)); - data.StandardMax.Add(Math.Round((double)30, 4)); - data.Labels.Add(label); + Title = "实时值", + Values = new ChartValues() + }; - // 超过最大点数时,移除最旧的数据 - if (data.ColumnSeries.Values.Count > MAX_POINTS) - { - data.ColumnSeries.Values.RemoveAt(0); - data.StandardMin.RemoveAt(0); - data.StandardAvg.RemoveAt(0); - data.StandardMax.RemoveAt(0); - data.Labels.RemoveAt(0); - } + var line1 = new LineSeries { Title = "标准下限", Values = data.StandardMin }; + var line2 = new LineSeries { Title = "标准均值", Values = data.StandardAvg }; + var line3 = new LineSeries { Title = "标准上限", Values = data.StandardMax }; - // 刷新 X 轴标签 - chart.AxisX[0].Labels = new List(data.Labels); - }); - } + chart.Series = new SeriesCollection { data.ColumnSeries, line1, line2, line3 }; - /// - /// 手动添加数据到指定图表 - /// - public void AddData(CartesianChart chart, double value, string label) - { - UpdateChartPoint(chart, label, value); - } + chart.AxisX.Clear(); + chart.AxisY.Clear(); - /// - /// 手动清除指定图表的数据 - /// - public void ClearChart(CartesianChart chart) - { - if (chart == null || !charts.TryGetValue(chart, out var data)) - return; - - dispatcher.Invoke(() => + chart.AxisX.Add(new Axis { - data.ColumnSeries.Values.Clear(); - data.StandardMin.Clear(); - data.StandardAvg.Clear(); - data.StandardMax.Clear(); - data.Labels.Clear(); - chart.AxisX[0].Labels.Clear(); + Title = "时间", + Labels = data.Labels }); - } - /// - /// 清除所有图表 - /// - public void ClearAllCharts() + chart.AxisY.Add(new Axis + { + Title = "数值" + }); + + charts[chart] = data; + }); + } + + /// + /// 接收到传感器实时数据(单点更新) + /// + private void OnSensorDataReceived(object sender, GeneralEventArgs e) + { + if (e is SensorDataEventArgs sensorArgs) { + string chartTitle = sensorArgs.ChartTitle; // 例如 "myChart1" + double value = sensorArgs.SensorValue; + string timeLabel = DateTime.Now.ToString("HH:mm:ss"); + + // 找到对应图表并更新 foreach (var chart in charts.Keys) { - ClearChart(chart); + if (chart.Name == chartTitle) + { + UpdateChartPoint(chart, timeLabel, value); + break; + } } } + } - /// - /// 订阅传感器数据事件 - /// - private void SubscribeToSensorDataEvents() + + /// + /// 更新单个图表的数据点(柱状图 + 标准线 + X轴标签) + /// + public void UpdateChartPoint(CartesianChart chart, string label, double value) + { + if (chart == null || !charts.TryGetValue(chart, out var data)) + return; + + dispatcher.Invoke(() => { - even?.AddEventHandler(SENSOR_DATA_EVENT, OnSensorDataReceived); + // 保留四位小数 + double roundedValue = Math.Round(value, 4); + data.ColumnSeries.Values.Add(roundedValue); + // 对标准线固定值,强制 double + data.StandardMin.Add(Math.Round((double)5, 4)); + data.StandardAvg.Add(Math.Round((double)10, 4)); + data.StandardMax.Add(Math.Round((double)30, 4)); + data.Labels.Add(label); + + // 超过最大点数时,移除最旧的数据 + if (data.ColumnSeries.Values.Count > MAX_POINTS) + { + data.ColumnSeries.Values.RemoveAt(0); + data.StandardMin.RemoveAt(0); + data.StandardAvg.RemoveAt(0); + data.StandardMax.RemoveAt(0); + data.Labels.RemoveAt(0); + } + + // 刷新 X 轴标签 + chart.AxisX[0].Labels = new List(data.Labels); + }); + } + + /// + /// 手动添加数据到指定图表 + /// + public void AddData(CartesianChart chart, double value, string label) + { + UpdateChartPoint(chart, label, value); + } + + /// + /// 手动清除指定图表的数据 + /// + public void ClearChart(CartesianChart chart) + { + if (chart == null || !charts.TryGetValue(chart, out var data)) + return; + + dispatcher.Invoke(() => + { + data.ColumnSeries.Values.Clear(); + data.StandardMin.Clear(); + data.StandardAvg.Clear(); + data.StandardMax.Clear(); + data.Labels.Clear(); + chart.AxisX[0].Labels.Clear(); + }); + } + + /// + /// 清除所有图表 + /// + public void ClearAllCharts() + { + foreach (var chart in charts.Keys) + { + ClearChart(chart); } } + + /// + /// 订阅传感器数据事件 + /// + private void SubscribeToSensorDataEvents() + { + even?.AddEventHandler(SENSOR_DATA_EVENT, OnSensorDataReceived); + } } diff --git a/Services/SensorChartManager.cs b/Services/SensorChartManager.cs index baa4e0e..8d8c319 100644 --- a/Services/SensorChartManager.cs +++ b/Services/SensorChartManager.cs @@ -2,95 +2,94 @@ using System.Windows; using WpfApp.src.components; -namespace WpfApp.Services +namespace WpfApp.Services; + +/// +/// SensorChart 管理器 - 负责传感器数据采集和更新 +/// +public class SensorChartManager { - /// - /// SensorChart 管理器 - 负责传感器数据采集和更新 - /// - public class SensorChartManager + private readonly Window dispatcherOwner; + private CancellationTokenSource cts; + private readonly Random rand = new Random(); + private readonly LogService log; + private readonly DatabaseService db; + private readonly EventService even; + + // 事件名称常量 + private const string SENSOR_DATA_EVENT = "SensorDataUpdate"; + + + // 绑定的传感器控件 + public SensorChart Sensor1 { get; set; } + public SensorChart Sensor2 { get; set; } + public SensorChart Sensor3 { get; set; } + + public SensorChartManager(Window owner, LogService logService, DatabaseService databaseService, EventService eventService) { - private readonly Window dispatcherOwner; - private CancellationTokenSource cts; - private readonly Random rand = new Random(); - private readonly LogService log; - private readonly DatabaseService db; - private readonly EventService even; + dispatcherOwner = owner; + log = logService; + db = databaseService; + even = eventService; + } - // 事件名称常量 - private const string SENSOR_DATA_EVENT = "SensorDataUpdate"; + /// + /// 启动模拟数据采集 + /// + public void Start() + { + if (Sensor1 == null || Sensor2 == null || Sensor3 == null) + throw new InvalidOperationException("请先绑定传感器控件"); + cts = new CancellationTokenSource(); - // 绑定的传感器控件 - public SensorChart Sensor1 { get; set; } - public SensorChart Sensor2 { get; set; } - public SensorChart Sensor3 { get; set; } - - public SensorChartManager(Window owner, LogService logService, DatabaseService databaseService, EventService eventService) + Task.Run(async () => { - dispatcherOwner = owner; - log = logService; - db = databaseService; - even = eventService; - } - - /// - /// 启动模拟数据采集 - /// - public void Start() - { - if (Sensor1 == null || Sensor2 == null || Sensor3 == null) - throw new InvalidOperationException("请先绑定传感器控件"); - - cts = new CancellationTokenSource(); - - Task.Run(async () => + while (!cts.Token.IsCancellationRequested) { - while (!cts.Token.IsCancellationRequested) + // 模拟数据 + double s1 = rand.NextDouble() * 100 - 50; + double s2 = rand.NextDouble() * 100 - 50; + double s3 = rand.NextDouble() * 100 - 50; + + // 更新 UI + dispatcherOwner.Dispatcher.Invoke(() => { - // 模拟数据 - double s1 = rand.NextDouble() * 100 - 50; - double s2 = rand.NextDouble() * 100 - 50; - double s3 = rand.NextDouble() * 100 - 50; + Sensor1.SetSensorData("传感器1", s1); + Sensor2.SetSensorData("传感器2", s2); + Sensor3.SetSensorData("传感器3", s3); + + // 通过事件将传感器数据传递到ChartManager + PublishSensorData("传感器1", s1, "myChart1"); + PublishSensorData("传感器2", s2, "myChart2"); + PublishSensorData("传感器3", s3, "myChart3"); + }); - // 更新 UI - dispatcherOwner.Dispatcher.Invoke(() => - { - Sensor1.SetSensorData("传感器1", s1); - Sensor2.SetSensorData("传感器2", s2); - Sensor3.SetSensorData("传感器3", s3); - - // 通过事件将传感器数据传递到ChartManager - PublishSensorData("传感器1", s1, "myChart1"); - PublishSensorData("传感器2", s2, "myChart2"); - PublishSensorData("传感器3", s3, "myChart3"); - }); - - await Task.Delay(1000); // 每1000毫秒采集一次 - } - }, cts.Token); - } - - /// - /// 停止采集 - /// - public void Stop() - { - cts?.Cancel(); - } - - /// - /// 发布传感器数据事件 - /// - /// 传感器标题 - /// 传感器值 - /// 图表标题 - private void PublishSensorData(string sensorTitle, double sensorValue, string chartTitle) - { - if (even != null) - { - var eventArgs = new SensorDataEventArgs(sensorTitle, sensorValue, chartTitle); - even.TriggerEvent(SENSOR_DATA_EVENT, this, eventArgs); + await Task.Delay(1000); // 每1000毫秒采集一次 } + }, cts.Token); + } + + /// + /// 停止采集 + /// + public void Stop() + { + cts?.Cancel(); + } + + /// + /// 发布传感器数据事件 + /// + /// 传感器标题 + /// 传感器值 + /// 图表标题 + private void PublishSensorData(string sensorTitle, double sensorValue, string chartTitle) + { + if (even != null) + { + var eventArgs = new SensorDataEventArgs(sensorTitle, sensorValue, chartTitle); + even.TriggerEvent(SENSOR_DATA_EVENT, this, eventArgs); } } } diff --git a/src/public/Excel/Report_2025_10_13.xlsx b/src/public/Excel/Report_2025_10_13.xlsx index b8f9606f744cb76ed8dffa58accca50b85a7083b..edef71e5604c7a45f1260aa98df5bb20b4689336 100644 GIT binary patch delta 1272 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 GQUU;nFB9(o