using System; using System.IO; using System.Windows.Input; using Logger; using Prism.Ioc; using TestingModule.ViewModels; using UIShare; using UIShare.GlobalVariable; using UIShare.PubEvent; using UIShare.UIViewModel; using UIShare.ViewModelBase; using static System.Formats.Asn1.AsnWriter; namespace MainModule.ViewModels { public class AutomatedTestingViewModel : NavigateViewModelBase, IRegionMemberLifetime, IDisposable { #region 私有字段 private string _testStatus; private readonly IScopedProvider _scope; #endregion #region 属性 public bool KeepAlive => true; // 保持存活 public string TestStatus { get => _testStatus; set => SetProperty(ref _testStatus, value); } // 该 AutomatedTestingView 实例独占的 ScopedContext,5 个子面板共享 public ScopedContext _scopedContext { get; } public StepRunning _stepRunning { get; } public GlobalInfo _globalInfo { get; } public SystemConfig _systemConfig { get; set; } public DeviceManager _deviceManager { get; set; } // 5 个子 ViewModel 全部从同一个 scope 解析,自动注入同一个 ScopedContext public CommandTreeViewModel CommandTreeVM { get; } public StepsManagerViewModel StepsManagerVM { get; } public SingleStepEditViewModel SingleStepEditVM { get; } public LogAreaViewModel LogAreaVM { get; } public ParametersManagerViewModel ParametersManagerVM { get; } #endregion public ICommand RefreshCommand { get; set; } public ICommand BackToProtocolCommand { get; set; } public AutomatedTestingViewModel(IContainerExtension container) : base(container) { // 每个 AutomatedTestingViewModel 实例创建独立的容器作用域 _scope = container.CreateScope(); _globalInfo =container.Resolve(); _systemConfig = _scope.Resolve(); //加载Json数据 if (ConfigService.IsExit(_globalInfo.CurrentOpeningScope)) { string filePath = System.IO.Path.Combine(_systemConfig.SystemPath, $"{_globalInfo.CurrentOpeningScope}.json"); if (System.IO.File.Exists(filePath)) { string json = System.IO.File.ReadAllText(filePath); Newtonsoft.Json.JsonConvert.PopulateObject(json, _systemConfig); } } //容器解析顺序不要改变!!! _scopedContext = _scope.Resolve(); _deviceManager = _scope.Resolve(); _stepRunning = _scope.Resolve(); // 从同一个 _scope 解析 5 个子 VM,DI 会把同一个 ScopedContext 注入它们 CommandTreeVM = _scope.Resolve(); StepsManagerVM = _scope.Resolve(); SingleStepEditVM = _scope.Resolve(); LogAreaVM = _scope.Resolve(); ParametersManagerVM = _scope.Resolve(); RefreshCommand = new DelegateCommand(OnRefresh); BackToProtocolCommand = new DelegateCommand(OnBackToProtocol); } public void Dispose() { // 1. 如果 TestStatus 为空,说明还没走到 OnNavigatedTo 赋值,直接释放 scope 即可 if (string.IsNullOrEmpty(TestStatus)) { _scope?.Dispose(); return; } try { // 2. 显式释放硬件资源(防止端口占用/死锁) if (_deviceManager is IDisposable disposableDevice) { disposableDevice.Dispose(); } (CommandTreeVM as IDisposable)?.Dispose(); (StepsManagerVM as IDisposable)?.Dispose(); (SingleStepEditVM as IDisposable)?.Dispose(); (LogAreaVM as IDisposable)?.Dispose(); (ParametersManagerVM as IDisposable)?.Dispose(); _globalInfo.ContextDic?.Remove(TestStatus); _globalInfo.StepRunningDic?.Remove(TestStatus); _globalInfo.ConfigDic?.Remove(TestStatus); _globalInfo.ScopeDic?.Remove(TestStatus); } catch (Exception ex) { Logger.LoggerHelper.ErrorWithNotify($"卸载机台 [{TestStatus}] 全局引用或资源失败: {ex.Message}"); } finally { _scope?.Dispose(); } } #region 命令处理与事件 private void OnRefresh() { // 双击:把自己的名字扔出去 _globalInfo.CurrentScope = TestStatus; _eventAggregator.GetEvent().Publish(TestStatus); } private void OnBackToProtocol() { // 返回:扔个空字符串出去 _eventAggregator.GetEvent().Publish(""); } #endregion #region 重写 public override void OnNavigatedTo(NavigationContext navigationContext) { base.OnNavigatedTo(navigationContext); if (navigationContext.Parameters.ContainsKey("Name")) { TestStatus = navigationContext.Parameters.GetValue("Name"); _globalInfo.ContextDic.Add(TestStatus, _scopedContext); _globalInfo.StepRunningDic.Add(TestStatus, _stepRunning); _globalInfo.ScopeDic.Add(TestStatus, _scope); _globalInfo.ConfigDic.Add(TestStatus, _systemConfig); if(_systemConfig.DefaultProgramFilePath != null&&File.Exists(_systemConfig.DefaultProgramFilePath)) { var filePath = _systemConfig.DefaultProgramFilePath; // 读取 JSON 文件 string json = File.ReadAllText(filePath); // 反序列化为 ProgramVM var program = Newtonsoft.Json.JsonConvert.DeserializeObject(json); if (program == null) { LoggerHelper.WarnWithNotify($"文件格式不正确或为空: {filePath}"); return; } // 💡 2. 严格赋值给快照锁定下的当前工位上下文,实现数据完全隔离 _scopedContext.Program.Parameters = program.Parameters; _scopedContext.Program.StepCollection = program.StepCollection; _scopedContext.Program.ErrorStepCollection = program.ErrorStepCollection; _scopedContext.CurrentFilePath = filePath; } } } #endregion } }