Files
ADP/TestingModule/ViewModels/StepsManagerViewModel.cs
2026-07-23 10:52:49 +08:00

334 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UIShare.PubEvent;
using UIShare.UIViewModel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Xml;
using UIShare.GlobalVariable;
using UIShare.ViewModelBase;
using Prism.Events;
namespace TestingModule.ViewModels
{
public class StepsManagerViewModel:NavigateViewModelBase, IDisposable
{
#region
private string _Title;
public string Title
{
get => _Title;
set => SetProperty(ref _Title, value);
}
private bool _Admin;
public bool Admin
{
get => _Admin;
set => SetProperty(ref _Admin, value);
}
private int _SelectedTabIndex;
public int SelectedTabIndex
{
get => _SelectedTabIndex;
set => SetProperty(ref _SelectedTabIndex, value);
}
private string _selectedTabHeader;
public string SelectedTabHeader
{
get { return _selectedTabHeader; }
set { SetProperty(ref _selectedTabHeader, value); }
}
private List<StepVM> _SelectedItems;
public List<StepVM> SelectedItems
{
get { return _SelectedItems; }
set { SetProperty(ref _SelectedItems, value); }
}
private StepVM _SelectedStep;
public StepVM SelectedStep
{
get => _SelectedStep;
set
{
if (SetProperty(ref _SelectedStep, value))
{
_ScopedContext.SelectedStep = value;
}
}
}
public ProgramVM Program
{
get => _ScopedContext.Program;
set
{
if (_ScopedContext.Program != value)
{
_ScopedContext.Program = value;
RaisePropertyChanged();
}
}
}
ScopedContext _ScopedContext { get; set; }
private readonly SystemConfig _systemConfig;
private readonly GlobalInfo _globalInfo;
private List<StepVM> tmpCopyList = new List<StepVM>();
// 追踪当前订阅的集合实例,用于在集合被整体替换时重新订阅
private ObservableCollection<StepVM> _trackedStepCollection;
private ObservableCollection<StepVM> _trackedErrorStepCollection;
#endregion
#region
public ICommand EditStepCommand { get;set; }
public ICommand CopyStepCommand { get;set; }
public ICommand PasteStepCommand { get;set; }
public ICommand DeleteStepCommand { get;set; }
public ICommand TabSelectionChangedCommand { get;set; }
public ICommand SelectionChangedCommand { get;set; }
#endregion
public StepsManagerViewModel(IContainerProvider containerProvider, ScopedContext scopedContext, SystemConfig systemConfig, GlobalInfo globalInfo) : base(containerProvider)
{
_ScopedContext = scopedContext;
_systemConfig = systemConfig;
_globalInfo = globalInfo;
Title = _systemConfig.Title;
EditStepCommand = new DelegateCommand(EditStep);
CopyStepCommand = new DelegateCommand(CopyStep);
PasteStepCommand = new DelegateCommand(PasteStep);
DeleteStepCommand = new DelegateCommand(DeleteStep);
TabSelectionChangedCommand = new DelegateCommand<string>(TabSelectionChanged);
SelectionChangedCommand = new DelegateCommand<object>(SelectionChanged);
SubscribeStepCollections();
Program.PropertyChanged += Program_PropertyChanged;
Admin = _globalInfo.IsAdmin;
}
private void SelectionChanged(object parameter)
{
var selectedList = parameter as IList;
if (selectedList != null)
{
SelectedItems = selectedList.Cast<StepVM>().ToList();
}
}
private void TabSelectionChanged(string SelectedTabHeader)
{
_ScopedContext.SelectedStepList = SelectedTabHeader;
}
#region
private void EditStep()
{
if (_globalInfo.IsAdmin && SelectedStep != null&& _ScopedContext.SelectedStep!=null)
{
_eventAggregator.GetEvent<EditSetpEvent>().Publish() ;
}
}
private void CopyStep()
{
if (_globalInfo.IsAdmin && SelectedItems.Any())
{
tmpCopyList.Clear();
foreach (var item in SelectedItems)
{
tmpCopyList.Add(item);
}
}
}
private void PasteStep()
{
// 权限校验并确保有可粘贴的内容
if (_globalInfo.IsAdmin && tmpCopyList.Any())
{
int insertIndex;
if (_ScopedContext.SelectedStepList == "主程序")
{
insertIndex = SelectedStep != null ? Program.StepCollection.IndexOf(SelectedStep) + 1 : Program.StepCollection.Count;
foreach (var item in tmpCopyList)
{
// 创建新副本,避免引用同一个对象,并赋予新 ID
var newStep = new StepVM(item) { ID = Guid.NewGuid() };
Program.StepCollection.Insert(insertIndex, newStep);
insertIndex++; // 递增索引,保证粘贴的多项顺序一致
}
}
else if (_ScopedContext.SelectedStepList == "错误程序")
{
insertIndex = SelectedStep != null ? Program.ErrorStepCollection.IndexOf(SelectedStep) + 1 : Program.ErrorStepCollection.Count;
foreach (var item in tmpCopyList)
{
var newStep = new StepVM(item) { ID = Guid.NewGuid() };
Program.ErrorStepCollection.Insert(insertIndex, newStep);
insertIndex++;
}
}
}
}
private void DeleteStep()
{
// 确保有选中的项
if (_globalInfo.IsAdmin && SelectedItems != null && SelectedItems.Any())
{
// 创建一个副本进行循环,防止在 Remove 过程中集合变化导致的问题
var toDelete = SelectedItems.ToList();
foreach (var item in toDelete)
{
_eventAggregator.GetEvent<DeletedStepEvent>().Publish(item.ID);
if (_ScopedContext.SelectedStepList == "主程序")
{
Program.StepCollection.Remove(item);
}
else if (_ScopedContext.SelectedStepList == "错误程序")
{
Program.ErrorStepCollection.Remove(item);
}
}
// 3. 清空 ViewModel 的选中状态,避免悬挂引用
SelectedStep = null;
SelectedItems.Clear();
_ScopedContext.SelectedStep = null;
}
}
#endregion
#region
/// <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>;
// Add/Move/Remove 都会触发,这里判断具体情形
if (e.Action == NotifyCollectionChangedAction.Add ||
e.Action == NotifyCollectionChangedAction.Move||
e.Action == NotifyCollectionChangedAction.Remove)
{
// 如果需要等 UI 更新完再处理,可也用 Dispatcher 延迟一小段时间
Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
{
if(_ScopedContext.SelectedStepList=="主程序")
{
for (int i = 0; i < Program.StepCollection.Count; i++)
Program.StepCollection[i].Index = i + 1;
}
else if (_ScopedContext.SelectedStepList == "错误程序")
for (int i = 0; i < Program.ErrorStepCollection.Count; i++)
Program.ErrorStepCollection[i].Index = i + 1;
}), System.Windows.Threading.DispatcherPriority.Background);
}
}
#endregion
public void Dispose()
{
try
{
// 1. 取消订阅 CollectionChanged 事件(从追踪的实例上取消,而非可能已被替换的当前实例)
UnsubscribeStepCollections();
// 2. 取消订阅 Program.PropertyChanged
if (Program != null)
{
Program.PropertyChanged -= Program_PropertyChanged;
}
// 3. 【核心修复】必须显式退订 Prism 全局事件AlarmEvent
// 注意:因为订阅时使用的是匿名 Lambda最安全稳妥的退订方式是把整个事件上的当前 VM 订阅者全部注销
_eventAggregator?.GetEvent<AlarmEvent>()?.Unsubscribe(null);
// 4. 清空临时缓存集合与 UI 绑定列表,避免悬挂指针
tmpCopyList?.Clear();
tmpCopyList = null!;
SelectedItems?.Clear();
SelectedItems = null!;
// 5. 清除选中项状态引用
SelectedStep = null;
if (_ScopedContext != null)
{
_ScopedContext.SelectedStep = null;
_ScopedContext = null!; // 断开上下文引用
}
}
catch (Exception ex)
{
Logger.LoggerHelper.Error($"释放步骤管理组件StepsManagerViewModel资源失败: {ex.Message}");
}
}
}
}