Compare commits

..

10 Commits

10 changed files with 820 additions and 283 deletions

View File

@ -31,8 +31,8 @@ public partial class MainWindow : Window
log = logService; log = logService;
db = databaseService; db = databaseService;
even = eventService; even = eventService;
menu = new MenuController(this);// 初始化菜单控制器 menu = new MenuController(this, log, db, even);// 初始化菜单控制器
sensorManager = new SensorChartManager(this) sensorManager = new SensorChartManager(this, log, db, even)
{ {
Sensor1 = Sensor1, Sensor1 = Sensor1,
Sensor2 = Sensor2, Sensor2 = Sensor2,
@ -51,13 +51,11 @@ public partial class MainWindow : Window
WindowHelper.SetWindowTitle(this, "FMSDGAUGE"); // 设置标题 WindowHelper.SetWindowTitle(this, "FMSDGAUGE"); // 设置标题
chartManager = new ChartManager(Dispatcher); chartManager = new ChartManager(Dispatcher, log, db, even);
chartManager.InitCharts(myChart1, myChart2, myChart3); // 初始化图表 chartManager.InitChart(myChart1);
chartManager.InitChart(myChart2);
chartManager.InitChart(myChart3);
// 启动实时数据刷新
chartManager.StartAutoUpdate(myChart1, chartCts.Token, "myChart1");
chartManager.StartAutoUpdate(myChart2, chartCts.Token, "myChart2");
chartManager.StartAutoUpdate(myChart3, chartCts.Token, "myChart3");
} }
@ -92,6 +90,8 @@ public partial class MainWindow : Window
if (!isDetecting) if (!isDetecting)
{ {
// 开始检测 // 开始检测
// 清空之前图表数据
chartManager.ClearAllCharts();
sensorManager.Start(); sensorManager.Start();
BtnSensorControl.Content = "检测确定"; BtnSensorControl.Content = "检测确定";
isDetecting = true; isDetecting = true;

View File

@ -1,105 +1,195 @@
using guoke; using guoke;
using LiveCharts;
using LiveCharts.Wpf; using LiveCharts.Wpf;
using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
using WpfApp.src.config;
using WpfApp.Utils;
namespace WpfApp.Services namespace WpfApp.Services;
public class ChartManager
{ {
/// <summary> private readonly Dispatcher dispatcher;
/// Chart 管理器 - 负责图表初始化和实时更新 private readonly LogService log;
/// </summary> private readonly DatabaseService db;
public class ChartManager 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>();
}
public ChartManager(Dispatcher uiDispatcher) // 管理多个图表
{ private Dictionary<CartesianChart, ChartData> charts = new Dictionary<CartesianChart, ChartData>();
dispatcher = uiDispatcher;
}
public ChartManager(LogService logService, DatabaseService databaseService, EventService<GeneralEventArgs> eventService)
{
log = logService;
db = databaseService;
even = eventService;
}
/// <summary> public ChartManager(Dispatcher uiDispatcher,
/// 初始化图表 LogService logService,
/// </summary> DatabaseService databaseService,
public void InitCharts(params CartesianChart[] charts) EventService<GeneralEventArgs> eventService)
{ {
var labels = new[] { "13:27 23", "13:27 45", "13:27 49", "13:27 50", "13:27 55" }; dispatcher = uiDispatcher;
log = logService;
db = databaseService;
even = eventService;
var config = new ChartConfig SubscribeToSensorDataEvents();
}
/// <summary>
/// 初始化图表(一次性设置标准线和柱状图)
/// </summary>
public void InitChart(CartesianChart chart)
{
dispatcher.Invoke(() =>
{
if (chart == null) return;
// 如果已经初始化过,先清除
if (charts.ContainsKey(chart))
{ {
ColumnData = new List<double> { 20, 10, 12, 5, 9 }, charts.Remove(chart);
Labels = labels.ToList(), }
LineConfigs = new List<LineConfig>
{ var data = new ChartData();
new LineConfig { Title = "标准1", Values = Enumerable.Repeat(5.0,5).ToList(), Stroke = Brushes.Blue }, data.ColumnSeries = new ColumnSeries
new LineConfig { Title = "标准2", Values = Enumerable.Repeat(10.0,5).ToList(), Stroke = Brushes.Green }, {
new LineConfig { Title = "标准3", Values = Enumerable.Repeat(30.0,5).ToList(), Stroke = Brushes.Red, Unit="A" } Title = "实时值",
} Values = new ChartValues<double>()
}; };
foreach (var chart in charts) 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
{ {
InitChart.InitCartesianChart(chart, config); 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;
}
} }
} }
}
/// <summary>
/// 动态更新图表数据(线程安全) /// <summary>
/// </summary> /// 更新单个图表的数据点(柱状图 + 标准线 + X轴标签
public void UpdateChart(CartesianChart chart, List<double> columnData, List<LineConfig> lineData) /// </summary>
public void UpdateChartPoint(CartesianChart chart, string label, double value)
{
if (chart == null || !charts.TryGetValue(chart, out var data))
return;
dispatcher.Invoke(() =>
{ {
dispatcher.Invoke(() => // 保留四位小数
{ double roundedValue = Math.Round(value, 4);
var config = new ChartConfig data.ColumnSeries.Values.Add(roundedValue);
{ // 对标准线固定值,强制 double
ColumnData = columnData, data.StandardMin.Add(Math.Round((double)5, 4));
Labels = chart.AxisX[0].Labels.ToList(), data.StandardAvg.Add(Math.Round((double)10, 4));
LineConfigs = lineData data.StandardMax.Add(Math.Round((double)30, 4));
}; data.Labels.Add(label);
InitChart.InitCartesianChart(chart, config);
});
}
/// <summary> // 超过最大点数时,移除最旧的数据
/// 模拟后台数据采集并实时刷新图表 if (data.ColumnSeries.Values.Count > MAX_POINTS)
/// </summary> {
public void StartAutoUpdate(CartesianChart chart, CancellationToken token) 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(() =>
{ {
Task.Run(async () => data.ColumnSeries.Values.Clear();
{ data.StandardMin.Clear();
var rand = new Random(); data.StandardAvg.Clear();
data.StandardMax.Clear();
data.Labels.Clear();
chart.AxisX[0].Labels.Clear();
});
}
while (!token.IsCancellationRequested) /// <summary>
{ /// 清除所有图表
// 模拟采集数据 /// </summary>
var columnData = Enumerable.Range(0, 5).Select(_ => rand.NextDouble() * 50).ToList(); public void ClearAllCharts()
// 这里实时获取从SensorChartManager中 {
var lineData = new List<LineConfig> foreach (var chart in charts.Keys)
{ {
//new LineConfig { Title = "标准1", Values = Enumerable.Range(0,5).Select(_ => rand.NextDouble()*20).ToList(), Stroke = Brushes.Blue }, ClearChart(chart);
//new LineConfig { Title = "标准2", Values = Enumerable.Range(0,5).Select(_ => rand.NextDouble()*30).ToList(), Stroke = Brushes.Green },
//new LineConfig { Title = "标准3", Values = Enumerable.Range(0,5).Select(_ => rand.NextDouble()*40).ToList(), Stroke = Brushes.Yellow }
new LineConfig { Title = "标准1", Values = new List<double> { 10, 10, 10, 10, 10 }, Stroke = Brushes.Blue },
new LineConfig { Title = "标准2", Values = new List<double> { 20, 20, 20, 20, 20 }, Stroke = Brushes.Green },
new LineConfig { Title = "标准3", Values = new List<double> { 30, 30, 30, 30, 30 }, Stroke = Brushes.Yellow }
};
// 更新图表(通过 Dispatcher 保证线程安全)
UpdateChart(chart, columnData, lineData);
await Task.Delay(6000); // 每秒更新一次
}
}, token);
} }
} }
/// <summary>
/// 订阅传感器数据事件
/// </summary>
private void SubscribeToSensorDataEvents()
{
even?.AddEventHandler(SENSOR_DATA_EVENT, OnSensorDataReceived);
}
} }

