Files
Sleep-Multi-functionality/Window4.xaml.cs
2026-05-04 14:46:58 +08:00

1062 lines
36 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.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 Window4 : Window, IDisposable
{
DataChange c = new DataChange();
#region /线
// 基础参数地址
private readonly ushort _pressureSettingRegisterAddress = 0x013A; // 单一故障气阻设置流量D314
private readonly ushort _noseRegisterAddress = 0x055C; // 鼻口压力地址
private readonly ushort _modifiedNoseRegisterAddress = 0x0048; // 鼻口压力校准地址M72
private readonly ushort _outRegisterAddress = 120; // 呼流量地址
private readonly ushort _inRegisterAddress = 1400; // 吸流量地址
private readonly ushort _flowRegisterAddress = 0x013C; // 呼气阻力记录D136
private readonly ushort _flowInRegisterAddress = 0x013E; // 吸气阻力记录D318
private readonly ushort _BreathOutRegisterAddress = 316; // 记录呼气阻力实时显示
private readonly ushort _BreathInRegisterAddress = 318; // 记录吸气阻力实时显示
// 线圈地址(控制指令)
private readonly ushort _testStartAddress = 0x0020; // 单一故障气阻测试启动M32
private readonly ushort _testStopAddress = 0x0022; // 单一故障气阻测试停止M34
#endregion
#region
private TcpClient _tcpClient;
private IModbusMaster _modbusMaster;
Function fc;
// 定时器
private System.Timers.Timer _outReadTimer; // 呼流量读取
private System.Timers.Timer _inReadTimer; // 吸流量读取
private System.Timers.Timer _noseReadTimer; // 鼻口压力读取
private System.Timers.Timer _settingReadTimer2; //
private System.Timers.Timer startTimer; // 启动状态实时定时器
#endregion
public Window4()
{
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;
// 初始化定时器
InitializeTimers();
fc = new Function(_modbusMaster);
// 初始化数据库
InitializeDatabase();
}
catch (Exception ex)
{
ShowError($"Modbus初始化失败: {ex.Message}");
}
}
/// <summary>
/// 统一初始化所有定时器
/// </summary>
private void InitializeTimers()
{
_outReadTimer = CreateTimer(1000, OnOutTimerElapsed);
_inReadTimer = CreateTimer(1000, OnInTimerElapsed);
_noseReadTimer = CreateTimer(1000, OnNoseTimerElapsed);
_settingReadTimer2 = CreateTimer(1000, OnSettingReadTimerTimerElapsed2);
startTimer = CreateTimer(1000, OnStartTimerElapsed);
}
/// <summary>
/// 实时流量读取定时器修正跨线程访问UI问题
/// </summary>
private void OnStartTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
bool[] result = _modbusMaster?.ReadCoils(0x01, 33, 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}");
}
}
private void OnSettingReadTimerTimerElapsed2(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_pressureSettingRegisterAddress, true,
value => UpdateSettingUI2(value.ToString())
);
}
private void UpdateSettingUI2(string value)
{
UpdateUiSafely(() =>
clostTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
/// <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>
/// 释放资源
/// </summary>
public void Dispose()
{
// 释放定时器
_outReadTimer?.Dispose();
_inReadTimer?.Dispose();
_noseReadTimer?.Dispose();
// 释放Modbus连接
_tcpClient?.Close();
_tcpClient?.Dispose();
_modbusMaster = null;
}
/// <summary>
/// 窗口关闭时释放资源
/// </summary>
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Dispose();
}
#endregion
#region +UI更新
/// <summary>
/// 呼流量读取定时器
/// </summary>
private void OnOutTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_outRegisterAddress, true,
value => UpdateOutUI(value.ToString())
);
}
/// <summary>
/// 吸流量读取定时器
/// </summary>
private void OnInTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_inRegisterAddress, true,
value => UpdateInUI(value.ToString())
);
}
/// <summary>
/// 鼻口压力读取定时器
/// </summary>
private void OnNoseTimerElapsed(object sender, ElapsedEventArgs e)
{
ReadAndUpdateRegister(
_noseRegisterAddress, true,
value => UpdateNoseUI(value.ToString())
);
}
/// <summary>
/// 通用寄存器读取并更新UI支持16位整数和32位浮点数
/// </summary>
/// <param name="address">起始地址</param>
/// <param name="isFloat">是否为浮点型占用2个寄存器</param>
/// <param name="updateAction">更新UI的回调函数</param>
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)
{
// 浮点型转换2个16位寄存器组合为32位浮点数
if (data.Length >= 2)
{
// 2. 解析寄存器值data[0]是D312data[1]是D313
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
{
// 16位整数直接返回
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 UpdateOutUI(string value)
{
UpdateUiSafely(() =>
outTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
/// <summary>
/// 更新吸流量UI
/// </summary>
private void UpdateInUI(string value)
{
UpdateUiSafely(() =>
InTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
/// <summary>
/// 更新鼻口压力UI
/// </summary>
private void UpdateNoseUI(string value)
{
UpdateUiSafely(() =>
NoseTxt.Text = IsModbusConnected() ? 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 (Dispatcher.HasShutdownStarted)
{
return;
}
try
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.Invoke(action, TimeSpan.FromSeconds(2));
}
else
{
action.Invoke();
}
}
catch (TaskCanceledException)
{
}
catch (Exception ex)
{
Console.WriteLine($"UI更新失败{ex.Message}");
}
}
#endregion
#region
///// <summary>
///// 流量值设置settingTxt
///// </summary>
//private async void Button_Click(object sender, RoutedEventArgs e)
//{
// await WriteRegisterWithValidation(
// inputControl: settingTxt,
// registerAddress: _pressureSettingRegisterAddress,
// minValue: 0,
// maxValue: 10000,
// successMsg: value => $"设置流量值: {value} L/min"
// );
//}
/// <summary>
/// 鼻口压力校准M72线圈
/// </summary>
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
await WriteCoilWithCheck(
coilAddress: _modifiedNoseRegisterAddress,
value: true,
successMsg: "校准指令已被设备接收并执行(二次验证通过)",
failMsg: "校准执行超时,状态异常",
logMsg: "校准指令执行成功"
);
}
/// <summary>
/// 单一故障气阻测试停止M34线圈
/// </summary>
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
await WriteCoilWithCheck(
coilAddress: 0x0022, // M34
value: true,
successMsg: null, // 无弹窗,仅日志
failMsg: "单一故障气阻测试停止超时,状态异常",
logMsg: "单一故障气阻测试停止"
);
TestStartButton.Content = "测试启动";
TestStartButton.Foreground = Brushes.White;
}
/// <summary>
/// 单一故障气阻测试启动M20线圈
/// </summary>
private async void Button_Click_4(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)
);
// 等待并验证状态
await Task.Delay(100);
UpdateButtonStatus("测试启动成功", Brushes.LightGreen);
}
catch (Exception ex)
{
Console.WriteLine($"测试启动异常: {ex.Message}");
UpdateButtonStatus("测试启动失败", Brushes.Red);
ShowError($"操作异常: {ex.Message}");
}
}
/// <summary>
/// 读取呼气阻力D136并保存
/// </summary>
private async void Button_Click_5(object sender, RoutedEventArgs e)
{
//await ReadAndSaveRegister(
// address: _flowRegisterAddress,
// address2: _flowInRegisterAddress,
// control: saveFlowOutTxt,
// isFlow: true
//);
if (!IsModbusConnected())
{
saveFlowOutTxt.Text = "连接断开";
ShowError("Modbus TCP 未连接");
return;
}
fc.BtnClickFunctionForNew(Function.ButtonType., 192);
fc.BtnClickFunctionForNew(Function.ButtonType., 192);
ReadAndUpdateRegister(
_BreathOutRegisterAddress, true,
value => UpdateFlowFlowUI(value.ToString())
);
ReadAndUpdateRegister(
_BreathInRegisterAddress, true,
value => UpdateCloseFlowUI2(value.ToString())
);
// 尝试将文本框内容转换为float
if (float.TryParse(saveFlowOutTxt.Text, out float flowValue) &&
float.TryParse(saveFlowInTxt.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 ExpiratoryResistance 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;
}
}
private void UpdateFlowFlowUI(string value)
{
UpdateUiSafely(() =>
saveFlowOutTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
private void UpdateCloseFlowUI2(string value)
{
UpdateUiSafely(() =>
saveFlowInTxt.Text = IsModbusConnected() ? value : "连接断开"
);
}
///// <summary>
///// 读取吸气阻力D318并保存
///// </summary>
//private async void Button_Click_6(object sender, RoutedEventArgs e)
//{
// await ReadAndSaveRegister(
// address: _flowInRegisterAddress,
// control: saveFlowInTxt,
// isFlow: false
// );
//}
/// <summary>
/// 返回主窗口
/// </summary>
private void Button_Click_2(object sender, RoutedEventArgs e)
{
var mainWindow = MainWindow.Instance;
// 检查窗口状态只在窗口未显示时调用ShowDialog
if (!mainWindow.IsVisible)
{
mainWindow.ShowDialog();
}
else
{
// 如果窗口已显示,可将其激活到前台
mainWindow.Activate();
}
Close();
}
/// <summary>
/// 打开报告窗口
/// </summary>
private void Button_Click_7(object sender, RoutedEventArgs e)
{
new ReportWindow4().ShowDialog();
}
#endregion
#region
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();
}
}
private void UpdatePressureUI(string value)
{
UpdateUiSafely(() => clostTxt.Text = value);
}
/// <summary>
/// 写入线圈并验证状态
/// </summary>
private async Task WriteCoilWithCheck(
ushort coilAddress,
bool value,
string successMsg,
string failMsg,
string logMsg)
{
if (!IsModbusConnected())
{
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>
/// 读取寄存器并刷新UI
/// </summary>
private async Task RefreshRegister(ushort address, TextBox control)
{
try
{
ushort[] data = await Task.Run(() =>
_modbusMaster?.ReadHoldingRegisters(0x01, address, 1)
);
control.Text = data[0].ToString();
}
catch (Exception ex)
{
Console.WriteLine($"刷新寄存器失败: {ex.Message}");
}
}
/// <summary>
/// 读取线圈状态
/// </summary>
private async Task<bool> ReadCoilStatus(ushort address)
{
return await Task.Run(() =>
{
try
{
bool[] status = _modbusMaster?.ReadCoils(0x01, address, 1);
return status[0];
}
catch (Exception ex)
{
Console.WriteLine($"读取线圈状态失败: {ex.Message}");
return false;
}
});
}
/// <summary>
/// 读取寄存器并保存到数据库
/// </summary>
private async Task ReadAndSaveRegister(ushort address, ushort address2, TextBox control, bool isFlow)
{
if (!IsModbusConnected())
{
control.Text = "连接断开";
ShowError("Modbus TCP 未连接");
return;
}
try
{
control.Text = "读取中...";
// 读取寄存器
ushort[] data = await Task.Run(() =>
_modbusMaster?.ReadHoldingRegisters(0x01, address, 1)
);
double value = data[0];
control.Text = value.ToString("0.00");
saveFlowInTxt.Text = "读取中...";
// 读取寄存器
ushort[] data2 = await Task.Run(() =>
_modbusMaster?.ReadHoldingRegisters(0x01, address2, 1)
);
double value2 = data2[0];
saveFlowInTxt.Text = value2.ToString("0.00");
// 保存到数据库呼气阻力存Flow吸气阻力存Pressure
SaveRecordToDatabase(value, value2);
}
catch (Exception ex)
{
control.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 ExpiratoryResistance (
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 ExpiratoryResistance(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 string logPath => System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "modbus_log.txt");
/// <summary>
/// 写入操作日志
/// </summary>
private void WriteLog(string content)
{
try
{
string log = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {content}\r\n";
System.IO.File.AppendAllText(logPath, log);
}
catch (Exception ex)
{
Console.WriteLine($"写入日志失败: {ex.Message}");
}
}
#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}");
}
}
/// <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;
}
private void RefreshClosePressure()
{
ReadAndUpdateRegister(_pressureSettingRegisterAddress, true, v => UpdateClosePressureUI(v.ToString()));
}
private void UpdateClosePressureUI(string value)
{
UpdateUiSafely(() => clostTxt.Text = value);
}
// 消息提示封装
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
/// <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(36, false, null, "呼吸类别", "呼吸类别");
break;
case "吸气":
await WriteCoilWithCheck(36, true, null, "呼吸类别", "呼吸类别");
break;
default:
return;
}
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
await WriteRegisterWithValidation(
inputControl: clostTxt,
registerAddress: _pressureSettingRegisterAddress,
minValue: 0,
maxValue: 10000
);
//_settingReadTimer2.Start();
}
finally
{
}
}
}
}