This commit is contained in:
YONGYE 2025-10-14 12:38:10 +08:00
parent 465d76d0db
commit 4b5ac96b7c
4 changed files with 240 additions and 247 deletions

View File

@ -93,7 +93,6 @@ public partial class MainWindow : Window
// 清空之前图表数据 // 清空之前图表数据
chartManager.ClearAllCharts(); chartManager.ClearAllCharts();
sensorManager.Start(); sensorManager.Start();
//chartManager.Start(); // 启动图表刷新
BtnSensorControl.Content = "检测确定"; BtnSensorControl.Content = "检测确定";
isDetecting = true; isDetecting = true;
} }
@ -101,7 +100,6 @@ public partial class MainWindow : Window
{ {
// 停止检测 // 停止检测
sensorManager.Stop(); sensorManager.Stop();
//chartManager.Stop(); // 停止图表刷新
BtnSensorControl.Content = "检测开始"; BtnSensorControl.Content = "检测开始";
isDetecting = false; isDetecting = false;
} }

View File

@ -1,199 +1,195 @@
using guoke; using guoke;
using LiveCharts; using LiveCharts;
using LiveCharts.Wpf; using LiveCharts.Wpf;
using System;
using System.Collections.Generic;
using System.Windows.Threading; 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<GeneralEventArgs> even;
private const string SENSOR_DATA_EVENT = "SensorDataUpdate";
// 最大保留点数
private const int MAX_POINTS = 20;
// 每个图表的数据封装
private class ChartData
{ {
private readonly Dispatcher dispatcher; public ColumnSeries ColumnSeries;
private readonly LogService log; public ChartValues<double> StandardMin = new ChartValues<double>();
private readonly DatabaseService db; public ChartValues<double> StandardAvg = new ChartValues<double>();
private readonly EventService<GeneralEventArgs> even; public ChartValues<double> StandardMax = new ChartValues<double>();
public List<string> Labels = new List<string>();
}
private const string SENSOR_DATA_EVENT = "SensorDataUpdate"; // 管理多个图表
private Dictionary<CartesianChart, ChartData> charts = new Dictionary<CartesianChart, ChartData>();
// 最大保留点数 public ChartManager(Dispatcher uiDispatcher,
private const int MAX_POINTS = 20; LogService logService,
DatabaseService databaseService,
EventService<GeneralEventArgs> eventService)
{
dispatcher = uiDispatcher;
log = logService;
db = databaseService;
even = eventService;
// 每个图表的数据封装 SubscribeToSensorDataEvents();
private class ChartData }
/// <summary>
/// 初始化图表(一次性设置标准线和柱状图)
/// </summary>
public void InitChart(CartesianChart chart)
{
dispatcher.Invoke(() =>
{ {
public ColumnSeries ColumnSeries; if (chart == null) return;
public ChartValues<double> StandardMin = new ChartValues<double>();
public ChartValues<double> StandardAvg = new ChartValues<double>();
public ChartValues<double> StandardMax = new ChartValues<double>();
public List<string> Labels = new List<string>();
}
// 管理多个图表 // 如果已经初始化过,先清除
private Dictionary<CartesianChart, ChartData> charts = new Dictionary<CartesianChart, ChartData>(); if (charts.ContainsKey(chart))
public ChartManager(Dispatcher uiDispatcher,
LogService logService,
DatabaseService databaseService,
EventService<GeneralEventArgs> eventService)
{
dispatcher = uiDispatcher;
log = logService;
db = databaseService;
even = eventService;
SubscribeToSensorDataEvents();
}
/// <summary>
/// 初始化图表(一次性设置标准线和柱状图)
/// </summary>
public void InitChart(CartesianChart chart)
{
dispatcher.Invoke(() =>
{ {
if (chart == null) return; charts.Remove(chart);
// 如果已经初始化过,先清除
if (charts.ContainsKey(chart))
{
charts.Remove(chart);
}
var data = new ChartData();
data.ColumnSeries = new ColumnSeries
{
Title = "实时值",
Values = new ChartValues<double>()
};
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;
});
}
/// <summary>
/// 接收到传感器实时数据(单点更新)
/// </summary>
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;
}
}
} }
}
var data = new ChartData();
/// <summary> data.ColumnSeries = new ColumnSeries
/// 更新单个图表的数据点(柱状图 + 标准线 + X轴标签
/// </summary>
public void UpdateChartPoint(CartesianChart chart, string label, double value)
{
if (chart == null || !charts.TryGetValue(chart, out var data))
return;
dispatcher.Invoke(() =>
{ {
// 保留四位小数 Title = "实时值",
double roundedValue = Math.Round(value, 4); Values = new ChartValues<double>()
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);
// 超过最大点数时,移除最旧的数据 var line1 = new LineSeries { Title = "标准下限", Values = data.StandardMin };
if (data.ColumnSeries.Values.Count > MAX_POINTS) var line2 = new LineSeries { Title = "标准均值", Values = data.StandardAvg };
{ var line3 = new LineSeries { Title = "标准上限", Values = data.StandardMax };
data.ColumnSeries.Values.RemoveAt(0);
data.StandardMin.RemoveAt(0);
data.StandardAvg.RemoveAt(0);
data.StandardMax.RemoveAt(0);
data.Labels.RemoveAt(0);
}
// 刷新 X 轴标签 chart.Series = new SeriesCollection { data.ColumnSeries, line1, line2, line3 };
chart.AxisX[0].Labels = new List<string>(data.Labels);
});
}
/// <summary> chart.AxisX.Clear();
/// 手动添加数据到指定图表 chart.AxisY.Clear();
/// </summary>
public void AddData(CartesianChart chart, double value, string label)
{
UpdateChartPoint(chart, label, value);
}
/// <summary> chart.AxisX.Add(new Axis
/// 手动清除指定图表的数据
/// </summary>
public void ClearChart(CartesianChart chart)
{
if (chart == null || !charts.TryGetValue(chart, out var data))
return;
dispatcher.Invoke(() =>
{ {
data.ColumnSeries.Values.Clear(); Title = "时间",
data.StandardMin.Clear(); Labels = data.Labels
data.StandardAvg.Clear();
data.StandardMax.Clear();
data.Labels.Clear();
chart.AxisX[0].Labels.Clear();
}); });
}
/// <summary> chart.AxisY.Add(new Axis
/// 清除所有图表 {
/// </summary> Title = "数值"
public void ClearAllCharts() });
charts[chart] = data;
});
}
/// <summary>
/// 接收到传感器实时数据(单点更新)
/// </summary>
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) foreach (var chart in charts.Keys)
{ {
ClearChart(chart); if (chart.Name == chartTitle)
{
UpdateChartPoint(chart, timeLabel, value);
break;
}
} }
} }
}
/// <summary>
/// 订阅传感器数据事件 /// <summary>
/// </summary> /// 更新单个图表的数据点(柱状图 + 标准线 + X轴标签
private void SubscribeToSensorDataEvents() /// </summary>
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<string>(data.Labels);
});
}
/// <summary>
/// 手动添加数据到指定图表
/// </summary>
public void AddData(CartesianChart chart, double value, string label)
{
UpdateChartPoint(chart, label, value);
}
/// <summary>
/// 手动清除指定图表的数据
/// </summary>
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();
});
}
/// <summary>
/// 清除所有图表
/// </summary>
public void ClearAllCharts()
{
foreach (var chart in charts.Keys)
{
ClearChart(chart);
} }
} }
/// <summary>
/// 订阅传感器数据事件
/// </summary>
private void SubscribeToSensorDataEvents()
{
even?.AddEventHandler(SENSOR_DATA_EVENT, OnSensorDataReceived);
}
} }

