2026-03-26 19:43:52 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2026-03-24 19:33:35 +08:00
|
|
|
|
using System.Windows;
|
2026-03-26 19:43:52 +08:00
|
|
|
|
using System.Windows.Controls;
|
2026-03-24 19:33:35 +08:00
|
|
|
|
using System.Windows.Input;
|
|
|
|
|
|
using System.Windows.Media;
|
|
|
|
|
|
using System.Windows.Threading;
|
2026-03-26 19:43:52 +08:00
|
|
|
|
using MembranePoreTester.Communication;
|
|
|
|
|
|
using MembranePoreTester.ViewModels;
|
2026-03-24 19:33:35 +08:00
|
|
|
|
|
|
|
|
|
|
namespace MembranePoreTester.Views
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class ParameterWindow : Window
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly IPlcService _plcService;
|
|
|
|
|
|
private readonly PlcConfiguration _config;
|
|
|
|
|
|
private DispatcherTimer _autoRefreshTimer;
|
2026-03-26 19:43:52 +08:00
|
|
|
|
|
|
|
|
|
|
// 用于快速查找文本框对应的写入地址和方法(可根据需要扩展)
|
|
|
|
|
|
private readonly Dictionary<TextBox, (ushort address, string paramName)> _textBoxMapping;
|
2026-03-24 19:33:35 +08:00
|
|
|
|
|
|
|
|
|
|
public ParameterWindow()
|
|
|
|
|
|
{
|
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
_plcService = App.PlcService;
|
|
|
|
|
|
_config = App.PlcConfig;
|
|
|
|
|
|
|
2026-03-26 19:43:52 +08:00
|
|
|
|
// 初始化文本框到寄存器地址的映射
|
|
|
|
|
|
_textBoxMapping = new Dictionary<TextBox, (ushort, string)>
|
|
|
|
|
|
{
|
2026-04-02 10:13:01 +08:00
|
|
|
|
//[txtPressureUpper] = (_config.PressureUpperLimit, "加压上限"),
|
|
|
|
|
|
//[txtPressureRate] = (_config.PressureRate, "加压速率"),
|
2026-03-27 21:35:32 +08:00
|
|
|
|
//[txtPressureCoeff] = (_config.PressureCoeff, "加压系数"),
|
2026-03-26 19:43:52 +08:00
|
|
|
|
|
2026-04-02 14:34:29 +08:00
|
|
|
|
//[txtHPCoeff11] = (_config.HPCoeff11, "工位1加压速率"),
|
2026-03-26 19:43:52 +08:00
|
|
|
|
[txtHPCoeff1] = (_config.HPCoeff1, "工位1高压系数"),
|
|
|
|
|
|
[txtLPCoeff1] = (_config.LPCoeff1, "工位1低压系数"),
|
|
|
|
|
|
[txtHPCoeff2] = (_config.HPCoeff2, "工位2高压系数"),
|
|
|
|
|
|
[txtLPCoeff2] = (_config.LPCoeff2, "工位2低压系数"),
|
|
|
|
|
|
[txtHPCoeff3] = (_config.HPCoeff3, "工位3高压系数"),
|
|
|
|
|
|
[txtLPCoeff3] = (_config.LPCoeff3, "工位3低压系数"),
|
|
|
|
|
|
|
|
|
|
|
|
[txtLargeFlow1] = (_config.LargeFlowCoeff1, "工位1大流量系数"),
|
|
|
|
|
|
[txtSmallFlow1] = (_config.SmallFlowCoeff1, "工位1小流量系数"),
|
|
|
|
|
|
[txtLargeFlow2] = (_config.LargeFlowCoeff2, "工位2大流量系数"),
|
|
|
|
|
|
[txtSmallFlow2] = (_config.SmallFlowCoeff2, "工位2小流量系数"),
|
|
|
|
|
|
[txtLargeFlow3] = (_config.LargeFlowCoeff3, "工位3大流量系数"),
|
|
|
|
|
|
[txtSmallFlow3] = (_config.SmallFlowCoeff3, "工位3小流量系数"),
|
|
|
|
|
|
|
|
|
|
|
|
//[txtPressureZero] = (_config.PressureCalibZero, "压力零点"),
|
|
|
|
|
|
//[txtPressureSpan] = (_config.PressureCalibSpan, "压力量程"),
|
|
|
|
|
|
//[txtFlowZero] = (_config.FlowCalibZero, "流量零点"),
|
|
|
|
|
|
//[txtFlowSpan] = (_config.FlowCalibSpan, "流量量程"),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 为所有文本框注册焦点事件
|
2026-03-24 19:33:35 +08:00
|
|
|
|
RegisterTextBoxEvents();
|
|
|
|
|
|
|
|
|
|
|
|
Loaded += async (s, e) =>
|
|
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
// 启动定时器
|
2026-03-24 19:33:35 +08:00
|
|
|
|
_autoRefreshTimer = new DispatcherTimer
|
|
|
|
|
|
{
|
|
|
|
|
|
Interval = TimeSpan.FromSeconds(1)
|
|
|
|
|
|
};
|
|
|
|
|
|
_autoRefreshTimer.Tick += AutoRefreshTimer_Tick;
|
|
|
|
|
|
_autoRefreshTimer.Start();
|
|
|
|
|
|
|
|
|
|
|
|
// 首次加载时读取一次
|
2026-03-26 19:43:52 +08:00
|
|
|
|
await LoadParameters();
|
2026-03-24 19:33:35 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Closed += (s, e) => _autoRefreshTimer?.Stop();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RegisterTextBoxEvents()
|
|
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
foreach (var tb in _textBoxMapping.Keys)
|
2026-03-24 19:33:35 +08:00
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
tb.GotFocus += (s, e) => { /* 什么都不做,只是为了让自动刷新跳过当前焦点的文本框 */ };
|
|
|
|
|
|
tb.LostFocus += async (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 失去焦点时,将当前文本框的值写入PLC
|
|
|
|
|
|
var (address, name) = _textBoxMapping[tb];
|
|
|
|
|
|
if (float.TryParse(tb.Text, out float value))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await WriteFloatAsync(address, 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);
|
|
|
|
|
|
// 重新从PLC读取该参数恢复原值
|
|
|
|
|
|
await UpdateSingleTextBox(tb, address);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2026-03-24 19:33:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-26 19:43:52 +08:00
|
|
|
|
/// 更新单个文本框的值(从PLC读取)
|
2026-03-24 19:33:35 +08:00
|
|
|
|
/// </summary>
|
2026-03-26 19:43:52 +08:00
|
|
|
|
private async Task UpdateSingleTextBox(TextBox tb, ushort address)
|
2026-03-24 19:33:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
float val = await ReadFloatAsync(address);
|
|
|
|
|
|
tb.Text = val.ToString("F3");
|
2026-03-24 19:33:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
System.Diagnostics.Debug.WriteLine($"更新文本框失败: {ex.Message}");
|
2026-03-24 19:33:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-26 19:43:52 +08:00
|
|
|
|
private async void AutoRefreshTimer_Tick(object sender, EventArgs e)
|
2026-03-24 19:33:35 +08:00
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
// 只更新当前没有获得焦点的文本框
|
|
|
|
|
|
await Dispatcher.InvokeAsync(async () =>
|
2026-03-24 19:33:35 +08:00
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
foreach (var kv in _textBoxMapping)
|
|
|
|
|
|
{
|
|
|
|
|
|
var tb = kv.Key;
|
|
|
|
|
|
var address = kv.Value.address;
|
|
|
|
|
|
if (!tb.IsFocused)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
float val = await ReadFloatAsync(address);
|
|
|
|
|
|
tb.Text = val.ToString("F3");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"自动刷新 {kv.Value.paramName} 失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 一次性加载所有参数(用于窗口启动)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private async Task LoadParameters()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var kv in _textBoxMapping)
|
2026-03-24 19:33:35 +08:00
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
await UpdateSingleTextBox(kv.Key, kv.Value.address);
|
2026-03-24 19:33:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-26 19:43:52 +08:00
|
|
|
|
// 以下方法与之前相同,但保留用于写入(已在LostFocus中调用)
|
2026-03-24 19:33:35 +08:00
|
|
|
|
private async Task<float> ReadFloatAsync(ushort address)
|
|
|
|
|
|
{
|
|
|
|
|
|
var registers = await ((ModbusTcpPlcService)_plcService).ReadHoldingRegistersAsync(address, 2);
|
2026-03-26 19:43:52 +08:00
|
|
|
|
return ((ModbusTcpPlcService)_plcService).UshortToFloat(registers[1], registers[0]);
|
2026-03-24 19:33:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task WriteFloatAsync(ushort address, float value)
|
|
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
await ((ModbusTcpPlcService)_plcService).WriteMultipleRegistersAsync(address, value);
|
2026-03-24 19:33:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Close_Click(object sender, RoutedEventArgs e) => Close();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|