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

390 lines
18 KiB
C#
Raw Normal View History

2026-05-18 15:18:28 +08:00
using System;
2026-05-05 15:31:24 +08:00
using System.Linq;
2026-05-19 17:27:12 +08:00
using System.Threading.Tasks;
2026-05-05 15:31:24 +08:00
using System.Windows;
2026-05-18 14:06:04 +08:00
using System.Windows.Controls;
2026-05-05 15:31:24 +08:00
using TabletTester2025.Models;
namespace TabletTester2025
{
public partial class SettingsWindow : Window
{
public SettingsWindow()
{
InitializeComponent();
LoadSettings();
2026-05-19 17:27:12 +08:00
Loaded += SettingsWindow_Loaded;
}
private async void SettingsWindow_Loaded(object sender, RoutedEventArgs e)
{
await LoadHardnessPressureAsync();
2026-05-19 21:00:08 +08:00
await LoadHardnessDamageThresholdAsync();
2026-05-19 21:11:24 +08:00
// 脆碎度
2026-05-19 21:17:29 +08:00
await LoadPlcFloatToTextBoxAsync(ResolveFriabilityRpmRegister(), FriabilityRpmBox);
2026-05-19 21:11:24 +08:00
await LoadPlcIntToTextBoxAsync(ResolveFriabilityRoundsRegister(), FriabilityRoundsBox);
// 溶出度
2026-05-20 09:45:34 +08:00
await LoadPlcFloatToTextBoxAsync(ResolveDissolution1SpeedRegister(), Dissolution1SpeedBox);
await LoadPlcFloatToTextBoxAsync(ResolveDissolution2SpeedRegister(), Dissolution2SpeedBox);
2026-05-20 10:16:02 +08:00
await LoadPlcFloatToTextBoxAsync(ResolveDissolution1IntervalRegister(), Dissolution1IntervalBox);
await LoadPlcFloatToTextBoxAsync(ResolveDissolution2IntervalRegister(), Dissolution2IntervalBox);
2026-05-05 15:31:24 +08:00
}
private void LoadSettings()
{
var p = App.CurrentPharmaParams;
HardnessCountBox.Text = p.HardnessTestCount.ToString();
2026-05-18 14:06:04 +08:00
FriabilityRpmBox.Text = p.FriabilityTargetRpm.ToString();
2026-05-20 07:05:45 +08:00
//FriabilityTimeBox.Text = ResolveFriabilityTargetTimeMin(p).ToString("0.###");
2026-05-19 18:44:56 +08:00
FriabilityRoundsBox.Text = ResolveFriabilityTargetRounds(p).ToString();
2026-05-05 15:31:24 +08:00
FriabilityMaxLossBox.Text = p.FriabilityMaxLossPercent.ToString();
2026-05-20 10:16:02 +08:00
DisintegrationTimeMinBox.Text = ResolveDisintegrationTimeMin(p).ToString("0.###");
2026-05-20 07:11:00 +08:00
//DisintegrationTempBox.Text = p.DisintegrationTemperatureC.ToString();
2026-05-20 07:05:45 +08:00
//DissolutionTempBox.Text = p.DissolutionTemperatureC.ToString();
2026-05-18 15:18:28 +08:00
Dissolution1IntervalBox.Text = p.Dissolution1SampleIntervalMin.ToString();
Dissolution2IntervalBox.Text = p.Dissolution2SampleIntervalMin.ToString();
2026-05-05 15:31:24 +08:00
}
2026-05-19 17:27:12 +08:00
private async void SaveButton_Click(object sender, RoutedEventArgs e)
2026-05-05 15:31:24 +08:00
{
try
{
2026-05-20 09:45:34 +08:00
var current = App.CurrentPharmaParams;
2026-05-19 17:19:54 +08:00
var p = new PharmaParameters
{
2026-05-20 09:45:34 +08:00
StandardVersion = current.StandardVersion,
HardnessMin_N = current.HardnessMin_N,
HardnessMax_N = current.HardnessMax_N,
2026-05-20 10:16:02 +08:00
FriabilityTargetTimeMin = current.FriabilityTargetTimeMin,
2026-05-20 09:45:34 +08:00
DissolutionMinPercentAt30min = current.DissolutionMinPercentAt30min,
2026-05-20 10:16:02 +08:00
DisintegrationDosageForm = current.DisintegrationDosageForm,
DisintegrationSpeedRpm = current.DisintegrationSpeedRpm,
DisintegrationTemperatureC = current.DisintegrationTemperatureC,
DissolutionTemperatureC = current.DissolutionTemperatureC,
2026-05-20 09:45:34 +08:00
Dissolution1TimeMin = current.Dissolution1TimeMin,
Dissolution2TimeMin = current.Dissolution2TimeMin,
DissolutionSampleTimes = current.DissolutionSampleTimes?.ToArray() ?? Array.Empty<int>()
2026-05-19 17:19:54 +08:00
};
2026-05-05 15:31:24 +08:00
p.HardnessTestCount = int.Parse(HardnessCountBox.Text);
2026-05-19 17:27:12 +08:00
double hardnessPressure = ParseFiniteDouble(HardnessPressureBox.Text, "加压压力");
2026-05-19 21:00:08 +08:00
int hardnessDamageThreshold = ParsePositiveInt(HardnessDamageThresholdBox.Text, "硬度破损判定");
2026-05-19 21:17:29 +08:00
double friabilityRpm = ParseFiniteDouble(FriabilityRpmBox.Text, "脆碎度转速");
p.FriabilityTargetRpm = friabilityRpm;
2026-05-20 07:05:45 +08:00
//p.FriabilityTargetTimeMin = ParseFiniteDouble(FriabilityTimeBox.Text, "脆碎度试验时间");
2026-05-19 18:44:56 +08:00
p.FriabilityTargetRounds = ParsePositiveInt(FriabilityRoundsBox.Text, "脆碎圈数");
2026-05-19 17:19:54 +08:00
p.FriabilityMaxLossPercent = ParseFiniteDouble(FriabilityMaxLossBox.Text, "最大失重率");
2026-05-20 10:16:02 +08:00
double disintegrationTimeMin = ParsePositiveDouble(DisintegrationTimeMinBox.Text, "崩解时间");
p.DisintegrationMaxSeconds = ToDisintegrationSeconds(disintegrationTimeMin);
2026-05-20 07:11:00 +08:00
//p.DisintegrationTemperatureC = ParseFiniteDouble(DisintegrationTempBox.Text, "崩解介质温度");
2026-05-20 07:05:45 +08:00
//p.DissolutionTemperatureC = ParseFiniteDouble(DissolutionTempBox.Text, "溶出介质温度");
2026-05-20 09:45:34 +08:00
double dissolution1Speed = ParsePositiveDouble(Dissolution1SpeedBox.Text, "溶出速度1");
double dissolution2Speed = ParsePositiveDouble(Dissolution2SpeedBox.Text, "溶出速度2");
2026-05-20 10:16:02 +08:00
p.Dissolution1SampleIntervalMin = ParsePositiveDouble(Dissolution1IntervalBox.Text, "溶出1取样间隔");
p.Dissolution2SampleIntervalMin = ParsePositiveDouble(Dissolution2IntervalBox.Text, "溶出2取样间隔");
2026-05-05 15:31:24 +08:00
2026-05-18 15:18:28 +08:00
ValidateParameters(p);
2026-05-19 17:27:12 +08:00
await WriteHardnessPressureAsync(hardnessPressure);
2026-05-19 21:00:08 +08:00
await WriteHardnessDamageThresholdAsync(hardnessDamageThreshold);
2026-05-19 21:17:29 +08:00
await WriteFriabilityRpmAsync(friabilityRpm);
2026-05-20 10:16:02 +08:00
await WriteDisintegrationTimeAsync(disintegrationTimeMin);
2026-05-20 09:45:34 +08:00
await WriteDissolution1SpeedAsync(dissolution1Speed);
await WriteDissolution2SpeedAsync(dissolution2Speed);
2026-05-20 10:16:02 +08:00
await WriteDissolution1IntervalAsync(p.Dissolution1SampleIntervalMin);
await WriteDissolution2IntervalAsync(p.Dissolution2SampleIntervalMin);
2026-05-19 17:19:54 +08:00
App.CurrentPharmaParams = p;
2026-05-18 15:18:28 +08:00
App.SaveCurrentPharmaParameters();
MessageBox.Show("参数已保存并立即生效", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
2026-05-05 15:31:24 +08:00
DialogResult = true;
Close();
}
catch (Exception ex)
{
MessageBox.Show($"输入格式错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
2026-05-14 09:51:54 +08:00
2026-05-18 15:18:28 +08:00
private static void ValidateParameters(PharmaParameters p)
{
2026-05-19 17:19:54 +08:00
if (!double.IsFinite(p.HardnessMin_N) || !double.IsFinite(p.HardnessMax_N))
throw new InvalidOperationException("硬度内控参数必须为有效数字。");
2026-05-18 15:18:28 +08:00
if (p.HardnessMin_N < 0 || p.HardnessMax_N <= p.HardnessMin_N)
throw new InvalidOperationException("硬度内控上限必须大于下限。");
if (p.HardnessTestCount <= 0)
throw new InvalidOperationException("硬度测试次数必须大于0。");
2026-05-19 17:19:54 +08:00
if (!double.IsFinite(p.FriabilityTargetRpm) || !double.IsFinite(p.FriabilityTargetTimeMin) || !double.IsFinite(p.FriabilityMaxLossPercent))
throw new InvalidOperationException("脆碎度参数必须为有效数字。");
2026-05-18 18:54:32 +08:00
if (p.FriabilityTargetRpm <= 0 || p.FriabilityTargetTimeMin <= 0 || p.FriabilityTargetRounds <= 0 || p.FriabilityMaxLossPercent <= 0)
2026-05-18 15:18:28 +08:00
throw new InvalidOperationException("脆碎度参数必须大于0。");
2026-05-19 17:19:54 +08:00
if (!double.IsFinite(p.DisintegrationSpeedRpm) || !double.IsFinite(p.DisintegrationTemperatureC))
throw new InvalidOperationException("崩解参数必须为有效数字。");
2026-05-18 15:18:28 +08:00
if (p.DisintegrationMaxSeconds <= 0 || p.DisintegrationSpeedRpm <= 0 || p.DisintegrationTemperatureC <= 0)
throw new InvalidOperationException("崩解参数必须大于0。");
2026-05-19 17:19:54 +08:00
if (!double.IsFinite(p.DissolutionMinPercentAt30min) || !double.IsFinite(p.DissolutionTemperatureC)
|| !double.IsFinite(p.Dissolution1SampleIntervalMin) || !double.IsFinite(p.Dissolution2SampleIntervalMin))
throw new InvalidOperationException("溶出度参数必须为有效数字。");
2026-05-18 15:18:28 +08:00
if (p.DissolutionMinPercentAt30min < 0 || p.DissolutionMinPercentAt30min > 150)
throw new InvalidOperationException("溶出度Q值应在0到150之间。");
if (p.DissolutionTemperatureC <= 0 || p.Dissolution1TimeMin <= 0 || p.Dissolution2TimeMin <= 0)
throw new InvalidOperationException("溶出温度和运行时间必须大于0。");
if (p.Dissolution1SampleIntervalMin <= 0 || p.Dissolution2SampleIntervalMin <= 0)
throw new InvalidOperationException("溶出取样间隔必须大于0。");
if (p.DissolutionSampleTimes == null || p.DissolutionSampleTimes.Length == 0 || p.DissolutionSampleTimes.Any(t => t <= 0))
2026-05-20 09:45:34 +08:00
throw new InvalidOperationException("溶出取样配置必须为有效的正数分钟值。");
2026-05-18 15:18:28 +08:00
}
2026-05-18 18:54:32 +08:00
2026-05-19 17:19:54 +08:00
private static double ParseFiniteDouble(string text, string fieldName)
{
if (!double.TryParse(text, out double value) || !double.IsFinite(value))
throw new InvalidOperationException($"{fieldName}必须为有效数字。");
2026-05-19 17:27:12 +08:00
if (value < 0)
throw new InvalidOperationException($"{fieldName}不能小于0。");
2026-05-19 17:19:54 +08:00
return value;
}
2026-05-19 18:44:56 +08:00
private static int ParsePositiveInt(string text, string fieldName)
{
if (!int.TryParse(text, out int value))
throw new InvalidOperationException($"{fieldName}必须为整数。");
if (value <= 0)
throw new InvalidOperationException($"{fieldName}必须大于0。");
return value;
}
2026-05-20 09:45:34 +08:00
private static double ParsePositiveDouble(string text, string fieldName)
{
double value = ParseFiniteDouble(text, fieldName);
if (value <= 0)
throw new InvalidOperationException($"{fieldName}必须大于0。");
return value;
}
2026-05-19 17:27:12 +08:00
private async Task LoadHardnessPressureAsync()
{
ushort registerAddress = ResolveHardnessPressureRegister();
if (registerAddress == 0)
return;
try
{
float value = await App.PlcService.ReadFloatAsync(registerAddress);
if (float.IsFinite(value))
HardnessPressureBox.Text = value.ToString("0.###");
}
catch
{
HardnessPressureBox.Text = "";
}
}
private static async Task WriteHardnessPressureAsync(double value)
{
ushort registerAddress = ResolveHardnessPressureRegister();
if (registerAddress == 0)
throw new InvalidOperationException("加压压力PLC寄存器地址未配置。");
await App.PlcService.WriteFloatAsync(registerAddress, (float)value);
}
private static ushort ResolveHardnessPressureRegister()
{
return App.PlcConfig.HardnessPressure != 0 ? App.PlcConfig.HardnessPressure : (ushort)1480;
}
2026-05-19 21:00:08 +08:00
private async Task LoadHardnessDamageThresholdAsync()
{
ushort registerAddress = ResolveHardnessDamageThresholdRegister();
if (registerAddress == 0)
return;
try
{
2026-05-20 11:29:20 +08:00
int value = await App.PlcService.ReadInt32Async(registerAddress);
2026-05-19 21:00:08 +08:00
if (value >= 0)
HardnessDamageThresholdBox.Text = value.ToString();
}
catch
{
HardnessDamageThresholdBox.Text = "";
}
}
private static async Task WriteHardnessDamageThresholdAsync(int value)
{
ushort registerAddress = ResolveHardnessDamageThresholdRegister();
if (registerAddress == 0)
throw new InvalidOperationException("硬度破损判定PLC寄存器地址未配置。");
2026-05-20 11:29:20 +08:00
await App.PlcService.WriteInt32Async(registerAddress, value);
2026-05-19 21:00:08 +08:00
}
private static ushort ResolveHardnessDamageThresholdRegister()
{
return App.PlcConfig.HardnessPoSun != 0 ? App.PlcConfig.HardnessPoSun : (ushort)400;
}
2026-05-19 21:11:24 +08:00
private async Task LoadPlcFloatToTextBoxAsync(ushort address, TextBox textBox)
{
if (address == 0) return;
try
{
float value = await App.PlcService.ReadFloatAsync(address);
if (float.IsFinite(value))
textBox.Text = value.ToString("0.###");
}
catch { textBox.Text = ""; }
}
private async Task LoadPlcIntToTextBoxAsync(ushort address, TextBox textBox)
{
if (address == 0) return;
try
{
int value = await App.PlcService.ReadIntAsync(address);
if (value >= 0)
textBox.Text = value.ToString();
}
catch { textBox.Text = ""; }
}
2026-05-19 21:17:29 +08:00
private static async Task WriteFriabilityRpmAsync(double value)
{
ushort registerAddress = ResolveFriabilityRpmRegister();
if (registerAddress == 0)
throw new InvalidOperationException("脆碎度转速PLC寄存器地址未配置。");
await App.PlcService.WriteFloatAsync(registerAddress, (float)value);
}
private static ushort ResolveFriabilityRpmRegister()
{
return App.PlcConfig.FriabilityRpm != 0 ? App.PlcConfig.FriabilityRpm : (ushort)320;
}
2026-05-19 21:11:24 +08:00
private static ushort ResolveFriabilityRoundsRegister()
{
if (App.PlcConfig.FriabilityRounds != 0)
return App.PlcConfig.FriabilityRounds;
if (App.PlcConfig.FriabilityRoundsBox != 0)
return App.PlcConfig.FriabilityRoundsBox;
return App.PlcConfig.FriabilityTestTime != 0 ? App.PlcConfig.FriabilityTestTime : (ushort)410;
}
2026-05-20 10:16:02 +08:00
private static ushort ResolveDisintegrationTimeRegister()
2026-05-19 21:11:24 +08:00
{
2026-05-20 10:16:02 +08:00
return App.PlcConfig.DisintegrationTime != 0 ? App.PlcConfig.DisintegrationTime : (ushort)420;
}
private static async Task WriteDisintegrationTimeAsync(double value)
{
ushort registerAddress = ResolveDisintegrationTimeRegister();
if (registerAddress == 0)
throw new InvalidOperationException("崩解时间PLC寄存器地址未配置。");
await App.PlcService.WriteRegisterAsync(registerAddress, (ushort)Math.Clamp(
(int)Math.Round(value, MidpointRounding.AwayFromZero),
1,
ushort.MaxValue));
2026-05-19 21:11:24 +08:00
}
2026-05-20 09:45:34 +08:00
private static async Task WriteDissolution1SpeedAsync(double value)
{
ushort registerAddress = ResolveDissolution1SpeedRegister();
if (registerAddress == 0)
throw new InvalidOperationException("溶出速度1 PLC寄存器地址未配置。");
await App.PlcService.WriteFloatAsync(registerAddress, (float)value);
}
private static async Task WriteDissolution2SpeedAsync(double value)
{
ushort registerAddress = ResolveDissolution2SpeedRegister();
if (registerAddress == 0)
throw new InvalidOperationException("溶出速度2 PLC寄存器地址未配置。");
await App.PlcService.WriteFloatAsync(registerAddress, (float)value);
}
2026-05-20 10:16:02 +08:00
private static async Task WriteDissolution1IntervalAsync(double value)
{
ushort registerAddress = ResolveDissolution1IntervalRegister();
if (registerAddress == 0)
throw new InvalidOperationException("溶出1取样间隔PLC寄存器地址未配置。");
await App.PlcService.WriteFloatAsync(registerAddress, (float)value);
}
private static async Task WriteDissolution2IntervalAsync(double value)
{
ushort registerAddress = ResolveDissolution2IntervalRegister();
if (registerAddress == 0)
throw new InvalidOperationException("溶出2取样间隔PLC寄存器地址未配置。");
await App.PlcService.WriteFloatAsync(registerAddress, (float)value);
}
2026-05-20 09:45:34 +08:00
private static ushort ResolveDissolution1SpeedRegister()
2026-05-19 21:11:24 +08:00
{
2026-05-20 09:45:34 +08:00
return App.PlcConfig.Dissolution1Speed != 0 ? App.PlcConfig.Dissolution1Speed : (ushort)340;
2026-05-19 21:11:24 +08:00
}
2026-05-20 09:45:34 +08:00
private static ushort ResolveDissolution2SpeedRegister()
2026-05-19 21:11:24 +08:00
{
2026-05-20 09:45:34 +08:00
return App.PlcConfig.Dissolution2Speed != 0 ? App.PlcConfig.Dissolution2Speed : (ushort)350;
2026-05-19 21:11:24 +08:00
}
private static ushort ResolveDissolution1IntervalRegister()
{
return App.PlcConfig.Dissolution1SampleInterval != 0 ? App.PlcConfig.Dissolution1SampleInterval : (ushort)432;
}
private static ushort ResolveDissolution2IntervalRegister()
{
return App.PlcConfig.Dissolution2SampleInterval != 0 ? App.PlcConfig.Dissolution2SampleInterval : (ushort)442;
}
2026-05-18 18:54:32 +08:00
private static double ResolveFriabilityTargetTimeMin(PharmaParameters p)
{
if (p.FriabilityTargetTimeMin > 0)
return p.FriabilityTargetTimeMin;
double rpm = p.FriabilityTargetRpm > 0 ? p.FriabilityTargetRpm : 25;
if (p.FriabilityTargetRounds > 0 && rpm > 0)
return p.FriabilityTargetRounds / rpm;
return 4.0;
}
2026-05-19 18:44:56 +08:00
private static int ResolveFriabilityTargetRounds(PharmaParameters p)
2026-05-18 18:54:32 +08:00
{
2026-05-19 18:44:56 +08:00
if (p.FriabilityTargetRounds > 0)
return p.FriabilityTargetRounds;
2026-05-18 18:54:32 +08:00
2026-05-19 18:44:56 +08:00
return 100;
2026-05-18 18:54:32 +08:00
}
2026-05-20 10:16:02 +08:00
private static double ResolveDisintegrationTimeMin(PharmaParameters p)
{
return p.DisintegrationMaxSeconds > 0
? p.DisintegrationMaxSeconds / 60.0
: 15.0;
}
private static int ToDisintegrationSeconds(double minutes)
{
return Math.Max(1, (int)Math.Round(minutes * 60, MidpointRounding.AwayFromZero));
}
2026-05-05 15:31:24 +08:00
}
2026-05-18 14:06:04 +08:00
}