View File

@ -2,95 +2,94 @@
using System.Windows; using System.Windows;
using WpfApp.src.components; using WpfApp.src.components;
namespace WpfApp.Services namespace WpfApp.Services;
/// <summary>
/// SensorChart 管理器 - 负责传感器数据采集和更新
/// </summary>
public class SensorChartManager
{ {
/// <summary> private readonly Window dispatcherOwner;
/// SensorChart 管理器 - 负责传感器数据采集和更新 private CancellationTokenSource cts;
/// </summary> private readonly Random rand = new Random();
public class SensorChartManager private readonly LogService log;
private readonly DatabaseService db;
private readonly EventService<GeneralEventArgs> 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<GeneralEventArgs> eventService)
{ {
private readonly Window dispatcherOwner; dispatcherOwner = owner;
private CancellationTokenSource cts; log = logService;
private readonly Random rand = new Random(); db = databaseService;
private readonly LogService log; even = eventService;
private readonly DatabaseService db; }
private readonly EventService<GeneralEventArgs> even;
// 事件名称常量 /// <summary>
private const string SENSOR_DATA_EVENT = "SensorDataUpdate"; /// 启动模拟数据采集
/// </summary>
public void Start()
{
if (Sensor1 == null || Sensor2 == null || Sensor3 == null)
throw new InvalidOperationException("请先绑定传感器控件");
cts = new CancellationTokenSource();
// 绑定的传感器控件 Task.Run(async () =>
public SensorChart Sensor1 { get; set; }
public SensorChart Sensor2 { get; set; }
public SensorChart Sensor3 { get; set; }
public SensorChartManager(Window owner, LogService logService, DatabaseService databaseService, EventService<GeneralEventArgs> eventService)
{ {
dispatcherOwner = owner; while (!cts.Token.IsCancellationRequested)
log = logService;
db = databaseService;
even = eventService;
}
/// <summary>
/// 启动模拟数据采集
/// </summary>
public void Start()
{
if (Sensor1 == null || Sensor2 == null || Sensor3 == null)
throw new InvalidOperationException("请先绑定传感器控件");
cts = new CancellationTokenSource();
Task.Run(async () =>
{ {
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(() =>
{ {
// 模拟数据 Sensor1.SetSensorData("传感器1", s1);
double s1 = rand.NextDouble() * 100 - 50; Sensor2.SetSensorData("传感器2", s2);
double s2 = rand.NextDouble() * 100 - 50; Sensor3.SetSensorData("传感器3", s3);
double s3 = rand.NextDouble() * 100 - 50;
// 通过事件将传感器数据传递到ChartManager
PublishSensorData("传感器1", s1, "myChart1");
PublishSensorData("传感器2", s2, "myChart2");
PublishSensorData("传感器3", s3, "myChart3");
});
// 更新 UI await Task.Delay(1000); // 每1000毫秒采集一次
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);
}
/// <summary>
/// 停止采集
/// </summary>
public void Stop()
{
cts?.Cancel();
}
/// <summary>
/// 发布传感器数据事件
/// </summary>
/// <param name="sensorTitle">传感器标题</param>
/// <param name="sensorValue">传感器值</param>
/// <param name="chartTitle">图表标题</param>
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);
} }
}, cts.Token);
}
/// <summary>
/// 停止采集
/// </summary>
public void Stop()
{
cts?.Cancel();
}
/// <summary>
/// 发布传感器数据事件
/// </summary>
/// <param name="sensorTitle">传感器标题</param>
/// <param name="sensorValue">传感器值</param>
/// <param name="chartTitle">图表标题</param>
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);
} }
} }
} }