Files
NoBuilding/建材不燃性试验炉/MainWindow.xaml.cs

1611 lines
56 KiB
C#
Raw Normal View History

2026-01-31 09:14:24 +08:00
using DevExpress.Xpf.Charts;
using jiancaiburanxing;
using Microsoft.Win32;
using NModbus;
using NModbus.Device;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using .Data; // 这是关键
namespace
{
public partial class MainWindow : Window
{
#region
private DispatcherTimer _statusTimer;
private DispatcherTimer _testTimer;
private TimeSpan _testElapsedTime = TimeSpan.Zero;
private bool _isTestRunning = false;
private bool _isCalibrating = false;
private BackgroundWorker _calibrationWorker;
private Random _random = new Random();
//温度平衡相关
private DispatcherTimer _balanceTimer; // 平衡判断定时器1秒触发一次
private int _balanceElapsedSeconds; // 已计时秒数
private int _balanceTotalSeconds; // 总计时秒数默认600秒
private double _maxTempDiffThreshold; // 最大温差阈值默认10°C
private double _tempRangeThreshold; // 温度范围阈值默认±2°C
private List<double> _tempDataList; // 存储采集的温度数据
private double _maxTemp; // 采集周期内最高温度
private double _minTemp; // 采集周期内最低温度
private double _avgTemp; // 采集周期内平均温度
private bool _isBalanceChecking; // 是否正在进行平衡判断
// Modbus相关
private TcpClient _tcpClient => Data.ModbusResourceManager.Instance?.TcpClient;
private IModbusMaster _modbusMaster => Data.ModbusResourceManager.Instance?.ModbusMaster;
Function ma;
DataChange c;
#endregion
#region
public MainWindow()
{
InitializeComponent();
InitializeTimers();
InitializeControls();
InitializeBalanceVariables();//温度平衡相关变量
}
private void InitializeBalanceVariables()
{
_tempDataList = new List<double>();
_balanceTotalSeconds = 600;
_maxTempDiffThreshold = 10;
_tempRangeThreshold = 2;
_isBalanceChecking = false;
}
private void InitializeTimers()
{
// 状态更新定时器
_statusTimer = new DispatcherTimer();
_statusTimer.Interval = TimeSpan.FromSeconds(1);
_statusTimer.Tick += StatusTimer_Tick;
// 试验计时器
_testTimer = new DispatcherTimer();
_testTimer.Interval = TimeSpan.FromSeconds(1);
_testTimer.Tick += TestTimer_Tick;
//初始化平衡判断定时器
_balanceTimer = new DispatcherTimer();
_balanceTimer.Interval = TimeSpan.FromSeconds(1);
_balanceTimer.Tick += BalanceTimer_Tick;
}
private void InitializeControls()
{
// 初始化重量计算
UpdateWeightCalculation();
//初始化温度平衡显示
InitializeBalanceDisplays();
}
private void InitializeBalanceDisplays()
{
txtBalanceTimeElapsed.Text = "0秒";
txtBalanceCondition.Text = "平衡条件: 炉内温度波动:±5℃10分钟 且 最大温差≤10°C 且 温度漂移≤±2°C";
txtBalanceStatus.Text = "温度平衡状态: 未开始判断";
balanceStatusBorder.Background = new SolidColorBrush(Colors.Gray);
txtBalanceResult.Text = "未判断";
}
#endregion
#region
private void ThemedWindow_Loaded(object sender, RoutedEventArgs e)
{
try
{
DisableFinalWeightInput();
UpdateStatusBar("系统加载完成,准备就绪");
// 连接Modbus设备已注释根据实际情况启用
string plcIp = "192.168.1.10";
bool initSuccess = Data.ModbusResourceManager.Instance.Init(plcIp, 502);
if (!initSuccess)
{
MessageBox.Show("连接Modbus服务器失败", "错误");
this.Close();
return;
}
// 检查连接状态
if (_tcpClient == null || !_tcpClient.Connected)
{
MessageBox.Show("Modbus连接异常", "错误");
this.Close();
return;
}
c = new DataChange();
ma = new Function(_modbusMaster);
// 启动状态定时器
_statusTimer.Start();
}
catch (Exception ex)
{
MessageBox.Show($"初始化失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
this.Close();
}
}
#endregion
#region
private void StatusTimer_Tick(object sender, EventArgs e)
{
// 更新当前时间
string currentTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// 温度更新从Modbus读取
UpdateSimulatedTemperatures();
// 更新系统状态
UpdateSystemStatus();
// 更新设备状态
UpdateEquipmentStatus();
// 更新按钮状态
UpdateTestFanStatus();
UpdateMoveUpStatus();
UpdateMoveDownStatus();
}
private void TestTimer_Tick(object sender, EventArgs e)
{
if (_isTestRunning)
{
_testElapsedTime = _testElapsedTime.Add(TimeSpan.FromSeconds(1));
txtTestTime.Text = _testElapsedTime.ToString(@"hh\:mm\:ss");
// 更新进度
UpdateTestProgress();
// 检查计时节点
CheckTimeReminders();
}
}
private void BalanceTimer_Tick(object sender, EventArgs e)
{
try
{
// 1. 计时递增
_balanceElapsedSeconds++;
txtBalanceTimeElapsed.Text = $"{_balanceElapsedSeconds}秒";
// 2. 采集当前炉壁温度
double currentTemp = GetCurrentFurnaceTemp();
_tempDataList.Add(currentTemp);
// 4. 计算最大值、最小值、平均值
_maxTemp = double.MinValue;
_minTemp = double.MaxValue;
double sumTemp = 0;
foreach (var temp in _tempDataList)
{
if (temp > _maxTemp) _maxTemp = temp;
if (temp < _minTemp) _minTemp = temp;
sumTemp += temp;
}
_avgTemp = sumTemp / _tempDataList.Count;
double currentMaxDiff = _maxTemp - _avgTemp; // 最大值与平均值的温差
double tempRange = _maxTemp - _minTemp; // 温度波动范围
txtBalanceCondition.Text = $"平衡条件: 最大温差≤{_maxTempDiffThreshold}°C 且 温度波动≤±{_tempRangeThreshold}°C (当前: {tempRange:F1}°C)";
// 6. 判断是否达到平衡条件(计时结束后)
if (_balanceElapsedSeconds >= _balanceTotalSeconds)
{
_balanceTimer.Stop(); // 停止定时器
_isBalanceChecking = false;
bool isBalanced = currentMaxDiff <= _maxTempDiffThreshold && tempRange <= _tempRangeThreshold * 2;
// 更新平衡状态显示
if (isBalanced)
{
balanceStatusBorder.Background = new SolidColorBrush(Colors.Green);
txtBalanceResult.Text = "已平衡";
txtBalanceStatus.Text = $"温度平衡状态: 达到平衡(最大温差{currentMaxDiff:F1}°C温度波动{tempRange:F1}°C";
UpdateStatusBar("温度平衡判断完成:炉温已稳定");
}
}
}
catch (Exception ex)
{
MessageBox.Show($"温度平衡判断出错:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
_balanceTimer.Stop();
_isBalanceChecking = false;
}
}
// 获取当前炉壁温度
private double GetCurrentFurnaceTemp()
{
try
{
ushort[] registers = _modbusMaster.ReadHoldingRegisters(1, 1230, 2);//炉内温度显示
if (registers != null && registers.Length >= 2)
{
float modbusTemperature = c.UshortToFloat(registers[1], registers[0]);
return modbusTemperature;
}
return 0.0;
}
catch (Exception ex)
{
Debug.WriteLine($"读取Modbus温度失败: {ex.Message}");
return 0.0;
}
}
#endregion
#region
//开始试验
private void btnStartTest_Click(object sender, RoutedEventArgs e)
{
StartTest();
try
{
_isTestRunning = true;
_testElapsedTime = TimeSpan.Zero;
// 更新按钮状态
btnStartTest.IsEnabled = false;
btnStop.IsEnabled = true;
// 更新系统状态
txtSystemStatus.Text = "试验中";
statusIndicator2.Fill = new SolidColorBrush(Colors.Red);
// 启动试验计时器
_testTimer.Start();
// 重置进度条
progressBar.Width = 0;
txtProgress.Text = "0%";
UpdateStatusBar("试验开始");
}
catch (Exception ex)
{
MessageBox.Show($"启动试验失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
_isTestRunning = false;
btnStartTest.IsEnabled = true;
btnStop.IsEnabled = false;
}
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
EndTest();
StopTest();
//停止平衡判断
if (_isBalanceChecking)
{
_balanceTimer.Stop();
_isBalanceChecking = false;
btnStartBalanceCheck.IsEnabled = true;
txtBalanceStatus.Text = "温度平衡状态: 已停止判断";
}
}
private void StopTest()
{
_isTestRunning = false;
_testTimer.Stop();
// 更新按钮状态
btnStartTest.IsEnabled = true;
btnStop.IsEnabled = false;
// 更新系统状态
txtSystemStatus.Text = "试验结束";
statusIndicator2.Fill = new SolidColorBrush(Colors.Green);
// 检查是否已进行后称重
string finalText = txtFinalWeight.Text;
bool hasAfterWeight = false;
if (!string.IsNullOrEmpty(finalText) && finalText != "请输入试验后重量(g)")
{
if (double.TryParse(finalText, out double afterWeight) && afterWeight >= 0.1)
{
hasAfterWeight = true;
}
}
if (!hasAfterWeight)
{
// 提醒进行后称重
Dispatcher.Invoke(() =>
{
var result = MessageBox.Show("试验已结束。\n\n请进行后称重并将结果输入到'试验后重量'文本框中。",
"后称重提醒",
MessageBoxButton.OK, MessageBoxImage.Information);
});
}
UpdateStatusBar("试验结束");
}
private void btnStartDevice_Click(object sender, RoutedEventArgs e)
{
ma?.BtnClickFunctionForNew(Function.ButtonType., 70);
}
private void UpdateTestProgress()
{
// 假设试验总时长为60分钟
TimeSpan totalDuration = TimeSpan.FromMinutes(60);
double progress = (_testElapsedTime.TotalSeconds / totalDuration.TotalSeconds) * 100;
if (progress > 100) progress = 100;
Dispatcher.Invoke(() =>
{
// 更新进度条
double maxWidth = 400; // 进度条容器宽度
progressBar.Width = maxWidth * (progress / 100);
txtProgress.Text = $"{progress:F1}%";
});
}
private void CheckTimeReminders()
{
if (!_isTestRunning) return;
TimeSpan reminderTime = TimeSpan.Zero;
string reminderText = "";
if (_testElapsedTime.TotalMinutes >= 10 && chkTime10min.IsChecked == true)
{
reminderTime = TimeSpan.FromMinutes(10);
reminderText = "10分钟节点";
}
else if (_testElapsedTime.TotalMinutes >= 30 && chkTime30min.IsChecked == true)
{
reminderTime = TimeSpan.FromMinutes(30);
reminderText = "30分钟节点";
}
else if (_testElapsedTime.TotalMinutes >= 60 && chkTime60min.IsChecked == true)
{
reminderTime = TimeSpan.FromMinutes(60);
reminderText = "60分钟节点";
}
if (reminderTime != TimeSpan.Zero)
{
txtTimeReminder.Text = $"已完成: {reminderText}";
// 显示消息
if (_testElapsedTime.TotalMinutes >= reminderTime.TotalMinutes &&
_testElapsedTime.TotalMinutes < reminderTime.TotalMinutes + 1)
{
UpdateStatusBar($"达到{reminderText}");
}
}
// 更新下一个节点
UpdateNextReminder();
}
private void UpdateNextReminder()
{
if (!_isTestRunning) return;
if (_testElapsedTime.TotalMinutes < 10 && chkTime10min.IsChecked == true)
{
txtTimeReminder.Text = $"下一个节点: 10分钟 (剩余:{10 - _testElapsedTime.TotalMinutes:F1}分钟)";
}
else if (_testElapsedTime.TotalMinutes < 30 && chkTime30min.IsChecked == true)
{
txtTimeReminder.Text = $"下一个节点: 30分钟 (剩余:{30 - _testElapsedTime.TotalMinutes:F1}分钟)";
}
else if (_testElapsedTime.TotalMinutes < 60 && chkTime60min.IsChecked == true)
{
txtTimeReminder.Text = $"下一个节点: 60分钟 (剩余:{60 - _testElapsedTime.TotalMinutes:F1}分钟)";
}
else
{
txtTimeReminder.Text = "所有计时节点已完成";
}
}
#endregion
#region
private bool _isTestStopped = false;
// 开始测试
private void StartTest()
{
_isTestStopped = false;
// 禁用后称重输入
DisableFinalWeightInput();
}
// 停止测试
private void EndTest()
{
_isTestStopped = true;
// 启用后称重输入
EnableFinalWeightInput();
}
// 禁用后称重输入
private void DisableFinalWeightInput()
{
if (Dispatcher.CheckAccess())
{
txtFinalWeight.IsEnabled = false;
txtFinalWeight.Background = Brushes.LightGray;
txtFinalWeight.Text = "请输入试验后重量(g)";
}
else
{
Dispatcher.Invoke(() => DisableFinalWeightInput());
}
}
// 启用后称重输入
private void EnableFinalWeightInput()
{
if (Dispatcher.CheckAccess())
{
txtFinalWeight.IsEnabled = true;
txtFinalWeight.Background = Brushes.White;
txtFinalWeight.Text = "";
}
else
{
Dispatcher.Invoke(() => EnableFinalWeightInput());
}
}
private void txtFinalWeight_TextChanged(object sender, TextChangedEventArgs e)
{
// 如果测试未停止,阻止输入
if (!_isTestStopped)
{
if (Dispatcher.CheckAccess())
{
txtFinalWeight.Text = "请输入试验后重量(g)";
}
else
{
Dispatcher.Invoke(() => txtFinalWeight.Text = "请输入试验后重量(g)");
}
return;
}
// 实时更新重量计算
UpdateWeightCalculation();
}
private void txtInitialWeight_TextChanged(object sender, TextChangedEventArgs e)
{
// 实时更新重量计算
UpdateWeightCalculation();
}
private void UpdateWeightCalculation()
{
try
{
double initialWeight = 0;
double finalWeight = 0;
bool hasInitialWeight = false;
bool hasFinalWeight = false;
// 解析前称重
string initialText = txtInitialWeight.Text;
if (!string.IsNullOrEmpty(initialText) && initialText != "请输入试验前重量(g)")
{
if (double.TryParse(initialText, out initialWeight) && initialWeight >= 0.1)
{
hasInitialWeight = true;
}
}
// 解析后称重
string finalText = txtFinalWeight.Text;
if (!string.IsNullOrEmpty(finalText) && finalText != "请输入试验后重量(g)")
{
if (double.TryParse(finalText, out finalWeight) && finalWeight >= 0.1)
{
hasFinalWeight = true;
}
}
// 计算重量损失
double weightLoss = 0;
double weightLossPercentage = 0;
string weightLossText = "";
string weightStatus = "";
Brush weightStatusColor = Brushes.Gray;
if (hasInitialWeight)
{
if (hasFinalWeight)
{
weightLoss = initialWeight - finalWeight;
weightLossPercentage = (weightLoss / initialWeight) * 100;
weightLossText = $"损失:{weightLossPercentage:F1}%";
weightStatus = "已称重";
// 根据损失百分比设置颜色
if (weightLossPercentage > 50)
{
weightStatusColor = Brushes.Red;
}
else if (weightLossPercentage > 20)
{
weightStatusColor = Brushes.Orange;
}
else if (weightLossPercentage >= 0)
{
weightStatusColor = Brushes.Green;
}
else
{
// 重量增加的情况
weightStatusColor = Brushes.Purple;
}
}
else
{
weightLossText = "等待后称重";
weightStatus = "前称重完成";
weightStatusColor = Brushes.Orange;
}
}
else
{
weightLossText = "未称重";
weightStatus = "未称重";
weightStatusColor = Brushes.Gray;
}
// 更新显示
Dispatcher.Invoke(() =>
{
string initialDisplay = hasInitialWeight ? $"{initialWeight:F1}g" : "未输入";
string finalDisplay = hasFinalWeight ? $"{finalWeight:F1}g" : "未输入";
txtCurrentWeight.Text = $"前:{initialDisplay} | 后:{finalDisplay}";
txtWeightLossDisplay.Text = weightLossText;
txtWeightState.Text = weightStatus;
weightStatusBorder.Background = weightStatusColor;
// 更新详细文本
if (hasInitialWeight && hasFinalWeight)
{
string lossDescription = weightLoss > 0 ? "减少" :
weightLoss < 0 ? "增加" : "无变化";
txtWeightLoss.Text = $"重量{lossDescription}: {Math.Abs(weightLoss):F1}g ({Math.Abs(weightLossPercentage):F1}%)";
txtWeightStatus.Text = weightLoss > 0 ? "试样质量减少" :
weightLoss < 0 ? "试样质量增加" : "试样质量无变化";
}
else if (hasInitialWeight)
{
txtWeightLoss.Text = "等待后称重数据";
txtWeightStatus.Text = "";
}
else
{
txtWeightLoss.Text = "";
txtWeightStatus.Text = "";
}
});
}
catch (Exception ex)
{
Debug.WriteLine($"重量计算错误: {ex.Message}");
}
}
#endregion
#region
private void chkHasFlame_Checked(object sender, RoutedEventArgs e)
{
UpdateCombustionStatus();
}
private void chkHasFlame_Unchecked(object sender, RoutedEventArgs e)
{
UpdateCombustionStatus();
}
private void chkHasSmoke_Checked(object sender, RoutedEventArgs e)
{
UpdateCombustionStatus();
}
private void chkHasSmoke_Unchecked(object sender, RoutedEventArgs e)
{
UpdateCombustionStatus();
}
private void txtCombustionNote_TextChanged(object sender, TextChangedEventArgs e)
{
SyncCombustionNoteToFireTime();
}
private void UpdateCombustionStatus()
{
string flameStatus = chkHasFlame.IsChecked == true ? "有火焰" : "无火焰";
string smokeStatus = chkHasSmoke.IsChecked == true ? "有冒烟" : "无冒烟";
texfire.Text = $"{flameStatus}";
SyncCombustionNoteToFireTime();
texsmoking.Text = $"{smokeStatus}";
}
private void SyncCombustionNoteToFireTime()
{
if (txtbfiretime != null && txtCombustionNote != null)
{
// 或者只在有内容时显示:
if (!string.IsNullOrWhiteSpace(txtCombustionNote.Text))
{
txtbfiretime.Text = $"火焰持续时间(s): {txtCombustionNote.Text}";
}
else
{
txtbfiretime.Text = "";
}
}
}
#endregion
#region
//private void UpdateSimulatedTemperatures()
//{
// // 试验中的温度模拟
// double furnaceWallTemp = 750 + (_random.NextDouble() * 10 - 5); // 750±5°C
// double sampleCenterTemp = 500 + (_random.NextDouble() * 50 - 25); // 500±25°C
// double sampleSurfaceTemp = 600 + (_random.NextDouble() * 40 - 20); // 600±20°C
// UpdateTemperatureDisplay(furnaceWallTemp, sampleCenterTemp, sampleSurfaceTemp);
//}
private void UpdateSimulatedTemperatures()
{
try
{
// 检查Modbus连接状态
if (_modbusMaster == null)
{
Debug.WriteLine("ModbusMaster为空跳过更新");
return;
}
// 检查TCP连接状态
if (_tcpClient == null || !_tcpClient.Connected)
{
Debug.WriteLine("TCP连接断开跳过更新");
return;
}
// 读取三个温度值
float furnaceTemp = 0, sampleInternalTemp = 0, sampleSurfaceTemp = 0;
// 炉内温度相关 (D1226, D1230)
ReadAndUpdateRegister(1230, 2, value =>
{
furnaceTemp = value;
Dispatcher.Invoke(() => txtFurnaceWallTemp.Text = $"{value:F1}°C");
});
// 样品内温度相关 (D1280)
ReadAndUpdateRegister(1280, 2, value =>
{
sampleInternalTemp= value;
Dispatcher.Invoke(() => txtSampleCenterTemp.Text = $"{value:F1}°C");
});
// 样品外温度相关 (D1330)
ReadAndUpdateRegister(1330, 2, value =>
{
sampleSurfaceTemp= value;
Dispatcher.Invoke(() => txtSampleSurfaceTemp.Text = $"{value:F1}°C");
});
// 检查温度波动
CheckAllTemperatureFluctuations(furnaceTemp, sampleInternalTemp, sampleSurfaceTemp);
}
catch (InvalidOperationException ioex)
{
Debug.WriteLine($"Modbus通信错误{ioex.Message}");
}
catch (IOException ioex)
{
Debug.WriteLine($"IO错误{ioex.Message}");
HandleConnectionLost();
}
catch (Exception ex)
{
Debug.WriteLine($"更新数据时发生未知错误:{ex.Message}");
}
}
private void HandleConnectionLost()
{
try
{
// 停止定时器
_statusTimer?.Stop();
// 显示连接错误
Dispatcher.Invoke(() =>
{
MessageBox.Show("Modbus连接丢失请检查网络连接", "连接错误",
MessageBoxButton.OK, MessageBoxImage.Warning);
});
}
catch (Exception ex)
{
Debug.WriteLine($"处理连接丢失时出错:{ex.Message}");
}
}
private void ReadAndUpdateRegister(int address, int count, Action<float> updateAction)
{
try
{
// 安全检查
if (_modbusMaster == null || c == null)
{
Debug.WriteLine($"ModbusMaster或DataChange为空地址{address}跳过");
return;
}
// 读取寄存器
ushort[] registers = _modbusMaster.ReadHoldingRegisters(1, (ushort)address, (ushort)count);
// 空值检查
if (registers == null || registers.Length < count)
{
Debug.WriteLine($"读取地址{address}返回空值或长度不足");
return;
}
// 转换为浮点数
float value = c.UshortToFloat(registers[1], registers[0]);
updateAction?.Invoke(value);
}
catch (Exception ex)
{
Debug.WriteLine($"读取地址{address}失败:{ex.Message}");
}
}
//private void UpdateTemperatureDisplay(double furnaceWallTemp, double centerTemp, double surfaceTemp)
//{
// Dispatcher.Invoke(() =>
// {
// txtFurnaceWallTemp.Text = $"{furnaceWallTemp:F1}°C";
// txtSampleCenterTemp.Text = $"{centerTemp:F1}°C";
// txtSampleSurfaceTemp.Text = $"{surfaceTemp:F1}°C";
// // 检查温度波动
// CheckTemperatureFluctuation(furnaceWallTemp);
// });
//}
private void CheckAllTemperatureFluctuations(float furnaceTemp, float sampleInternalTemp, float sampleSurfaceTemp)
{
try
{
// 获取允许的波动范围
if (!double.TryParse(txtTempFluctuation.Text, out double allowedFluctuation))
{
allowedFluctuation = 5.0; // 默认值
}
// 获取目标温度
if (!double.TryParse(txtTestTemp.Text, out double targetTemp))
{
targetTemp = 0;
}
// 检查炉内温度波动
CheckSingleTemperature("炉内", furnaceTemp, targetTemp, allowedFluctuation,
txtFurnaceTempStatus);
// 检查样品内部温度波动
CheckSingleTemperature("样品内部", sampleInternalTemp, targetTemp, allowedFluctuation,
txtSampleInternalTempStatus);
// 检查样品表面温度波动
CheckSingleTemperature("样品表面", sampleSurfaceTemp, targetTemp, allowedFluctuation,
txtSampleSurfaceTempStatus);
}
catch (Exception ex)
{
Debug.WriteLine($"检查温度波动时出错:{ex.Message}");
}
}
private void CheckSingleTemperature(string tempName, double currentTemp, double targetTemp,
double allowedFluctuation, TextBlock statusTextBlock)
{
try
{
// 计算实际波动
double actualFluctuation = Math.Abs(currentTemp - targetTemp);
// 确定状态和颜色
string statusText;
string backgroundColor;
if (Math.Abs(targetTemp) < 0.001) // 目标温度为0表示未设置
{
statusText = $"{tempName}温度: {currentTemp:F1}°C";
backgroundColor = "#95A5A6"; // 灰色 - 未设置目标
}
else if (actualFluctuation <= allowedFluctuation)
{
statusText = $"{tempName}温度波动正常 (±{actualFluctuation:F1}°C)";
backgroundColor = "#27AE60"; // 绿色 - 正常
}
else if (actualFluctuation <= allowedFluctuation * 2) // 在2倍范围内
{
statusText = $"{tempName}温度波动警告 (±{actualFluctuation:F1}°C)";
backgroundColor = "#F39C12"; // 橙色 - 警告
}
else
{
statusText = $"{tempName}温度波动异常 (±{actualFluctuation:F1}°C)";
backgroundColor = "#E74C3C"; // 红色 - 异常
}
// 更新UI
Dispatcher.Invoke(() =>
{
statusTextBlock.Text = statusText;
Border border = statusTextBlock.Parent as Border;
if (border != null)
{
border.Background = new SolidColorBrush(
(Color)ColorConverter.ConvertFromString(backgroundColor));
}
});
}
catch (Exception ex)
{
Debug.WriteLine($"检查{tempName}温度波动时出错:{ex.Message}");
}
}
#endregion
#region
private void UpdateSystemStatus()
{
if (_tcpClient == null || _tcpClient.Connected)
{
txtStatusBar.Text = $"系统就绪 | {DateTime.Now:HH:mm:ss}";
}
else
{
txtStatusBar.Text = $"连接断开 | {DateTime.Now:HH:mm:ss}";
}
}
#endregion
#region
private void UpdateEquipmentStatus()
{
try
{
// 快速失败检查
if (_modbusMaster == null || _tcpClient == null || !_tcpClient.Connected)
{
SetDeviceStatusUI("设备未连接", "启动设备", Brushes.Gray);
return;
}
// 读取设备状态
bool[] isStart;
try
{
isStart = _modbusMaster.ReadCoils(1, 70, 1);
}
catch
{
SetDeviceStatusUI("读取失败", "启动设备", Brushes.Orange);
return;
}
// 验证数据
if (isStart == null || isStart.Length == 0)
{
SetDeviceStatusUI("状态未知", "启动设备", Brushes.Orange);
return;
}
// 更新UI
bool deviceStatus = isStart[0];
if (deviceStatus)
{
SetDeviceStatusUI("设备运行中", "运行中", Brushes.LimeGreen);
}
else
{
SetDeviceStatusUI("设备未启动", "启动设备", Brushes.Gray);
}
}
catch (Exception ex)
{
Debug.WriteLine($"更新设备状态时发生错误:{ex.GetType().Name}: {ex.Message}");
SetDeviceStatusUI("状态异常", "启动设备", ex is IOException ? Brushes.Red : Brushes.Orange);
}
}
private void SetDeviceStatusUI(string statusText, string buttonText, Brush statusColor)
{
try
{
// 检查UI控件是否为空
if (txtDeviceStatus == null || btnStartDevice == null || statusIndicator == null)
{
Debug.WriteLine("UI控件为空无法更新状态");
return;
}
// 确保在UI线程上执行
if (Dispatcher.CheckAccess())
{
// 当前线程是UI线程
txtDeviceStatus.Text = statusText;
btnStartDevice.Content = buttonText;
statusIndicator.Background = statusColor;
}
else
{
// 从非UI线程调用
Dispatcher.Invoke(() =>
{
txtDeviceStatus.Text = statusText;
btnStartDevice.Content = buttonText;
statusIndicator.Background = statusColor;
});
}
}
catch (Exception ex)
{
Debug.WriteLine($"更新UI状态时发生错误{ex.Message}");
}
}
#endregion
#region
private void UpdateButtonStatus(byte slaveId, ushort coilAddress, Button button, string activeText, string inactiveText)
{
try
{
// 快速失败检查
if (_modbusMaster == null || _tcpClient == null || !_tcpClient.Connected) return;
// 读取线圈状态
bool[] coilStatus;
try
{
// 假设参数是slaveId, startAddress, numberOfPoints
coilStatus = _modbusMaster.ReadCoils(slaveId, coilAddress, 1);
}
catch (Exception ex)
{
Debug.WriteLine($"读取线圈地址 {coilAddress} (slaveId: {slaveId}) 时失败: {ex.Message}");
return;
}
// 验证数据
if (coilStatus == null || coilStatus.Length == 0)
{
Debug.WriteLine($"线圈地址 {coilAddress} 返回数据为空");
return;
}
// 更新UI
bool isActive = coilStatus[0];
string buttonText = isActive ? activeText : inactiveText;
Debug.WriteLine($"线圈地址 {coilAddress} 状态: {isActive}, 更新文本: {buttonText}");
UpdateButtonText(button, buttonText);
}
catch (Exception ex)
{
Debug.WriteLine($"更新线圈状态时发生错误:{ex.GetType().Name}: {ex.Message}");
}
}
private void UpdateTestFanStatus()
{
UpdateButtonStatus(1, 0, btnTestFan, "腔体风机工作中", "测试腔体风机");
}
private void UpdateMoveUpStatus()
{
UpdateButtonStatus(1, 1, btnMoveUp, "上升中", "上升");
}
private void UpdateMoveDownStatus()
{
UpdateButtonStatus(1, 2, btnMoveDown, "下降中", "下降");
}
private void UpdateButtonText(Button button, string buttonText)
{
try
{
// 检查UI控件是否为空
if (button == null)
{
Debug.WriteLine("按钮控件为空,无法更新状态");
return;
}
// 确保在UI线程上执行
if (button.Dispatcher.CheckAccess())
{
Debug.WriteLine($"直接更新按钮文本: {buttonText}");
button.Content = buttonText;
}
else
{
Debug.WriteLine($"通过Dispatcher更新按钮文本: {buttonText}");
button.Dispatcher.Invoke(() =>
{
button.Content = buttonText;
});
}
}
catch (Exception ex)
{
Debug.WriteLine($"更新按钮状态时发生错误:{ex.Message}");
}
}
#endregion
#region
private void btnShowChart_Click(object sender, RoutedEventArgs e)
{
try
{
// 创建并显示温度曲线图窗口
TemperatureChartWindow chartWindow = new TemperatureChartWindow();
chartWindow.Owner = this;
chartWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
chartWindow.Show();
UpdateStatusBar("打开温度曲线图");
}
catch (Exception ex)
{
MessageBox.Show($"无法打开温度曲线图: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
//private void btnBalanceChart_Click(object sender, RoutedEventArgs e)
//{
// try
// {
// // 创建并显示温度曲线图窗口
// BalanceChartWindow chartWindow2 = new BalanceChartWindow();
// chartWindow2.Owner = this;
// chartWindow2.WindowStartupLocation = WindowStartupLocation.CenterOwner;
// chartWindow2.Show();
// UpdateStatusBar("打开温度曲线图");
// }
// catch (Exception ex)
// {
// MessageBox.Show($"无法打开温度曲线图: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
// }
//}
private void btnClearData_Click(object sender, RoutedEventArgs e)
{
var result = MessageBox.Show("确定要清空所有数据吗?", "确认",
MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
ClearAllData();
UpdateStatusBar("数据已清空");
}
}
private void ClearAllData()
{
// 清空文本框
txtSampleName.Text = "";
txtSampleSpec.Text = "";
txtTestNo.Text = "";
txtInitialWeight.Text = "";
txtFinalWeight.Text = "";
txtTestTemp.Text = "750";
txtTempFluctuation.Text = "5";
txtCombustionNote.Text = "";
// 重置复选框
chkTime10min.IsChecked = false;
chkTime30min.IsChecked = false;
chkTime60min.IsChecked = false;
chkHasFlame.IsChecked = false;
chkHasSmoke.IsChecked = false;
// 重置状态显示
txtCurrentWeight.Text = "前:0.0g | 后:0.0g";
txtWeightLossDisplay.Text = "损失:0.0%";
txtWeightState.Text = "未称重";
weightStatusBorder.Background = Brushes.Gray;
// 停止试验
if (_isTestRunning)
{
StopTest();
}
// 重置试验时间
_testElapsedTime = TimeSpan.Zero;
txtTestTime.Text = "00:00:00";
// 重置进度条
progressBar.Width = 0;
txtProgress.Text = "0%";
}
private void btnSaveData_Click(object sender, RoutedEventArgs e)
{
try
{
SaveTestData();
UpdateStatusBar("数据已保存");
}
catch (Exception ex)
{
MessageBox.Show($"保存数据失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void btnExportData_Click(object sender, RoutedEventArgs e)
{
try
{
ExportTestReport();
UpdateStatusBar("报告已导出");
}
catch (Exception ex)
{
MessageBox.Show($"导出报告失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void SaveTestData()
{
// 创建数据保存对话框
SaveFileDialog saveDialog = new SaveFileDialog();
saveDialog.Filter = "文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*";
saveDialog.FileName = $"试验数据_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
if (saveDialog.ShowDialog() == true)
{
StringBuilder data = new StringBuilder();
data.AppendLine("建材不燃性试验数据记录");
data.AppendLine($"生成时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
data.AppendLine("=".PadRight(50, '='));
data.AppendLine();
// 试样信息
data.AppendLine("一、试样信息");
data.AppendLine($" 名称/型号: {txtSampleName.Text}");
data.AppendLine($" 规格: {txtSampleSpec.Text}");
data.AppendLine($" 试验编号: {txtTestNo.Text}");
data.AppendLine();
// 重量数据
data.AppendLine("二、重量数据 (g)");
data.AppendLine($" 试验前重量: {txtInitialWeight.Text}");
data.AppendLine($" 试验后重量: {txtFinalWeight.Text}");
if (!string.IsNullOrEmpty(txtWeightLoss.Text))
{
data.AppendLine($" 重量损失: {txtWeightLoss.Text}");
}
data.AppendLine();
// 温度数据
data.AppendLine("三、温度数据 (°C)");
data.AppendLine($" 试验温度: {txtTestTemp.Text}");
data.AppendLine($" 允许波动: ±{txtTempFluctuation.Text}°C");
data.AppendLine();
// 试验过程
data.AppendLine("四、试验过程");
data.AppendLine($" 试验时间: {txtTestTime.Text}");
data.AppendLine($" 火焰: {(chkHasFlame.IsChecked == true ? "" : "")}");
data.AppendLine($" 冒烟: {(chkHasSmoke.IsChecked == true ? "" : "")}");
data.AppendLine($" 备注: {txtCombustionNote.Text}");
data.AppendLine();
data.AppendLine("=".PadRight(50, '='));
data.AppendLine("记录人: 系统自动生成");
data.AppendLine($"符合标准: GB/T 5464-2010");
// 写入文件
File.WriteAllText(saveDialog.FileName, data.ToString(), Encoding.UTF8);
MessageBox.Show($"数据已保存到:\n{saveDialog.FileName}", "保存成功",
MessageBoxButton.OK, MessageBoxImage.Information);
}
}
private void ExportTestReport()
{
// 创建报告导出对话框
SaveFileDialog saveDialog = new SaveFileDialog();
saveDialog.Filter = "CSV文件 (*.csv)|*.csv|所有文件 (*.*)|*.*";
saveDialog.FileName = $"试验报告_{DateTime.Now:yyyyMMdd_HHmmss}.csv";
if (saveDialog.ShowDialog() == true)
{
StringBuilder csv = new StringBuilder();
// CSV标题行
csv.AppendLine("项目,数值,单位,备注");
// 添加数据行
csv.AppendLine($"试样名称,{txtSampleName.Text},,");
csv.AppendLine($"试样规格,{txtSampleSpec.Text},mm,");
csv.AppendLine($"试验编号,{txtTestNo.Text},,");
csv.AppendLine($"试验前重量,{txtInitialWeight.Text},g,");
csv.AppendLine($"试验后重量,{txtFinalWeight.Text},g,");
csv.AppendLine($"重量损失百分比,{txtWeightLossDisplay.Text.Replace(":", "")},%,");
csv.AppendLine($"试验温度,{txtTestTemp.Text},°C,");
csv.AppendLine($"温度波动允许值,{txtTempFluctuation.Text},°C,");
csv.AppendLine($"试验时间,{txtTestTime.Text},,");
csv.AppendLine($"是否有火焰,{(chkHasFlame.IsChecked == true ? "" : "")},,");
csv.AppendLine($"是否有冒烟,{(chkHasSmoke.IsChecked == true ? "" : "")},,");
csv.AppendLine($"燃烧状态备注,{txtCombustionNote.Text},,");
csv.AppendLine($"生成时间,{DateTime.Now:yyyy-MM-dd HH:mm:ss},,");
// 写入文件
File.WriteAllText(saveDialog.FileName, csv.ToString(), Encoding.UTF8);
MessageBox.Show($"报告已导出到:\n{saveDialog.FileName}", "导出成功",
MessageBoxButton.OK, MessageBoxImage.Information);
}
}
//测试风机
private void btnTestFan_Click(object sender, RoutedEventArgs e)
{
ma?.BtnClickFunctionForNew(Function.ButtonType., 0);
}
//上升
private void btnMoveUp_Click(object sender, RoutedEventArgs e)
{
ma?.BtnClickFunctionForNew(Function.ButtonType., 1);
}
//下降
private void btnMoveDown_Click(object sender, RoutedEventArgs e)
{
ma?.BtnClickFunctionForNew(Function.ButtonType., 2);
}
#endregion
#region
// 开始平衡判断按钮点击事件
private void btnStartBalanceCheck_Click(object sender, RoutedEventArgs e)
{
if (_isBalanceChecking)
{
MessageBox.Show("温度平衡判断正在进行中,请等待完成", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
try
{
// 1. 获取用户设置的参数
if (!int.TryParse(txtBalanceTime.Text, out _balanceTotalSeconds) || _balanceTotalSeconds <= 0)
{
MessageBox.Show("请输入有效的平衡计时秒数(正数)", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
if (!double.TryParse(txtMaxTempDiff.Text, out _maxTempDiffThreshold) || _maxTempDiffThreshold < 0)
{
MessageBox.Show("请输入有效的最大温差阈值(非负数)", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
if (!double.TryParse(txtTempRange.Text, out _tempRangeThreshold) || _tempRangeThreshold < 0)
{
MessageBox.Show("请输入有效的温度范围阈值(非负数)", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// 2. 重置变量
_balanceElapsedSeconds = 0;
_tempDataList.Clear();
_maxTemp = double.MinValue;
_minTemp = double.MaxValue;
_avgTemp = 0;
_isBalanceChecking = true;
// 3. 更新界面
txtBalanceTimeElapsed.Text = $"0秒";
txtBalanceStatus.Text = $"温度平衡状态: 正在判断";
balanceStatusBorder.Background = new SolidColorBrush(Colors.Gray);
txtBalanceResult.Text = "判断中";
UpdateStatusBar($"开始温度平衡判断,计时...");
// 4. 启动定时器
_balanceTimer.Start();
// 5. 打开温度曲线图窗口
OpenBalanceChartWindow();
}
catch (Exception ex)
{
MessageBox.Show($"启动平衡判断失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void OpenBalanceChartWindow()
{
try
{
// 创建温度获取函数
Func<double> getFurnaceTemperature = () =>
{
try
{
// 从Modbus读取炉内温度
if (_modbusMaster != null && _tcpClient != null && _tcpClient.Connected)
{
ushort[] registers = _modbusMaster.ReadHoldingRegisters(1, 1230, 2);
if (registers != null && registers.Length >= 2)
{
float temperature = c.UshortToFloat(registers[1], registers[0]);
return temperature;
}
}
return 0.0;
}
catch (Exception ex)
{
Debug.WriteLine($"获取炉内温度失败: {ex.Message}");
return 0.0;
}
};
// 创建并显示温度曲线图窗口
BalanceChartWindow chartWindow = new BalanceChartWindow(getFurnaceTemperature);
chartWindow.Owner = this;
chartWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
chartWindow.Show();
UpdateStatusBar("打开温度平衡曲线图");
}
catch (Exception ex)
{
MessageBox.Show($"无法打开温度曲线图: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void btnStopBalanceCheck_Click(object sender, RoutedEventArgs e)
{
if (!_isBalanceChecking)
{
MessageBox.Show("当前未进行温度平衡判断", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// 1. 停止定时器
_balanceTimer.Stop();
// 2. 重置状态
_isBalanceChecking = false;
// 3. 更新界面提示
txtBalanceStatus.Text = $"温度平衡状态: 已手动停止(已计时{_balanceElapsedSeconds}秒)";
txtBalanceResult.Text = "已停止";
balanceStatusBorder.Background = new SolidColorBrush(Colors.Orange);
UpdateStatusBar($"温度平衡判断已手动停止(已计时{_balanceElapsedSeconds}秒)");
}
#endregion
#region
private void UpdateStatusBar(string message)
{
Dispatcher.Invoke(() =>
{
txtStatusBar.Text = $"{DateTime.Now:HH:mm:ss} - {message}";
});
}
// 辅助方法 - 安全获取值(保留,用于类型转换)
private decimal GetDecimalValue(string text)
{
if (decimal.TryParse(text, out decimal result))
{
return result;
}
return 0m;
}
private double GetDoubleValue(string text)
{
if (double.TryParse(text, out double result))
{
return result;
}
return 0;
}
#endregion
#region
private void Window_Closing(object sender, CancelEventArgs e)
{
base.OnClosing(e);
// 停止所有定时器
_statusTimer.Stop();
_testTimer.Stop();
_balanceTimer.Stop();
// 如果有试验在进行,询问是否保存
if (_isTestRunning)
{
var result = MessageBox.Show("试验正在进行中,确定要退出吗?", "确认退出",
MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.No)
{
e.Cancel = true;
}
}
}
#endregion
2026-01-31 15:36:02 +08:00
#region
2026-01-31 09:14:24 +08:00
private CofficientSetting _cofficientSetting;
2026-01-31 15:36:02 +08:00
private TestReportWindow _testReportWindow;
2026-01-31 09:14:24 +08:00
private DispatcherTimer _longPressTimer;
2026-01-31 15:36:02 +08:00
private void Button_Click(object sender, RoutedEventArgs e)
{
SwitchWindow(ref _testReportWindow, () => new TestReportWindow());
}
2026-01-31 09:14:24 +08:00
private void btnCoefficient_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// 启动长按计时器1秒
_longPressTimer = new DispatcherTimer();
_longPressTimer.Interval = TimeSpan.FromSeconds(1);
_longPressTimer.Tick += (s, args) =>
{
_longPressTimer.Stop();
SwitchWindow(ref _cofficientSetting, () => new CofficientSetting());
};
_longPressTimer.Start();
}
private void btnCoefficient_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// 释放鼠标时停止计时器
_longPressTimer?.Stop();
}
private void SwitchWindow<T>(ref T windowInstance, Func<T> createFunc) where T : Window, new()
{
// 1. 停止当前窗口的定时器(不释放资源)
_statusTimer?.Stop();
// 2. 复用窗口实例:不存在则创建,存在则激活
if (windowInstance == null)
{
windowInstance = createFunc();
// 添加窗口关闭事件处理
windowInstance.Closed += (s, args) =>
{
// 窗口关闭时重新启动定时器并显示当前窗口
_statusTimer?.Start();
this.Show();
this.Activate();
};
}
else
{
// 激活已存在的窗口(前置显示)
windowInstance.Activate();
return;
}
// 3. 切换窗口:隐藏当前窗口,显示目标窗口(非模态)
this.Hide();
windowInstance.Show();
}
2026-01-31 15:36:02 +08:00
2026-01-31 09:14:24 +08:00
#endregion
}
}