解决stepsmanager bug
This commit is contained in:
@@ -4,6 +4,8 @@ using System;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -79,6 +81,10 @@ namespace TestingModule.ViewModels
|
|||||||
private readonly GlobalInfo _globalInfo;
|
private readonly GlobalInfo _globalInfo;
|
||||||
private List<StepVM> tmpCopyList = new List<StepVM>();
|
private List<StepVM> tmpCopyList = new List<StepVM>();
|
||||||
|
|
||||||
|
// 追踪当前订阅的集合实例,用于在集合被整体替换时重新订阅
|
||||||
|
private ObservableCollection<StepVM> _trackedStepCollection;
|
||||||
|
private ObservableCollection<StepVM> _trackedErrorStepCollection;
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region 命令
|
#region 命令
|
||||||
@@ -101,8 +107,8 @@ namespace TestingModule.ViewModels
|
|||||||
DeleteStepCommand = new DelegateCommand(DeleteStep);
|
DeleteStepCommand = new DelegateCommand(DeleteStep);
|
||||||
TabSelectionChangedCommand = new DelegateCommand<string>(TabSelectionChanged);
|
TabSelectionChangedCommand = new DelegateCommand<string>(TabSelectionChanged);
|
||||||
SelectionChangedCommand = new DelegateCommand<object>(SelectionChanged);
|
SelectionChangedCommand = new DelegateCommand<object>(SelectionChanged);
|
||||||
Program.StepCollection.CollectionChanged += StepCollection_CollectionChanged;
|
SubscribeStepCollections();
|
||||||
Program.ErrorStepCollection.CollectionChanged += StepCollection_CollectionChanged;
|
Program.PropertyChanged += Program_PropertyChanged;
|
||||||
Admin = _globalInfo.IsAdmin;
|
Admin = _globalInfo.IsAdmin;
|
||||||
_eventAggregator.GetEvent<AlarmEvent>().Subscribe(() =>
|
_eventAggregator.GetEvent<AlarmEvent>().Subscribe(() =>
|
||||||
{
|
{
|
||||||
@@ -206,13 +212,67 @@ namespace TestingModule.ViewModels
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 辅助方法
|
#region 辅助方法
|
||||||
private void StepCollection_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
|
||||||
|
/// <summary>
|
||||||
|
/// 订阅当前 Program 的 StepCollection 和 ErrorStepCollection 的 CollectionChanged 事件。
|
||||||
|
/// </summary>
|
||||||
|
private void SubscribeStepCollections()
|
||||||
|
{
|
||||||
|
_trackedStepCollection = Program.StepCollection;
|
||||||
|
_trackedErrorStepCollection = Program.ErrorStepCollection;
|
||||||
|
|
||||||
|
if (_trackedStepCollection != null)
|
||||||
|
_trackedStepCollection.CollectionChanged += StepCollection_CollectionChanged;
|
||||||
|
if (_trackedErrorStepCollection != null)
|
||||||
|
_trackedErrorStepCollection.CollectionChanged += StepCollection_CollectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 取消订阅当前追踪的集合事件。
|
||||||
|
/// </summary>
|
||||||
|
private void UnsubscribeStepCollections()
|
||||||
|
{
|
||||||
|
if (_trackedStepCollection != null)
|
||||||
|
{
|
||||||
|
_trackedStepCollection.CollectionChanged -= StepCollection_CollectionChanged;
|
||||||
|
_trackedStepCollection = null;
|
||||||
|
}
|
||||||
|
if (_trackedErrorStepCollection != null)
|
||||||
|
{
|
||||||
|
_trackedErrorStepCollection.CollectionChanged -= StepCollection_CollectionChanged;
|
||||||
|
_trackedErrorStepCollection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当 Program 的 StepCollection / ErrorStepCollection 被整体替换时,自动重新订阅并刷新序号。
|
||||||
|
/// </summary>
|
||||||
|
private void Program_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(ProgramVM.StepCollection) ||
|
||||||
|
e.PropertyName == nameof(ProgramVM.ErrorStepCollection))
|
||||||
|
{
|
||||||
|
UnsubscribeStepCollections();
|
||||||
|
SubscribeStepCollections();
|
||||||
|
|
||||||
|
// 集合被整体替换后,对新集合重新编号
|
||||||
|
Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Program.StepCollection.Count; i++)
|
||||||
|
Program.StepCollection[i].Index = i + 1;
|
||||||
|
for (int i = 0; i < Program.ErrorStepCollection.Count; i++)
|
||||||
|
Program.ErrorStepCollection[i].Index = i + 1;
|
||||||
|
}), System.Windows.Threading.DispatcherPriority.Background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StepCollection_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
var collection = sender as ObservableCollection<StepVM>;
|
var collection = sender as ObservableCollection<StepVM>;
|
||||||
// Add/Move/Remove 都会触发,这里判断具体情形
|
// Add/Move/Remove 都会触发,这里判断具体情形
|
||||||
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add ||
|
if (e.Action == NotifyCollectionChangedAction.Add ||
|
||||||
e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Move||
|
e.Action == NotifyCollectionChangedAction.Move||
|
||||||
e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
|
e.Action == NotifyCollectionChangedAction.Remove)
|
||||||
{
|
{
|
||||||
// 如果需要等 UI 更新完再处理,可也用 Dispatcher 延迟一小段时间
|
// 如果需要等 UI 更新完再处理,可也用 Dispatcher 延迟一小段时间
|
||||||
Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
|
Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
|
||||||
@@ -238,31 +298,27 @@ namespace TestingModule.ViewModels
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 1. 【核心修复】必须取消订阅 CollectionChanged 事件,否则 VM 永远无法被释放
|
// 1. 取消订阅 CollectionChanged 事件(从追踪的实例上取消,而非可能已被替换的当前实例)
|
||||||
|
UnsubscribeStepCollections();
|
||||||
|
|
||||||
|
// 2. 取消订阅 Program.PropertyChanged
|
||||||
if (Program != null)
|
if (Program != null)
|
||||||
{
|
{
|
||||||
if (Program.StepCollection != null)
|
Program.PropertyChanged -= Program_PropertyChanged;
|
||||||
{
|
|
||||||
Program.StepCollection.CollectionChanged -= StepCollection_CollectionChanged;
|
|
||||||
}
|
|
||||||
if (Program.ErrorStepCollection != null)
|
|
||||||
{
|
|
||||||
Program.ErrorStepCollection.CollectionChanged -= StepCollection_CollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 【核心修复】必须显式退订 Prism 全局事件(AlarmEvent)
|
// 3. 【核心修复】必须显式退订 Prism 全局事件(AlarmEvent)
|
||||||
// 注意:因为订阅时使用的是匿名 Lambda,最安全稳妥的退订方式是把整个事件上的当前 VM 订阅者全部注销
|
// 注意:因为订阅时使用的是匿名 Lambda,最安全稳妥的退订方式是把整个事件上的当前 VM 订阅者全部注销
|
||||||
_eventAggregator?.GetEvent<AlarmEvent>()?.Unsubscribe(null);
|
_eventAggregator?.GetEvent<AlarmEvent>()?.Unsubscribe(null);
|
||||||
|
|
||||||
// 3. 清空临时缓存集合与 UI 绑定列表,避免悬挂指针
|
// 4. 清空临时缓存集合与 UI 绑定列表,避免悬挂指针
|
||||||
tmpCopyList?.Clear();
|
tmpCopyList?.Clear();
|
||||||
tmpCopyList = null!;
|
tmpCopyList = null!;
|
||||||
|
|
||||||
SelectedItems?.Clear();
|
SelectedItems?.Clear();
|
||||||
SelectedItems = null!;
|
SelectedItems = null!;
|
||||||
|
|
||||||
// 4. 清除选中项状态引用
|
// 5. 清除选中项状态引用
|
||||||
SelectedStep = null;
|
SelectedStep = null;
|
||||||
if (_ScopedContext != null)
|
if (_ScopedContext != null)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user