添加项目文件。

This commit is contained in:
xyy
2026-03-24 20:40:26 +08:00
commit d15af841ea
666 changed files with 86392 additions and 0 deletions

View File

@@ -0,0 +1,232 @@
using MembranePoreTester.Communication;
using MembranePoreTester.Helpers;
using MembranePoreTester.Models;
using Microsoft.Win32;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
namespace MembranePoreTester.ViewModels
{
public class BubblePointViewModel : ViewModelBase
{
private BubblePointRecord _record = new();
private TestLiquid _selectedLiquid;
private bool _isCustomLiquid;
private double _customSurfaceTension = 30.0;
// 添加字段
private readonly IPlcService _plcService;
private readonly PlcConfiguration _plcConfig;
public ICommand ReadPlcCommand { get; }
public BubblePointRecord Record
{
get => _record;
set => SetProperty(ref _record, value);
}
public List<TestLiquid> Liquids => TestLiquid.Predefined;
public List<string> PressureUnits => new() { "Pa", "cmHg", "psi" };
public List<string> MembraneTypes => new() { "平板膜", "中空纤维膜" };
public TestLiquid SelectedLiquid
{
get => _selectedLiquid;
set
{
if (SetProperty(ref _selectedLiquid, value))
{
Record.Liquid = value;
OnPropertyChanged(nameof(Record.MaxPoreSize));
}
}
}
public bool IsCustomLiquid
{
get => _isCustomLiquid;
set
{
if (SetProperty(ref _isCustomLiquid, value))
{
UpdateCustomLiquid();
}
}
}
public double CustomSurfaceTension
{
get => _customSurfaceTension;
set
{
if (SetProperty(ref _customSurfaceTension, value))
{
UpdateCustomLiquid();
}
}
}
private void UpdateCustomLiquid()
{
if (IsCustomLiquid)
{
Record.Liquid = new TestLiquid
{
Name = "自定义",
SurfaceTension = CustomSurfaceTension
};
OnPropertyChanged(nameof(Record.MaxPoreSize));
}
}
public ICommand CalculateCommand { get; }
public ICommand GenerateReportCommand { get; }
public ICommand OpenPressureCalibCommand { get; }
public BubblePointViewModel()
{
_plcService = App.PlcService;
_plcConfig = App.PlcConfig;
CalculateCommand = new RelayCommand(Calculate);
GenerateReportCommand = new RelayCommand(GenerateReport);
SelectedLiquid = Liquids[0];
ReadPlcCommand = new RelayCommand(async () => await ReadPlcAsync());
SaveCommand = new RelayCommand(SaveToDatabase);
ExportCommand = new RelayCommand(ExportToExcel);
OpenPressureCalibCommand = new RelayCommand(OpenPressureCalibration);
}
private async Task ReadPlcAsync()
{
try
{
float rawPressure = await _plcService.ReadPressureAsync(StationId);
Record.BubblePointPressure = rawPressure * _plcConfig.PressureFactor;
OnPropertyChanged(nameof(Record.BubblePointPressure));
}
catch (Exception ex)
{
MessageBox.Show($"读取PLC失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public double MaxPoreSize => Record.MaxPoreSize;
private void Calculate()
{
// 触发最大孔径重新计算(通过绑定已自动刷新)
OnPropertyChanged(nameof(Record.MaxPoreSize));
}
private void GenerateReport()
{
ReportGenerator.GenerateBubblePointReport(Record);
}
public void UpdateBubblePointPressure(double pressure)
{
Record.BubblePointPressure = pressure;
OnPropertyChanged(nameof(Record.BubblePointPressure));
OnPropertyChanged(nameof(MaxPoreSize)); // 最大孔径依赖于压力
}
private int _stationId;
public int StationId
{
get => _stationId;
set => SetProperty(ref _stationId, value);
}
// 保存当前记录到数据库
public void SaveToDatabase()
{
var entity = new BubblePointEntity
{
StationId = StationId,
TestDate = Record.TestDate,
Tester = Record.Tester,
SampleType = Record.SampleType,
SampleSpec = Record.SampleSpec,
RoomTemperature = Record.RoomTemperature,
SoakingTime = Record.SoakingTime,
LiquidName = Record.Liquid?.Name,
LiquidSurfaceTension = Record.Liquid?.SurfaceTension ?? 0,
LiquidManufacturer = Record.LiquidManufacturer,
BubblePointPressure = Record.BubblePointPressure,
PressureUnit = Record.PressureUnit,
MaxPoreSize = Record.MaxPoreSize
};
using var db = new AppDbContext();
db.BubblePointRecords.Add(entity);
db.SaveChanges();
}
public void LoadFromDatabase(int recordId)
{
using var db = new AppDbContext();
var entity = db.BubblePointRecords.Find(recordId);
if (entity == null) return;
Record.SampleType = entity.SampleType;
Record.SampleSpec = entity.SampleSpec;
Record.RoomTemperature = entity.RoomTemperature;
Record.SoakingTime = entity.SoakingTime;
Record.Liquid = TestLiquid.Predefined.FirstOrDefault(l => l.Name == entity.LiquidName)
?? new TestLiquid { Name = entity.LiquidName, SurfaceTension = entity.LiquidSurfaceTension };
Record.LiquidManufacturer = entity.LiquidManufacturer;
Record.BubblePointPressure = entity.BubblePointPressure;
Record.PressureUnit = entity.PressureUnit;
Record.TestDate = entity.TestDate;
Record.Tester = entity.Tester;
OnPropertyChanged(nameof(Record));
OnPropertyChanged(nameof(MaxPoreSize)); // 触发界面更新
}
public ICommand SaveCommand { get; }
public ICommand ExportCommand { get; }
private void OpenPressureCalibration()
{
// 使用简单的输入框获取新零点系数和量程系数
string zeroStr = Microsoft.VisualBasic.Interaction.InputBox("请输入压力零点系数", "压力校准", "0");
string spanStr = Microsoft.VisualBasic.Interaction.InputBox("请输入压力量程系数", "压力校准", "1");
if (float.TryParse(zeroStr, out float zero) && float.TryParse(spanStr, out float span))
{
Task.Run(async () =>
{
await WriteFloatAsync(_plcConfig.PressureCalibZero, zero);
await WriteFloatAsync(_plcConfig.PressureCalibSpan, span);
MessageBox.Show("压力校准系数已写入", "完成");
});
}
}
private void ExportToExcel()
{
var saveFileDialog = new SaveFileDialog
{
Filter = "Excel文件|*.xlsx",
FileName = $"泡点法_工位{StationId}_{DateTime.Now:yyyyMMddHHmmss}.xlsx"
};
if (saveFileDialog.ShowDialog() == true)
{
// 转换为Entity后导出
var entity = new BubblePointEntity { /* 从Record复制 */ };
ExportHelper.ExportBubblePoint(entity, saveFileDialog.FileName);
MessageBox.Show("导出成功");
}
}
}
}

View File

@@ -0,0 +1,6 @@
public interface IStationViewModel
{
int StationId { get; set; }
void SaveToDatabase();
void LoadFromDatabase(int recordId); // 加载指定记录
}

160
ViewModels/MainViewModel.cs Normal file
View File

@@ -0,0 +1,160 @@
using MembranePoreTester.Communication;
using System.Collections.ObjectModel;
using System.ComponentModel; // 用于 PropertyChanged
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace MembranePoreTester.ViewModels
{
public class MainViewModel : ViewModelBase
{
public ObservableCollection<StationItem> Stations { get; } = new();
public class StationItem : ViewModelBase
{
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 => _highLowPressure;
set
{
if (SetProperty(ref _highLowPressure, value))
{
// 当选择变化时,写入 PLC 压力模式寄存器
Task.Run(async () => await WritePressureModeAsync(value));
}
}
}
public string PressButtonText
{
get => _pressButtonText;
set => SetProperty(ref _pressButtonText, value);
}
// 使能状态(只读)
public bool EnableStatus
{
get => _enableStatus;
private set => SetProperty(ref _enableStatus, value);
}
// 使能状态显示文本
public string EnableStatusText => EnableStatus ? "运行中" : "未启动";
// 使能状态显示颜色(绿色表示运行中,灰色表示未启动)
public string EnableStatusColor => EnableStatus ? "Green" : "Gray";
// 定时器,用于轮询 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; } // 备用,但可以使用复选框直接绑定
public StationItem()
{
_plcService = App.PlcService;
_plcConfig = App.PlcConfig;
PressCommand = new RelayCommand(async () => await TogglePressAsync());
//BurstCommand = new RelayCommand(async () => await ReadBurstPressureAsync());
StartCommand = new RelayCommand(async () => await WriteCoilAsync(_plcConfig.StartCoil, true));
StopCommand = new RelayCommand(async () => await WriteCoilAsync(_plcConfig.StopCoil, true));
// 启动定时器,每秒读取一次 M21 状态
_timer = new System.Windows.Threading.DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(1);
_timer.Tick += async (s, e) => await ReadEnableStatusAsync();
_timer.Start();
}
private async Task TogglePressAsync()
{
_isPressing = !_isPressing;
await WriteCoilAsync(_plcConfig.PressCoil, _isPressing);
PressButtonText = _isPressing ? "停止加压" : "加压";
}
private async Task ReadEnableStatusAsync()
{
try
{
bool status = await _plcService.ReadCoilAsync(_plcConfig.EnableCoil); // 读取 M21
EnableStatus = status;
}
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)
{
ushort val = mode == "高压" ? (ushort)1 : (ushort)0;
try
{
await _plcService.WriteRegisterAsync(_plcConfig.PressureModeRegister, val);
}
catch (Exception ex)
{
MessageBox.Show($"写压力模式失败: {ex.Message}");
}
}
}
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);
}
}
}
}

