using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Threading; using MembranePoreTester.Communication; namespace MembranePoreTester { public partial class ParameterWindow : Window { private readonly IPlcService _plcService; private readonly PlcConfiguration _config; private DispatcherTimer _autoRefreshTimer; // 文本框映射:(文本框, 地址, 参数名, 是否浮点数) private readonly List<(TextBox textBox, ushort address, string name, bool isFloat)> _textBoxMapping = new(); public ParameterWindow() { InitializeComponent(); _plcService = App.PlcService; _config = App.PlcConfig; // 16位整数(灯条、中灯、电机) AddMapping(txtUpperLampData1, _config.UpperLampData1, "上灯条数据1", false); AddMapping(txtLowerLampData1, _config.LowerLampData1, "下灯条数据1", false); AddMapping(txtUpperLampData2, _config.UpperLampData2, "上灯条数据2", false); AddMapping(txtLowerLampData2, _config.LowerLampData2, "下灯条数据2", false); AddMapping(txtUpperLampData3, _config.UpperLampData3, "上灯条数据3", false); AddMapping(txtLowerLampData3, _config.LowerLampData3, "下灯条数据3", false); AddMapping(txtUpperLampData4, _config.UpperLampData4, "上灯条数据4", false); AddMapping(txtLowerLampData4, _config.LowerLampData4, "下灯条数据4", false); AddMapping(txtUpperLampData5, _config.UpperLampData5, "上灯条数据5", false); AddMapping(txtLowerLampData5, _config.LowerLampData5, "下灯条数据5", false); AddMapping(txtUpperLampData6, _config.UpperLampData6, "上灯条数据6", false); AddMapping(txtLowerLampData6, _config.LowerLampData6, "下灯条数据6", false); AddMapping(txtMiddleLamp1, _config.MiddleLamp1, "中灯1", false); AddMapping(txtMiddleLamp2, _config.MiddleLamp2, "中灯2", false); AddMapping(txtMiddleLamp3, _config.MiddleLamp3, "中灯3", false); AddMapping(txtMiddleLamp4, _config.MiddleLamp4, "中灯4", false); AddMapping(txtMiddleLamp5, _config.MiddleLamp5, "中灯5", false); AddMapping(txtMiddleLamp6, _config.MiddleLamp6, "中灯6", false); AddMapping(txtMiddleLamp7, _config.MiddleLamp7, "中灯7", false); AddMapping(txtMotorLimit, _config.MotorLimit, "电机限位", true); AddMapping(txtResetCompensation, _config.ResetCompensation, "复位补偿", true); AddMapping(txtLeftEyeAreaCoeff, _config.LeftEyeAreaCoeff, "左眼面积系数", true); AddMapping(txtRightEyeAreaCoeff, _config.RightEyeAreaCoeff, "右眼面积系数", true); AddMapping(txtSaveRateCorrectionCoeff, _config.SaveRateCorrectionCoeff, "保存率矫正系数", true); RegisterTextBoxEvents(); Loaded += async (s, e) => { _autoRefreshTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) }; _autoRefreshTimer.Tick += AutoRefreshTimer_Tick; _autoRefreshTimer.Start(); await LoadAllParameters(); }; Closed += (s, e) => _autoRefreshTimer?.Stop(); } private void AddMapping(TextBox textBox, ushort address, string name, bool isFloat) { if (textBox != null) { _textBoxMapping.Add((textBox, address, name, isFloat)); } } private void RegisterTextBoxEvents() { foreach (var (tb, addr, name, isFloat) in _textBoxMapping) { tb.LostFocus += async (s, e) => { if (float.TryParse(tb.Text, out float value)) { try { if (isFloat) await WriteFloatAsync(addr, value); else await WriteInt16Async(addr, (ushort)value); System.Diagnostics.Debug.WriteLine($"{name} 已写入: {value}"); } catch (Exception ex) { MessageBox.Show($"写入 {name} 失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } else { MessageBox.Show($"请输入有效的数值", "输入错误", MessageBoxButton.OK, MessageBoxImage.Warning); await UpdateSingleParameter(tb, addr, isFloat); } }; } } private async void AutoRefreshTimer_Tick(object sender, EventArgs e) { await Dispatcher.InvokeAsync(async () => { foreach (var (tb, addr, name, isFloat) in _textBoxMapping) { if (!tb.IsFocused) { try { if (isFloat) { float val = await ReadFloatAsync(addr); tb.Text = val.ToString("F3"); } else { ushort val = await ReadInt16Async(addr); tb.Text = val.ToString(); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"自动刷新 {name} 失败: {ex.Message}"); } } } }); } private async Task UpdateSingleParameter(TextBox tb, ushort addr, bool isFloat) { try { if (isFloat) { float val = await ReadFloatAsync(addr); tb.Text = val.ToString("F3"); } else { ushort val = await ReadInt16Async(addr); tb.Text = val.ToString(); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"更新失败: {ex.Message}"); } } private async Task LoadAllParameters() { foreach (var (tb, addr, name, isFloat) in _textBoxMapping) { await UpdateSingleParameter(tb, addr, isFloat); } } // 16位整数读写 private async Task ReadInt16Async(ushort address) { var registers = await ((ModbusTcpPlcService)_plcService).ReadHoldingRegistersAsync(address, 1); return registers[0]; } private async Task WriteInt16Async(ushort address, ushort value) { await ((ModbusTcpPlcService)_plcService).WriteSingleRegisterAsync(address, value); } // 32位浮点数读写 private async Task ReadFloatAsync(ushort address) { var registers = await ((ModbusTcpPlcService)_plcService).ReadHoldingRegistersAsync(address, 2); return ((ModbusTcpPlcService)_plcService).UshortToFloat(registers[1], registers[0]); } private async Task WriteFloatAsync(ushort address, float value) { await ((ModbusTcpPlcService)_plcService).WriteMultipleRegistersAsync(address, value); } } }