177 lines
7.2 KiB
C#
177 lines
7.2 KiB
C#
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 ICommand LoadedCommand { get; set; }
|
||
|
||
public AutomatedTestingViewModel(IContainerExtension container) : base(container)
|
||
{
|
||
// 每个 AutomatedTestingViewModel 实例创建独立的容器作用域
|
||
_scope = container.CreateScope();
|
||
_globalInfo =container.Resolve<GlobalInfo>();
|
||
_systemConfig = _scope.Resolve<SystemConfig>();
|
||
//加载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<ScopedContext>();
|
||
_deviceManager = _scope.Resolve<DeviceManager>();
|
||
_stepRunning = _scope.Resolve<StepRunning>();
|
||
// 从同一个 _scope 解析 5 个子 VM,DI 会把同一个 ScopedContext 注入它们
|
||
CommandTreeVM = _scope.Resolve<CommandTreeViewModel>();
|
||
StepsManagerVM = _scope.Resolve<StepsManagerViewModel>();
|
||
SingleStepEditVM = _scope.Resolve<SingleStepEditViewModel>();
|
||
LogAreaVM = _scope.Resolve<LogAreaViewModel>();
|
||
ParametersManagerVM = _scope.Resolve<ParametersManagerViewModel>();
|
||
RefreshCommand = new DelegateCommand(OnRefresh);
|
||
BackToProtocolCommand = new DelegateCommand(OnBackToProtocol);
|
||
LoadedCommand = new AsyncDelegateCommand(OnLoad);
|
||
}
|
||
|
||
|
||
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 async Task OnLoad()
|
||
{
|
||
await _deviceManager.ConnectAllDevices();
|
||
}
|
||
|
||
private void OnRefresh()
|
||
{
|
||
// 双击:把自己的名字扔出去
|
||
_globalInfo.CurrentScope = TestStatus;
|
||
_eventAggregator.GetEvent<ExpandViewEvent>().Publish(TestStatus);
|
||
|
||
}
|
||
|
||
private void OnBackToProtocol()
|
||
{
|
||
// 返回:扔个空字符串出去
|
||
_eventAggregator.GetEvent<ExpandViewEvent>().Publish("");
|
||
}
|
||
#endregion
|
||
|
||
#region 重写
|
||
public override void OnNavigatedTo(NavigationContext navigationContext)
|
||
{
|
||
base.OnNavigatedTo(navigationContext);
|
||
if (navigationContext.Parameters.ContainsKey("Name"))
|
||
{
|
||
TestStatus = navigationContext.Parameters.GetValue<string>("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<ProgramVM>(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
|
||
}
|
||
} |