Files
ACP/TestingModule/ViewModels/StepsManagerViewModel.cs
T
2026-08-07 13:46:11 +08:00

461 lines
17 KiB
C#

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;
using Prism.Commands;
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; }
public ICommand OpenSubProgramCommand { get; set; }
public ICommand GoBackCommand { get; set; }
#endregion
#region 子程序导航
/// <summary>
/// 当前显示的程序(绑定到 DataGrid 的 ItemsSource 根)。
/// 委托到 ScopedContext.CurrentProgram,保证 ShellViewModel 也能通过 ScopedContext 访问。
/// </summary>
public ProgramVM CurrentProgram
{
get => _ScopedContext.CurrentProgram;
set
{
if (_ScopedContext.CurrentProgram != value)
{
_ScopedContext.CurrentProgram = value;
RaisePropertyChanged();
}
}
}
public string BreadcrumbPath
{
get => _ScopedContext.BreadcrumbPath;
set
{
if (_ScopedContext.BreadcrumbPath != value)
{
_ScopedContext.BreadcrumbPath = value;
RaisePropertyChanged();
}
}
}
public bool CanGoBack => _ScopedContext.CanGoBack;
#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);
OpenSubProgramCommand = new DelegateCommand(OpenSubProgram);
GoBackCommand = new DelegateCommand(GoBack);
SubscribeStepCollections();
Program.PropertyChanged += Program_PropertyChanged;
Admin = _globalInfo.IsAdmin;
// 初始化 CurrentProgram 为根程序
_ScopedContext.CurrentProgram = Program;
_ScopedContext.BreadcrumbPath = "主程序";
// 订阅 ScopedContext 属性变化,外部(ShellViewModel)修改时转发通知给 UI
_ScopedContext.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(ScopedContext.CurrentProgram))
RaisePropertyChanged(nameof(CurrentProgram));
else if (e.PropertyName == nameof(ScopedContext.BreadcrumbPath))
RaisePropertyChanged(nameof(BreadcrumbPath));
else if (e.PropertyName == nameof(ScopedContext.CanGoBack))
RaisePropertyChanged(nameof(CanGoBack));
};
// 订阅子程序导航事件(运行时由 StepRunning 发布)
_eventAggregator.GetEvent<SubProgramNavigateEvent>()
.Subscribe(OnSubProgramNavigate, ThreadOption.UIThread, false,
payload => payload.Scope == _systemConfig.Title);
}
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>
/// 编辑模式:右键打开子程序
/// </summary>
private void OpenSubProgram()
{
if (SelectedStep == null || SelectedStep.StepType != "子程序" || SelectedStep.SubProgram == null)
return;
// 压栈:保存当前程序
_ScopedContext.SubProgramNavigationStack.Push(CurrentProgram);
_ScopedContext.UpdateCanGoBack();
// 更新面包屑
var stepName = SelectedStep.Name ?? "子程序";
BreadcrumbPath = $"{BreadcrumbPath} > {stepName}";
// 切换到子程序
CurrentProgram = SelectedStep.SubProgram;
RaisePropertyChanged(nameof(CanGoBack));
}
/// <summary>
/// 返回上一级程序
/// </summary>
private void GoBack()
{
if (_ScopedContext.SubProgramNavigationStack.Count == 0)
return;
// 出栈:恢复上一级程序
var parentProgram = _ScopedContext.SubProgramNavigationStack.Pop();
_ScopedContext.UpdateCanGoBack();
CurrentProgram = parentProgram;
// 更新面包屑:去掉最后一段
var parts = BreadcrumbPath.Split(" > ");
if (parts.Length > 1)
BreadcrumbPath = string.Join(" > ", parts.Take(parts.Length - 1));
else
BreadcrumbPath = "主程序";
RaisePropertyChanged(nameof(CanGoBack));
}
/// <summary>
/// 运行时:处理 StepRunning 发布的子程序导航事件
/// </summary>
private void OnSubProgramNavigate(SubProgramNavigatePayload payload)
{
if (payload.Action == NavigateAction.Enter && payload.SubProgram != null)
{
_ScopedContext.SubProgramNavigationStack.Push(CurrentProgram);
_ScopedContext.UpdateCanGoBack();
CurrentProgram = payload.SubProgram;
var stepName = payload.StepName ?? "子程序";
BreadcrumbPath = $"{BreadcrumbPath} > {stepName}";
RaisePropertyChanged(nameof(CanGoBack));
}
else if (payload.Action == NavigateAction.Exit)
{
GoBack();
}
}
#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 全局事件
_eventAggregator?.GetEvent<AlarmEvent>()?.Unsubscribe(null);
_eventAggregator?.GetEvent<SubProgramNavigateEvent>()?.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}");
}
}
}
}