Files
CSI-Z420-Tablet-Multi-Funct…/Views/ShowData.xaml.cs

207 lines
8.4 KiB
C#
Raw Normal View History

2026-05-15 09:59:49 +08:00
using Microsoft.Win32;
using System;
2026-05-15 09:04:36 +08:00
using System.Threading;
using System.Threading.Tasks;
2026-05-14 15:22:17 +08:00
using System.Windows;
using System.Windows.Controls;
2026-05-18 14:06:04 +08:00
using TabletTester2025.Helpers;
2026-05-19 18:22:00 +08:00
using TabletTester2025.Models;
2026-05-15 09:04:36 +08:00
using TabletTester2025.Services;
2026-05-14 15:22:17 +08:00
namespace .Views
{
public partial class ShowData : Window
{
2026-05-15 09:04:36 +08:00
private readonly IPlcService _plc;
2026-05-19 18:22:00 +08:00
private readonly PlcParamMapping[] _paramMappings;
private CancellationTokenSource? _cts;
2026-05-15 09:04:36 +08:00
2026-05-19 18:22:00 +08:00
public ShowData(IPlcService plc, PlcConfiguration plcConfig)
2026-05-14 15:22:17 +08:00
{
InitializeComponent();
2026-05-15 09:04:36 +08:00
_plc = plc;
2026-05-19 18:22:00 +08:00
_paramMappings = BuildParamMappings(plcConfig);
2026-05-15 09:04:36 +08:00
Loaded += ShowData_Loaded;
Closing += ShowData_Closing;
}
private async void ShowData_Loaded(object sender, RoutedEventArgs e)
{
2026-05-19 18:22:00 +08:00
var cts = new CancellationTokenSource();
_cts = cts;
2026-05-15 09:04:36 +08:00
BindAllTextBoxWriteEvents();
2026-05-19 18:22:00 +08:00
await StartPlcReadLoop(cts.Token);
2026-05-15 09:04:36 +08:00
}
2026-05-19 18:22:00 +08:00
private void ShowData_Closing(object? sender, System.ComponentModel.CancelEventArgs e)
2026-05-15 09:04:36 +08:00
{
_cts?.Cancel();
}
// ====================== 读取 PLC ======================
private async Task StartPlcReadLoop(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
try
{
foreach (var m in _paramMappings)
{
var tb = FindName(m.TextBoxName) as TextBox;
if (tb == null) continue;
2026-05-18 14:06:04 +08:00
if (NumericInput.GetIsKeypadOpen(tb) || tb.IsKeyboardFocusWithin)
continue;
2026-05-15 09:04:36 +08:00
if (m.Type == PlcParamType.Int)
{
2026-05-15 11:13:06 +08:00
int value = await _plc.ReadIntAsync((ushort)m.Address);
Dispatcher.Invoke(() => tb.Text = value.ToString());
2026-05-15 09:04:36 +08:00
}
else
{
2026-05-15 11:13:06 +08:00
float value = await _plc.ReadFloatAsync((ushort)m.Address);
2026-05-19 16:55:00 +08:00
Dispatcher.Invoke(() => tb.Text = float.IsFinite(value) ? value.ToString("0.###") : string.Empty);
2026-05-15 11:13:06 +08:00
2026-05-15 09:04:36 +08:00
}
}
2026-05-15 10:20:30 +08:00
// 正常循环的Delay同样处理取消异常
try
{
await Task.Delay(1000, token);
}
catch (OperationCanceledException)
{
break;
}
}
catch (OperationCanceledException)
{
// 窗口关闭时的取消异常,正常退出循环
break;
2026-05-15 09:04:36 +08:00
}
2026-05-19 17:19:54 +08:00
catch
{
try
{
await Task.Delay(1000, token);
}
catch (OperationCanceledException)
{
break;
}
}
2026-05-15 09:04:36 +08:00
2026-05-15 10:20:30 +08:00
//await Task.Delay(1000, token);
2026-05-15 09:04:36 +08:00
}
}
// ====================== 写入 PLC ======================
private void BindAllTextBoxWriteEvents()
{
foreach (var m in _paramMappings)
{
var tb = FindName(m.TextBoxName) as TextBox;
if (tb == null) continue;
2026-05-18 14:06:04 +08:00
if (tb.IsReadOnly)
continue;
NumericInput.SetIsEnabled(tb, true);
NumericInput.SetAllowDecimal(tb, m.Type != PlcParamType.Int);
NumericInput.SetAllowNegative(tb, false);
NumericInput.AddValueCommittedHandler(tb, async (_, _) => await WritePlcValueAsync(m, tb));
}
}
private async Task WritePlcValueAsync(PlcParamMapping mapping, TextBox textBox)
{
try
{
if (mapping.Type == PlcParamType.Int)
2026-05-15 09:04:36 +08:00
{
2026-05-18 14:06:04 +08:00
if (int.TryParse(textBox.Text, out int val))
await _plc.WriteRegisterAsync((ushort)mapping.Address, (ushort)Math.Clamp(val, 0, ushort.MaxValue));
}
else
{
2026-05-19 16:55:00 +08:00
if (double.TryParse(textBox.Text, out double val) && double.IsFinite(val))
2026-05-15 09:04:36 +08:00
{
2026-05-19 16:55:00 +08:00
textBox.Text = val.ToString("0.###");
2026-05-18 14:06:04 +08:00
await _plc.WriteFloatAsync((ushort)mapping.Address, (float)val);
2026-05-15 09:04:36 +08:00
}
2026-05-18 14:06:04 +08:00
}
2026-05-15 09:04:36 +08:00
}
2026-05-18 14:06:04 +08:00
catch { }
2026-05-14 15:22:17 +08:00
}
2026-05-15 09:04:36 +08:00
// ====================== 地址映射表 ======================
2026-05-19 18:22:00 +08:00
private static PlcParamMapping[] BuildParamMappings(PlcConfiguration plcConfig)
2026-05-15 09:04:36 +08:00
{
2026-05-19 18:22:00 +08:00
return new[]
{
new PlcParamMapping("txt_HardnessSpeed", AddressOrDefault(plcConfig.HardnessSudu, 300), PlcParamType.Float),
new PlcParamMapping("txt_HardnessDisplacement", AddressOrDefault(plcConfig.HardnessWeiyi, 310), PlcParamType.Float),
new PlcParamMapping("txt_HardnessMotorLimit", AddressOrDefault(plcConfig.HardnessLimit, 298), PlcParamType.Float),
new PlcParamMapping("txt_HardnessDamageThreshold", AddressOrDefault(plcConfig.HardnessPoSun, 400), PlcParamType.Float),
new PlcParamMapping("txt_BrittlenessTestTime", AddressOrDefault(plcConfig.FriabilityTestTime, 410), PlcParamType.Int),
new PlcParamMapping("txt_PreBrittlenessMass", ResolveWeightRegister(plcConfig.FriabilityWeightBefore, plcConfig.WeightBefore, 412), PlcParamType.Float),
new PlcParamMapping("txt_PostBrittlenessMass", ResolveWeightRegister(plcConfig.FriabilityWeightAfter, plcConfig.WeightAfter, 414), PlcParamType.Float),
new PlcParamMapping("txt_WeightLossRate", 416, PlcParamType.Int),
new PlcParamMapping("txt_DisintegrationSpeed", AddressOrDefault(plcConfig.DisintegrationSpeed, 330), PlcParamType.Float),
new PlcParamMapping("txt_DisintegrationTime", AddressOrDefault(plcConfig.DisintegrationTime, 420), PlcParamType.Int),
new PlcParamMapping("txt_DissolutionTime", AddressOrDefault(plcConfig.Dissolution1Time, 430), PlcParamType.Int),
new PlcParamMapping("txt_Dissolution2Time", AddressOrDefault(plcConfig.Dissolution2Time, 440), PlcParamType.Int),
new PlcParamMapping("txt_Dissolution1SamplingInterval", AddressOrDefault(plcConfig.Dissolution1SampleInterval, 432), PlcParamType.Float),
new PlcParamMapping("txt_Dissolution2SamplingInterval", AddressOrDefault(plcConfig.Dissolution2SampleInterval, 442), PlcParamType.Float),
new PlcParamMapping("txt_ForceCoefficient", 1320, PlcParamType.Float),
new PlcParamMapping("txt_ForceProtection", 1322, PlcParamType.Float),
new PlcParamMapping("txt_TemperatureDisplay", AddressOrDefault(plcConfig.DisintegrationTemp, 1430), PlcParamType.Float),
new PlcParamMapping("txt_MaxForceCollect", AddressOrDefault(plcConfig.HardnessMax, 72), PlcParamType.Float),
new PlcParamMapping("txt_ForceDisplay", AddressOrDefault(plcConfig.HardnessShishilizhi, 1314), PlcParamType.Float),
new PlcParamMapping("txt_TemperatureCoefficient", 1428, PlcParamType.Float),
};
}
private static ushort AddressOrDefault(ushort configuredAddress, ushort fallbackAddress)
{
return configuredAddress != 0 ? configuredAddress : fallbackAddress;
}
private static ushort ResolveWeightRegister(ushort primaryAddress, ushort compatibleAddress, ushort fallbackAddress)
{
if (primaryAddress != 0)
return primaryAddress;
return AddressOrDefault(compatibleAddress, fallbackAddress);
}
2026-05-15 09:04:36 +08:00
}
internal class PlcParamMapping
{
public string TextBoxName { get; }
public int Address { get; }
public PlcParamType Type { get; }
public PlcParamMapping(string textBoxName, int address, PlcParamType type)
{
TextBoxName = textBoxName;
Address = address;
Type = type;
}
}
internal enum PlcParamType
{
Int,
Float
2026-05-14 15:22:17 +08:00
}
2026-05-16 16:58:57 +08:00
}