View File

@ -2,77 +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>
/// 启动模拟数据采集
/// </summary>
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) Task.Run(async () =>
{ {
dispatcherOwner = owner; while (!cts.Token.IsCancellationRequested)
}
public SensorChartManager(LogService logService, DatabaseService databaseService, EventService<GeneralEventArgs> eventService)
{
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;
// 更新 UI // 通过事件将传感器数据传递到ChartManager
dispatcherOwner.Dispatcher.Invoke(() => PublishSensorData("传感器1", s1, "myChart1");
{ PublishSensorData("传感器2", s2, "myChart2");
Sensor1.SetSensorData("传感器1", s1); PublishSensorData("传感器3", s3, "myChart3");
Sensor2.SetSensorData("传感器2", s2); });
Sensor3.SetSensorData("传感器3", s3);
// 这里应当跨线程将传感器1 2 3的同时将实时值传递到ChartManger中
}); await Task.Delay(1000); // 每1000毫秒采集一次
}
}, cts.Token);
}
await Task.Delay(1000); // 每1000毫秒采集一次 /// <summary>
} /// 停止采集
}, cts.Token); /// </summary>
} public void Stop()
{
cts?.Cancel();
}
/// <summary> /// <summary>
/// 停止采集 /// 发布传感器数据事件
/// </summary> /// </summary>
public void Stop() /// <param name="sensorTitle">传感器标题</param>
/// <param name="sensorValue">传感器值</param>
/// <param name="chartTitle">图表标题</param>
private void PublishSensorData(string sensorTitle, double sensorValue, string chartTitle)
{
if (even != null)
{ {
cts?.Cancel(); var eventArgs = new SensorDataEventArgs(sensorTitle, sensorValue, chartTitle);
even.TriggerEvent(SENSOR_DATA_EVENT, this, eventArgs);
} }
} }
} }

