2026-05-15 09:59:49 +08:00
|
|
|
|
using Microsoft.Win32;
|
2026-05-15 16:13:45 +08:00
|
|
|
|
using Sunny.UI;
|
2026-05-15 09:59:49 +08:00
|
|
|
|
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-15 09:04:36 +08:00
|
|
|
|
using TabletTester2025.Services;
|
2026-05-15 16:13:45 +08:00
|
|
|
|
using static OfficeOpenXml.ExcelErrorValue;
|
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;
|
|
|
|
|
|
private CancellationTokenSource _cts;
|
|
|
|
|
|
|
|
|
|
|
|
public ShowData(IPlcService plc)
|
2026-05-14 15:22:17 +08:00
|
|
|
|
{
|
|
|
|
|
|
InitializeComponent();
|
2026-05-15 09:04:36 +08:00
|
|
|
|
_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 (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);
|
|
|
|
|
|
|
|
|
|
|
|
Dispatcher.Invoke(() => tb.Text = value.ToString("F2"));
|
|
|
|
|
|
|
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-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-15 16:33:15 +08:00
|
|
|
|
tb.GotFocus += async (s, e) =>
|
2026-05-15 09:04:36 +08:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m.Type == PlcParamType.Int)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (int.TryParse(tb.Text, out int val))
|
|
|
|
|
|
await _plc.WriteRegisterAsync((ushort)m.Address, (ushort)val);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-05-15 16:13:45 +08:00
|
|
|
|
if (double.TryParse(tb.Text, out double val))
|
2026-05-15 09:04:36 +08:00
|
|
|
|
{
|
2026-05-15 16:33:15 +08:00
|
|
|
|
// 弹窗修改值
|
2026-05-15 16:13:45 +08:00
|
|
|
|
if (UIInputDialog.ShowInputDoubleDialog(ref val, UIStyle.Inherited, 3, desc: "请输入值", showMask: false))
|
|
|
|
|
|
{
|
2026-05-15 16:33:15 +08:00
|
|
|
|
// 更新界面
|
|
|
|
|
|
tb.Text = val.ToString("F3");
|
2026-05-15 16:13:45 +08:00
|
|
|
|
|
2026-05-15 16:33:15 +08:00
|
|
|
|
// 写入PLC(浮点数双寄存器)
|
|
|
|
|
|
byte[] bytes = BitConverter.GetBytes(val);
|
|
|
|
|
|
ushort[] regs = new ushort[2];
|
|
|
|
|
|
regs[0] = (ushort)BitConverter.ToUInt16(bytes, 2);
|
|
|
|
|
|
regs[1] = (ushort)BitConverter.ToUInt16(bytes, 0);
|
2026-05-15 16:13:45 +08:00
|
|
|
|
await _plc.WriteRegisterAsync((ushort)m.Address, (ushort)val);
|
|
|
|
|
|
}
|
2026-05-15 09:04:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2026-05-14 15:22:17 +08:00
|
|
|
|
}
|
2026-05-15 09:04:36 +08:00
|
|
|
|
|
|
|
|
|
|
// ====================== 地址映射表 ======================
|
|
|
|
|
|
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),
|
2026-05-15 10:20:30 +08:00
|
|
|
|
|
2026-05-15 09:04:36 +08:00
|
|
|
|
|
|
|
|
|
|
new PlcParamMapping("txt_BrittlenessTestTime", 410, PlcParamType.Int),
|
|
|
|
|
|
new PlcParamMapping("txt_PreBrittlenessMass", 412, PlcParamType.Int),
|
|
|
|
|
|
new PlcParamMapping("txt_PostBrittlenessMass", 414, PlcParamType.Int),
|
|
|
|
|
|
new PlcParamMapping("txt_WeightLossRate", 416, PlcParamType.Int),
|
|
|
|
|
|
|
|
|
|
|
|
new PlcParamMapping("txt_DisintegrationSpeed", 330, PlcParamType.Float),
|
|
|
|
|
|
new PlcParamMapping("txt_DisintegrationTime", 420, PlcParamType.Int),
|
|
|
|
|
|
|
|
|
|
|
|
new PlcParamMapping("txt_DissolutionTime", 430, PlcParamType.Int),
|
|
|
|
|
|
new PlcParamMapping("txt_DissolutionSamplingInterval", 432, PlcParamType.Int),
|
|
|
|
|
|
|
2026-05-15 10:20:30 +08:00
|
|
|
|
|
2026-05-15 09:04:36 +08:00
|
|
|
|
new PlcParamMapping("txt_ForceCoefficient", 1320, PlcParamType.Float),
|
|
|
|
|
|
new PlcParamMapping("txt_ForceProtection", 1322, PlcParamType.Float),
|
2026-05-15 10:20:30 +08:00
|
|
|
|
|
2026-05-15 09:04:36 +08:00
|
|
|
|
new PlcParamMapping("txt_TemperatureDisplay", 1430, PlcParamType.Float),
|
2026-05-15 10:20:30 +08:00
|
|
|
|
|
|
|
|
|
|
new PlcParamMapping("txt_MaxForceCollect", 72, PlcParamType.Float),//读取
|
|
|
|
|
|
new PlcParamMapping("txt_ForceDisplay", 1314, PlcParamType.Float),//读取
|
|
|
|
|
|
new PlcParamMapping("txt_TemperatureCoefficient", 1428, PlcParamType.Float),//读取
|
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-15 09:04:36 +08:00
|
|
|
|
}
|