This commit is contained in:
@@ -126,9 +126,30 @@ namespace MembranePoreTester.ViewModels
|
||||
_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));
|
||||
|
||||
|
||||
// 在 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);
|
||||
@@ -242,7 +263,12 @@ namespace MembranePoreTester.ViewModels
|
||||
}
|
||||
|
||||
|
||||
|
||||
private bool _isPoreDistributionActive;
|
||||
public bool IsPoreDistributionActive
|
||||
{
|
||||
get => _isPoreDistributionActive;
|
||||
set => SetProperty(ref _isPoreDistributionActive, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,17 +3,171 @@ using MembranePoreTester.Helpers;
|
||||
using MembranePoreTester.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Win32;
|
||||
using OxyPlot;
|
||||
using OxyPlot.Axes;
|
||||
using OxyPlot.Legends;
|
||||
using OxyPlot.Series;
|
||||
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
|
||||
{
|
||||
|
||||
#region
|
||||
|
||||
public class PressureModeItem
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public int Value { get; set; }
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Text; // 直接返回要显示的文本
|
||||
}
|
||||
}
|
||||
|
||||
private PressureModeItem _selectedPressureMode;
|
||||
private List<PressureModeItem> _pressureModeList;
|
||||
|
||||
public List<PressureModeItem> PressureModeList => _pressureModeList ??= new List<PressureModeItem>
|
||||
{
|
||||
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 WriteFlowModeAsync(value?.Text ?? "小流量"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
// 添加字段
|
||||
private System.Windows.Threading.DispatcherTimer _autoCollectTimer;
|
||||
private bool _isCollecting = false;
|
||||
|
||||
// 添加公共方法供工位调用
|
||||
public void StartCollecting()
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
// 如果当前不在孔分布界面,不启动采集
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isCollecting) return;
|
||||
_isCollecting = true;
|
||||
_autoCollectTimer = new System.Windows.Threading.DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(1)
|
||||
};
|
||||
_autoCollectTimer.Tick += AutoCollectTimer_Tick;
|
||||
_autoCollectTimer.Start();
|
||||
}
|
||||
|
||||
public void StopCollecting()
|
||||
{
|
||||
_isCollecting = false;
|
||||
_autoCollectTimer?.Stop();
|
||||
_autoCollectTimer = null;
|
||||
}
|
||||
|
||||
private async void AutoCollectTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (!IsActive) return; // 不在当前标签页,跳过采集
|
||||
try
|
||||
{
|
||||
// 1. 读取当前压力
|
||||
float rawPressure = await _plcService.ReadPressureAsync(StationId);
|
||||
double pressure = Math.Round(rawPressure,2);
|
||||
|
||||
double flow = 0;
|
||||
if (TestMode == "湿膜")
|
||||
{
|
||||
float rawFlow = await _plcService.ReadWetFlowAsync();
|
||||
flow = rawFlow;
|
||||
}
|
||||
else
|
||||
{
|
||||
float rawFlow = await _plcService.ReadDryFlowAsync();
|
||||
flow = rawFlow;
|
||||
}
|
||||
|
||||
flow = Math.Round(flow,2);
|
||||
// 3. 在 DataPoints 中查找是否存在相同压力的行(允许微小误差)
|
||||
var existing = Record.DataPoints.FirstOrDefault(p => Math.Abs(p.Pressure - pressure) < 0.001);
|
||||
if (existing != null)
|
||||
{
|
||||
// 更新对应列
|
||||
if (TestMode == "湿膜")
|
||||
existing.WetFlow = flow;
|
||||
else
|
||||
existing.DryFlow = flow;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 新增一行
|
||||
var newPoint = new Models.DataPoint { Pressure = pressure };
|
||||
if (TestMode == "湿膜")
|
||||
newPoint.WetFlow = flow;
|
||||
else
|
||||
newPoint.DryFlow = flow;
|
||||
Record.DataPoints.Add(newPoint);
|
||||
}
|
||||
|
||||
// 4. 刷新曲线
|
||||
UpdatePlot();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"自动采集失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有数据点,重置表格和曲线
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
// 清空数据点集合
|
||||
Record.DataPoints.Clear();
|
||||
|
||||
// 重置曲线
|
||||
UpdatePlot();
|
||||
|
||||
// 重置计算结果
|
||||
AveragePoreSize = 0;
|
||||
RangePercentage = 0;
|
||||
|
||||
// 可选:显示提示
|
||||
System.Diagnostics.Debug.WriteLine("孔分布数据已清空");
|
||||
}
|
||||
|
||||
private bool _isActive;
|
||||
public bool IsActive
|
||||
{
|
||||
get => _isActive;
|
||||
set => SetProperty(ref _isActive, value);
|
||||
}
|
||||
|
||||
|
||||
private PoreDistributionRecord _record = new();
|
||||
private TestLiquid _selectedLiquid;
|
||||
private bool _isCustomLiquid;
|
||||
@@ -27,11 +181,11 @@ namespace MembranePoreTester.ViewModels
|
||||
// 添加字段
|
||||
private readonly IPlcService _plcService;
|
||||
private readonly PlcConfiguration _plcConfig;
|
||||
private DataPoint _selectedDataPoint;
|
||||
private Models.DataPoint _selectedDataPoint;
|
||||
|
||||
|
||||
// 添加属性
|
||||
public DataPoint SelectedDataPoint
|
||||
public Models.DataPoint SelectedDataPoint
|
||||
{
|
||||
get => _selectedDataPoint;
|
||||
set => SetProperty(ref _selectedDataPoint, value);
|
||||
@@ -127,8 +281,49 @@ namespace MembranePoreTester.ViewModels
|
||||
|
||||
|
||||
Record.DataPoints.CollectionChanged += (s, e) => UpdatePlot();
|
||||
|
||||
|
||||
|
||||
// 延迟2秒后读取,确保连接稳定
|
||||
Task.Delay(2000).ContinueWith(async _ =>
|
||||
{
|
||||
await ReadPressureModeAsync();
|
||||
}, TaskScheduler.Default);
|
||||
|
||||
}
|
||||
|
||||
private async Task ReadPressureModeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
ushort[] values = await _plcService.ReadHoldingRegistersAsync(_plcConfig.FlowModeRegister, 1);
|
||||
ushort val = values[0];
|
||||
string newValue = val == 0 ? "大流量" : "小流量";
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
// 更新选中项
|
||||
HighLowPressure = newValue;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"读取流量模式失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public string HighLowPressure
|
||||
{
|
||||
get => _selectedPressureMode?.Text ?? "小流量";
|
||||
set
|
||||
{
|
||||
var mode = PressureModeList.FirstOrDefault(m => m.Text == value);
|
||||
if (mode != null)
|
||||
{
|
||||
SelectedPressureMode = mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReadPlcAsync()
|
||||
{
|
||||
@@ -156,7 +351,7 @@ namespace MembranePoreTester.ViewModels
|
||||
else
|
||||
{
|
||||
// 新增一行
|
||||
var newPoint = new DataPoint { Pressure = pressure };
|
||||
var newPoint = new Models.DataPoint { Pressure = pressure };
|
||||
if (TestMode == "湿膜")
|
||||
{
|
||||
float rawWet = await _plcService.ReadWetFlowAsync();
|
||||
@@ -178,7 +373,7 @@ namespace MembranePoreTester.ViewModels
|
||||
|
||||
private void AddDataPoint()
|
||||
{
|
||||
Record.DataPoints.Add(new DataPoint());
|
||||
Record.DataPoints.Add(new Models.DataPoint());
|
||||
}
|
||||
|
||||
private void RemoveDataPoint()
|
||||
@@ -302,7 +497,7 @@ namespace MembranePoreTester.ViewModels
|
||||
Record.DataPoints.Clear();
|
||||
foreach (var dp in entity.DataPoints)
|
||||
{
|
||||
Record.DataPoints.Add(new DataPoint
|
||||
Record.DataPoints.Add(new Models.DataPoint
|
||||
{
|
||||
Pressure = dp.Pressure,
|
||||
WetFlow = dp.WetFlow,
|
||||
@@ -347,19 +542,6 @@ namespace MembranePoreTester.ViewModels
|
||||
set => SetProperty(ref _testMode, value);
|
||||
}
|
||||
|
||||
private string _selectedFlowModeIndex; // 0=大流量,1=小流量
|
||||
public string SelectedFlowModeIndex
|
||||
{
|
||||
get => _selectedFlowModeIndex;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedFlowModeIndex, value))
|
||||
{
|
||||
// 当选择变化时,写入 PLC 压力模式寄存器
|
||||
Task.Run(async () => await WriteFlowModeAsync(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private OxyPlot.PlotModel _plotModel;
|
||||
@@ -371,10 +553,10 @@ namespace MembranePoreTester.ViewModels
|
||||
|
||||
private async Task WriteFlowModeAsync(string mode)
|
||||
{
|
||||
float val = mode == "大流量" ? 0.0f : 1.0f;
|
||||
ushort val = mode.ToString().Contains("大流量") ? (ushort)0 : (ushort)1;
|
||||
try
|
||||
{
|
||||
await _plcService.WriteMultipleRegistersAsync(_plcConfig.PressureModeRegister, val);
|
||||
await _plcService.WriteSingleRegisterAsync(_plcConfig.FlowModeRegister, val);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -382,6 +564,8 @@ namespace MembranePoreTester.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void UpdatePlot()
|
||||
{
|
||||
var sorted = Record.DataPoints.OrderBy(p => p.Pressure).ToList();
|
||||
@@ -391,12 +575,53 @@ namespace MembranePoreTester.ViewModels
|
||||
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 model = new PlotModel
|
||||
{
|
||||
Title = "流量-压力曲线",
|
||||
TitleFontSize = 14,
|
||||
TitleFontWeight = 1
|
||||
};
|
||||
|
||||
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 };
|
||||
|
||||
|
||||
// 添加坐标轴
|
||||
model.Axes.Add(new LinearAxis
|
||||
{
|
||||
Position = AxisPosition.Bottom,
|
||||
Title = "压力 (kPa)",
|
||||
TitleFontSize = 12
|
||||
});
|
||||
|
||||
model.Axes.Add(new LinearAxis
|
||||
{
|
||||
Position = AxisPosition.Left,
|
||||
Title = "流量 (L/min)",
|
||||
TitleFontSize = 12
|
||||
});
|
||||
|
||||
// 湿膜流量 - 使用更清晰的标题
|
||||
var wetSeries = new LineSeries
|
||||
{
|
||||
Title = "● 湿膜流量 (Wet Flow)",
|
||||
Color = OxyColors.Blue,
|
||||
MarkerType = MarkerType.Circle,
|
||||
MarkerSize = 4,
|
||||
MarkerStroke = OxyColors.Blue,
|
||||
MarkerFill = OxyColors.Blue,
|
||||
StrokeThickness = 2
|
||||
};
|
||||
|
||||
// 干膜流量 - 使用更清晰的标题
|
||||
var drySeries = new LineSeries
|
||||
{
|
||||
Title = "▲ 干膜流量 (Dry Flow)",
|
||||
Color = OxyColors.Red,
|
||||
MarkerType = MarkerType.Triangle,
|
||||
MarkerSize = 5,
|
||||
MarkerStroke = OxyColors.Red,
|
||||
MarkerFill = OxyColors.Red,
|
||||
StrokeThickness = 2
|
||||
};
|
||||
|
||||
foreach (var dp in sorted)
|
||||
{
|
||||
@@ -411,5 +636,10 @@ namespace MembranePoreTester.ViewModels
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user