Files
VacuumPressureMembranePoreS…/ViewModels/PoreDistributionViewModel.cs

415 lines
14 KiB
C#
Raw Normal View History

2026-02-27 16:58:02 +08:00
using MembranePoreTester.Communication;
using MembranePoreTester.Helpers;
2026-02-27 16:03:49 +08:00
using MembranePoreTester.Models;
2026-03-02 18:50:30 +08:00
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
2026-02-27 16:03:49 +08:00
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
2026-02-27 16:58:02 +08:00
using System.Windows;
2026-02-27 16:03:49 +08:00
using System.Windows.Input;
2026-03-24 19:33:35 +08:00
2026-02-27 16:03:49 +08:00
namespace MembranePoreTester.ViewModels
{
2026-03-02 18:50:30 +08:00
public class PoreDistributionViewModel : ViewModelBase, IStationViewModel
2026-02-27 16:03:49 +08:00
{
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;
2026-02-27 16:58:02 +08:00
// 添加字段
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; }
2026-02-27 16:03:49 +08:00
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()
{
2026-02-27 16:58:02 +08:00
_plcService = App.PlcService;
_plcConfig = App.PlcConfig;
2026-02-27 16:03:49 +08:00
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"
2026-02-27 16:58:02 +08:00
ReadPlcCommand = new RelayCommand(async () => await ReadPlcAsync());
2026-03-02 18:50:30 +08:00
SaveCommand = new RelayCommand(SaveToDatabase);
ExportCommand = new RelayCommand(ExportToExcel);
2026-03-24 19:33:35 +08:00
OpenFlowCalibCommand = new RelayCommand(OpenFlowCalibration);
Record.DataPoints.CollectionChanged += (s, e) => UpdatePlot();
2026-02-27 16:58:02 +08:00
}
private async Task ReadPlcAsync()
{
try
{
2026-03-11 20:37:53 +08:00
// 始终读取压力
2026-03-19 20:40:54 +08:00
float rawPressure = await _plcService.ReadPressureAsync(StationId);
2026-02-27 16:58:02 +08:00
double pressure = rawPressure * _plcConfig.PressureFactor;
if (SelectedDataPoint != null)
{
2026-03-11 20:37:53 +08:00
// 更新选中行
2026-02-27 16:58:02 +08:00
SelectedDataPoint.Pressure = pressure;
2026-03-11 20:37:53 +08:00
if (TestMode == "湿膜")
{
float rawWet = await _plcService.ReadWetFlowAsync();
SelectedDataPoint.WetFlow = rawWet * _plcConfig.WetFlowFactor;
}
else
{
float rawDry = await _plcService.ReadDryFlowAsync();
SelectedDataPoint.DryFlow = rawDry * _plcConfig.DryFlowFactor;
}
2026-02-27 16:58:02 +08:00
}
else
{
2026-03-11 20:37:53 +08:00
// 新增一行
var newPoint = new DataPoint { Pressure = pressure };
if (TestMode == "湿膜")
2026-02-27 16:58:02 +08:00
{
2026-03-11 20:37:53 +08:00
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);
2026-02-27 16:58:02 +08:00
}
}
catch (Exception ex)
{
MessageBox.Show($"读取PLC失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
2026-02-27 16:03:49 +08:00
}
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);
}
2026-03-02 18:50:30 +08:00
2026-03-24 19:33:35 +08:00
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("流量校准系数已写入", "完成");
});
}
}
2026-03-02 18:50:30 +08:00
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; }
2026-03-24 19:33:35 +08:00
public ICommand OpenFlowCalibCommand { get; }
2026-03-02 18:50:30 +08:00
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("导出成功");
}
}
2026-03-11 20:37:53 +08:00
private string _testMode = "湿膜";
public string TestMode
{
get => _testMode;
set => SetProperty(ref _testMode, value);
}
2026-03-26 19:43:52 +08:00
private string _selectedFlowModeIndex; // 0=大流量1=小流量
public string SelectedFlowModeIndex
2026-03-24 19:33:35 +08:00
{
get => _selectedFlowModeIndex;
set
{
if (SetProperty(ref _selectedFlowModeIndex, value))
{
2026-03-26 19:43:52 +08:00
// 当选择变化时,写入 PLC 压力模式寄存器
Task.Run(async () => await WriteFlowModeAsync(value));
2026-03-24 19:33:35 +08:00
}
}
}
private OxyPlot.PlotModel _plotModel;
public OxyPlot.PlotModel PlotModel
{
get => _plotModel;
set => SetProperty(ref _plotModel, value);
}
2026-03-26 19:43:52 +08:00
private async Task WriteFlowModeAsync(string mode)
{
float val = mode == "大流量" ? 0.0f : 1.0f;
try
{
await _plcService.WriteMultipleRegistersAsync(_plcConfig.PressureModeRegister, val);
}
catch (Exception ex)
{
MessageBox.Show($"写流量模式失败: {ex.Message}");
}
}
2026-03-24 19:33:35 +08:00
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;
}
2026-03-11 20:37:53 +08:00
2026-02-27 16:03:49 +08:00
}
}