Files
NoBuilding/建材不燃性试验炉/CofficientSetting.xaml.cs
2026-01-31 09:14:24 +08:00

371 lines
13 KiB
C#
Raw 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 DevExpress.ClipboardSource.SpreadsheetML;
using NModbus;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using .Data; // 这是关键
namespace
{
/// <summary>
/// CofficientSetting.xaml 的交互逻辑
/// </summary>
public partial class CofficientSetting : Window
{
#region
//状态计时器
private DispatcherTimer _statusTimer;
private bool _isManualInput = false; // 手动输入标记true=输入中暂停读取false=正常读取
private TcpClient _tcpClient => Data.ModbusResourceManager.Instance?.TcpClient;
private IModbusMaster _modbusMaster => Data.ModbusResourceManager.Instance?.ModbusMaster;
Function ma;
DataChange c;
#endregion
#region
public CofficientSetting()
{
InitializeComponent();
InitializeTimers();
}
private void InitializeTimers()
{
// 状态更新定时器
_statusTimer = new DispatcherTimer();
_statusTimer.Interval = TimeSpan.FromSeconds(1);
_statusTimer.Tick += StatusTimer_Tick;
}
#endregion
#region
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
// 连接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();
// 启动状态定时器
_statusTimer.Start();
}
catch (Exception ex)
{
MessageBox.Show($"初始化失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
this.Close();
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// 停止所有计时器
_statusTimer?.Stop();
}
#endregion
#region
private void StatusTimer_Tick(object sender, EventArgs e)
{
// 如果正在手动输入,暂停读取
if (_isManualInput) return;
// 温度和系数更新
UpdateTemperaturesAndCofficient();
}
private void UpdateTemperaturesAndCofficient()
{
try
{
// 检查Modbus连接状态
if (_modbusMaster == null)
{
Debug.WriteLine("ModbusMaster为空跳过更新");
return;
}
// 检查TCP连接状态
if (_tcpClient == null || !_tcpClient.Connected)
{
Debug.WriteLine("TCP连接断开跳过更新");
return;
}
// 一次性读取所有相关寄存器,减少通信次数
// 定义要读取的寄存器地址范围
var readTasks = new List<Task>();
// 输出电压相关 (D304-D306)
ReadAndUpdateRegister(304, 2, value =>
Dispatcher.Invoke(() => txtOutputVoltageCoefficient.Text = value.ToString("F2")));
ReadAndUpdateRegister(306, 2, value =>
Dispatcher.Invoke(() => txtOutputVoltageAnalog.Text = value.ToString("F2")));
// 炉内温度相关 (D1226, D1230)
ReadAndUpdateRegister(1226, 2, value =>
Dispatcher.Invoke(() => txtFurnaceTempCoefficient.Text = value.ToString("F2")));
ReadAndUpdateRegister(1230, 2, value =>
Dispatcher.Invoke(() => txtFurnaceTempDisplay.Text = value.ToString("F2")));
// 样品内温度相关 (D1276, D1280)
ReadAndUpdateRegister(1276, 2, value =>
Dispatcher.Invoke(() => txtSampleInnerTempCoefficient.Text = value.ToString("F2")));
ReadAndUpdateRegister(1280, 2, value =>
Dispatcher.Invoke(() => txtSampleInnerTempDisplay.Text = value.ToString("F2")));
// 样品外温度相关 (D1328, D1330)
ReadAndUpdateRegister(1328, 2, value =>
Dispatcher.Invoke(() => txtSampleOuterTempCoefficient.Text = value.ToString("F2")));
ReadAndUpdateRegister(1330, 2, value =>
Dispatcher.Invoke(() => txtSampleOuterTempDisplay.Text = value.ToString("F2")));
// 电压表相关 (D1378, D1380)
ReadAndUpdateRegister(1378, 2, value =>
Dispatcher.Invoke(() => txtVoltmeterCoefficient.Text = value.ToString("F2")));
ReadAndUpdateRegister(1380, 2, value =>
Dispatcher.Invoke(() => txtVoltmeterDisplay.Text = value.ToString("F2")));
// 电流相关 (D1428, D1430)
ReadAndUpdateRegister(1428, 2, value =>
Dispatcher.Invoke(() => txtCurrentCoefficient.Text = value.ToString("F2")));
ReadAndUpdateRegister(1430, 2, value =>
Dispatcher.Invoke(() => txtCurrentDisplay.Text = value.ToString("F2")));
}
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 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 HandleConnectionLost()
{
try
{
// 停止定时器
_statusTimer?.Stop();
// 显示连接错误
Dispatcher.Invoke(() =>
{
MessageBox.Show("Modbus连接丢失请检查网络连接", "连接错误",
MessageBoxButton.OK, MessageBoxImage.Warning);
});
}
catch (Exception ex)
{
Debug.WriteLine($"处理连接丢失时出错:{ex.Message}");
}
}
#endregion
#region GotFocus写入事件
//输出电压系数D304
private void txtOutputVoltageCoefficient_GotFocus(object sender, RoutedEventArgs e)
{
_isManualInput = true; // 进入手动输入模式
// 延迟写入,确保用户有时间修改
Task.Delay(100).ContinueWith(_ =>
{
ma?.WriteToPLCForNew(txtOutputVoltageCoefficient.Text.Trim(), 304,Function.DataType.);
_isManualInput = false; // 写入后恢复自动读取
}, TaskScheduler.FromCurrentSynchronizationContext());
}
//炉内温度系数D1226
private void txtFurnaceTempCoefficient_GotFocus(object sender, RoutedEventArgs e)
{
_isManualInput = true;
Task.Delay(100).ContinueWith(_ =>
{
ma?.WriteToPLCForNew(txtFurnaceTempCoefficient.Text.Trim(), 1226, Function.DataType.);
_isManualInput = false;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
//样品内温度系数D1276
private void txtSampleInnerTempCoefficient_GotFocus(object sender, RoutedEventArgs e)
{
_isManualInput = true;
Task.Delay(100).ContinueWith(_ =>
{
ma?.WriteToPLCForNew(txtSampleInnerTempCoefficient.Text.Trim(), 1276, Function.DataType.);
_isManualInput = false;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
//样品外温度系数D1328
private void txtSampleOuterTempCoefficient_GotFocus(object sender, RoutedEventArgs e)
{
_isManualInput = true;
Task.Delay(100).ContinueWith(_ =>
{
ma?.WriteToPLCForNew(txtSampleOuterTempCoefficient.Text.Trim(), 1328, Function.DataType.);
_isManualInput = false;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
//电压表系数D1378
private void txtVoltmeterCoefficient_GotFocus(object sender, RoutedEventArgs e)
{
_isManualInput = true;
Task.Delay(100).ContinueWith(_ =>
{
ma?.WriteToPLCForNew(txtVoltmeterCoefficient.Text.Trim(), 1378, Function.DataType.);
_isManualInput = false;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
//电压表系数D1428
private void txtCurrentCoefficient_GotFocus(object sender, RoutedEventArgs e)
{
_isManualInput = true;
Task.Delay(100).ContinueWith(_ =>
{
ma?.WriteToPLCForNew(txtCurrentCoefficient.Text.Trim(), 1428, Function.DataType.);
_isManualInput = false;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
#endregion
#region
private MainWindow _mainWindow;
//返回
private void btnReturn_Click(object sender, RoutedEventArgs e)
{
SwitchWindow(ref _mainWindow, () => new MainWindow());
}
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();
}
#endregion
}
}