Files
Sleep-Multi-functionality/Window3.xaml.cs

1295 lines
44 KiB
C#
Raw Normal View History

2026-05-04 14:46:58 +08:00
using Microsoft.Win32;
using Modbus.Device;
using Modbus;
using OfficeOpenXml;
using System;
using System.Configuration;
using System.Data.SQLite;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ;
using static ShanghaiEnvironmentalTechnology.Window5;
namespace ShanghaiEnvironmentalTechnology
{
/// <summary>
/// 防窒息压力测试窗口Modbus通信+压力数据处理)
/// </summary>
public partial class Window3 : Window, IDisposable
{
DataChange c = new DataChange();
#region /线
// 压力设置相关
private readonly ushort _pressureSettingRegisterAddress = 350; // 开阀压差判别D350
private readonly ushort _pressureCloseSettingRegisterAddress = 352; // 关阀压差判别D352
private readonly ushort _openRegisterAddress = 202; // 开阀压力记录地址
private readonly ushort _closeRegisterAddress = 206; // 关阀压力记录地址
private readonly ushort _pressureRegisterAddress = 1372; // 实时压力读取地址
// 测试控制线圈
private readonly ushort _testStartAddress = 0x0014; // 防窒息压力测试启动M20
private readonly ushort _testStopAddress = 0x001E; // 防窒息压力测试停止M30
private readonly ushort _calibrationCoilAddress = 0x0048; // 校准线圈M72
#endregion
#region
private TcpClient _tcpClient;
private IModbusMaster _modbusMaster;
private System.Timers.Timer _pressureReadTimer; // 实时压力读取定时器
private System.Timers.Timer _settingReadTimer; // 开阀压力设置定时器
private System.Timers.Timer _settingReadTimer2; // 关阀压力设置定时器
private System.Timers.Timer startTimer; // 启动状态实时定时器
Function fc;
#endregion
public Window3()
{
InitializeComponent();
InitializeModbusTcp();
Loaded += Window_Loaded;
}
#region
/// <summary>
/// 初始化Modbus连接和定时器
/// </summary>
private void InitializeModbusTcp()
{
try
{
string plcIp = ConfigurationManager.AppSettings["PLC1_IP"];
int plcPort = int.Parse(ConfigurationManager.AppSettings["PLC1_Port"]);
_tcpClient = new TcpClient(plcIp, plcPort);
_modbusMaster = ModbusIpMaster.CreateIp(_tcpClient);
_modbusMaster.Transport.ReadTimeout = 3000;
_modbusMaster.Transport.WriteTimeout = 3000;
// 初始化定时器
_pressureReadTimer = CreateTimer(1000, OnPressureTimerElapsed);
_settingReadTimer = CreateTimer(1000, OnSettingReadTimerTimerElapsed);
_settingReadTimer2 = CreateTimer(1000, OnSettingReadTimerTimerElapsed2);
startTimer = CreateTimer(1000, OnStartTimerElapsed);
fc = new Function(_modbusMaster);
// 初始化数据库
InitializeDatabase();
}
catch (Exception ex)
{
ShowError($"Modbus初始化失败: {ex.Message}");
}
}
/// <summary>
/// 通用定时器创建方法
/// </summary>
private System.Timers.Timer CreateTimer(int intervalMs, ElapsedEventHandler elapsedAction)
{
var timer = new System.Timers.Timer(intervalMs)
{
AutoReset = true,
Enabled = true
};
timer.Elapsed += elapsedAction;
return timer;
}
/// <summary>
/// 实时流量读取定时器修正跨线程访问UI问题
/// </summary>
private void OnStartTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
bool[] result = _modbusMaster?.ReadCoils(0x01, 21, 1);
bool isTestRunning = result != null && result.Length > 0 && result[0];
TestStartButton.Dispatcher.Invoke(() =>
{
if (isTestRunning)
{
TestStartButton.Content = "测试启动成功";
TestStartButton.Foreground = Brushes.LightGreen;
}
else
{
TestStartButton.Content = "测试启动";
TestStartButton.Foreground = Brushes.White;
}
});
}
catch (Exception ex)
{
Console.WriteLine($"读取线圈或更新UI失败{ex.Message}");
}
}
/// <summary>
/// 释放资源定时器、TCP连接
/// </summary>
public void Dispose()
{
_pressureReadTimer?.Dispose();
_settingReadTimer?.Dispose();
_settingReadTimer2?.Dispose();
_tcpClient?.Close();
_tcpClient?.Dispose();
_modbusMaster = null;
}
/// <summary>
/// 窗口关闭时释放资源
/// </summary>
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Dispose();
}
#endregion
#region
/// <summary>
/// 实时压力读取定时器
/// </summary>
private void OnPressureTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_pressureRegisterAddress,
true,
value => UpdateRealTimerPressureUI(value.ToString())
);
}
/// <summary>
/// 开阀压力设置定时器(带编辑锁判断)
/// </summary>
private void OnSettingReadTimerTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_pressureSettingRegisterAddress, false,
value => UpdateSettingUI(value.ToString())
);
}
/// <summary>
/// 关阀压力设置定时器(带编辑锁判断)
/// </summary>
private void OnSettingReadTimerTimerElapsed2(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_pressureCloseSettingRegisterAddress, false,
value => UpdateSettingUI2(value.ToString())
);
}
/// <summary>
/// 通用寄存器读取并更新UI支持16位整数和32位浮点数
/// </summary>
private void ReadAndUpdateRegister(ushort address, bool isFloat, Action<object> updateAction)
{
if (!IsModbusConnected())
{
updateAction?.Invoke(isFloat ? (object)float.NaN : (ushort)0);
return;
}
try
{
int registerCount = isFloat ? 2 : 1;
ushort[] data = _modbusMaster?.ReadHoldingRegisters(0x01, address, (ushort)registerCount);
if (isFloat)
{
if (data.Length >= 2)
{
ushort a = data[0]; // 高位寄存器值
ushort b = data[1]; // 低位寄存器值
float floatValue = c.UshortToFloat(b, a);
floatValue = (float)Math.Round(floatValue, 2);
updateAction?.Invoke(floatValue);
}
else
{
updateAction?.Invoke(float.NaN);
}
}
else
{
updateAction?.Invoke(data.Length > 0 ? data[0] : (ushort)0);
}
}
catch (Exception ex)
{
Console.WriteLine($"读取寄存器[{address:X4}]失败: {ex.Message}");
updateAction?.Invoke(isFloat ? (object)float.NaN : (ushort)0);
}
}
#endregion
#region UI更新线
/// <summary>
/// 更新实时压力UI
/// </summary>
private void UpdateRealTimerPressureUI(string value)
{
UpdateUiSafely(() =>
TimerPressTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
/// <summary>
/// 更新开阀压力设置UI
/// </summary>
private void UpdateSettingUI(string value)
{
UpdateUiSafely(() =>
SettingPaTextBox.Text = IsModbusConnected() ? value : "连接断开"
);
}
/// <summary>
/// 更新关阀压力设置UI
/// </summary>
private void UpdateSettingUI2(string value)
{
UpdateUiSafely(() =>
clostTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
/// <summary>
/// 更新开阀压力设置UI旧方法兼容
/// </summary>
private void UpdatePressureUI(string value)
{
UpdateUiSafely(() => SettingPaTextBox.Text = value);
}
/// <summary>
/// 更新关阀压力设置UI旧方法兼容
/// </summary>
private void UpdateClosePressureUI(string value)
{
UpdateUiSafely(() => clostTxt.Text = value);
}
/// <summary>
/// 更新测试按钮状态UI
/// </summary>
private void UpdateButtonStatus(string text, Brush color)
{
UpdateUiSafely(() =>
{
TestStartButton.Content = text;
TestStartButton.Foreground = color;
});
}
/// <summary>
/// 线程安全的UI更新通用方法
/// </summary>
private void UpdateUiSafely(Action action)
{
if (action == null) return;
if (this.Dispatcher.HasShutdownStarted || this.Dispatcher.HasShutdownFinished)
return;
if (!Dispatcher.CheckAccess())
{
try
{
Dispatcher.BeginInvoke(action);
}
catch (TaskCanceledException)
{
}
}
else
{
action.Invoke();
}
}
#endregion
#region
/// <summary>
/// 开阀压差判别设置SettingPaTextBox
/// </summary>
private async void Button_Click(object sender, RoutedEventArgs e)
{
await WriteRegisterWithValidation(
inputControl: SettingPaTextBox,
registerAddress: _pressureSettingRegisterAddress,
minValue: 0,
maxValue: 10000,
successMsg: value => $"设置开阀压差判别: {value} Pa",
refreshAction: () => RefreshCurrentPressure()
);
}
/// <summary>
/// 关阀压差判别设置clostTxt
/// </summary>
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
await WriteRegisterWithValidation(
inputControl: clostTxt,
registerAddress: _pressureCloseSettingRegisterAddress,
minValue: 0,
maxValue: 10000,
successMsg: value => $"设置关阀压差判别: {value} Pa",
refreshAction: () => RefreshClosePressure()
);
}
/// <summary>
/// 读取开阀/关阀压力记录并保存
/// </summary>
private async void Button_Click_2(object sender, RoutedEventArgs e)
{
await ReadRegisterAndSave(
address: _openRegisterAddress,
address2: _closeRegisterAddress,
control: recordOpenTxt
);
}
/// <summary>
/// 防窒息压力校准M72线圈
/// </summary>
private async void Button_Click_4(object sender, RoutedEventArgs e)
{
await WriteCoilWithCheck(
coilAddress: _calibrationCoilAddress,
value: true,
successMsg: "防窒息压力校准指令已被设备接收并执行",
failMsg: "校准执行超时,状态异常",
logMsg: "防窒息压力校准指令执行成功"
);
}
/// <summary>
/// 返回主窗口
/// </summary>
private void Button_Click_5(object sender, RoutedEventArgs e)
{
var mainWindow = MainWindow.Instance;
// 检查窗口状态只在窗口未显示时调用ShowDialog
if (!mainWindow.IsVisible)
{
mainWindow.ShowDialog();
}
else
{
// 如果窗口已显示,可将其激活到前台
mainWindow.Activate();
}
Close();
}
/// <summary>
/// 打开报告窗口
/// </summary>
private void Button_Click_6(object sender, RoutedEventArgs e)
{
new ReportWindow3().Show();
}
/// <summary>
/// 防窒息压力测试启动M20线圈
/// </summary>
private async void Button_Click_7(object sender, RoutedEventArgs e)
{
if (!IsModbusConnected())
{
UpdateButtonStatus("连接断开", Brushes.Red);
ShowError("Modbus TCP 未连接");
return;
}
try
{
UpdateButtonStatus("正在启动...", Brushes.LightGreen);
// 写入启动线圈(脉冲式触发)
await Task.Run(() => _modbusMaster.WriteSingleCoilAsync(0x01, _testStartAddress, true));
await Task.Delay(100);
await Task.Run(() => _modbusMaster.WriteSingleCoilAsync(0x01, _testStartAddress, false));
UpdateButtonStatus("测试启动成功", Brushes.LightGreen);
}
catch (Exception ex)
{
UpdateButtonStatus("测试启动失败", Brushes.Red);
ShowError($"操作异常: {ex.Message}");
}
}
/// <summary>
/// 防窒息压力测试停止M30线圈
/// </summary>
private async void Button_Click_8(object sender, RoutedEventArgs e)
{
await WriteCoilWithCheck(
coilAddress: _testStopAddress,
value: true,
successMsg: null,
failMsg: "防窒息压力测试停止超时,状态异常",
logMsg: "防窒息压力测试停止"
);
TestStartButton.Content = "测试启动";
TestStartButton.Foreground = Brushes.White;
}
#endregion
#region
/// <summary>
/// 带输入验证的寄存器写入(带成功消息)
/// </summary>
private async Task WriteRegisterWithValidation(
TextBox inputControl,
ushort registerAddress,
int minValue,
int maxValue,
Func<int, string> successMsg,
Action refreshAction)
{
if (!IsModbusConnected())
{
ShowError("Modbus TCP 未连接");
return;
}
// 输入验证
if (!int.TryParse(inputControl.Text.Trim(), out int value) ||
value < minValue || value > maxValue)
{
ShowWarning($"请输入{minValue}~{maxValue}的整数");
return;
}
try
{
inputControl.Text = "操作中...";
// 写入寄存器
await Task.Run(() =>
_modbusMaster.WriteSingleRegister(0x01, registerAddress, (ushort)value)
);
// 等待并刷新
await Task.Delay(300);
refreshAction?.Invoke();
ShowSuccess(successMsg(value));
}
catch (Exception ex)
{
ShowError($"操作失败: {ex.Message}");
}
finally
{
inputControl.Text = value.ToString();
}
}
/// <summary>
/// 带输入验证的寄存器写入(开阀压力专用)
/// </summary>
private async Task WriteRegisterWithValidation(
TextBox inputControl,
ushort registerAddress,
float minValue,
float maxValue)
{
if (!IsModbusConnected())
{
ShowError("Modbus TCP 未连接");
return;
}
// 输入验证
if (!float.TryParse(inputControl.Text.Trim(), out float value) ||
value < minValue || value > maxValue)
{
ShowWarning($"请输入{minValue}~{maxValue}的数字");
return;
}
try
{
inputControl.Text = "操作中...";
Function ma = new Function(_modbusMaster);
ma.WriteToPLCForNew(value.ToString(), registerAddress, Function.DataType.);
// 等待并刷新
await Task.Delay(300);
ReadAndUpdateRegister(registerAddress, true, v => UpdatePressureUI(v.ToString()));
}
catch (Exception ex)
{
ShowError($"操作失败: {ex.Message}");
}
finally
{
inputControl.Text = value.ToString();
}
}
/// <summary>
/// 带输入验证的寄存器写入(关阀压力专用)
/// </summary>
private async Task WriteRegisterWithValidation2(
TextBox inputControl,
ushort registerAddress,
float minValue,
float maxValue)
{
if (!IsModbusConnected())
{
ShowError("Modbus TCP 未连接");
return;
}
// 输入验证
if (!float.TryParse(inputControl.Text.Trim(), out float value) ||
value < minValue || value > maxValue)
{
ShowWarning($"请输入{minValue}~{maxValue}的数字");
return;
}
try
{
inputControl.Text = "操作中...";
Function ma = new Function(_modbusMaster);
ma.WriteToPLCForNew(value.ToString(), registerAddress, Function.DataType.);
// 等待并刷新
await Task.Delay(300);
ReadAndUpdateRegister(registerAddress, true, v => UpdateClosePressureUI(v.ToString()));
}
catch (Exception ex)
{
ShowError($"操作失败: {ex.Message}");
}
finally
{
inputControl.Text = value.ToString();
}
}
/// <summary>
/// 写入线圈并验证状态
/// </summary>
private async Task WriteCoilWithCheck(
ushort coilAddress,
bool value,
string successMsg,
string failMsg,
string logMsg)
{
if (!IsModbusConnected())
{
//ShowError("Modbus TCP 未连接");
InitializeModbusTcp();
return;
}
try
{
// 写入线圈
await Task.Run(() =>
_modbusMaster.WriteSingleCoilAsync(0x01, coilAddress, value)
);
Thread.Sleep(200);
// 停止/校准指令需要复位线圈
if (failMsg != null && (failMsg.Contains("停止") || failMsg.Contains("校准")))
{
await Task.Run(() =>
_modbusMaster.WriteSingleCoilAsync(0x01, coilAddress, false)
);
}
Thread.Sleep(100);
// 验证状态
await Task.Delay(500);
bool[] status = await _modbusMaster?.ReadCoilsAsync(0x01, coilAddress, 1);
if (failMsg != null && !failMsg.Contains("停止") && !failMsg.Contains("校准"))
{
if (status[0] == value)
{
WriteLog($"{logMsg} - 地址:{coilAddress},状态:{value}");
if (!string.IsNullOrEmpty(successMsg))
{
ShowSuccess(successMsg);
}
}
else
{
ShowError(failMsg);
}
}
}
catch (Exception ex)
{
ShowError($"通信错误: {ex.Message}");
}
}
/// <summary>
/// 下拉框选择变化事件处理
/// </summary>
private async void CaptureModeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender == null) return;
var comboBox = sender as ComboBox;
if (comboBox == null) return;
var selectedItem = comboBox.SelectedItem as ComboBoxItem;
if (selectedItem == null) return;
var content = selectedItem.Content?.ToString();
if (string.IsNullOrEmpty(content)) return;
switch (content)
{
case "开阀捕捉":
await WriteCoilWithCheck(0, true, null, "停止", "开关阀选择");
break;
case "关阀捕捉":
await WriteCoilWithCheck(1, true, null, "停止", "开关阀选择");
break;
default:
return;
}
}
/// <summary>
/// 刷新开阀压力设置
/// </summary>
private void RefreshCurrentPressure()
{
ReadAndUpdateRegister(_pressureSettingRegisterAddress, true, v => UpdatePressureUI(v.ToString()));
}
/// <summary>
/// 刷新关阀压力设置
/// </summary>
private void RefreshClosePressure()
{
ReadAndUpdateRegister(_pressureCloseSettingRegisterAddress, true, v => UpdateClosePressureUI(v.ToString()));
}
/// <summary>
/// 读取寄存器并保存到数据库
/// </summary>
private async Task ReadRegisterAndSave(ushort address, ushort address2, TextBlock control)
{
if (!IsModbusConnected())
{
control.Text = "连接断开";
ShowError("Modbus TCP 未连接");
return;
}
try
{
control.Text = "读取中...";
recordCloseTxt.Text = "读取中...";
// 读取开阀压力
ushort[] data = await Task.Run(() =>
_modbusMaster?.ReadHoldingRegisters(0x01, address, 2)
);
ushort a = data[0];
ushort b = data[1];
float value = c.UshortToFloat(b, a);
value = (float)Math.Round(value, 2);
control.Text = value.ToString("0.00");
// 读取关阀压力
ushort[] data2 = await Task.Run(() =>
_modbusMaster?.ReadHoldingRegisters(0x01, address2, 2)
);
ushort a2 = data2[0];
ushort b2 = data2[1];
float value2 = c.UshortToFloat(b2, a2);
value2 = (float)Math.Round(value2, 2);
recordCloseTxt.Text = value2.ToString("0.00");
// 保存到数据库
SaveRecordToDatabase(value, value2);
}
catch (Exception ex)
{
control.Text = "读取失败";
recordCloseTxt.Text = "读取失败";
ShowError($"读取失败: {ex.Message}");
}
}
#endregion
#region
/// <summary>
/// 初始化数据库
/// </summary>
private void InitializeDatabase()
{
try
{
using (var conn = new SQLiteConnection(CSConstant.DbConnectionString))
{
conn.Open();
string createSql = @"
CREATE TABLE IF NOT EXISTS PreventSuffocation (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Flow REAL NOT NULL,
Pressure REAL NOT NULL,
RecordTime DATETIME NOT NULL
);";
using (var cmd = new SQLiteCommand(createSql, conn))
{
cmd.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
Console.WriteLine($"数据库初始化失败: {ex.Message}");
ShowError($"数据库错误: {ex.Message}");
}
}
/// <summary>
/// 保存记录到数据库
/// </summary>
private void SaveRecordToDatabase(double flow, double pressure)
{
try
{
flow = Math.Round(flow, 2);
pressure = Math.Round(pressure, 2);
using (var conn = new SQLiteConnection(CSConstant.DbConnectionString))
{
conn.Open();
string insertSql = @"
INSERT INTO PreventSuffocation (Flow, Pressure, RecordTime)
VALUES (@Flow, @Pressure, @RecordTime);";
using (var cmd = new SQLiteCommand(insertSql, conn))
{
cmd.Parameters.AddWithValue("@Flow", flow);
cmd.Parameters.AddWithValue("@Pressure", pressure);
cmd.Parameters.AddWithValue("@RecordTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
cmd.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
Console.WriteLine($"保存数据库失败: {ex.Message}");
ShowWarning($"数据保存失败: {ex.Message}");
}
}
/// <summary>
/// 写入操作日志
/// </summary>
private void WriteLog(string content)
{
try
{
string log = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {content}\r\n";
string logPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "modbus_log.txt");
System.IO.File.AppendAllText(logPath, log);
}
catch (Exception ex)
{
Console.WriteLine($"写入日志失败: {ex.Message}");
}
}
#endregion
#region
///// <summary>
///// SettingPaTextBox获取焦点暂停定时器标记编辑状态
///// </summary>
//private void SettingPaTextBox_GotFocus(object sender, RoutedEventArgs e)
//{
// _isEditingSettingPa = true;
// _settingReadTimer.Stop();
//}
///// <summary>
///// SettingPaTextBox失去焦点恢复定时器取消编辑状态
///// </summary>
//private async void SettingPaTextBox_LostFocus(object sender, RoutedEventArgs e)
//{
// if (!_isWriting)
// {
// _isWriting = true;
// try
// {
// // 保存用户输入
// await WriteRegisterWithValidation(
// inputControl: SettingPaTextBox,
// registerAddress: _pressureSettingRegisterAddress,
// minValue: 0,
// maxValue: 10000
// );
// // 恢复更新
// _isEditingSettingPa = false;
// _settingReadTimer.Start();
// // 手动同步一次最新值
// RefreshCurrentPressure();
// }
// finally
// {
// _isWriting = false;
// }
// }
// EndEditing(sender as TextBox);
//}
///// <summary>
///// clostTxt获取焦点暂停定时器标记编辑状态
///// </summary>
//private void ClostTxt_GotFocus(object sender, RoutedEventArgs e)
//{
// _isEditingClostTxt = true;
// _settingReadTimer2.Stop();
//}
///// <summary>
///// clostTxt失去焦点恢复定时器取消编辑状态
///// </summary>
//private async void ClostTxt_LostFocus(object sender, RoutedEventArgs e)
//{
// if (!_isWriting)
// {
// _isWriting = true;
// try
// {
// // 保存用户输入
// await WriteRegisterWithValidation2(
// inputControl: clostTxt,
// registerAddress: _pressureCloseSettingRegisterAddress,
// minValue: 0,
// maxValue: 10000
// );
// // 恢复更新
// _isEditingClostTxt = false;
// _settingReadTimer2.Start();
// // 手动同步一次最新值
// RefreshClosePressure();
// }
// finally
// {
// _isWriting = false;
// }
// }
//}
/// <summary>
/// SettingPaTextBox输入验证仅允许数字和小数点
/// </summary>
private void SettingPaTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
var isNumber = System.Text.RegularExpressions.Regex.IsMatch(e.Text, @"^[0-9]*(?:\.[0-9]*)?$");
e.Handled = !isNumber;
}
/// <summary>
/// clostTxt输入验证仅允许数字和小数点
/// </summary>
private void ClostTxt_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
var isNumber = System.Text.RegularExpressions.Regex.IsMatch(e.Text, @"^[0-9]*(?:\.[0-9]*)?$");
e.Handled = !isNumber;
}
/// <summary>
/// SettingPaTextBox鼠标离开事件
/// </summary>
private async void SettingPaTextBox_MouseLeave(object sender, MouseEventArgs e)
{
}
///// <summary>
///// clostTxt鼠标离开事件
///// </summary>
//private async void ClostTxt_MouseLeave(object sender, MouseEventArgs e)
//{
// if (clostTxt.IsFocused)
// {
// clostTxt.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
// }
// if (!_isWriting && !_isEditingClostTxt)
// {
// _isWriting = true;
// try
// {
// await WriteRegisterWithValidation2(
// inputControl: clostTxt,
// registerAddress: _pressureCloseSettingRegisterAddress,
// minValue: 0,
// maxValue: 10000
// );
// _settingReadTimer2.Start();
// }
// finally
// {
// _isWriting = false;
// }
// }
//}
#endregion
#region
/// <summary>
/// 检查Modbus连接状态
/// </summary>
private bool IsModbusConnected()
{
return _modbusMaster != null && _tcpClient?.Connected == true;
}
/// <summary>
/// 加载窗口背景
/// </summary>
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
string imgPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources/sleep2.jpg");
if (System.IO.File.Exists(imgPath))
{
Background = new ImageBrush
{
ImageSource = new BitmapImage(new Uri(imgPath, UriKind.Absolute))
};
}
else
{
Console.WriteLine($"背景图片不存在: {imgPath}");
}
}
catch (Exception ex)
{
Console.WriteLine($"加载背景失败: {ex.Message}");
}
}
// 消息提示封装
private void ShowSuccess(string msg) => MessageBox.Show(msg, "成功", MessageBoxButton.OK, MessageBoxImage.Information);
private void ShowWarning(string msg) => MessageBox.Show(msg, "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
#endregion
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
if (!IsModbusConnected())
{
recordOpenTxt.Text = "连接断开";
ShowError("Modbus TCP 未连接");
return;
}
fc.BtnClickFunctionForNew(Function.ButtonType., 170);
fc.BtnClickFunctionForNew(Function.ButtonType., 170);
ReadAndUpdateRegister(
_openRegisterAddress, true,
value => UpdateFlowFlowUI(value.ToString())
);
ReadAndUpdateRegister(
_closeRegisterAddress, true,
value => UpdateCloseFlowUI(value.ToString())
);
// 尝试将文本框内容转换为float
if (float.TryParse(recordOpenTxt.Text, out float flowValue) &&
float.TryParse(recordCloseTxt.Text, out float pressureValue))
{
SaveRecordToDatabase(flowValue, pressureValue);
}
else
{
// 转换失败,提示错误信息
ShowError("流量或压力值格式不正确,请检查输入");
}
// 步骤2读取CO2表数据
List<CO2Record> co2Records = ReadCO2RecordsFromDatabase();
if (co2Records == null || !co2Records.Any())
{
MessageBox.Show("防室息阀压力表中无数据,无法导出", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// 步骤3导出Excel
bool exportSuccess = ExportCO2RecordsToExcel(co2Records);
if (exportSuccess)
{
MessageBox.Show("数据已成功导出到Excel", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
MessageBox.Show("Excel导出失败请检查文件是否被占用", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private bool ExportCO2RecordsToExcel(List<CO2Record> records)
{
try
{
// WPF 原生保存对话框(替代 WinForms
SaveFileDialog saveDialog = new SaveFileDialog
{
Filter = "Excel文件 (*.xlsx)|*.xlsx",
FileName = $"防室息阀压力记录_{DateTime.Now:yyyyMMddHHmmss}.xlsx",
Title = "保存防室息阀压力记录"
};
// 用户取消选择则返回
bool? result = saveDialog.ShowDialog(); if (!(result ?? false)) return false;
// EPPlus 许可设置(.NET 8 必须显式设置)
ExcelPackage.LicenseContext = LicenseContext.NonCommercial; // 非商业用途
// 创建并写入Excel
using (ExcelPackage package = new ExcelPackage(new FileInfo(saveDialog.FileName)))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("防室息阀压力记录");
// 表头对应DataGrid列
worksheet.Cells[1, 1].Value = "开阀压力pa";
worksheet.Cells[1, 2].Value = "关阀压力pa";
worksheet.Cells[1, 3].Value = "时间";
// 表头样式(加粗、居中)
using (var headerRange = worksheet.Cells[1, 1, 1, 6])
{
headerRange.Style.Font.Bold = true;
headerRange.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
}
// 填充数据从第2行开始
for (int i = 0; i < records.Count; i++)
{
int row = i + 2;
var record = records[i];
worksheet.Cells[row, 1].Value = record.Flow;
worksheet.Cells[row, 2].Value = record.Pressure;
worksheet.Cells[row, 3].Value = record.RecordTime.ToString("yyyy-MM-dd HH:mm:ss");
}
// 自动调整列宽
worksheet.Cells.AutoFitColumns();
// 保存文件
package.Save();
}
return true;
}
catch (Exception ex)
{
MessageBox.Show($"导出失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
}
/// <summary>
///
/// </summary>
private List<CO2Record> ReadCO2RecordsFromDatabase()
{
List<CO2Record> records = new List<CO2Record>();
try
{
using (SQLiteConnection conn = new SQLiteConnection(CSConstant.DbConnectionString))
{
conn.Open();
// 查询CO2表所有记录按时间排序
string query = "SELECT Flow, Pressure, RecordTime FROM PreventSuffocation ORDER BY RecordTime desc limit 1 ";
using (SQLiteCommand cmd = new SQLiteCommand(query, conn))
{
using (SQLiteDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
records.Add(new CO2Record
{
Flow = reader.GetDouble(0), // 二氧化碳浓度(%
Pressure = reader.GetDouble(1), // 压力pa
RecordTime = reader.GetDateTime(2) // 时间
});
}
}
}
}
return records;
}
catch (Exception ex)
{
MessageBox.Show($"读取防室息阀压力表失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}
}
/// <summary>
/// 更新实时流量UI
/// </summary>
private void UpdateFlowFlowUI(string value)
{
UpdateUiSafely(() =>
recordOpenTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
/// <summary>
/// 更新实时流量UI
/// </summary>
private void UpdateCloseFlowUI(string value)
{
UpdateUiSafely(() =>
recordCloseTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
private void Button_Click_9(object sender, RoutedEventArgs e)
{
if (!IsModbusConnected())
{
recordOpenTxt.Text = "连接断开";
ShowError("Modbus TCP 未连接");
return;
}
fc.BtnClickFunctionForNew(Function.ButtonType., 11);
fc.BtnClickFunctionForNew(Function.ButtonType., 11);
ReadAndUpdateRegister(
_openRegisterAddress, true,
value => UpdateFlowFlowUI(value.ToString())
);
ReadAndUpdateRegister(
_closeRegisterAddress, true,
value => UpdateCloseFlowUI(value.ToString())
);
// 尝试将文本框内容转换为float
if (float.TryParse(recordOpenTxt.Text, out float flowValue) &&
float.TryParse(recordCloseTxt.Text, out float pressureValue))
{
SaveRecordToDatabase(flowValue, pressureValue);
}
else
{
// 转换失败,提示错误信息
ShowError("流量或压力值格式不正确,请检查输入");
}
// 步骤2读取CO2表数据
List<CO2Record> co2Records = ReadCO2RecordsFromDatabase();
if (co2Records == null || !co2Records.Any())
{
MessageBox.Show("防室息阀压力表中无数据,无法导出", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// 步骤3导出Excel
bool exportSuccess = ExportCO2RecordsToExcel(co2Records);
if (exportSuccess)
{
MessageBox.Show("数据已成功导出到Excel", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
MessageBox.Show("Excel导出失败请检查文件是否被占用", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async void Button_Click_10(object sender, RoutedEventArgs e)
{
try
{
await WriteRegisterWithValidation(
inputControl: SettingPaTextBox,
registerAddress: _pressureSettingRegisterAddress,
minValue: 0,
maxValue: 10000
);
_settingReadTimer.Start();
}
finally
{
}
}
private async void Button_Click_11(object sender, RoutedEventArgs e)
{
try
{
await WriteRegisterWithValidation2(
inputControl: clostTxt,
registerAddress: _pressureCloseSettingRegisterAddress,
minValue: 0,
maxValue: 10000
);
_settingReadTimer2.Start();
}
finally
{
}
}
}
}