diff --git a/DeviceEditModule/Views/IT7800EView.xaml b/DeviceEditModule/Views/IT7800EView.xaml
index e64e850..48a9778 100644
--- a/DeviceEditModule/Views/IT7800EView.xaml
+++ b/DeviceEditModule/Views/IT7800EView.xaml
@@ -13,51 +13,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/DeviceEditModule/Views/N36200View.xaml b/DeviceEditModule/Views/N36200View.xaml
index cba29bc..9185c2e 100644
--- a/DeviceEditModule/Views/N36200View.xaml
+++ b/DeviceEditModule/Views/N36200View.xaml
@@ -12,47 +12,6 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/MonitorModule/ViewModels/MonitorViewModel.cs b/MonitorModule/ViewModels/MonitorViewModel.cs
index 6fea2e0..5fd15d4 100644
--- a/MonitorModule/ViewModels/MonitorViewModel.cs
+++ b/MonitorModule/ViewModels/MonitorViewModel.cs
@@ -1,6 +1,7 @@
using Common.Attributes;
using Model.Entity;
using Model.Models;
+using NLog;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Legends;
@@ -19,6 +20,7 @@ using System.Windows.Input;
using System.Windows.Threading;
using UIShare.GlobalVariable;
using UIShare.PubEvent;
+using UIShare.UIViewModel;
using UIShare.ViewModelBase;
@@ -42,13 +44,25 @@ namespace MonitorModule.ViewModels
public PlotModel Plot { get; }
/// 已添加的监测通道列表
- public ObservableCollection Channels { get; } = new();
+ public ObservableCollection Channels
+ {
+ get => _systemConfig?.Channels ?? new ObservableCollection();
+ set
+ {
+ if (_systemConfig != null && _systemConfig.Channels != value)
+ {
+ _systemConfig.Channels = value;
+ RaisePropertyChanged();
+ }
+ }
+ }
+
/// 可添加的设备方法列表(供用户选择)
public ObservableCollection AvailableMethods { get; } = new();
- private MonitorChannel? _selectedChannel;
- public MonitorChannel? SelectedChannel
+ private MonitorChannelVM? _selectedChannel;
+ public MonitorChannelVM? SelectedChannel
{
get => _selectedChannel;
set => SetProperty(ref _selectedChannel, value);
@@ -75,12 +89,14 @@ namespace MonitorModule.ViewModels
public ICommand ResetViewCommand { get; }
public ICommand RefreshDataCommand { get; }
public ICommand RefreshCommand { get; }
+ public ICommand SaveCommand { get; }
#endregion
#region 私有字段
private bool IsInitiated = false;
private IScopedProvider? _scope;
private DeviceManager? _deviceManager;
+ private SystemConfig? _systemConfig;
private CancellationTokenSource? _monitorCTS = new();
// 颜色调色盘
@@ -125,6 +141,7 @@ namespace MonitorModule.ViewModels
ResetViewCommand = new DelegateCommand(OnResetView);
RefreshDataCommand = new DelegateCommand(OnRefreshData);
RefreshCommand = new DelegateCommand(OnExpand);
+ SaveCommand = new DelegateCommand(OnSave);
// OxyPlot 刷新定时器(1000ms,只负责视觉更新)
_plotRefreshTimer = new DispatcherTimer(DispatcherPriority.Background)
@@ -134,6 +151,8 @@ namespace MonitorModule.ViewModels
_plotRefreshTimer.Tick += OnPlotRefreshTick;
}
+
+
public void Dispose()
{
_monitorCTS?.Cancel();
@@ -159,7 +178,21 @@ namespace MonitorModule.ViewModels
Channels.Clear();
AvailableMethods.Clear();
}
-
+ private void OnSave()
+ {
+ // 将当前 Channels 序列化为 MonitorChannelConfig 列表保存到 MonitorChannels
+ if (_systemConfig != null)
+ {
+ _systemConfig.MonitorChannels = new ObservableCollection(Channels
+ .Select(c => new MonitorChannelConfig
+ {
+ Fingerprint = c.Fingerprint,
+ MethodName = c.MethodName,
+ IsDisplayed = c.IsDisplayed
+ }));
+ }
+ ConfigService.Save(_systemConfig);
+ }
#region 事件驱动:接收广播数据
///
/// 由 HardwareDataBroadcaster 通过 EventAggregator 广播触发。
@@ -275,6 +308,8 @@ namespace MonitorModule.ViewModels
_scope = _globalInfo.ScopeDic[TestStatus];
_scopedContext = _scope.Resolve();
_deviceManager = _scope.Resolve();
+ _systemConfig = _scope.Resolve();
+ RaisePropertyChanged(nameof(Channels));
_broadcaster = _scope.Resolve();
IsInitiated = true;
@@ -286,15 +321,18 @@ namespace MonitorModule.ViewModels
// 2. 扫描可监测方法(供 UI 选择)
DiscoverAvailableMethods();
- // 3. 启动广播器(Discover + Start)
+ // 3. 从配置自动恢复已保存的监测通道
+ RestoreChannelsFromConfig();
+
+ // 4. 启动广播器(Discover + Start)
_broadcaster.Discover();
_broadcaster.Start();
- // 4. 订阅 HardwareDataReportedEvent(UI 线程回调)
+ // 5. 订阅 HardwareDataReportedEvent(UI 线程回调)
_subscriptionToken = _eventAggregator.GetEvent()
.Subscribe(OnHardwareDataReceived, ThreadOption.UIThread);
- // 5. 启动 OxyPlot 视觉刷新定时器
+ // 6. 启动 OxyPlot 视觉刷新定时器
_stopwatch.Start();
_plotRefreshTimer.Start();
}
@@ -404,6 +442,72 @@ namespace MonitorModule.ViewModels
? $"发现 {AvailableMethods.Count} 个可监测项"
: "未发现可监测的设备方法";
}
+
+ ///
+ /// 从 SystemConfig.MonitorChannels 持久化列表自动还原监测通道。
+ ///
+ private void RestoreChannelsFromConfig()
+ {
+ if (_systemConfig?.MonitorChannels == null || _systemConfig.MonitorChannels.Count == 0) return;
+ if (AvailableMethods.Count == 0) return;
+
+ int restored = 0;
+ foreach (var config in _systemConfig.MonitorChannels)
+ {
+ if (string.IsNullOrWhiteSpace(config.Fingerprint) ||
+ string.IsNullOrWhiteSpace(config.MethodName)) continue;
+
+ // 已在 Channels 中存在则跳过
+ if (Channels.Any(c => c.Fingerprint == config.Fingerprint && c.MethodName == config.MethodName))
+ continue;
+
+ // 在 AvailableMethods 中查找匹配项
+ var method = AvailableMethods.FirstOrDefault(m =>
+ m.Fingerprint == config.Fingerprint && m.MethodName == config.MethodName);
+ if (method == null) continue;
+
+ var color = _palette[_colorIndex % _palette.Length];
+ _colorIndex++;
+
+ var channel = new MonitorChannelVM
+ {
+ DeviceName = method.DeviceName,
+ Fingerprint = method.Fingerprint,
+ MethodName = method.MethodName,
+ DisplayName = method.DisplayName,
+ Color = color,
+ IsMonitored = true,
+ IsDisplayed = config.IsDisplayed
+ };
+
+ // 仅当 IsDisplayed=true 时才创建 LineSeries
+ if (channel.IsDisplayed)
+ {
+ channel.Series = new LineSeries
+ {
+ Title = channel.DisplayName,
+ Color = color,
+ StrokeThickness = 1.5
+ };
+ Plot.Series.Add(channel.Series);
+ }
+
+ channel.PropertyChanged += (s, e) =>
+ {
+ if (e.PropertyName == nameof(MonitorChannelVM.IsDisplayed))
+ OnChannelDisplayChanged(channel);
+ };
+
+ Channels.Add(channel);
+ restored++;
+ }
+
+ if (restored > 0)
+ {
+ Plot.InvalidatePlot(true);
+ StatusMessage = $"已从配置自动恢复 {restored} 个监测通道";
+ }
+ }
#endregion
#region 命令处理
@@ -426,7 +530,7 @@ namespace MonitorModule.ViewModels
var color = _palette[_colorIndex % _palette.Length];
_colorIndex++;
- var channel = new MonitorChannel
+ var channel = new MonitorChannelVM
{
DeviceName = method.DeviceName,
Fingerprint = method.Fingerprint,
@@ -447,7 +551,7 @@ namespace MonitorModule.ViewModels
channel.PropertyChanged += (s, e) =>
{
- if (e.PropertyName == nameof(MonitorChannel.IsDisplayed))
+ if (e.PropertyName == nameof(MonitorChannelVM.IsDisplayed))
OnChannelDisplayChanged(channel);
};
@@ -497,7 +601,7 @@ namespace MonitorModule.ViewModels
#endregion
#region 显示/隐藏切换与数学变换
- public void OnChannelDisplayChanged(MonitorChannel channel)
+ public void OnChannelDisplayChanged(MonitorChannelVM channel)
{
if (channel.IsDisplayed)
{
@@ -530,7 +634,7 @@ namespace MonitorModule.ViewModels
}
}
- public void OnChannelMathChanged(MonitorChannel channel)
+ public void OnChannelMathChanged(MonitorChannelVM channel)
{
if (channel.Series == null) return;
var points = channel.DataPoints.ToArray();
diff --git a/MonitorModule/Views/MonitorViewView.xaml b/MonitorModule/Views/MonitorView.xaml
similarity index 98%
rename from MonitorModule/Views/MonitorViewView.xaml
rename to MonitorModule/Views/MonitorView.xaml
index cc55bbc..f20f5ab 100644
--- a/MonitorModule/Views/MonitorViewView.xaml
+++ b/MonitorModule/Views/MonitorView.xaml
@@ -89,6 +89,10 @@
Command="{Binding RefreshDataCommand}"
Padding="12,4" Margin="6,0,0,0"
ToolTip="重新绘制图表"/>
+
diff --git a/MonitorModule/Views/MonitorViewView.xaml.cs b/MonitorModule/Views/MonitorView.xaml.cs
similarity index 100%
rename from MonitorModule/Views/MonitorViewView.xaml.cs
rename to MonitorModule/Views/MonitorView.xaml.cs
diff --git a/UIShare/GlobalVariable/SystemConfig.cs b/UIShare/GlobalVariable/SystemConfig.cs
index e876110..869a0d6 100644
--- a/UIShare/GlobalVariable/SystemConfig.cs
+++ b/UIShare/GlobalVariable/SystemConfig.cs
@@ -33,6 +33,12 @@ namespace UIShare.GlobalVariable
public ObservableCollection ConfigurationList = new();
public ObservableCollection dbcAutoLoadList = new();
public ObservableCollection ValueLimitList = new();
+ [JsonIgnore]
+ public ObservableCollection Channels = new();
+ ///
+ /// 监测通道持久化配置列表(包含 Fingerprint、MethodName、IsDisplayed)
+ ///
+ public ObservableCollection MonitorChannels = new();
public ZLGCANFD CANFD = new();
[JsonIgnore]
public ObservableCollection ParameterList = new()
diff --git a/UIShare/UIShare.csproj b/UIShare/UIShare.csproj
index e8edad5..b248086 100644
--- a/UIShare/UIShare.csproj
+++ b/UIShare/UIShare.csproj
@@ -15,6 +15,7 @@
+
diff --git a/MonitorModule/ViewModels/MonitorChannel.cs b/UIShare/UIViewModel/MonitorChannel.cs
similarity index 97%
rename from MonitorModule/ViewModels/MonitorChannel.cs
rename to UIShare/UIViewModel/MonitorChannel.cs
index 36f1785..8912480 100644
--- a/MonitorModule/ViewModels/MonitorChannel.cs
+++ b/UIShare/UIViewModel/MonitorChannel.cs
@@ -4,7 +4,7 @@ using System.Collections.Concurrent;
using Prism.Mvvm;
using NCalc;
-namespace MonitorModule.ViewModels
+namespace UIShare.UIViewModel
{
///
/// 监测通道:一个设备方法对应一个通道。
@@ -12,7 +12,7 @@ namespace MonitorModule.ViewModels
/// - IsMonitored=true 时始终记录 DataPoints
/// - IsDisplayed=true 时才创建 LineSeries 并绘制
///
- public class MonitorChannel : BindableBase
+ public class MonitorChannelVM : BindableBase
{
// ===== 标识 =====
public string DeviceName { get; init; } = string.Empty;
diff --git a/UIShare/UIViewModel/MonitorChannelConfig.cs b/UIShare/UIViewModel/MonitorChannelConfig.cs
new file mode 100644
index 0000000..28d1be4
--- /dev/null
+++ b/UIShare/UIViewModel/MonitorChannelConfig.cs
@@ -0,0 +1,17 @@
+namespace UIShare.UIViewModel
+{
+ ///
+ /// 监测通道持久化配置(用于 JSON 保存/恢复)。
+ ///
+ public class MonitorChannelConfig
+ {
+ /// 硬件指纹(物理设备唯一标识)
+ public string Fingerprint { get; set; } = string.Empty;
+
+ /// 监测方法名
+ public string MethodName { get; set; } = string.Empty;
+
+ /// 是否在图表上显示该通道的线图
+ public bool IsDisplayed { get; set; } = true;
+ }
+}