This commit is contained in:
@@ -1,10 +1,59 @@
|
||||
namespace MembranePoreTester.Models
|
||||
{
|
||||
public class DataPoint
|
||||
{
|
||||
public double Pressure { get; set; } // 压力
|
||||
public double WetFlow { get; set; } // 湿膜流量(L/min)
|
||||
public double DryFlow { get; set; } // 干膜流量(L/min)
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace MembranePoreTester.Models
|
||||
{
|
||||
// 数据点实现 INotifyPropertyChanged,保证 UI(DataGrid/Plot)在属性变化时刷新
|
||||
public class DataPoint : INotifyPropertyChanged
|
||||
{
|
||||
private double _pressure;
|
||||
private double _wetFlow;
|
||||
private double _dryFlow;
|
||||
|
||||
public double Pressure
|
||||
{
|
||||
get => _pressure;
|
||||
set
|
||||
{
|
||||
if (_pressure != value)
|
||||
{
|
||||
_pressure = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double WetFlow
|
||||
{
|
||||
get => _wetFlow;
|
||||
set
|
||||
{
|
||||
if (_wetFlow != value)
|
||||
{
|
||||
_wetFlow = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double DryFlow
|
||||
{
|
||||
get => _dryFlow;
|
||||
set
|
||||
{
|
||||
if (_dryFlow != value)
|
||||
{
|
||||
_dryFlow = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ using OxyPlot.Legends;
|
||||
using OxyPlot.Series;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
@@ -138,7 +140,7 @@ namespace MembranePoreTester.ViewModels
|
||||
{
|
||||
// 清空数据点集合
|
||||
Record.DataPoints.Clear();
|
||||
|
||||
PlotModel = new PlotModel();
|
||||
// 重置曲线
|
||||
UpdatePlot();
|
||||
|
||||
@@ -186,7 +188,14 @@ namespace MembranePoreTester.ViewModels
|
||||
public PoreDistributionRecord Record
|
||||
{
|
||||
get => _record;
|
||||
set => SetProperty(ref _record, value);
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _record, value))
|
||||
{
|
||||
// 当 Record 替换时(例如从数据库加载),重新订阅其 DataPoints 集合
|
||||
HookDataPointsCollection(_record?.DataPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<TestLiquid> Liquids => TestLiquid.Predefined;
|
||||
@@ -270,7 +279,8 @@ namespace MembranePoreTester.ViewModels
|
||||
OpenFlowCalibCommand = new RelayCommand(OpenFlowCalibration);
|
||||
OpenFlowCalibCommand2 = new RelayCommand(OpenFlowCalibration2);
|
||||
|
||||
Record.DataPoints.CollectionChanged += (s, e) => UpdatePlot();
|
||||
// 订阅集合变更并为每个项订阅属性变化,保证 DataGrid 和 Plot 在项内容变化时同步刷新
|
||||
HookDataPointsCollection(Record.DataPoints);
|
||||
|
||||
ClearAllCommand = new RelayCommand(ClearAllData);
|
||||
|
||||
@@ -440,6 +450,59 @@ namespace MembranePoreTester.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
// 监听 DataPoints 集合与其子项的属性变更,确保 UI 同步更新
|
||||
private void HookDataPointsCollection(ObservableCollection<Models.DataPoint> collection)
|
||||
{
|
||||
if (collection == null) return;
|
||||
|
||||
// 先解绑已有(避免重复订阅)
|
||||
collection.CollectionChanged -= DataPoints_CollectionChanged;
|
||||
collection.CollectionChanged += DataPoints_CollectionChanged;
|
||||
|
||||
// 为已有项订阅 PropertyChanged
|
||||
foreach (var item in collection)
|
||||
{
|
||||
if (item is INotifyPropertyChanged inpc)
|
||||
{
|
||||
inpc.PropertyChanged -= DataPoint_PropertyChanged;
|
||||
inpc.PropertyChanged += DataPoint_PropertyChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DataPoints_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (var old in e.OldItems)
|
||||
{
|
||||
if (old is INotifyPropertyChanged inpc)
|
||||
inpc.PropertyChanged -= DataPoint_PropertyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
foreach (var nw in e.NewItems)
|
||||
{
|
||||
if (nw is INotifyPropertyChanged inpc)
|
||||
{
|
||||
inpc.PropertyChanged -= DataPoint_PropertyChanged;
|
||||
inpc.PropertyChanged += DataPoint_PropertyChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 集合结构变化时刷新曲线
|
||||
UpdatePlot();
|
||||
}
|
||||
|
||||
private void DataPoint_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
// 某个数据点属性改变时也刷新曲线
|
||||
UpdatePlot();
|
||||
}
|
||||
|
||||
// 添加私有字段和公共属性
|
||||
private double _averagePoreSize;
|
||||
public double AveragePoreSize
|
||||
@@ -681,6 +744,9 @@ namespace MembranePoreTester.ViewModels
|
||||
set => SetProperty(ref _plotModel, value);
|
||||
}
|
||||
|
||||
// 用于保护绘图更新,避免并发导致渲染丢失
|
||||
private readonly object _plotLock = new();
|
||||
|
||||
private async Task WriteFlowModeAsync(string mode)
|
||||
{
|
||||
ushort val = mode.ToString().Contains("大流量") ? (ushort)0 : (ushort)1;
|
||||
@@ -698,6 +764,13 @@ namespace MembranePoreTester.ViewModels
|
||||
|
||||
private void UpdatePlot()
|
||||
{
|
||||
// Ensure we run on UI thread because we update PlotModel (bound to UI)
|
||||
if (Application.Current != null && !Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
Application.Current.Dispatcher.BeginInvoke((Action)UpdatePlot);
|
||||
return;
|
||||
}
|
||||
|
||||
var sorted = Record.DataPoints.OrderBy(p => p.Pressure).ToList();
|
||||
if (sorted.Count == 0)
|
||||
{
|
||||
@@ -762,7 +835,10 @@ namespace MembranePoreTester.ViewModels
|
||||
model.Series.Add(wetSeries);
|
||||
model.Series.Add(drySeries);
|
||||
|
||||
PlotModel = model;
|
||||
lock (_plotLock)
|
||||
{
|
||||
PlotModel = model;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user