180 lines
6.4 KiB
C#
180 lines
6.4 KiB
C#
using Microsoft.Win32;
|
||
using Sunny.UI;
|
||
using System;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using TabletTester2025.Helpers;
|
||
using TabletTester2025.Services;
|
||
using static OfficeOpenXml.ExcelErrorValue;
|
||
|
||
namespace 片剂四用仪.Views
|
||
{
|
||
public partial class ShowData : Window
|
||
{
|
||
private readonly IPlcService _plc;
|
||
private CancellationTokenSource _cts;
|
||
|
||
public ShowData(IPlcService plc)
|
||
{
|
||
InitializeComponent();
|
||
_plc = plc;
|
||
Loaded += ShowData_Loaded;
|
||
Closing += ShowData_Closing;
|
||
}
|
||
|
||
private async void ShowData_Loaded(object sender, RoutedEventArgs e)
|
||
{
|
||
_cts = new CancellationTokenSource();
|
||
BindAllTextBoxWriteEvents();
|
||
await StartPlcReadLoop(_cts.Token);
|
||
}
|
||
|
||
private void ShowData_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||
{
|
||
_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;
|
||
if (NumericInput.GetIsKeypadOpen(tb) || tb.IsKeyboardFocusWithin)
|
||
continue;
|
||
|
||
if (m.Type == PlcParamType.Int)
|
||
{
|
||
int value = await _plc.ReadIntAsync((ushort)m.Address);
|
||
|
||
Dispatcher.Invoke(() => tb.Text = value.ToString());
|
||
|
||
}
|
||
else
|
||
{
|
||
float value = await _plc.ReadFloatAsync((ushort)m.Address);
|
||
|
||
Dispatcher.Invoke(() => tb.Text = value.ToString("F2"));
|
||
|
||
}
|
||
}
|
||
// 正常循环的Delay,同样处理取消异常
|
||
try
|
||
{
|
||
await Task.Delay(1000, token);
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
// 窗口关闭时的取消异常,正常退出循环
|
||
break;
|
||
}
|
||
|
||
//await Task.Delay(1000, token);
|
||
}
|
||
}
|
||
|
||
// ====================== 写入 PLC ======================
|
||
private void BindAllTextBoxWriteEvents()
|
||
{
|
||
foreach (var m in _paramMappings)
|
||
{
|
||
var tb = FindName(m.TextBoxName) as TextBox;
|
||
if (tb == null) continue;
|
||
|
||
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)
|
||
{
|
||
if (int.TryParse(textBox.Text, out int val))
|
||
await _plc.WriteRegisterAsync((ushort)mapping.Address, (ushort)Math.Clamp(val, 0, ushort.MaxValue));
|
||
}
|
||
else
|
||
{
|
||
if (double.TryParse(textBox.Text, out double val))
|
||
{
|
||
textBox.Text = val.ToString("F3");
|
||
await _plc.WriteFloatAsync((ushort)mapping.Address, (float)val);
|
||
}
|
||
}
|
||
}
|
||
catch { }
|
||
}
|
||
|
||
// ====================== 地址映射表 ======================
|
||
private readonly PlcParamMapping[] _paramMappings = new[]
|
||
{
|
||
new PlcParamMapping("txt_HardnessSpeed", 300, PlcParamType.Float),
|
||
new PlcParamMapping("txt_HardnessDisplacement", 310, PlcParamType.Float),
|
||
new PlcParamMapping("txt_HardnessMotorLimit", 298, PlcParamType.Float),
|
||
new PlcParamMapping("txt_HardnessDamageThreshold", 400, PlcParamType.Float),
|
||
|
||
|
||
new PlcParamMapping("txt_BrittlenessTestTime", 410, PlcParamType.Int),
|
||
new PlcParamMapping("txt_PreBrittlenessMass", 412, PlcParamType.Float),
|
||
new PlcParamMapping("txt_PostBrittlenessMass", 414, PlcParamType.Float),
|
||
new PlcParamMapping("txt_WeightLossRate", 416, PlcParamType.Int),
|
||
|
||
new PlcParamMapping("txt_DisintegrationSpeed", 330, PlcParamType.Float),
|
||
new PlcParamMapping("txt_DisintegrationTime", 420, PlcParamType.Float),
|
||
|
||
new PlcParamMapping("txt_DissolutionTime", 430, PlcParamType.Int),
|
||
new PlcParamMapping("txt_Dissolution1SamplingInterval", 432, PlcParamType.Float),
|
||
new PlcParamMapping("txt_Dissolution2SamplingInterval", 442, PlcParamType.Float),
|
||
|
||
|
||
new PlcParamMapping("txt_ForceCoefficient", 1320, PlcParamType.Float),
|
||
new PlcParamMapping("txt_ForceProtection", 1322, PlcParamType.Float),
|
||
|
||
new PlcParamMapping("txt_TemperatureDisplay", 1430, PlcParamType.Float),
|
||
|
||
new PlcParamMapping("txt_MaxForceCollect", 72, PlcParamType.Float),//读取
|
||
new PlcParamMapping("txt_ForceDisplay", 1314, PlcParamType.Float),//读取
|
||
new PlcParamMapping("txt_TemperatureCoefficient", 1428, PlcParamType.Float),//读取
|
||
};
|
||
}
|
||
|
||
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
|
||
}
|
||
}
|