View File

@@ -0,0 +1,409 @@
using MembranePoreTester.Communication;
using MembranePoreTester.Helpers;
using MembranePoreTester.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
namespace MembranePoreTester.ViewModels
{
public class PoreDistributionViewModel : ViewModelBase, IStationViewModel
{
private PoreDistributionRecord _record = new();
private TestLiquid _selectedLiquid;
private bool _isCustomLiquid;
private double _customSurfaceTension = 30.0;
private double _lowerPore = 0.2;
private double _upperPore = 0.8;
private double _rangePercentage;
// 添加字段
private readonly IPlcService _plcService;
private readonly PlcConfiguration _plcConfig;
private DataPoint _selectedDataPoint;
// 添加属性
public DataPoint SelectedDataPoint
{
get => _selectedDataPoint;
set => SetProperty(ref _selectedDataPoint, value);
}
public ICommand ReadPlcCommand { get; }
public PoreDistributionRecord Record
{
get => _record;
set => SetProperty(ref _record, value);
}
public List<TestLiquid> Liquids => TestLiquid.Predefined;
public List<string> PressureUnits => new() { "Pa", "cmHg", "psi" };
public List<string> MembraneTypes => new() { "平板膜", "中空纤维膜" };
public TestLiquid SelectedLiquid
{
get => _selectedLiquid;
set
{
if (SetProperty(ref _selectedLiquid, value))
{
Record.Liquid = value;
}
}
}
public bool IsCustomLiquid
{
get => _isCustomLiquid;
set
{
if (SetProperty(ref _isCustomLiquid, value))
{
UpdateCustomLiquid();
}
}
}
public double CustomSurfaceTension
{
get => _customSurfaceTension;
set
{
if (SetProperty(ref _customSurfaceTension, value))
{
UpdateCustomLiquid();
}
}
}
public double LowerPore
{
get => _lowerPore;
set => SetProperty(ref _lowerPore, value);
}
public double UpperPore
{
get => _upperPore;
set => SetProperty(ref _upperPore, value);
}
public double RangePercentage
{
get => _rangePercentage;
set => SetProperty(ref _rangePercentage, value);
}
public ICommand AddDataPointCommand { get; }
public ICommand RemoveDataPointCommand { get; }
public ICommand CalculateCommand { get; }
public ICommand GenerateReportCommand { get; }
public PoreDistributionViewModel()
{
_plcService = App.PlcService;
_plcConfig = App.PlcConfig;
AddDataPointCommand = new RelayCommand(AddDataPoint);
RemoveDataPointCommand = new RelayCommand(RemoveDataPoint, () => Record.DataPoints.Any());
CalculateCommand = new RelayCommand(Calculate);
GenerateReportCommand = new RelayCommand(GenerateReport);
SelectedLiquid = Liquids[0];
Record.PressureUnit = PressureUnits[0]; // 默认 "Pa"
ReadPlcCommand = new RelayCommand(async () => await ReadPlcAsync());
SaveCommand = new RelayCommand(SaveToDatabase);
ExportCommand = new RelayCommand(ExportToExcel);
OpenFlowCalibCommand = new RelayCommand(OpenFlowCalibration);
Record.DataPoints.CollectionChanged += (s, e) => UpdatePlot();
}
private async Task ReadPlcAsync()
{
try
{
// 始终读取压力
float rawPressure = await _plcService.ReadPressureAsync(StationId);
double pressure = rawPressure * _plcConfig.PressureFactor;
if (SelectedDataPoint != null)
{
// 更新选中行
SelectedDataPoint.Pressure = pressure;
if (TestMode == "湿膜")
{
float rawWet = await _plcService.ReadWetFlowAsync();
SelectedDataPoint.WetFlow = rawWet * _plcConfig.WetFlowFactor;
}
else
{
float rawDry = await _plcService.ReadDryFlowAsync();
SelectedDataPoint.DryFlow = rawDry * _plcConfig.DryFlowFactor;
}
}
else
{
// 新增一行
var newPoint = new DataPoint { Pressure = pressure };
if (TestMode == "湿膜")
{
float rawWet = await _plcService.ReadWetFlowAsync();
newPoint.WetFlow = rawWet * _plcConfig.WetFlowFactor;
}
else
{
float rawDry = await _plcService.ReadDryFlowAsync();
newPoint.DryFlow = rawDry * _plcConfig.DryFlowFactor;
}
Record.DataPoints.Add(newPoint);
}
}
catch (Exception ex)
{
MessageBox.Show($"读取PLC失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void AddDataPoint()
{
Record.DataPoints.Add(new DataPoint());
}
private void RemoveDataPoint()
{
if (Record.DataPoints.Any())
Record.DataPoints.RemoveAt(Record.DataPoints.Count - 1);
}
private void UpdateCustomLiquid()
{
if (IsCustomLiquid)
{
Record.Liquid = new TestLiquid
{
Name = "自定义",
SurfaceTension = CustomSurfaceTension
};
}
}
// 添加私有字段和公共属性
private double _averagePoreSize;
public double AveragePoreSize
{
get => _averagePoreSize;
set => SetProperty(ref _averagePoreSize, value);
}
// 修改 Calculate 方法:
private void Calculate()
{
if (Record.DataPoints.Count < 2) return;
AveragePoreSize = PoreDistributionAnalysis.CalculateAveragePore(
Record.DataPoints, Record.PressureUnit, Record.Liquid);
RangePercentage = PoreDistributionAnalysis.CalculatePoreRangePercentage(
Record.DataPoints, Record.PressureUnit, Record.Liquid, LowerPore, UpperPore);
}
private void GenerateReport()
{
ReportGenerator.GeneratePoreDistributionReport(Record);
}
private void OpenFlowCalibration()
{
string zeroStr = Microsoft.VisualBasic.Interaction.InputBox("请输入流量零点系数", "流量校准", "0");
string spanStr = Microsoft.VisualBasic.Interaction.InputBox("请输入流量量程系数", "流量校准", "1");
if (float.TryParse(zeroStr, out float zero) && float.TryParse(spanStr, out float span))
{
Task.Run(async () =>
{
await WriteFloatAsync(_plcConfig.FlowCalibZero, zero);
await WriteFloatAsync(_plcConfig.FlowCalibSpan, span);
MessageBox.Show("流量校准系数已写入", "完成");
});
}
}
private int _stationId;
public int StationId
{
get => _stationId;
set => SetProperty(ref _stationId, value);
}
public void SaveToDatabase()
{
var entity = new PoreDistributionEntity
{
StationId = this.StationId,
TestDate = Record.TestDate,
Tester = Record.Tester,
SampleType = Record.SampleType,
SampleSpec = Record.SampleSpec,
RoomTemperature = Record.RoomTemperature,
SoakingTime = Record.SoakingTime,
LiquidName = Record.Liquid?.Name,
LiquidSurfaceTension = Record.Liquid?.SurfaceTension ?? 0,
LiquidManufacturer = Record.LiquidManufacturer,
PressureUnit = Record.PressureUnit,
BubblePointPressure = Record.BubblePointPressure,
AveragePoreSize = AveragePoreSize, // 使用计算后的属性
DataPoints = Record.DataPoints.Select(dp => new DataPointEntity
{
Pressure = dp.Pressure,
WetFlow = dp.WetFlow,
DryFlow = dp.DryFlow
}).ToList()
};
using var db = new AppDbContext();
db.PoreDistributionRecords.Add(entity);
db.SaveChanges();
MessageBox.Show("保存成功!", "提示");
}
public void LoadFromDatabase(int recordId)
{
using var db = new AppDbContext();
var entity = db.PoreDistributionRecords
.Include(p => p.DataPoints)
.FirstOrDefault(p => p.Id == recordId);
if (entity == null) return;
Record.SampleType = entity.SampleType;
Record.SampleSpec = entity.SampleSpec;
Record.RoomTemperature = entity.RoomTemperature;
Record.SoakingTime = entity.SoakingTime;
Record.Liquid = TestLiquid.Predefined.FirstOrDefault(l => l.Name == entity.LiquidName)
?? new TestLiquid { Name = entity.LiquidName, SurfaceTension = entity.LiquidSurfaceTension };
Record.LiquidManufacturer = entity.LiquidManufacturer;
Record.PressureUnit = entity.PressureUnit;
Record.BubblePointPressure = entity.BubblePointPressure;
Record.TestDate = entity.TestDate;
Record.Tester = entity.Tester;
Record.DataPoints.Clear();
foreach (var dp in entity.DataPoints)
{
Record.DataPoints.Add(new DataPoint
{
Pressure = dp.Pressure,
WetFlow = dp.WetFlow,
DryFlow = dp.DryFlow
});
}
// 重新计算平均孔径和分布(触发计算命令)
Calculate();
}
public ICommand SaveCommand { get; }
public ICommand OpenFlowCalibCommand { get; }
public ICommand ExportCommand { get; }
private void ExportToExcel()
{
var saveFileDialog = new SaveFileDialog
{
Filter = "Excel文件|*.xlsx",
FileName = $"泡点法_工位{StationId}_{DateTime.Now:yyyyMMddHHmmss}.xlsx"
};
if (saveFileDialog.ShowDialog() == true)
{
// 转换为Entity后导出
var entity = new BubblePointEntity { /* 从Record复制 */ };
ExportHelper.ExportBubblePoint(entity, saveFileDialog.FileName);
MessageBox.Show("导出成功");
}
}
private string _testMode = "湿膜";
public string TestMode
{
get => _testMode;
set => SetProperty(ref _testMode, value);
}
private int _selectedFlowModeIndex; // 0=大流量1=小流量
public int SelectedFlowModeIndex
{
get => _selectedFlowModeIndex;
set
{
if (SetProperty(ref _selectedFlowModeIndex, value))
{
ushort reg = StationId switch
{
1 => _plcConfig.FlowModeRegister1,
2 => _plcConfig.FlowModeRegister2,
3 => _plcConfig.FlowModeRegister3,
_ => 0
};
Task.Run(async () => await _plcService.WriteSingleRegisterAsync(reg, (ushort)value));
}
}
}
private OxyPlot.PlotModel _plotModel;
public OxyPlot.PlotModel PlotModel
{
get => _plotModel;
set => SetProperty(ref _plotModel, value);
}
private void UpdatePlot()
{
var sorted = Record.DataPoints.OrderBy(p => p.Pressure).ToList();
if (sorted.Count == 0)
{
PlotModel = null;
return;
}
var model = new OxyPlot.PlotModel { Title = "流量-压力曲线" };
model.Axes.Add(new OxyPlot.Axes.LinearAxis { Position = OxyPlot.Axes.AxisPosition.Bottom, Title = "压力" });
model.Axes.Add(new OxyPlot.Axes.LinearAxis { Position = OxyPlot.Axes.AxisPosition.Left, Title = "流量 (L/min)" });
var wetSeries = new OxyPlot.Series.LineSeries { Title = "湿膜流量", Color = OxyPlot.OxyColors.Blue, MarkerType = OxyPlot.MarkerType.Circle };
var drySeries = new OxyPlot.Series.LineSeries { Title = "干膜流量", Color = OxyPlot.OxyColors.Red, MarkerType = OxyPlot.MarkerType.Circle };
foreach (var dp in sorted)
{
wetSeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.WetFlow));
drySeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.DryFlow));
}
model.Series.Add(wetSeries);
model.Series.Add(drySeries);
PlotModel = model;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Windows.Input;
namespace MembranePoreTester.ViewModels
{
public class RelayCommand : ICommand
{
private readonly Action _execute;
private readonly Func<bool> _canExecute;
public RelayCommand(Action execute, Func<bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute();
public void Execute(object parameter) => _execute();
}
public class RelayCommand<T> : ICommand
{
private readonly Action<T> _execute;
private readonly Func<T, bool> _canExecute;
public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute((T)parameter);
public void Execute(object parameter) => _execute((T)parameter);
}
}

View File

@@ -0,0 +1,97 @@
using System.Windows.Input;
using MembranePoreTester.Communication;
using System.Threading.Tasks;
using System.Windows;
namespace MembranePoreTester.ViewModels
{
public class StationViewModel : ViewModelBase
{
private readonly IPlcService _plcService;
private readonly PlcConfiguration _plcConfig;
private bool _isPressing;
private string _pressButtonText = "加压";
private string _highLowPressure = "低压";
private bool _enableChecked;
public int StationId { get; set; }
public BubblePointViewModel BubblePointVM { get; } = new();
public PoreDistributionViewModel PoreDistributionVM { get; } = new();
public string HighLowPressure
{
get => _highLowPressure;
set => SetProperty(ref _highLowPressure, value);
}
public string PressButtonText
{
get => _pressButtonText;
set => SetProperty(ref _pressButtonText, value);
}
public bool EnableChecked
{
get => _enableChecked;
set => SetProperty(ref _enableChecked, value);
}
public ICommand PressCommand { get; }
public ICommand BurstCommand { get; }
public ICommand StartCommand { get; }
public ICommand StopCommand { get; }
public ICommand EnableCommand { get; } // 用于使能复选框
public StationViewModel()
{
_plcService = App.PlcService;
_plcConfig = App.PlcConfig;
BubblePointVM.StationId = StationId;
PoreDistributionVM.StationId = StationId;
// 初始化按钮文字
_pressButtonText = "加压"; // 直接设置字段,避免触发属性通知循环
PressButtonText = "加压"; // 或者通过属性设置
System.Diagnostics.Debug.WriteLine($"工位{StationId} PressButtonText初始值: {PressButtonText}");
PressCommand = new RelayCommand(async () => await TogglePressAsync());
BurstCommand = new RelayCommand(async () => await ReadBurstPressureAsync());
StartCommand = new RelayCommand(async () => await WriteCoilAsync(_plcConfig.StartCoil, true));
StopCommand = new RelayCommand(async () => await WriteCoilAsync(_plcConfig.StopCoil, true));
// 使能复选框点击时写入对应线圈
EnableCommand = new RelayCommand(async () => await WriteCoilAsync(_plcConfig.EnableCoil, EnableChecked));
}
private async Task TogglePressAsync()
{
_isPressing = !_isPressing;
await WriteCoilAsync(_plcConfig.PressCoil, _isPressing);
PressButtonText = _isPressing ? "停止加压" : "加压";
}
private async Task ReadBurstPressureAsync()
{
try
{
float pressure = await ((ModbusTcpPlcService)_plcService).ReadPressureAsync(StationId);
BubblePointVM.UpdateBubblePointPressure(pressure * _plcConfig.PressureFactor);
MessageBox.Show($"涨破压力: {pressure} {BubblePointVM.Record.PressureUnit}", "提示");
}
catch (Exception ex)
{
MessageBox.Show($"读取压力失败: {ex.Message}");
}
}
private async Task WriteCoilAsync(ushort coil, bool value)
{
try
{
await ((ModbusTcpPlcService)_plcService).WriteCoilAsync(coil, value);
}
catch (Exception ex)
{
MessageBox.Show($"写线圈失败: {ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,34 @@
using MembranePoreTester.Communication;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace MembranePoreTester.ViewModels
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
protected async Task WriteFloatAsync(ushort address, float value)
{
byte[] bytes = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
ushort high = (ushort)((bytes[0] << 8) | bytes[1]);
ushort low = (ushort)((bytes[2] << 8) | bytes[3]);
await App.PlcService.WriteSingleRegisterAsync(address, high);
await App.PlcService.WriteSingleRegisterAsync((ushort)(address + 1), low);
}
}
}