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 _SelectedItems; public List 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 tmpCopyList = new List(); // 追踪当前订阅的集合实例,用于在集合被整体替换时重新订阅 private ObservableCollection _trackedStepCollection; private ObservableCollection _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 子程序导航(主程序 / 错误程序各自独立) // --- 主程序 Tab 导航属性 --- public ProgramVM MainCurrentProgram => _ScopedContext.MainNav.CurrentProgram; public string MainBreadcrumbPath => _ScopedContext.MainNav.BreadcrumbPath; public bool MainCanGoBack => _ScopedContext.MainNav.CanGoBack; public ObservableCollection MainDisplaySteps => _ScopedContext.MainNav.DisplaySteps; // --- 错误程序 Tab 导航属性 --- public ProgramVM ErrorCurrentProgram => _ScopedContext.ErrorNav.CurrentProgram; public string ErrorBreadcrumbPath => _ScopedContext.ErrorNav.BreadcrumbPath; public bool ErrorCanGoBack => _ScopedContext.ErrorNav.CanGoBack; public ObservableCollection ErrorDisplaySteps => _ScopedContext.ErrorNav.DisplaySteps; /// /// 当前激活的导航状态(根据选中的 Tab 索引决定) /// private ProgramNavigationState ActiveNav => SelectedTabIndex == 1 ? _ScopedContext.ErrorNav : _ScopedContext.MainNav; #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(TabSelectionChanged); SelectionChangedCommand = new DelegateCommand(SelectionChanged); OpenSubProgramCommand = new DelegateCommand(OpenSubProgram); GoBackCommand = new DelegateCommand(GoBack); SubscribeStepCollections(); Program.PropertyChanged += Program_PropertyChanged; Admin = _globalInfo.IsAdmin; // 初始化两套导航状态 _ScopedContext.MainNav.Initialize(Program, "主程序"); _ScopedContext.ErrorNav.Initialize(Program, "错误程序"); // 订阅主程序导航状态变化 → 转发给 UI _ScopedContext.MainNav.PropertyChanged += (s, e) => { if (e.PropertyName == nameof(ProgramNavigationState.CurrentProgram)) { RaisePropertyChanged(nameof(MainCurrentProgram)); RaisePropertyChanged(nameof(MainDisplaySteps)); } else if (e.PropertyName == nameof(ProgramNavigationState.BreadcrumbPath)) RaisePropertyChanged(nameof(MainBreadcrumbPath)); else if (e.PropertyName == nameof(ProgramNavigationState.CanGoBack)) RaisePropertyChanged(nameof(MainCanGoBack)); }; // 订阅错误程序导航状态变化 → 转发给 UI _ScopedContext.ErrorNav.PropertyChanged += (s, e) => { if (e.PropertyName == nameof(ProgramNavigationState.CurrentProgram)) { RaisePropertyChanged(nameof(ErrorCurrentProgram)); RaisePropertyChanged(nameof(ErrorDisplaySteps)); } else if (e.PropertyName == nameof(ProgramNavigationState.BreadcrumbPath)) RaisePropertyChanged(nameof(ErrorBreadcrumbPath)); else if (e.PropertyName == nameof(ProgramNavigationState.CanGoBack)) RaisePropertyChanged(nameof(ErrorCanGoBack)); }; // 订阅子程序导航事件(运行时由 StepRunning 发布) _eventAggregator.GetEvent() .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().ToList(); } } private void TabSelectionChanged(string SelectedTabHeader) { _ScopedContext.SelectedStepList = SelectedTabHeader; } #region 委托命令 private void EditStep() { if (_globalInfo.IsAdmin && SelectedStep != null&& _ScopedContext.SelectedStep!=null) { _eventAggregator.GetEvent().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().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 子程序导航方法 /// /// 编辑模式:右键打开子程序(操作当前激活的 Tab 的导航状态) /// private void OpenSubProgram() { if (SelectedStep == null || SelectedStep.StepType != "子程序" || SelectedStep.SubProgram == null) return; var nav = ActiveNav; nav.NavigationStack.Push(nav.CurrentProgram); nav.UpdateCanGoBack(); var stepName = SelectedStep.Name ?? "子程序"; nav.BreadcrumbPath = $"{nav.BreadcrumbPath} > {stepName}"; nav.CurrentProgram = SelectedStep.SubProgram; } /// /// 返回上一级程序(操作当前激活的 Tab 的导航状态) /// private void GoBack() { var nav = ActiveNav; if (nav.NavigationStack.Count == 0) return; var parentProgram = nav.NavigationStack.Pop(); nav.UpdateCanGoBack(); nav.CurrentProgram = parentProgram; var parts = nav.BreadcrumbPath.Split(" > "); nav.BreadcrumbPath = parts.Length > 1 ? string.Join(" > ", parts.Take(parts.Length - 1)) : nav == _ScopedContext.MainNav ? "主程序" : "错误程序"; } /// /// 运行时:处理 StepRunning 发布的子程序导航事件 /// private void OnSubProgramNavigate(SubProgramNavigatePayload payload) { var nav = payload.IsErrorProgram ? _ScopedContext.ErrorNav : _ScopedContext.MainNav; if (payload.Action == NavigateAction.Enter && payload.SubProgram != null) { nav.NavigationStack.Push(nav.CurrentProgram); nav.UpdateCanGoBack(); nav.CurrentProgram = payload.SubProgram; var stepName = payload.StepName ?? "子程序"; nav.BreadcrumbPath = $"{nav.BreadcrumbPath} > {stepName}"; } else if (payload.Action == NavigateAction.Exit) { if (nav.NavigationStack.Count == 0) return; var parentProgram = nav.NavigationStack.Pop(); nav.UpdateCanGoBack(); nav.CurrentProgram = parentProgram; var parts = nav.BreadcrumbPath.Split(" > "); nav.BreadcrumbPath = parts.Length > 1 ? string.Join(" > ", parts.Take(parts.Length - 1)) : nav == _ScopedContext.MainNav ? "主程序" : "错误程序"; } } #endregion #region 辅助方法 /// /// 订阅当前 Program 的 StepCollection 和 ErrorStepCollection 的 CollectionChanged 事件。 /// private void SubscribeStepCollections() { _trackedStepCollection = Program.StepCollection; _trackedErrorStepCollection = Program.ErrorStepCollection; if (_trackedStepCollection != null) _trackedStepCollection.CollectionChanged += StepCollection_CollectionChanged; if (_trackedErrorStepCollection != null) _trackedErrorStepCollection.CollectionChanged += StepCollection_CollectionChanged; } /// /// 取消订阅当前追踪的集合事件。 /// private void UnsubscribeStepCollections() { if (_trackedStepCollection != null) { _trackedStepCollection.CollectionChanged -= StepCollection_CollectionChanged; _trackedStepCollection = null; } if (_trackedErrorStepCollection != null) { _trackedErrorStepCollection.CollectionChanged -= StepCollection_CollectionChanged; _trackedErrorStepCollection = null; } } /// /// 当 Program 的 StepCollection / ErrorStepCollection 被整体替换时,自动重新订阅并刷新序号。 /// private void Program_PropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(ProgramVM.StepCollection) || e.PropertyName == nameof(ProgramVM.ErrorStepCollection)) { UnsubscribeStepCollections(); SubscribeStepCollections(); // 通知 UI 刷新 DisplaySteps(导航状态虽然引用同一 Program,但集合实例已变) RaisePropertyChanged(nameof(MainDisplaySteps)); RaisePropertyChanged(nameof(ErrorDisplaySteps)); RaisePropertyChanged(nameof(MainCurrentProgram)); RaisePropertyChanged(nameof(ErrorCurrentProgram)); // 集合被整体替换后,对新集合重新编号 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; // 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()?.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}"); } } } }