添加项目文件。

This commit is contained in:
xyy
2026-06-17 15:04:35 +08:00
parent ba1c916dd7
commit 09072ccda5
32 changed files with 2710 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Windows;
namespace HME_MoistureLossMeter.ViewModels
{
public partial class MainViewModel : ViewModelBase
{
private readonly IServiceProvider _serviceProvider;
[ObservableProperty]
private object _currentView;
[ObservableProperty]
private string _currentViewName = "测试画面";
[ObservableProperty]
private bool _isConnected;
[ObservableProperty]
private string _connectionStatus = "未连接";
[ObservableProperty]
private bool _isTesting;
[ObservableProperty]
private DateTime _currentTime = DateTime.Now;
public TestViewModel TestViewModel { get; }
public ManualControlViewModel ManualControlViewModel { get; }
public RecordViewModel RecordViewModel { get; }
public ReportViewModel ReportViewModel { get; }
public MainViewModel(IServiceProvider serviceProvider,
TestViewModel testViewModel,
ManualControlViewModel manualControlViewModel,
RecordViewModel recordViewModel,
ReportViewModel reportViewModel)
{
_serviceProvider = serviceProvider;
TestViewModel = testViewModel;
ManualControlViewModel = manualControlViewModel;
RecordViewModel = recordViewModel;
ReportViewModel = reportViewModel;
CurrentView = TestViewModel;
CurrentViewName = "测试画面";
var timer = new System.Timers.Timer(1000);
timer.Elapsed += (s, e) => CurrentTime = DateTime.Now;
timer.Start();
}
[RelayCommand]
private void NavigateToTest()
{
CurrentView = TestViewModel;
CurrentViewName = "测试画面";
}
[RelayCommand]
private void NavigateToManual()
{
CurrentView = ManualControlViewModel;
CurrentViewName = "手动控制";
}
[RelayCommand]
private void NavigateToRecord()
{
CurrentView = RecordViewModel;
CurrentViewName = "记录画面";
}
[RelayCommand]
private void NavigateToReport()
{
CurrentView = ReportViewModel;
CurrentViewName = "报表";
}
[RelayCommand]
private void ExitApplication()
{
var result = MessageBox.Show("确定要退出程序吗?", "确认退出",
MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
Application.Current.Shutdown();
}
}
}

View File

@@ -0,0 +1,176 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HME_MoistureLossMeter.Services;
using System.Threading.Tasks;
using System.Windows;
using Serilog;
namespace HME_MoistureLossMeter.ViewModels
{
public partial class ManualControlViewModel : ViewModelBase
{
private readonly IPlcService _plcService;
[ObservableProperty]
private float _manualSpeed;
[ObservableProperty]
private float _tidalCoeff;
[ObservableProperty]
private float _freqCoeff;
[ObservableProperty]
private bool _isConnected;
public ManualControlViewModel(IPlcService plcService)
{
_plcService = plcService;
// 启动时读取参数
Task.Run(async () => await ReadParameters());
}
private async Task ReadParameters()
{
try
{
if (!_plcService.IsConnected)
await _plcService.EnsureConnectedAsync();
ManualSpeed = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_MANUAL_SPEED);
TidalCoeff = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_TIDAL_COEFF);
FreqCoeff = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_FREQ_COEFF);
IsConnected = true;
StatusMessage = "参数读取成功";
}
catch (Exception ex)
{
IsConnected = false;
StatusMessage = $"读取参数失败: {ex.Message}";
Log.Error(ex, "读取手动参数失败");
}
}
[RelayCommand]
private async Task SaveParameters()
{
try
{
IsBusy = true;
await _plcService.WriteMultipleRegistersAsync(ModbusTcpPlcService.ADDR_MANUAL_SPEED, ManualSpeed);
await _plcService.WriteMultipleRegistersAsync(ModbusTcpPlcService.ADDR_TIDAL_COEFF, TidalCoeff);
await _plcService.WriteMultipleRegistersAsync(ModbusTcpPlcService.ADDR_FREQ_COEFF, FreqCoeff);
StatusMessage = "参数保存成功";
Log.Information("手动参数已保存");
}
catch (Exception ex)
{
StatusMessage = $"保存参数失败: {ex.Message}";
Log.Error(ex, "保存手动参数失败");
MessageBox.Show($"保存参数失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task ManualInhale()
{
await ExecuteCoilCommand(ModbusTcpPlcService.COIL_MANUAL_INHALE, "手动吸气");
}
[RelayCommand]
private async Task ManualExhale()
{
await ExecuteCoilCommand(ModbusTcpPlcService.COIL_MANUAL_EXHALE, "手动呼气");
}
[RelayCommand]
private async Task MoveLeft()
{
await ExecuteCoilCommand(ModbusTcpPlcService.COIL_LEFT, "左移");
}
[RelayCommand]
private async Task MoveRight()
{
await ExecuteCoilCommand(ModbusTcpPlcService.COIL_RIGHT, "右移");
}
[RelayCommand]
private async Task MoveUp()
{
await ExecuteCoilCommand(ModbusTcpPlcService.COIL_UP, "上升");
}
[RelayCommand]
private async Task MoveDown()
{
await ExecuteCoilCommand(ModbusTcpPlcService.COIL_DOWN, "下降");
}
[RelayCommand]
private async Task ZeroCalibration()
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_ZERO, true);
StatusMessage = "校零已触发";
Log.Information("校零触发");
// 等待完成后自动复位
await Task.Delay(2000);
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_ZERO, false);
StatusMessage = "校零完成";
}
catch (Exception ex)
{
StatusMessage = $"校零失败: {ex.Message}";
Log.Error(ex, "校零失败");
MessageBox.Show($"校零失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
private async Task ExecuteCoilCommand(ushort coilAddress, string commandName)
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(coilAddress, true);
StatusMessage = $"{commandName}已执行";
Log.Information("{Command}执行", commandName);
// 短暂延迟后自动复位
await Task.Delay(200);
await _plcService.WriteCoilAsync(coilAddress, false);
}
catch (Exception ex)
{
StatusMessage = $"{commandName}失败: {ex.Message}";
Log.Error(ex, "{Command}失败", commandName);
MessageBox.Show($"{commandName}失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task RefreshParameters()
{
await ReadParameters();
}
}
}

View File

@@ -0,0 +1,141 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HME_MoistureLossMeter.Models;
using HME_MoistureLossMeter.Services;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
using Serilog;
using System;
namespace HME_MoistureLossMeter.ViewModels
{
public partial class RecordViewModel : ViewModelBase
{
private readonly IMesService _mesService;
private readonly DeviceConfiguration _deviceConfig;
[ObservableProperty]
private ObservableCollection<HistoryRecordModel> _records = new();
[ObservableProperty]
private HistoryRecordModel _selectedRecord;
public RecordViewModel(IMesService mesService, DeviceConfiguration deviceConfig)
{
_mesService = mesService;
_deviceConfig = deviceConfig;
// 加载测试数据
LoadTestRecords();
}
private void LoadTestRecords()
{
// 从本地存储或数据库加载历史记录
// 这里使用示例数据,实际应从数据库读取
Records.Add(new HistoryRecordModel
{
RecordId = 1,
TestTime = DateTime.Now.AddHours(-1).ToString("yyyy-MM-dd HH:mm:ss"),
OperatorId = 1001,
BatchNo = "BATCH-2024-001",
ExperimentId = 1,
InitialMass = 50.5f,
FinalMass = 48.2f,
MoistureLoss = 2.3f
});
Records.Add(new HistoryRecordModel
{
RecordId = 2,
TestTime = DateTime.Now.AddHours(-2).ToString("yyyy-MM-dd HH:mm:ss"),
OperatorId = 1002,
BatchNo = "BATCH-2024-002",
ExperimentId = 2,
InitialMass = 45.8f,
FinalMass = 44.1f,
MoistureLoss = 1.7f
});
}
[RelayCommand]
private async Task SyncToMes()
{
try
{
IsBusy = true;
StatusMessage = "正在同步历史数据到MES...";
var historyData = new HistoryDataModel
{
DeviceId = _deviceConfig.DeviceId,
Records = Records.ToList()
};
bool success = await _mesService.SendHistoryDataAsync(historyData);
if (success)
{
StatusMessage = "历史数据同步成功";
Log.Information("历史数据同步到MES成功");
MessageBox.Show("历史数据同步成功", "提示",
MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
StatusMessage = "历史数据同步失败";
MessageBox.Show("历史数据同步失败,请检查网络连接", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
catch (Exception ex)
{
StatusMessage = $"同步失败: {ex.Message}";
Log.Error(ex, "同步历史数据到MES失败");
MessageBox.Show($"同步失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private void ClearRecords()
{
var result = MessageBox.Show("确定要清除所有历史记录吗?", "确认清除",
MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
Records.Clear();
StatusMessage = "历史记录已清除";
Log.Information("历史记录已清除");
}
}
[RelayCommand]
private void DeleteSelectedRecord()
{
if (SelectedRecord == null)
{
MessageBox.Show("请先选择要删除的记录", "提示",
MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var result = MessageBox.Show($"确定要删除记录 #{SelectedRecord.RecordId} 吗?", "确认删除",
MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
Records.Remove(SelectedRecord);
SelectedRecord = null;
StatusMessage = "记录已删除";
Log.Information("记录已删除");
}
}
}
}

View File

@@ -0,0 +1,12 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace HME_MoistureLossMeter.ViewModels
{
public partial class ReportViewModel : ViewModelBase
{
public ReportViewModel()
{
StatusMessage = "报表视图(待扩展)";
}
}
}

573
ViewModels/TestViewModel.cs Normal file
View File

@@ -0,0 +1,573 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HME_MoistureLossMeter.Models;
using HME_MoistureLossMeter.Services;
using Serilog;
using System;
using System.Collections.ObjectModel;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Media3D;
namespace HME_MoistureLossMeter.ViewModels
{
public partial class TestViewModel : ViewModelBase
{
private readonly IPlcService _plcService;
private readonly IMesService _mesService;
private readonly DeviceConfiguration _deviceConfig;
private CancellationTokenSource _cts;
private bool _isDataLoopRunning;
private float _totalWaterTemp;
private float _totalChamberTemp;
private float _totalTidalVolume;
private float _totalFrequency;
private float _totalAirVolume;
private float _totalOutletFlow;
private int _dataSampleCount;
// 实时数据属性
[ObservableProperty]
private float _waterTemp;
[ObservableProperty]
private float _chamberTemp;
[ObservableProperty]
private float _weight;
[ObservableProperty]
private float _airVolume;
[ObservableProperty]
private float _outletFlow;
[ObservableProperty]
private int _presetHour;
[ObservableProperty]
private int _presetMinute;
[ObservableProperty]
private int _displayHour;
[ObservableProperty]
private int _displayMinute;
[ObservableProperty]
private int _displaySecond;
[ObservableProperty]
private float _initialMass;
[ObservableProperty]
private float _finalMass;
[ObservableProperty]
private float _moistureLoss;
[ObservableProperty]
private string _batchNo = "";
[ObservableProperty]
private int _operatorId;
[ObservableProperty]
private int _experimentId;
[ObservableProperty]
private float _tidalVolume;
[ObservableProperty]
private float _frequency;
[ObservableProperty]
private int _breathCount;
[ObservableProperty]
private float _dryAirFlow;
[ObservableProperty]
private bool _isTesting;
[ObservableProperty]
private bool _isHeating;
[ObservableProperty]
private bool _isInhale;
[ObservableProperty]
private bool _isExhale;
[ObservableProperty]
private bool _isRising;
[ObservableProperty]
private bool _isFalling;
[ObservableProperty]
private bool _isConnected;
[ObservableProperty]
private string _connectionStatus = "未连接";
[ObservableProperty]
private DateTime _currentTime = DateTime.Now;
public ObservableCollection<HistoryRecordModel> TestRecords { get; } = new();
[RelayCommand]
private async Task MoveUp() => await ExecuteCoilCommand(ModbusTcpPlcService.COIL_UP, "上升");
[RelayCommand]
private async Task MoveDown() => await ExecuteCoilCommand(ModbusTcpPlcService.COIL_DOWN, "下降");
[RelayCommand]
private async Task ManualInhale() => await ExecuteCoilCommand(ModbusTcpPlcService.COIL_MANUAL_INHALE, "手动吸气");
[RelayCommand]
private async Task ManualExhale() => await ExecuteCoilCommand(ModbusTcpPlcService.COIL_MANUAL_EXHALE, "手动呼气");
// 辅助方法
private async Task ExecuteCoilCommand(ushort coilAddress, string commandName)
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(coilAddress, true);
StatusMessage = $"{commandName}已执行";
await Task.Delay(200);
await _plcService.WriteCoilAsync(coilAddress, false);
}
catch (Exception ex)
{
StatusMessage = $"{commandName}失败: {ex.Message}";
Log.Error(ex, "{Command}失败", commandName);
MessageBox.Show($"{commandName}失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
public TestViewModel(IPlcService plcService, IMesService mesService, DeviceConfiguration deviceConfig)
{
_plcService = plcService;
_mesService = mesService;
_deviceConfig = deviceConfig;
// 初始化定时更新
var timer = new System.Timers.Timer(1000);
timer.Elapsed += (s, e) => CurrentTime = DateTime.Now;
timer.Start();
}
partial void OnIsTestingChanged(bool value)
{
if (value)
{
// 开始测试时重置数据
_dataSampleCount = 0;
_totalWaterTemp = 0;
_totalChamberTemp = 0;
_totalTidalVolume = 0;
_totalFrequency = 0;
_totalAirVolume = 0;
_totalOutletFlow = 0;
}
}
[RelayCommand]
private async Task Connect()
{
try
{
IsBusy = true;
StatusMessage = "正在连接PLC...";
await _plcService.EnsureConnectedAsync();
IsConnected = true;
ConnectionStatus = "已连接";
StatusMessage = "PLC连接成功";
Log.Information("PLC连接成功");
// 启动数据循环
StartDataLoop();
}
catch (Exception ex)
{
IsConnected = false;
ConnectionStatus = "连接失败";
StatusMessage = $"连接失败: {ex.Message}";
Log.Error(ex, "PLC连接失败");
MessageBox.Show($"PLC连接失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private void Disconnect()
{
StopDataLoop();
IsConnected = false;
ConnectionStatus = "已断开";
StatusMessage = "已断开PLC连接";
Log.Information("PLC连接已断开");
}
private void StartDataLoop()
{
if (_isDataLoopRunning) return;
_cts = new CancellationTokenSource();
_isDataLoopRunning = true;
Task.Run(async () =>
{
while (!_cts.Token.IsCancellationRequested && IsConnected)
{
try
{
await ReadAllData();
await Task.Delay(_deviceConfig.UpdateIntervalMs, _cts.Token);
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
Log.Error(ex, "读取数据异常");
StatusMessage = $"读取数据异常: {ex.Message}";
await Task.Delay(2000);
}
}
}, _cts.Token);
}
private void StopDataLoop()
{
_isDataLoopRunning = false;
_cts?.Cancel();
_cts?.Dispose();
_cts = null;
}
private async Task ReadAllData()
{
try
{
// 读取浮点数数据
WaterTemp = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_WATER_TEMP);
ChamberTemp = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_CHAMBER_TEMP);
Weight = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_WEIGHT);
AirVolume = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_AIR_VOLUME);
OutletFlow = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_OUTLET_FLOW);
TidalVolume = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_TIDAL_VOLUME);
Frequency = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_FREQUENCY);
DryAirFlow = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_DRY_AIR_FLOW);
InitialMass = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_INITIAL_MASS);
FinalMass = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_FINAL_MASS);
MoistureLoss = await _plcService.ReadFloatAsync(ModbusTcpPlcService.ADDR_MOISTURE_LOSS);
// 读取整数数据
PresetHour = await _plcService.ReadInt32Async(ModbusTcpPlcService.ADDR_PRESET_HOUR);
PresetMinute = await _plcService.ReadInt32Async(ModbusTcpPlcService.ADDR_PRESET_MINUTE);
DisplayHour = await _plcService.ReadInt32Async(ModbusTcpPlcService.ADDR_DISPLAY_HOUR);
DisplayMinute = await _plcService.ReadInt32Async(ModbusTcpPlcService.ADDR_DISPLAY_MINUTE);
DisplaySecond = await _plcService.ReadInt32Async(ModbusTcpPlcService.ADDR_DISPLAY_SECOND);
BreathCount = await _plcService.ReadInt32Async(ModbusTcpPlcService.ADDR_BREATH_COUNT);
OperatorId = await _plcService.ReadInt32Async(ModbusTcpPlcService.ADDR_OPERATOR_ID);
ExperimentId = await _plcService.ReadInt32Async(ModbusTcpPlcService.ADDR_EXPERIMENT_ID);
// 读取字符串(批号)
var batchRegs = await _plcService.ReadHoldingRegistersAsync(ModbusTcpPlcService.ADDR_BATCH_NO, 10);
BatchNo = RegistersToString(batchRegs);
// 读取线圈状态
IsTesting = await _plcService.ReadCoilAsync(ModbusTcpPlcService.COIL_TEST);
IsHeating = await _plcService.ReadCoilAsync(ModbusTcpPlcService.COIL_HEAT);
IsInhale = await _plcService.ReadCoilAsync(ModbusTcpPlcService.COIL_INHALE);
IsExhale = await _plcService.ReadCoilAsync(ModbusTcpPlcService.COIL_EXHALE);
IsRising = await _plcService.ReadCoilAsync(ModbusTcpPlcService.COIL_UP);
IsFalling = await _plcService.ReadCoilAsync(ModbusTcpPlcService.COIL_DOWN);
// 如果正在测试,收集数据用于平均值计算
if (IsTesting)
{
_dataSampleCount++;
_totalWaterTemp += WaterTemp;
_totalChamberTemp += ChamberTemp;
_totalTidalVolume += TidalVolume;
_totalFrequency += Frequency;
_totalAirVolume += AirVolume;
_totalOutletFlow += OutletFlow;
// 发送实时数据到MES
await SendRealtimeDataToMes();
}
StatusMessage = "数据读取成功";
IsConnected = true;
ConnectionStatus = "已连接";
}
catch (Exception ex)
{
IsConnected = false;
ConnectionStatus = "通信异常";
Log.Error(ex, "读取数据失败");
throw;
}
}
private string RegistersToString(ushort[] registers)
{
var bytes = new byte[registers.Length * 2];
for (int i = 0; i < registers.Length; i++)
{
var regBytes = BitConverter.GetBytes(registers[i]);
bytes[i * 2] = regBytes[0];
bytes[i * 2 + 1] = regBytes[1];
}
return System.Text.Encoding.ASCII.GetString(bytes).TrimEnd('\0');
}
private async Task SendRealtimeDataToMes()
{
try
{
var data = new RealtimeDataModel
{
DeviceId = _deviceConfig.DeviceId,
Timestamp = DateTime.Now.ToString("o"),
Realtime = new RealtimeData
{
WaterTemp = WaterTemp,
ChamberTemp = ChamberTemp,
Weight = Weight,
AirVolume = AirVolume,
OutletFlow = OutletFlow,
TidalVolume = TidalVolume,
Frequency = Frequency,
BreathRate = BreathCount,
DryAirFlow = DryAirFlow
},
Settings = new SettingsData
{
PresetHour = PresetHour,
PresetMinute = PresetMinute,
PresetSecond = DisplaySecond,
OperatorId = OperatorId,
BatchNo = BatchNo,
ExperimentId = ExperimentId
},
Status = new StatusData
{
IsTesting = IsTesting,
IsFault = false
}
};
await _mesService.SendRealtimeDataAsync(data);
}
catch (Exception ex)
{
Log.Error(ex, "发送实时数据到MES失败");
}
}
// 测试控制命令
[RelayCommand]
private async Task StartTest()
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_TEST, true);
StatusMessage = "测试已启动";
Log.Information("测试启动");
}
catch (Exception ex)
{
Log.Error(ex, "启动测试失败");
MessageBox.Show($"启动测试失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task StopTest()
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_STOP, true);
StatusMessage = "测试已停止";
Log.Information("测试停止");
}
catch (Exception ex)
{
Log.Error(ex, "停止测试失败");
MessageBox.Show($"停止测试失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task Reset()
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_RESET, true);
StatusMessage = "已复位";
Log.Information("设备复位");
}
catch (Exception ex)
{
Log.Error(ex, "复位失败");
MessageBox.Show($"复位失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task Clear()
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_CLEAR, true);
StatusMessage = "已清零";
Log.Information("数据清零");
}
catch (Exception ex)
{
Log.Error(ex, "清零失败");
MessageBox.Show($"清零失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task ToggleHeat()
{
try
{
IsBusy = true;
bool currentState = await _plcService.ReadCoilAsync(ModbusTcpPlcService.COIL_HEAT);
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_HEAT, !currentState);
StatusMessage = currentState ? "加热关闭" : "加热开启";
Log.Information("加热切换: {State}", !currentState);
}
catch (Exception ex)
{
Log.Error(ex, "切换加热失败");
MessageBox.Show($"切换加热失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task RecordP1()
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_P1_RECORD, true);
StatusMessage = "P1记录已触发";
Log.Information("P1记录触发");
}
catch (Exception ex)
{
Log.Error(ex, "P1记录失败");
MessageBox.Show($"P1记录失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task RecordP2()
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_P2_RECORD, true);
StatusMessage = "P2记录已触发";
Log.Information("P2记录触发");
}
catch (Exception ex)
{
Log.Error(ex, "P2记录失败");
MessageBox.Show($"P2记录失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
[RelayCommand]
private async Task Print()
{
try
{
IsBusy = true;
await _plcService.WriteCoilAsync(ModbusTcpPlcService.COIL_PRINT, true);
StatusMessage = "打印已触发";
Log.Information("打印触发");
}
catch (Exception ex)
{
Log.Error(ex, "打印失败");
MessageBox.Show($"打印失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsBusy = false;
}
}
public void Dispose()
{
StopDataLoop();
_plcService?.Dispose();
}
}
}

View File

@@ -0,0 +1,21 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace HME_MoistureLossMeter.ViewModels
{
public abstract class ViewModelBase : ObservableObject
{
private bool _isBusy;
public bool IsBusy
{
get => _isBusy;
set => SetProperty(ref _isBusy, value);
}
private string _statusMessage = "就绪";
public string StatusMessage
{
get => _statusMessage;
set => SetProperty(ref _statusMessage, value);
}
}
}