View File

@ -0,0 +1,39 @@
using guoke;
namespace WpfApp.Services
{
/// <summary>
/// 传感器数据事件参数类,用于传递传感器的实时数据
/// </summary>
public class SensorDataEventArgs : GeneralEventArgs
{
/// <summary>
/// 传感器标题/名称
/// </summary>
public string SensorTitle { get; set; }
/// <summary>
/// 传感器实时值
/// </summary>
public double SensorValue { get; set; }
/// <summary>
/// 图表标题,用于区分不同的图表
/// </summary>
public string ChartTitle { get; set; }
/// <summary>
/// 初始化传感器数据事件参数
/// </summary>
/// <param name="sensorTitle">传感器标题</param>
/// <param name="sensorValue">传感器实时值</param>
/// <param name="chartTitle">图表标题</param>
public SensorDataEventArgs(string sensorTitle, double sensorValue, string chartTitle)
: base($"传感器数据更新: {sensorTitle}", sensorValue)
{
SensorTitle = sensorTitle;
SensorValue = sensorValue;
ChartTitle = chartTitle;
}
}
}

View File

@ -8,6 +8,13 @@
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="新文件夹\**" />
<EmbeddedResource Remove="新文件夹\**" />
<None Remove="新文件夹\**" />
<Page Remove="新文件夹\**" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="src\public\Icons\main1-file-icon.png" /> <None Remove="src\public\Icons\main1-file-icon.png" />
<None Remove="src\public\Icons\main2-config-icon.png" /> <None Remove="src\public\Icons\main2-config-icon.png" />
@ -67,7 +74,6 @@
<ItemGroup> <ItemGroup>
<Folder Include="src\public\Excel\" /> <Folder Include="src\public\Excel\" />
<Folder Include="新文件夹\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -13,6 +13,14 @@
"Connection": "DataSource=LocalData.db", "Connection": "DataSource=LocalData.db",
"Remarks": "", "Remarks": "",
"Print": false "Print": false
},
{
"Name": "D1",
"Enabled": true,
"Type": 2,
"Connection": "DataSource=D1.db",
"Remarks": "产品数据库",
"Print": true
} }
] ]
} }

View File

