using MembranePoreTester.Communication; using System.Collections.ObjectModel; using System.ComponentModel; // 用于 PropertyChanged using System.Net; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using static OfficeOpenXml.ExcelErrorValue; namespace MembranePoreTester.ViewModels { public class MainViewModel : ViewModelBase { public ObservableCollection Stations { get; } = new(); public class PressureModeItem { public string Text { get; set; } public int Value { get; set; } public override string ToString() { return Text; // 直接返回要显示的文本 } } public class StationItem : ViewModelBase { private PressureModeItem _selectedPressureMode; private List _pressureModeList; public List PressureModeList => _pressureModeList ??= new List { new PressureModeItem { Text = "低压", Value = 1 }, new PressureModeItem { Text = "高压", Value = 0 } }; public PressureModeItem SelectedPressureMode { get => _selectedPressureMode; set { if (SetProperty(ref _selectedPressureMode, value)) { Task.Run(async () => await WritePressureModeAsync(value?.Text ?? "低压")); } } } private readonly IPlcService _plcService; private readonly PlcConfiguration _plcConfig; private bool _isPressing; private string _pressButtonText = "加压"; private string _highLowPressure = "低压"; private bool _enableStatus; // M21 状态 public string Name { get; set; } public BubblePointViewModel BubblePointVM { get; set; } public PoreDistributionViewModel PoreDistributionVM { get; set; } public int StationId { get; set; } public string HighLowPressure { get => _selectedPressureMode?.Text ?? "低压"; set { var mode = PressureModeList.FirstOrDefault(m => m.Text == value); if (mode != null) { SelectedPressureMode = mode; } } } public string PressButtonText { get => _pressButtonText; set => SetProperty(ref _pressButtonText, value); } public bool EnableStatus { get => _enableStatus; private set { if (SetProperty(ref _enableStatus, value)) { // 当设备停止运行时,停止孔分布自动采集 if (!value) { PoreDistributionVM?.StopCollecting(); } OnPropertyChanged(nameof(EnableStatusText)); OnPropertyChanged(nameof(EnableStatusColor)); } } } // 使能状态显示文本 public string EnableStatusText => EnableStatus ? "运行中" : "未启动"; // 使能状态显示颜色(绿色表示运行中,灰色表示未启动) // 使能状态显示颜色(更亮的颜色) public string EnableStatusColor => EnableStatus ? "#00FF00" : "#FF3333"; // 定时器,用于轮询 M21 状态 private System.Windows.Threading.DispatcherTimer _timer; public ICommand PressCommand { get; } //public ICommand BurstCommand { get; } public ICommand StartCommand { get; } public ICommand StopCommand { get; } public ICommand EnableCommand { get; } // 备用,但可以使用复选框直接绑定 private double _pressureUpperLimit; private double _pressureRate; // 防止从PLC读取时触发校验弹窗 private bool _suppressPressureValidation = false; public double PressureUpperLimit { get => _pressureUpperLimit; set { // 如果不是从PLC读取(即用户交互或程序主动设置),先校验再设置 if (!_suppressPressureValidation && HighLowPressure.Contains("低压") && value > 200) { MessageBox.Show("低压模式,加压上限不能超过200!"); return; } bool changed = SetProperty(ref _pressureUpperLimit, value); // 仅在非抑制模式下将改变写回PLC,避免把PLC读回的值再次写入造成循环 if (changed && !_suppressPressureValidation) { _ = _plcService.WriteMultipleRegistersAsync(_plcConfig.PressureUpperLimit, (float)value); } } } public double PressureRate { get => _pressureRate; set { if (SetProperty(ref _pressureRate, value)) { // 值改变时写入PLC _ = _plcService.WriteMultipleRegistersAsync(_plcConfig.PressureRate, (float)value); } } } // 添加读取这两个参数的方法 private async Task ReadPressureParametersAsync() { try { float upperLimit = await _plcService.ReadFloatAsync(_plcConfig.PressureUpperLimit); float rate = await _plcService.ReadFloatAsync(_plcConfig.PressureRate); Application.Current.Dispatcher.Invoke(() => { // 在将PLC读取的值赋回到属性时,抑制用户校验提示和避免回写PLC _suppressPressureValidation = true; PressureUpperLimit = upperLimit; PressureRate = rate; _suppressPressureValidation = false; }); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"读取压力参数失败: {ex.Message}"); } } public StationItem() { if (IsInDesignMode()) { return; // 设计时跳过PLC初始化 } _plcService = App.PlcService; _plcConfig = App.PlcConfig; PressCommand = new RelayCommand(async () => await TogglePressAsync()); // 在 StationItem 构造函数中 StartCommand = new RelayCommand(async () => { // 启动PLC await WriteCoilAsync(_plcConfig.StartCoil, true); // 启动孔分布自动采集 PoreDistributionVM.StartCollecting(); }); StopCommand = new RelayCommand(async () => { // 停止自动采集 PoreDistributionVM.StopCollecting(); // 停止PLC await WriteCoilAsync(_plcConfig.StopCoil, true); }); // 启动定时器,每秒读取一次 M21 状态 _timer = new System.Windows.Threading.DispatcherTimer(); _timer.Interval = TimeSpan.FromSeconds(1); _timer.Tick += async (s, e) => { await ReadEnableStatusAsync(); await ReadPressureParametersAsync(); // 新增:读取压力参数 }; _timer.Start(); // 延迟2秒后读取,确保连接稳定 Task.Delay(2000).ContinueWith(async _ => { await ReadPressureModeAsync(); await ReadPressureParametersAsync(); // 新增:读取压力参数 }, TaskScheduler.Default); } private async Task ReadPressureModeAsync() { await SafeExecuteAsync($"ReadPressureModeAsync{StationId}", async () => { try { ushort[] values = await _plcService.ReadHoldingRegistersAsync(_plcConfig.PressureModeRegister, 1); ushort val = values[0]; string newValue = val == 0 ? "高压" : "低压"; Application.Current.Dispatcher.Invoke(() => { // 更新选中项 HighLowPressure = newValue; }); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"读取压力模式失败: {ex.Message}"); } }); } private async Task TogglePressAsync() { try { ushort coilAddress = _plcConfig.PressCoil; // 根据工位选择不同的线圈地址 switch (StationId) { case 1: coilAddress = _plcConfig.PressCoil; break; case 2: coilAddress = _plcConfig.PressCoil2; break; case 3: coilAddress = _plcConfig.PressCoil3; break; } // 先读取PLC当前的加压状态 bool currentStatus = await _plcService.ReadCoilAsync(coilAddress); // 切换状态 _isPressing = !currentStatus; // 写入新状态到PLC await WriteCoilAsync(coilAddress, _isPressing); // 更新按钮文字 PressButtonText = _isPressing ? "停止加压" : "加压"; } catch (Exception ex) { MessageBox.Show($"读取加压状态失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } // 在 StationItem 类中添加字段 private bool _lastEnableReadFailed = false; private DateTime _lastEnableErrorTime = DateTime.MinValue; private async Task ReadEnableStatusAsync() { await SafeExecuteAsync($"ReadEnableStatus_Station{StationId}", async () => { try { bool status = await _plcService.ReadCoilAsync(_plcConfig.EnableCoil); // 读取 M21 EnableStatus = status; bool pressStatus = await _plcService.ReadCoilAsync(_plcConfig.PressCoil);//这里也要更新加压的按钮状态 _isPressing = pressStatus; // 在UI线程更新按钮文字 Application.Current.Dispatcher.Invoke(() => { PressButtonText = pressStatus ? "停止加压" : "加压"; }); } catch (Exception ex) { // 读取出错时保持原状态或显示错误 System.Diagnostics.Debug.WriteLine($"读取使能状态失败: {ex.Message}"); } }); } private async Task WriteCoilAsync(ushort coil, bool value) { try { await _plcService.WriteCoilAsync(coil, value); } catch (Exception ex) { MessageBox.Show($"写线圈失败: {ex.Message}"); } } private async Task WritePressureModeAsync(string mode) { if (IsDisposed) return; ushort val = mode.ToString().Contains("高压") ? (ushort)0 : (ushort)1; try { await _plcService.WriteSingleRegisterAsync(_plcConfig.PressureModeRegister, val); } catch (Exception ex) { MessageBox.Show($"写压力模式失败: {ex.Message}"); } } private bool _isPoreDistributionActive; public bool IsPoreDistributionActive { get => _isPoreDistributionActive; set => SetProperty(ref _isPoreDistributionActive, value); } } public MainViewModel() { for (int i = 1; i <= 3; i++) { var station = new StationItem { Name = $"工位 {i}", BubblePointVM = new BubblePointViewModel { StationId = i }, PoreDistributionVM = new PoreDistributionViewModel { StationId = i }, StationId = i }; Stations.Add(station); } } } }