WpfApp/Services/ChartManager.cs

196 lines
5.7 KiB
C#
Raw Normal View History

using guoke;
using LiveCharts;
using LiveCharts.Wpf;
2025-10-13 15:19:35 +08:00
using System.Windows.Threading;
2025-10-13 15:00:50 +08:00
2025-10-14 12:38:10 +08:00
namespace WpfApp.Services;
public class ChartManager
2025-10-13 15:00:50 +08:00
{
2025-10-14 12:38:10 +08:00
private readonly Dispatcher dispatcher;
private readonly LogService log;
private readonly DatabaseService db;
private readonly EventService<GeneralEventArgs> even;
2025-10-13 15:19:35 +08:00
2025-10-14 12:38:10 +08:00
private const string SENSOR_DATA_EVENT = "SensorDataUpdate";
2025-10-14 12:38:10 +08:00
// 最大保留点数
private const int MAX_POINTS = 20;
2025-10-14 12:38:10 +08:00
// 每个图表的数据封装
private class ChartData
{
public ColumnSeries ColumnSeries;
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>();
}
2025-10-14 12:38:10 +08:00
// 管理多个图表
private Dictionary<CartesianChart, ChartData> charts = new Dictionary<CartesianChart, ChartData>();
2025-10-14 12:38:10 +08:00
public ChartManager(Dispatcher uiDispatcher,
LogService logService,
DatabaseService databaseService,
EventService<GeneralEventArgs> eventService)
{
dispatcher = uiDispatcher;
log = logService;
db = databaseService;
even = eventService;
2025-10-14 12:38:10 +08:00
SubscribeToSensorDataEvents();
}
2025-10-13 15:19:35 +08:00
2025-10-14 12:38:10 +08:00
/// <summary>
/// 初始化图表(一次性设置标准线和柱状图)
/// </summary>
public void InitChart(CartesianChart chart)
{
dispatcher.Invoke(() =>
2025-10-13 15:19:35 +08:00
{
2025-10-14 12:38:10 +08:00
if (chart == null) return;
2025-10-13 15:19:35 +08:00
2025-10-14 12:38:10 +08:00
// 如果已经初始化过,先清除
if (charts.ContainsKey(chart))
{
charts.Remove(chart);
}
2025-10-14 12:38:10 +08:00
var data = new ChartData();
data.ColumnSeries = new ColumnSeries
{
Title = "实时值",
Values = new ChartValues<double>()
};
2025-10-14 12:38:10 +08:00
var line1 = new LineSeries { Title = "标准下限", Values = data.StandardMin };
var line2 = new LineSeries { Title = "标准均值", Values = data.StandardAvg };
var line3 = new LineSeries { Title = "标准上限", Values = data.StandardMax };
2025-10-14 12:38:10 +08:00
chart.Series = new SeriesCollection { data.ColumnSeries, line1, line2, line3 };
2025-10-14 12:38:10 +08:00
chart.AxisX.Clear();
chart.AxisY.Clear();
2025-10-14 12:38:10 +08:00
chart.AxisX.Add(new Axis
{
Title = "时间",
Labels = data.Labels
});
2025-10-14 12:38:10 +08:00
chart.AxisY.Add(new Axis
{
Title = "数值"
});
2025-10-14 12:38:10 +08:00
charts[chart] = data;
});
}
/// <summary>
/// 接收到传感器实时数据(单点更新)
/// </summary>
private void OnSensorDataReceived(object sender, GeneralEventArgs e)
{
if (e is SensorDataEventArgs sensorArgs)
{
2025-10-14 12:38:10 +08:00
string chartTitle = sensorArgs.ChartTitle; // 例如 "myChart1"
double value = sensorArgs.SensorValue;
string timeLabel = DateTime.Now.ToString("HH:mm:ss");
2025-10-14 12:38:10 +08:00
// 找到对应图表并更新
foreach (var chart in charts.Keys)
{
if (chart.Name == chartTitle)
{
2025-10-14 12:38:10 +08:00
UpdateChartPoint(chart, timeLabel, value);
break;
}
2025-10-13 15:19:35 +08:00
}
}
2025-10-14 12:38:10 +08:00
}
2025-10-13 15:19:35 +08:00
2025-10-14 12:38:10 +08:00
/// <summary>
/// 更新单个图表的数据点(柱状图 + 标准线 + X轴标签
/// </summary>
public void UpdateChartPoint(CartesianChart chart, string label, double value)
{
if (chart == null || !charts.TryGetValue(chart, out var data))
return;
2025-10-14 12:38:10 +08:00
dispatcher.Invoke(() =>
{
// 保留四位小数
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)
2025-10-13 15:19:35 +08:00
{
2025-10-14 12:38:10 +08:00
data.ColumnSeries.Values.RemoveAt(0);
data.StandardMin.RemoveAt(0);
data.StandardAvg.RemoveAt(0);
data.StandardMax.RemoveAt(0);
data.Labels.RemoveAt(0);
}
2025-10-13 15:19:35 +08:00
2025-10-14 12:38:10 +08:00
// 刷新 X 轴标签
chart.AxisX[0].Labels = new List<string>(data.Labels);
});
}
2025-10-14 12:38:10 +08:00
/// <summary>
/// 手动添加数据到指定图表
/// </summary>
public void AddData(CartesianChart chart, double value, string label)
{
UpdateChartPoint(chart, label, value);
}
2025-10-14 12:38:10 +08:00
/// <summary>
/// 手动清除指定图表的数据
/// </summary>
public void ClearChart(CartesianChart chart)
{
if (chart == null || !charts.TryGetValue(chart, out var data))
return;
2025-10-13 15:19:35 +08:00
2025-10-14 12:38:10 +08:00
dispatcher.Invoke(() =>
{
2025-10-14 12:38:10 +08:00
data.ColumnSeries.Values.Clear();
data.StandardMin.Clear();
data.StandardAvg.Clear();
data.StandardMax.Clear();
data.Labels.Clear();
chart.AxisX[0].Labels.Clear();
});
}
2025-10-14 12:38:10 +08:00
/// <summary>
/// 清除所有图表
/// </summary>
public void ClearAllCharts()
{
foreach (var chart in charts.Keys)
{
2025-10-14 12:38:10 +08:00
ClearChart(chart);
2025-10-13 15:19:35 +08:00
}
}
2025-10-14 12:38:10 +08:00
/// <summary>
/// 订阅传感器数据事件
/// </summary>
private void SubscribeToSensorDataEvents()
{
even?.AddEventHandler(SENSOR_DATA_EVENT, OnSensorDataReceived);
}
2025-10-13 15:00:50 +08:00
}