@ -1,4 +1,5 @@
using System.Windows; using guoke;
using System.Windows;
using WpfApp.src.view; using WpfApp.src.view;
using WpfApp.Utils; using WpfApp.Utils;
@ -10,9 +11,14 @@ namespace WpfApp.src.controllers
public class MenuController public class MenuController
{ {
private readonly Window mainWindow; private readonly Window mainWindow;
private readonly LogService log;
public MenuController(Window window) private readonly DatabaseService db;
private readonly EventService<GeneralEventArgs> even;
public MenuController(Window window, LogService logService, DatabaseService databaseService, EventService<GeneralEventArgs> eventService)
{ {
log = logService;
db = databaseService;
even = eventService;
mainWindow = window; mainWindow = window;
} }
@ -32,7 +38,7 @@ namespace WpfApp.src.controllers
/// </summary> /// </summary>
public void OpenConfigPage() public void OpenConfigPage()
{ {
WindowHelper.ShowPageDialog(new ConfigPage(), WindowHelper.ShowPageDialog(new ConfigPage(log, db, even),
"配置", 972, 648, "配置", 972, 648,
isResizable: false, isResizable: false,
IconHelper.GetIconPath("main2-Config.ico")); IconHelper.GetIconPath("main2-Config.ico"));

View File

@ -43,8 +43,8 @@
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Text="产品名称" FontWeight="Bold" VerticalAlignment="Center" Margin="0,0,10,0"/> <TextBlock Text="产品名称" FontWeight="Bold" VerticalAlignment="Center" Margin="0,0,10,0"/>
<TextBox Grid.Column="1" Text="DFPV C15TE" Height="30" Background="#E6F3FF" VerticalContentAlignment="Center"/> <TextBox Grid.Column="1" x:Name="ProductNameTextBox" Text="DFPV C15TE" Height="30" Background="#E6F3FF" VerticalContentAlignment="Center"/>
</Grid> </Grid>
</Border> </Border>
@ -63,10 +63,10 @@
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<CheckBox Grid.Row="0" Grid.Column="0" Content="数字传感器1" IsChecked="True" Margin="5"/> <CheckBox x:Name="chkDigitalSensor1" Grid.Row="0" Grid.Column="0" Content="数字传感器1" IsChecked="True" Margin="5"/>
<CheckBox Grid.Row="0" Grid.Column="1" Content="数字传感器2" IsChecked="True" Margin="5"/> <CheckBox x:Name="chkDigitalSensor2" Grid.Row="0" Grid.Column="1" Content="数字传感器2" IsChecked="True" Margin="5"/>
<CheckBox Grid.Row="1" Grid.Column="0" Content="数字传感器3" IsChecked="True" Margin="5"/> <CheckBox x:Name="chkDigitalSensor3" Grid.Row="1" Grid.Column="0" Content="数字传感器3" IsChecked="True" Margin="5"/>
<CheckBox Grid.Row="1" Grid.Column="1" Content="数字传感器4" Margin="5"/> <CheckBox x:Name="chkDigitalSensor4" Grid.Row="1" Grid.Column="1" Content="数字传感器4" Margin="5"/>
</Grid> </Grid>
</StackPanel> </StackPanel>
</Border> </Border>
@ -141,10 +141,10 @@
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<RadioButton Grid.Row="0" Grid.Column="0" Content="数字传感器1" IsChecked="True" GroupName="MainSensor" Margin="5"/> <RadioButton x:Name="chkDigitalMainSensor1" Grid.Row="0" Grid.Column="0" Content="数字传感器1" IsChecked="True" GroupName="MainSensor" Margin="5"/>
<RadioButton Grid.Row="0" Grid.Column="1" Content="数字传感器2" GroupName="MainSensor" Margin="5"/> <RadioButton x:Name="chkDigitalMainSensor2" Grid.Row="0" Grid.Column="1" Content="数字传感器2" GroupName="MainSensor" Margin="5"/>
<RadioButton Grid.Row="1" Grid.Column="0" Content="数字传感器3" GroupName="MainSensor" Margin="5"/> <RadioButton x:Name="chkDigitalMainSensor3" Grid.Row="1" Grid.Column="0" Content="数字传感器3" GroupName="MainSensor" Margin="5"/>
<RadioButton Grid.Row="1" Grid.Column="1" Content="数字传感器4" GroupName="MainSensor" Margin="5"/> <RadioButton x:Name="chkDigitalMainSensor4" Grid.Row="1" Grid.Column="1" Content="数字传感器4" GroupName="MainSensor" Margin="5"/>
</Grid> </Grid>
</StackPanel> </StackPanel>
</Border> </Border>
@ -215,11 +215,11 @@
Background="#333333" Foreground="White" HorizontalAlignment="Center" Margin="0,30,0,0"/> Background="#333333" Foreground="White" HorizontalAlignment="Center" Margin="0,30,0,0"/>
<!-- 数值行 --> <!-- 数值行 -->
<TextBlock Grid.Row="1" Grid.Column="0" Text="下限" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,30,0,0" /> <TextBlock Grid.Row="1" Grid.Column="0" x:Name="LowerLimitTextBlock" Text="下限" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,30,0,0" />
<TextBlock Grid.Row="1" Grid.Column="1" Text="&lt;" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16" Margin="0,30,0,0"/> <TextBlock Grid.Row="1" Grid.Column="1" Text="&lt;" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16" Margin="0,30,0,0"/>
<TextBox Grid.Row="1" Grid.Column="2" Text="-0.0090" Height="30" Background="#E6F3FF" HorizontalAlignment="Center" Width="100" Margin="0,30,0,0"/> <TextBox Grid.Row="1" Grid.Column="2" x:Name="HighLimitTextBox" Text="-0.0090" Height="30" Background="#E6F3FF" HorizontalAlignment="Center" Width="100" Margin="0,30,0,0"/>
<Border Grid.Row="1" Grid.Column="3" Background="#CCCCCC" Height="30" Width="50" Margin="0,30,0,0"> <Border Grid.Row="1" Grid.Column="3" Background="#CCCCCC" Height="30" Width="50" Margin="0,30,0,0">
<TextBlock Text="NG" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold"/> <TextBlock x:Name="UnitMarkTextBlock" Text="NG" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold"/>
</Border> </Border>
</Grid> </Grid>
</StackPanel> </StackPanel>
@ -234,7 +234,7 @@
<!-- 底部按钮区域 --> <!-- 底部按钮区域 -->
<Border Grid.Row="1" Background="#E0E0E0" BorderBrush="#CCCCCC" BorderThickness="0,1,0,0"> <Border Grid.Row="1" Background="#E0E0E0" BorderBrush="#CCCCCC" BorderThickness="0,1,0,0">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="20,0"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="20,0">
<Button Content="保存" Width="80" Height="35" Background="#90EE90" Margin="10,0"/> <Button Click="CreateOrUpdateData_Click" Content="保存" Width="80" Height="35" Background="#90EE90" Margin="10,0"/>
<Button Content="取消" Width="80" Height="35" Background="#F0F0F0" Margin="10,0"/> <Button Content="取消" Width="80" Height="35" Background="#F0F0F0" Margin="10,0"/>
<Button Content="完成" Width="80" Height="35" Background="#F0F0F0" Margin="10,0"/> <Button Content="完成" Width="80" Height="35" Background="#F0F0F0" Margin="10,0"/>
</StackPanel> </StackPanel>

View File

@ -1,137 +1,508 @@
using System; using guoke;
using System.Collections.Generic; using SqlSugar;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using WpfApp.src.model;
using System.Windows.Navigation; namespace WpfApp.src.view;
using System.Windows.Shapes;
namespace WpfApp.src.view /// <summary>
/// ConfigPage.xaml 的交互逻辑
/// </summary>
public partial class ConfigPage : Page
{ {
/// <summary> // 等级数据字典,每个等级对应 LevelInfo
/// ConfigPage.xaml 的交互逻辑 private Dictionary<string, LevelInfo> levelData;
/// </summary> private Dictionary<int, SensorToleranceData> sensorData;
public partial class ConfigPage : Page private readonly LogService log;
{ private readonly DatabaseService db;
// 传感器数据字典,存储每个传感器的公差设定值 private readonly EventService<GeneralEventArgs> even;
private Dictionary<int, SensorToleranceData> sensorData;
public ConfigPage() public ConfigPage(LogService logService, DatabaseService databaseService, EventService<GeneralEventArgs> eventService)
{
InitializeComponent();
log = logService;
db = databaseService;
even = eventService;
SqlSugarScope scope = db.GetScope("D1");
scope.guokeCheckToCreate<Product>();
scope.guokeCheckToCreate<SensorSelection>();
scope.guokeCheckToCreate<SensorToleranceData>();
scope.guokeCheckToCreate<MainSensorSelection>();
scope.guokeCheckToCreate<LevelInfo>();
// 传感器选择
LoadSensorSelectionFromDb();
// 传感器公差
InitializeSensorData();
// 主传感器选择
LoadMainSensorSelectionFromDb();
// 等级
InitializeLevelData();
// 加载产品名称
LoadProductGroupName();
// 注册等级标签按钮点击事件
LevelTabUnder.Click += LevelTab_Click;
LevelTabA.Click += LevelTab_Click;
LevelTabB.Click += LevelTab_Click;
LevelTabC.Click += LevelTab_Click;
LevelTabD.Click += LevelTab_Click;
LevelTabE.Click += LevelTab_Click;
LevelTabF.Click += LevelTab_Click;
LevelTabG.Click += LevelTab_Click;
LevelTabOver.Click += LevelTab_Click;
}
#region
// 加载产品名称
private void LoadProductGroupName() {
SqlSugarScope scope = db.GetScope("D1");
var ProductGroupName = scope.Queryable<Product>().First();
if (ProductGroupName != null) {
LoadProductGroup(ProductGroupName);
}
}
private void LoadProductGroup(Product product)
{
ProductNameTextBox.Text = product.Name;
}
private void SaveProductGroupNameToDb()
{
}
#endregion
#region
// 从数据库加载传感器选择
private void LoadSensorSelectionFromDb()
{
SqlSugarScope scope = db.GetScope("D1");
// 假设只取第一个产品的主传感器数据
var mainSensor = scope.Queryable<SensorSelection>().First();
if (mainSensor != null)
{ {
InitializeComponent(); LoadSensorSelection(mainSensor);
InitializeSensorData(); }
}
// 每次 CheckBox 状态改变保存到数据库
private void Sensor_CheckedChanged(object sender, RoutedEventArgs e)
{
SaveSensorToDb();
}
/// <summary>
/// 将数据库中的主传感器数据加载到界面 CheckBox
/// </summary>
private void LoadSensorSelection(SensorSelection data)
{
chkDigitalSensor1.IsChecked = data.Sensor1;
chkDigitalSensor2.IsChecked = data.Sensor2;
chkDigitalSensor3.IsChecked = data.Sensor3;
chkDigitalSensor4.IsChecked = data.Sensor4;
}
/// <summary>
/// 保存界面 CheckBox 状态到数据库
/// </summary>
private void SaveSensorToDb()
{
var data = new SensorSelection
{
Sensor1 = chkDigitalSensor1.IsChecked == true,
Sensor2 = chkDigitalSensor2.IsChecked == true,
Sensor3 = chkDigitalSensor3.IsChecked == true,
Sensor4 = chkDigitalSensor4.IsChecked == true,
ProductName = "默认产品名" // 可以根据实际情况设置
};
SqlSugarScope scope = db.GetScope("D1");
// 如果数据库已存在该产品的主传感器数据,则更新,否则插入
var exist = scope.Queryable<SensorSelection>()
.Where(s => s.ProductName == data.ProductName)
.First();
if (exist != null)
{
data.Id = exist.Id; // 设置 Id 才能更新
scope.Updateable(data).ExecuteCommand();
}
else
{
scope.Insertable(data).ExecuteCommand();
} }
// 初始化传感器数据 log.Info($"保存传感器选择:{data.ProductName}");
private void InitializeSensorData() }
#endregion
#region
// 初始化传感器数据
private void InitializeSensorData()
{
sensorData = new Dictionary<int, SensorToleranceData>();
SqlSugarScope scope = db.GetScope("D1");
if (scope == null)
{ {
sensorData = new Dictionary<int, SensorToleranceData> MessageBox.Show("SqlSugarScope 获取失败!");
return;
}
string productName = "DFPV C15TE"; // TODO: 根据实际选择的产品替换
// 查询数据库
var sensors = scope.Queryable<SensorToleranceData>()
.Where(s => s.ProductName == productName)
.ToList();
for (int i = 1; i <= 4; i++)
{
var sensor = sensors.FirstOrDefault(s => s.SensorName == $"传感器{i}");
sensorData[i] = sensor ?? new SensorToleranceData
{ {
{ 1, new SensorToleranceData { MaxTolerance = "9.00", BaseTolerance = "72.9410", MinTolerance = "-9.00" } }, SensorName = $"传感器{i}",
{ 2, new SensorToleranceData { MaxTolerance = "8.50", BaseTolerance = "72.8500", MinTolerance = "-8.50" } }, MaxTolerance = "0.00",
{ 3, new SensorToleranceData { MaxTolerance = "7.80", BaseTolerance = "72.7800", MinTolerance = "-7.80" } }, BaseTolerance = "0.00",
{ 4, new SensorToleranceData { MaxTolerance = "6.90", BaseTolerance = "72.6900", MinTolerance = "-6.90" } } MinTolerance = "0.00",
ProductName = productName
}; };
} }
// 传感器标签页点击事件处理 // 加载第一个传感器数据到界面
private void SensorTab_Click(object sender, RoutedEventArgs e) LoadSensorData(1);
}
// 标签切换事件(只加载,不保存)
private void SensorTab_Click(object sender, RoutedEventArgs e)
{
if (sender is Button clickedButton && int.TryParse(clickedButton.Tag?.ToString(), out int sensorIndex))
{ {
Button clickedButton = sender as Button;
if (clickedButton == null) return;
int sensorIndex = int.Parse(clickedButton.Tag.ToString());
// 保存当前传感器的数据
SaveCurrentSensorData();
// 更新标签页样式
UpdateTabStyles(sensorIndex); UpdateTabStyles(sensorIndex);
// 加载选中传感器的数据
LoadSensorData(sensorIndex); LoadSensorData(sensorIndex);
} }
// 保存当前传感器的数据
private void SaveCurrentSensorData()
{
// 获取当前选中的传感器索引
int currentSensorIndex = GetCurrentSelectedSensorIndex();
if (sensorData.ContainsKey(currentSensorIndex))
{
sensorData[currentSensorIndex].MaxTolerance = MaxToleranceTextBox.Text;
sensorData[currentSensorIndex].BaseTolerance = BaseToleranceTextBox.Text;
sensorData[currentSensorIndex].MinTolerance = MinToleranceTextBox.Text;
}
}
// 获取当前选中的传感器索引
private int GetCurrentSelectedSensorIndex()
{
if (SensorTab1.Background is SolidColorBrush brush1 && brush1.Color == ((SolidColorBrush)new BrushConverter().ConvertFrom("#E6F3FF")).Color)
return 1;
if (SensorTab2.Background is SolidColorBrush brush2 && brush2.Color == ((SolidColorBrush)new BrushConverter().ConvertFrom("#E6F3FF")).Color)
return 2;
if (SensorTab3.Background is SolidColorBrush brush3 && brush3.Color == ((SolidColorBrush)new BrushConverter().ConvertFrom("#E6F3FF")).Color)
return 3;
if (SensorTab4.Background is SolidColorBrush brush4 && brush4.Color == ((SolidColorBrush)new BrushConverter().ConvertFrom("#E6F3FF")).Color)
return 4;
return 1; // 默认返回传感器1
}
// 更新标签页样式
private void UpdateTabStyles(int selectedIndex)
{
// 重置所有标签页样式
SensorTab1.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F0F0F0"));
SensorTab2.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F0F0F0"));
SensorTab3.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F0F0F0"));
SensorTab4.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F0F0F0"));
// 设置选中标签页样式
switch (selectedIndex)
{
case 1:
SensorTab1.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E6F3FF"));
break;
case 2:
SensorTab2.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E6F3FF"));
break;
case 3:
SensorTab3.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E6F3FF"));
break;
case 4:
SensorTab4.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E6F3FF"));
break;
}
}
// 加载传感器数据
private void LoadSensorData(int sensorIndex)
{
if (sensorData.ContainsKey(sensorIndex))
{
var data = sensorData[sensorIndex];
MaxToleranceTextBox.Text = data.MaxTolerance;
BaseToleranceTextBox.Text = data.BaseTolerance;
MinToleranceTextBox.Text = data.MinTolerance;
}
}
} }
// 传感器公差数据类 // 更新标签页样式
public class SensorToleranceData private void UpdateTabStyles(int selectedIndex)
{ {
public string MaxTolerance { get; set; } var buttons = new[] { SensorTab1, SensorTab2, SensorTab3, SensorTab4 };
public string BaseTolerance { get; set; } for (int i = 0; i < buttons.Length; i++)
public string MinTolerance { get; set; } {
buttons[i].Background = (i + 1 == selectedIndex)
? new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E6F3FF"))
: new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F0F0F0"));
}
} }
// 加载数据到界面
private void LoadSensorData(int sensorIndex)
{
if (sensorData.ContainsKey(sensorIndex) &&
MaxToleranceTextBox != null &&
BaseToleranceTextBox != null &&
MinToleranceTextBox != null)
{
var data = sensorData[sensorIndex];
MaxToleranceTextBox.Text = data.MaxTolerance;
BaseToleranceTextBox.Text = data.BaseTolerance;
MinToleranceTextBox.Text = data.MinTolerance;
}
}
// 保存按钮事件
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
int currentSensorIndex = GetCurrentSelectedSensorIndex();
// 保存当前界面数据到字典
if (sensorData.ContainsKey(currentSensorIndex))
{
sensorData[currentSensorIndex].MaxTolerance = MaxToleranceTextBox.Text;
sensorData[currentSensorIndex].BaseTolerance = BaseToleranceTextBox.Text;
sensorData[currentSensorIndex].MinTolerance = MinToleranceTextBox.Text;
}
// 写回数据库
SqlSugarScope scope = db.GetScope("D1");
foreach (var sensor in sensorData.Values)
{
var exist = scope.Queryable<SensorToleranceData>()
.Where(s => s.ProductName == sensor.ProductName && s.SensorName == sensor.SensorName)
.First();
if (exist != null)
{
sensor.Id = exist.Id;
scope.Updateable(sensor).ExecuteCommand();
}
else
{
scope.Insertable(sensor).ExecuteCommand();
}
}
MessageBox.Show("保存成功!");
}
// 获取当前选中的传感器索引
private int GetCurrentSelectedSensorIndex()
{
if (SensorTab1.Background is SolidColorBrush brush1 && brush1.Color == ((SolidColorBrush)new BrushConverter().ConvertFrom("#E6F3FF")).Color)
return 1;
if (SensorTab2.Background is SolidColorBrush brush2 && brush2.Color == ((SolidColorBrush)new BrushConverter().ConvertFrom("#E6F3FF")).Color)
return 2;
if (SensorTab3.Background is SolidColorBrush brush3 && brush3.Color == ((SolidColorBrush)new BrushConverter().ConvertFrom("#E6F3FF")).Color)
return 3;
if (SensorTab4.Background is SolidColorBrush brush4 && brush4.Color == ((SolidColorBrush)new BrushConverter().ConvertFrom("#E6F3FF")).Color)
return 4;
return 1;
}
// 保存传感器公差数据到数据库
private void SaveSensorToleranceDataToDb()
{
}
#endregion
#region
// 主传感器
private void LoadMainSensorSelectionFromDb()
{
SqlSugarScope scope = db.GetScope("D1");
// 假设只取第一个产品的主传感器数据
var mainSensor = scope.Queryable<MainSensorSelection>().First();
if (mainSensor != null)
{
LoadMainSensorSelection(mainSensor);
}
}
/// <summary>
/// 将数据库中的主传感器数据加载到界面 CheckBox
/// </summary>
private void LoadMainSensorSelection(MainSensorSelection data)
{
chkDigitalMainSensor1.IsChecked = data.DigitalSensor1;
chkDigitalMainSensor2.IsChecked = data.DigitalSensor2;
chkDigitalMainSensor3.IsChecked = data.DigitalSensor3;
chkDigitalMainSensor4.IsChecked = data.DigitalSensor4;
}
/// <summary>
/// 保存界面 CheckBox 状态到数据库
/// </summary>
private void SaveMainSensorToDb()
{
var data = new MainSensorSelection
{
DigitalSensor1 = chkDigitalMainSensor1.IsChecked == true,
DigitalSensor2 = chkDigitalMainSensor2.IsChecked == true,
DigitalSensor3 = chkDigitalMainSensor3.IsChecked == true,
DigitalSensor4 = chkDigitalMainSensor4.IsChecked == true,
ProductName = "默认产品名" // 可以根据实际情况设置
};
SqlSugarScope scope = db.GetScope("D1");
// 如果数据库已存在该产品的主传感器数据,则更新,否则插入
var exist = scope.Queryable<SensorSelection>()
.Where(s => s.ProductName == data.ProductName)
.First();
if (exist != null)
{
data.Id = exist.Id; // 设置 Id 才能更新
scope.Updateable(data).ExecuteCommand();
}
else
{
scope.Insertable(data).ExecuteCommand();
}
log.Info($"保存传感器选择:{data.ProductName}");
}
#endregion
#region
// 初始化等级数据
private void InitializeLevelData()
{
levelData = new Dictionary<string, LevelInfo>();
SqlSugarScope scope = db.GetScope("D1");
if (scope == null)
{
MessageBox.Show("SqlSugarScope 获取失败!");
return;
}
string productName = "DFPV C15TE"; // TODO: 根据实际选择的产品替换
string[] tabs = { "Under", "A", "B", "C", "D", "E", "F", "G", "Over" };
// 从数据库查询该产品的等级数据
var sensorsRank = scope.Queryable<LevelInfo>()
.Where(s => s.ProductName == productName)
.ToList();
// 初始化每个等级
foreach (var tab in tabs)
{
var sensorRank = sensorsRank.FirstOrDefault(s => s.Name == tab);
if (sensorRank != null)
{
levelData[tab] = sensorRank;
}
else
{
// 没有数据库记录则初始化默认值
levelData[tab] = new LevelInfo
{
Name = tab,
Low = "0.0",
High = "0.0",
Mark = "NG",
Status = "NG",
ProductName = productName
};
}
}
// 默认加载第一个等级
LoadLevelData(tabs[0]);
}
// 加载数据到界面
private void LoadLevelData(string sensorIndex)
{
if (!levelData.ContainsKey(sensorIndex))
return;
var data = levelData[sensorIndex];
// 加强防护,防止 NullReferenceException
if (LowerLimitTextBlock != null)
LowerLimitTextBlock.Text = data.Low ?? "下限";
if (HighLimitTextBox != null)
HighLimitTextBox.Text = data.High ?? "0.0";
if (UnitMarkTextBlock != null)
UnitMarkTextBlock.Text = data.Mark ?? "NG";
}
// 等级标签按钮点击事件
private void LevelTab_Click(object sender, RoutedEventArgs e)
{
if (sender is Button btn && btn.Tag is string tabName)
{
// 保存当前等级修改
SaveCurrentLevelData();
// 更新标签样式
UpdateTabStyles(btn);
// 加载新等级
LoadLevelData(tabName);
}
}
// 保存当前显示的等级数据
private void SaveCurrentLevelData()
{
string currentTab = GetCurrentSelectedTab();
if (currentTab == null || !levelData.ContainsKey(currentTab))
return;
var data = levelData[currentTab];
// 直接取命名控件的值最稳妥
if (LowerLimitTextBlock != null)
data.Low = LowerLimitTextBlock.Text ?? "0.0";
if (HighLimitTextBox != null)
data.High = HighLimitTextBox.Text ?? "0.0";
if (UnitMarkTextBlock != null)
data.Mark = UnitMarkTextBlock.Text ?? "NG";
}
// 获取当前选中的标签名
private string GetCurrentSelectedTab()
{
if (LevelTabUnder?.Parent is Grid grid)
{
foreach (var child in grid.Children)
{
if (child is Button b && b.Background is SolidColorBrush brush)
{
var activeColor = (Color)ColorConverter.ConvertFromString("#E6F3FF");
if (brush.Color == activeColor)
return b.Tag?.ToString();
}
}
}
return null;
}
// 更新等级标签按钮样式
private void UpdateTabStyles(Button selectedBtn)
{
if (selectedBtn?.Parent is Grid grid)
{
foreach (var child in grid.Children)
{
if (child is Button b)
{
b.Background = (b == selectedBtn)
? new SolidColorBrush((Color)ColorConverter.ConvertFromString("#E6F3FF")) // 选中浅蓝
: new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F0F0F0")); // 未选灰
}
}
}
}
// 保存等级数据到数据库
private void SaveLevelDataToDb()
{
}
#endregion
#region ||
private void CreateOrUpdateData_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("保存数据!");
// 这里分成四个部分 进行保存判定
/*
1
2
3
4
*/
// 1-保存产品组名称到数据库
SaveProductGroupNameToDb();
// 2-保存多选传感器的状态到数据库
SaveSensorToDb();
// 3-保存传感器公差数据到数据库
SaveSensorToleranceDataToDb();
// 4-保存单选主传感器的状态到数据库
SaveMainSensorToDb();
// 5-
SaveLevelDataToDb();
}
#endregion
} }