Compare commits
4 Commits
bd871ee6c5
...
0b68413bf9
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b68413bf9 | |||
| f91d5c3e98 | |||
| 00c0eaab57 | |||
| 8ef4a199c4 |
@@ -65,7 +65,13 @@ namespace TabletTester2025.ViewModels
|
||||
OpenCalibrationCommand = new AsyncRelayCommand(() => { MessageBox.Show("校准功能待实现"); return Task.CompletedTask; });
|
||||
|
||||
// 跳转到 PlcDataPage 页面
|
||||
ShowDataCommand = new AsyncRelayCommand(() => { new ShowData().ShowDialog(); return Task.CompletedTask; });
|
||||
|
||||
ShowDataCommand = new AsyncRelayCommand(async () =>
|
||||
{
|
||||
// 用你项目里已有的PLC实例(假设叫 _plcClient)
|
||||
var window = new ShowData(_plc);
|
||||
window.ShowDialog();
|
||||
});
|
||||
}
|
||||
|
||||
private async Task ConnectToPlc()
|
||||
|
||||
@@ -138,6 +138,7 @@ namespace TabletTester2025.ViewModels
|
||||
// 硬度命令
|
||||
HardnessUpCommand = new AsyncRelayCommand(async () =>
|
||||
{
|
||||
|
||||
await _plc.WriteCoilAsync(0x20, true);
|
||||
await Task.Delay(100);
|
||||
await _plc.WriteCoilAsync(0x20, false);
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
<Window x:Class="片剂四用仪.Views.ShowData"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:片剂四用仪.Views"
|
||||
mc:Ignorable="d"
|
||||
Title="ShowData" Height="768" Width="1024"
|
||||
Title="药典参数设置" Height="768" Width="1024"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#F5F5F5">
|
||||
Background="#F0F2F5">
|
||||
|
||||
|
||||
<Window.Resources>
|
||||
@@ -15,7 +11,7 @@
|
||||
<Style x:Key="CardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="CornerRadius" Value="10"/>
|
||||
<Setter Property="Margin" Value="15"/>
|
||||
<Setter Property="Margin" Value="15,15,80,15"/>
|
||||
<Setter Property="Padding" Value="15"/>
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
@@ -44,7 +40,7 @@
|
||||
<!-- 输入框样式 -->
|
||||
<Style x:Key="SettingTextBox" TargetType="TextBox">
|
||||
<Setter Property="Width" Value="160"/>
|
||||
<Setter Property="Height" Value="30"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Margin" Value="0 6 0 6"/>
|
||||
<Setter Property="Padding" Value="8"/>
|
||||
@@ -79,7 +75,7 @@
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource SettingLabel}" Text="最大力采集"/>
|
||||
<TextBox Style="{StaticResource SettingTextBox}" Name="txt_MaxForceCollect"/>
|
||||
<TextBox Style="{StaticResource SettingTextBox}" Name="txt_MaxForceCollect" IsReadOnly="True"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
@@ -143,7 +139,7 @@
|
||||
<TextBlock Style="{StaticResource GroupTitle}" Text="⚙ 力值与温度校准"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource SettingLabel}" Text="力显示"/>
|
||||
<TextBox Style="{StaticResource SettingTextBox}" Name="txt_ForceDisplay"/>
|
||||
<TextBox Style="{StaticResource SettingTextBox}" Name="txt_ForceDisplay" IsReadOnly="True"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource SettingLabel}" Text="力系数"/>
|
||||
@@ -155,7 +151,7 @@
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource SettingLabel}" Text="温度系数"/>
|
||||
<TextBox Style="{StaticResource SettingTextBox}" Name="txt_TemperatureCoefficient"/>
|
||||
<TextBox Style="{StaticResource SettingTextBox}" Name="txt_TemperatureCoefficient" IsReadOnly="True"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource SettingLabel}" Text="温度显示"/>
|
||||
|
||||
@@ -1,25 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
using TabletTester2025.Services;
|
||||
|
||||
namespace 片剂四用仪.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// ShowData.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ShowData : Window
|
||||
{
|
||||
public ShowData()
|
||||
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 (m.Type == PlcParamType.Int)
|
||||
{
|
||||
ushort[] res = await _plc.ReadHoldingRegistersAsync((ushort)m.Address, 1);
|
||||
if (_plc.IsConnected)
|
||||
{
|
||||
Dispatcher.Invoke(() => tb.Text = res[0].ToString());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.Invoke(() => tb.Text = "0"); // 读取失败时显示占位符
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ushort[] res = await _plc.ReadHoldingRegistersAsync((ushort)m.Address, 2);
|
||||
|
||||
// 同样增加有效性判断
|
||||
if (_plc.IsConnected)
|
||||
{
|
||||
float value = BitConverter.ToSingle(BitConverter.GetBytes((uint)(res[0] << 16 | res[1])), 0);
|
||||
Dispatcher.Invoke(() => tb.Text = value.ToString("F2"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.Invoke(() => tb.Text = "0"); // 读取失败时显示占位符
|
||||
}
|
||||
}
|
||||
}
|
||||
// 正常循环的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;
|
||||
|
||||
tb.LostFocus += async (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m.Type == PlcParamType.Int)
|
||||
{
|
||||
if (int.TryParse(tb.Text, out int val))
|
||||
await _plc.WriteRegisterAsync((ushort)m.Address, (ushort)val);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (float.TryParse(tb.Text, out float val))
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(val);
|
||||
ushort[] regs = new ushort[2];
|
||||
regs[0] = (ushort)(BitConverter.ToUInt16(bytes, 2));
|
||||
regs[1] = (ushort)(BitConverter.ToUInt16(bytes, 0));
|
||||
await _plc.WriteRegisterAsync((ushort)m.Address, (ushort)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.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),
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user