diff --git a/ADP/App.xaml.cs b/ADP/App.xaml.cs index 0e19940..ad332b4 100644 --- a/ADP/App.xaml.cs +++ b/ADP/App.xaml.cs @@ -59,6 +59,10 @@ namespace ADP } protected override void OnInitialized() { + // 配置全局日志分发器:按 CurrentScope 路由到对应 LogArea + var globalInfo = Container.Resolve(); + LoggerHelper.Progress = new ScopeLogDispatcher(globalInfo); + //初始化数据库 //DatabaseConfig.SetTenant(10001); //DatabaseConfig.InitMySql("127.0.0.1",3306,"ADP","root","123456"); diff --git a/ADP/ViewModels/ShellViewModel.cs b/ADP/ViewModels/ShellViewModel.cs index 6e27550..86e9243 100644 --- a/ADP/ViewModels/ShellViewModel.cs +++ b/ADP/ViewModels/ShellViewModel.cs @@ -6,6 +6,7 @@ using Notifications.Wpf.Core; using System.Collections.Concurrent; using System.Diagnostics; using System.IO; +using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using System.Windows.Media; @@ -226,7 +227,7 @@ namespace ADP.ViewModels if (targetContext.RunState == "运行") { targetContext.SingleStep = false; - LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 运行命令"); + LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 执行工位 [{runningScope}] 运行命令"); targetContext.RunState = "暂停"; targetContext.RunIcon = PackIconKind.Pause; @@ -252,7 +253,7 @@ namespace ADP.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 异常中止: {ex.Message}"); + LoggerHelper.ErrorWithNotify(runningScope, $"工位 [{runningScope}] 异常中止: {ex.Message}"); } // 💡 测试正常完毕或取消:停止当前工位的 SW,并将最终时间固化到 RunningTime 字段中 @@ -285,7 +286,7 @@ namespace ADP.ViewModels } else // 用户点击了暂停 { - LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 点击工位 [{runningScope}] 暂停命令"); + LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 点击工位 [{runningScope}] 暂停命令"); targetContext.SingleStep = true; targetContext.IsStop = true; targetContext.RunState = "运行"; @@ -308,7 +309,7 @@ namespace ADP.ViewModels if (targetContext.RunState == "运行") { targetContext.SingleStep = true; - LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 单步执行命令"); + LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 执行工位 [{runningScope}] 单步执行命令"); targetContext.RunState = "暂停"; targetContext.RunIcon = PackIconKind.Pause; @@ -334,7 +335,7 @@ namespace ADP.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 单步执行异常: {ex.Message}"); + LoggerHelper.ErrorWithNotify(runningScope, $"工位 [{runningScope}] 单步执行异常: {ex.Message}"); } // 💡 单步单步完成后会被 StepRunning 挂起,在此暂时停止 SW @@ -378,7 +379,7 @@ namespace ADP.ViewModels return; } - LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 复位命令"); + LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 执行工位 [{runningScope}] 复位命令"); _executionTasks.TryGetValue(runningScope, out var currentTask); _errorExecutionTasks.TryGetValue(runningScope, out var errorTask); @@ -428,7 +429,7 @@ namespace ADP.ViewModels return; } - LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 异常流程命令"); + LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 执行工位 [{runningScope}] 异常流程命令"); // 💡 异常测试启动计时 targetContext.SW.Start(); @@ -445,7 +446,7 @@ namespace ADP.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 异常流程执行出错: {ex.Message}"); + LoggerHelper.ErrorWithNotify(runningScope, $"工位 [{runningScope}] 异常流程执行出错: {ex.Message}"); } // 💡 异常测试结束停止计时 @@ -479,7 +480,7 @@ namespace ADP.ViewModels { CurrentConfig.DefaultProgramFilePath = targetContext.CurrentFilePath; ConfigService.Save(CurrentConfig); - LoggerHelper.SuccessWithNotify($"工位 [{runningScope}] 已成功将当前程序设为默认启动程序"); + LoggerHelper.SuccessWithNotify(runningScope, $"工位 [{runningScope}] 已成功将当前程序设为默认启动程序"); } } @@ -505,7 +506,7 @@ namespace ADP.ViewModels } targetContext.Program.Parameters.Add(item); } - LoggerHelper.InfoWithNotify($"工位 [{runningScope}] 创建了空程序文件"); + LoggerHelper.InfoWithNotify(runningScope, $"工位 [{runningScope}] 创建了空程序文件"); // 如果当前正看着该工位,刷新 UI 显示 if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties(); @@ -539,7 +540,7 @@ namespace ADP.ViewModels // 确认文件存在 if (!File.Exists(filePath)) { - LoggerHelper.ErrorWithNotify($"文件不存在: {filePath}"); + LoggerHelper.ErrorWithNotify(runningScope, $"文件不存在: {filePath}"); return; } @@ -551,7 +552,7 @@ namespace ADP.ViewModels if (program == null) { - LoggerHelper.WarnWithNotify($"文件格式不正确或为空: {filePath}"); + LoggerHelper.WarnWithNotify(runningScope, $"文件格式不正确或为空: {filePath}"); return; } @@ -571,7 +572,7 @@ namespace ADP.ViewModels } } - LoggerHelper.SuccessWithNotify($"工位 [{runningScope}] 成功打开文件: {filePath}"); + LoggerHelper.SuccessWithNotify(runningScope, $"工位 [{runningScope}] 成功打开文件: {filePath}"); // 💡 3. 安全调用异步复位,确保重置的是对应工位的数据 // 注意:由于在 OnRestoration 内部第一行也做了快照拦截, @@ -580,7 +581,7 @@ namespace ADP.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 打开文件失败: {ex.Message}"); + LoggerHelper.ErrorWithNotify(runningScope, $"工位 [{runningScope}] 打开文件失败: {ex.Message}"); } finally { @@ -619,7 +620,7 @@ namespace ADP.ViewModels // 💡 3. 调用你的底层文件保存逻辑,传入快照工位的 Program 模型 SaveProgramToFile(targetContext.CurrentFilePath, targetContext.Program); - LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 另存为文件成功: {saveFileDialog.FileName}"); + LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 另存为文件成功: {saveFileDialog.FileName}"); if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties(); } @@ -644,7 +645,7 @@ namespace ADP.ViewModels // 💡 3. 持久化当前快照工位的 Program SaveProgramToFile(targetContext.CurrentFilePath, targetContext.Program); - LoggerHelper.SuccessWithNotify($"工位 [{runningScope}] 程序保存成功!"); + LoggerHelper.SuccessWithNotify(_globalInfo.CurrentScope,$"工位 [{runningScope}] 程序保存成功!"); } // 💡 辅助方法:建议将你的通用序列化落盘代码调整为接收 ProgramVM 参数,提高复用性 @@ -657,7 +658,7 @@ namespace ADP.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"写入程序文件失败: {ex.Message}"); + LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope,$"写入程序文件失败: {ex.Message}"); } } diff --git a/Logger/Logger.csproj b/Logger/Logger.csproj index 7a0942c..849f8f0 100644 --- a/Logger/Logger.csproj +++ b/Logger/Logger.csproj @@ -10,4 +10,10 @@ + + + PreserveNewest + + + diff --git a/Logger/LoggerHelper.cs b/Logger/LoggerHelper.cs index 2999674..a0f5f49 100644 --- a/Logger/LoggerHelper.cs +++ b/Logger/LoggerHelper.cs @@ -12,23 +12,23 @@ namespace Logger { public static readonly ILogger Logger = LogManager.GetLogger("InfoLogger"); public static readonly ILogger sqlLogger = LogManager.GetLogger("SqlLogger"); - public static IProgress<(string message, string color, int depth)> Progress { get; set; } + public static IProgress<(string scope, string message, string color, int depth)> Progress { get; set; } static LoggerHelper() { - Progress = new Progress<(string message, string color, int depth)>(); + Progress = new Progress<(string scope, string message, string color, int depth)>(); } - public static void InfoWithNotify(string message, int depth = 0) - { - Logger.Info(message); // 写入 NLog - NotifyUI(message, "blue", depth); // 触发UI显示 - } - - public static void SuccessWithNotify(string message, int depth = 0) + public static void InfoWithNotify(string scope, string message, int depth = 0) { Logger.Info(message); - NotifyUI(message, "lightgreen", depth); + NotifyUI(scope, message, "blue", depth); } - public static void WarnWithNotify(string message, string stackTrace = null, int depth = 0) + + public static void SuccessWithNotify(string scope, string message, int depth = 0) + { + Logger.Info(message); + NotifyUI(scope, message, "lightgreen", depth); + } + public static void WarnWithNotify(string scope, string message, string stackTrace = null, int depth = 0) { if (!string.IsNullOrEmpty(stackTrace)) { @@ -37,10 +37,10 @@ namespace Logger } Logger.Warn(message); - NotifyUI(message, "orange", depth); + NotifyUI(scope, message, "orange", depth); } - public static void ErrorWithNotify(string message, string stackTrace = null, int depth = 0) + public static void ErrorWithNotify(string scope, string message, string stackTrace = null, int depth = 0) { if (!string.IsNullOrEmpty(stackTrace)) { @@ -49,11 +49,11 @@ namespace Logger } Logger.Error(message); - NotifyUI(message, "red", depth); + NotifyUI(scope, message, "red", depth); } - private static void NotifyUI(string message, string color, int depth) + private static void NotifyUI(string scope, string message, string color, int depth) { - Progress.Report((message, color, depth)); + Progress.Report((scope, message, color, depth)); } public static void Info(string message, int depth = 0) @@ -95,20 +95,18 @@ namespace Logger foreach (var line in lines) { - // 匹配你项目的命名空间路径 if (line.Contains("ADP")) { - // 提取 "in 文件路径:line 行号" var match = Regex.Match(line, @"in (.+?):line (\d+)"); if (match.Success) { - return match.Value; // 返回类似 C:\...\MainViewModel.cs:line 37 + return match.Value; } return line.Trim(); } } - return lines[0].Trim(); // 如果找不到就返回第一条 + return lines[0].Trim(); } } } diff --git a/MainModule/ViewModels/AutomatedTestingViewModel.cs b/MainModule/ViewModels/AutomatedTestingViewModel.cs index 865034a..f608534 100644 --- a/MainModule/ViewModels/AutomatedTestingViewModel.cs +++ b/MainModule/ViewModels/AutomatedTestingViewModel.cs @@ -110,7 +110,7 @@ namespace MainModule.ViewModels } catch (Exception ex) { - Logger.LoggerHelper.ErrorWithNotify($"卸载机台 [{TestStatus}] 全局引用或资源失败: {ex.Message}"); + Logger.LoggerHelper.ErrorWithNotify(TestStatus, $"卸载机台 [{TestStatus}] 全局引用或资源失败: {ex.Message}"); } finally { @@ -164,7 +164,7 @@ namespace MainModule.ViewModels if (program == null) { - LoggerHelper.WarnWithNotify($"文件格式不正确或为空: {filePath}"); + LoggerHelper.WarnWithNotify(_globalInfo.CurrentScope, $"文件格式不正确或为空: {filePath}"); return; } diff --git a/MonitorModule/ViewModels/RecordViewModel.cs b/MonitorModule/ViewModels/RecordViewModel.cs index b9b27d4..ca39e72 100644 --- a/MonitorModule/ViewModels/RecordViewModel.cs +++ b/MonitorModule/ViewModels/RecordViewModel.cs @@ -217,7 +217,7 @@ namespace MonitorModule.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"加载数据表失败:{ex.Message}"); + LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope,$"加载数据表失败:{ex.Message}"); StatusMessage = $"加载失败:{ex.Message}"; } } @@ -256,7 +256,7 @@ namespace MonitorModule.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"查询失败:{ex.Message}"); + LoggerHelper.ErrorWithNotify(TestStatus,$"查询失败:{ex.Message}"); StatusMessage = $"查询失败:{ex.Message}"; ResultTable = new DataTable(); TotalCount = 0; @@ -295,11 +295,11 @@ namespace MonitorModule.ViewModels WriteCsv(dlg.FileName, dt); StatusMessage = $"导出完成:{dlg.FileName}({dt.Rows.Count} 行)"; - LoggerHelper.InfoWithNotify($"工位 [{TestStatus}] 导出 [{SelectedTable}] 至 {dlg.FileName},共 {dt.Rows.Count} 行"); + LoggerHelper.InfoWithNotify(TestStatus, $"工位 [{TestStatus}] 导出 [{SelectedTable}] 至 {dlg.FileName},共 {dt.Rows.Count} 行"); } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"导出失败:{ex.Message}"); + LoggerHelper.ErrorWithNotify(TestStatus, $"导出失败:{ex.Message}"); StatusMessage = $"导出失败:{ex.Message}"; } } diff --git a/SettingModule/ViewModels/SettingViewModel.cs b/SettingModule/ViewModels/SettingViewModel.cs index d1ba846..c9156d2 100644 --- a/SettingModule/ViewModels/SettingViewModel.cs +++ b/SettingModule/ViewModels/SettingViewModel.cs @@ -101,7 +101,7 @@ namespace SettingModule.ViewModels } catch (Exception ex) { - Logger.LoggerHelper.ErrorWithNotify($"释放配置管理组件(SettingViewModel)资源失败: {ex.Message}"); + Logger.LoggerHelper.ErrorWithNotify(TestStatus,$"释放配置管理组件(SettingViewModel)资源失败: {ex.Message}"); } } diff --git a/TestingModule/ViewModels/CommandTreeViewModel.cs b/TestingModule/ViewModels/CommandTreeViewModel.cs index 28fd431..512c2c7 100644 --- a/TestingModule/ViewModels/CommandTreeViewModel.cs +++ b/TestingModule/ViewModels/CommandTreeViewModel.cs @@ -210,7 +210,7 @@ namespace TestingModule.ViewModels } catch (Exception ex) { - LoggerHelper.WarnWithNotify($"无法加载程序集 {Path.GetFileName(dllPath)}: {ex.Message}"); + LoggerHelper.WarnWithNotify(_globalInfo.CurrentScope, $"无法加载程序集 {Path.GetFileName(dllPath)}: {ex.Message}"); } } } @@ -237,7 +237,7 @@ namespace TestingModule.ViewModels } catch (Exception ex) { - LoggerHelper.WarnWithNotify($"加载子程序错误: {filePath} - {ex.Message}"); + LoggerHelper.WarnWithNotify(_globalInfo.CurrentScope, $"加载子程序错误: {filePath} - {ex.Message}"); } } } @@ -317,7 +317,7 @@ namespace TestingModule.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"加载类型错误: {assembly.FullName} - {ex.Message}"); + LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope, $"加载类型错误: {assembly.FullName} - {ex.Message}"); } if (validTypes.Count > 0) @@ -504,7 +504,7 @@ namespace TestingModule.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"添加方法失败: {method.Name} - {ex.Message}"); + LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope, $"添加方法失败: {method.Name} - {ex.Message}"); } } @@ -537,7 +537,7 @@ namespace TestingModule.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"添加子程序失败: {subProgram.Name} - {ex.Message}"); + LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope, $"添加子程序失败: {subProgram.Name} - {ex.Message}"); ; } } diff --git a/TestingModule/ViewModels/LogAreaViewModel.cs b/TestingModule/ViewModels/LogAreaViewModel.cs index 49af0fb..1f534b8 100644 --- a/TestingModule/ViewModels/LogAreaViewModel.cs +++ b/TestingModule/ViewModels/LogAreaViewModel.cs @@ -1,18 +1,20 @@ using UIShare.GlobalVariable; using Logger; +using Prism.Ioc; using Prism.Mvvm; +using System; using System.Collections.ObjectModel; using System.Reflection; -using System.Windows; using System.Windows.Input; using System.Windows.Media; -using System.Windows.Threading; using UIShare.ViewModelBase; namespace TestingModule.ViewModels { public class LogAreaViewModel : NavigateViewModelBase, IDisposable { + + // 日志集合 private ObservableCollection _logs = new(); @@ -23,20 +25,23 @@ namespace TestingModule.ViewModels } public ICommand ClearLogCommand { get; set; } + private readonly ScopedContext _scopedContext; + private readonly GlobalInfo _globalInfo; + private IProgress<(string Message, Brush Color, int Depth)>? _logProgress; + public LogAreaViewModel(IContainerProvider containerProvider) : base(containerProvider) { ClearLogCommand = new DelegateCommand(ClearLog); + _scopedContext = containerProvider.Resolve(); + _globalInfo = containerProvider.Resolve(); - // 2. 保持原有逻辑,但请确保在 Dispose 中对其进行清理 - LoggerHelper.Progress = new System.Progress<(string message, string color, int depth)>( - log => - { - // 增加防御性代码:防止进入销毁流程时异步回调引发空引用异常 - if (Logs == null) return; - - var brush = (Brush)new BrushConverter().ConvertFromString(log.color); - Logs.Add(new LogItem(log.message, brush, log.depth)); - }); + // 创建本作用域专属的日志接收器并注册到 ScopedContext + _logProgress = new Progress<(string Message, Brush Color, int Depth)>(log => + { + if (Logs == null) return; + Logs.Add(new LogItem(log.Message, log.Color, log.Depth)); + }); + _scopedContext.LogProgress = _logProgress; } private void ClearLog() @@ -51,16 +56,22 @@ namespace TestingModule.ViewModels { try { - LoggerHelper.Progress = null!; + // 注销本作用域的日志接收器,避免 Dispose 后仍收到旧消息 + if (_scopedContext != null && _scopedContext.LogProgress == _logProgress) + { + _scopedContext.LogProgress = null; + } + _logProgress = null; + if (Logs != null) { Logs.Clear(); - Logs = null!; + Logs = null!; } } catch (Exception ex) { - Logger.LoggerHelper.ErrorWithNotify($"释放日志组件(LogAreaViewModel)资源失败: {ex.Message}"); + Logger.LoggerHelper.ErrorWithNotify(_scopedContext != null ? _globalInfo.CurrentScope : "", $"释放日志组件(LogAreaViewModel)资源失败: {ex.Message}"); } } } diff --git a/TestingModule/ViewModels/ParametersManagerViewModel.cs b/TestingModule/ViewModels/ParametersManagerViewModel.cs index 3a2b5b4..8b0b9e0 100644 --- a/TestingModule/ViewModels/ParametersManagerViewModel.cs +++ b/TestingModule/ViewModels/ParametersManagerViewModel.cs @@ -175,7 +175,7 @@ namespace TestingModule.ViewModels } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"打开设备编辑窗口 [{type}] 失败:{ex.Message}"); + LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope, $"打开设备编辑窗口 [{type}] 失败:{ex.Message}"); } } diff --git a/TestingModule/ViewModels/SingleStepEditViewModel.cs b/TestingModule/ViewModels/SingleStepEditViewModel.cs index afdaa7b..dc25e49 100644 --- a/TestingModule/ViewModels/SingleStepEditViewModel.cs +++ b/TestingModule/ViewModels/SingleStepEditViewModel.cs @@ -47,6 +47,7 @@ namespace TestingModule.ViewModels } #endregion private ScopedContext _ScopedContext; + private GlobalInfo _globalInfo; #region 命令 public ICommand CancelEditCommand { get; set; } public ICommand SaveStepCommand { get; set; } @@ -54,6 +55,7 @@ namespace TestingModule.ViewModels public SingleStepEditViewModel(IContainerProvider containerProvider, ScopedContext scopedContext) : base(containerProvider) { _ScopedContext = scopedContext; + _globalInfo=containerProvider.Resolve(); _eventAggregator.GetEvent().Subscribe(EditSingleStep); CancelEditCommand = new DelegateCommand(CancelEdit); SaveStepCommand = new DelegateCommand(SaveStep); @@ -100,7 +102,7 @@ namespace TestingModule.ViewModels } catch { - LoggerHelper.ErrorWithNotify("循环指令参数设置错误:类型转换失败"); + LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope,"循环指令参数设置错误:类型转换失败"); } } else diff --git a/UIShare/GlobalVariable/ConfigService.cs b/UIShare/GlobalVariable/ConfigService.cs index f556206..e088918 100644 --- a/UIShare/GlobalVariable/ConfigService.cs +++ b/UIShare/GlobalVariable/ConfigService.cs @@ -62,7 +62,7 @@ namespace UIShare.GlobalVariable } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"格子 [{title}] 配置加载失败: {ex.Message}"); + LoggerHelper.ErrorWithNotify(title, $"格子 [{title}] 配置加载失败: {ex.Message}"); return new SystemConfig { Title = title }; } } @@ -90,11 +90,11 @@ namespace UIShare.GlobalVariable }); File.WriteAllText(configPath, json); - LoggerHelper.InfoWithNotify($"配置 [{config.Title}] 已保存。"); + LoggerHelper.InfoWithNotify(config.Title, $"配置 [{config.Title}] 已保存。"); } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"配置 [{config.Title}] 保存失败: {ex.Message}"); + LoggerHelper.ErrorWithNotify(config.Title, $"配置 [{config.Title}] 保存失败: {ex.Message}"); } } } diff --git a/UIShare/GlobalVariable/DeviceManager.cs b/UIShare/GlobalVariable/DeviceManager.cs index 07d753e..6c0d1a8 100644 --- a/UIShare/GlobalVariable/DeviceManager.cs +++ b/UIShare/GlobalVariable/DeviceManager.cs @@ -128,7 +128,7 @@ namespace UIShare.GlobalVariable catch (Exception ex) { var inner = ex.InnerException?.Message ?? ex.Message; - LoggerHelper.ErrorWithNotify($"设备 [{config.DeviceName}] 实例化失败:{inner}"); + LoggerHelper.ErrorWithNotify(_scopeName, $"设备 [{config.DeviceName}] 实例化失败:{inner}"); } } } @@ -288,7 +288,7 @@ namespace UIShare.GlobalVariable { if (info != null) info.IsConnected = false; var inner = ex.InnerException?.Message ?? ex.Message; - LoggerHelper.ErrorWithNotify($"设备 [{name}/{conn}] 连接异常:{inner}"); + LoggerHelper.ErrorWithNotify(_scopeName, $"设备 [{name}/{conn}] 连接异常:{inner}"); } } diff --git a/UIShare/GlobalVariable/ScopeLogDispatcher.cs b/UIShare/GlobalVariable/ScopeLogDispatcher.cs new file mode 100644 index 0000000..7d4d8de --- /dev/null +++ b/UIShare/GlobalVariable/ScopeLogDispatcher.cs @@ -0,0 +1,41 @@ +using Logger; +using System; +using System.Windows.Media; + +namespace UIShare.GlobalVariable +{ + /// + /// 作用域日志分发器:根据显式传入的 scope 参数把日志路由到对应 + /// ,实现每个台架/作用域拥有独立 LogArea。 + /// + public class ScopeLogDispatcher : IProgress<(string scope, string message, string color, int depth)> + { + private readonly GlobalInfo _globalInfo; + + public ScopeLogDispatcher(GlobalInfo globalInfo) + { + _globalInfo = globalInfo ?? throw new ArgumentNullException(nameof(globalInfo)); + } + + public void Report((string scope, string message, string color, int depth) value) + { + var scope = value.scope; + if (string.IsNullOrEmpty(scope)) return; + + if (!_globalInfo.ContextDic.TryGetValue(scope, out var context)) return; + if (context?.LogProgress == null) return; + + Brush? brush = null; + try + { + brush = (Brush)new BrushConverter().ConvertFromString(value.color); + } + catch + { + brush = Brushes.Black; + } + + context.LogProgress.Report((value.message, brush, value.depth)); + } + } +} diff --git a/UIShare/GlobalVariable/ScopedContext.cs b/UIShare/GlobalVariable/ScopedContext.cs index 84c3038..f8701fa 100644 --- a/UIShare/GlobalVariable/ScopedContext.cs +++ b/UIShare/GlobalVariable/ScopedContext.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using System.Windows.Media; using UIShare.UIViewModel; namespace UIShare.GlobalVariable @@ -30,6 +31,10 @@ namespace UIShare.GlobalVariable public ParameterVM SelectedParameter { get; set; } public List DeviceList { get; set; } = new(); + + /// 当前作用域的日志接收器,LogAreaViewModel 订阅此处实现按作用域隔离日志。 + public IProgress<(string Message, Brush Color, int Depth)>? LogProgress { get; set; } + // 【新增测试属性】:每个实例被 new 出来时独一无二的随机身份 // 证 ID public int DebugRandomId { get; private set; } diff --git a/UIShare/GlobalVariable/StepRunning.cs b/UIShare/GlobalVariable/StepRunning.cs index f359849..a668922 100644 --- a/UIShare/GlobalVariable/StepRunning.cs +++ b/UIShare/GlobalVariable/StepRunning.cs @@ -88,7 +88,7 @@ namespace UIShare } else { - LoggerHelper.ErrorWithNotify("程序循环指令未闭合,请检查后重试"); + LoggerHelper.ErrorWithNotify(_systemConfig.Title, "程序循环指令未闭合,请检查后重试"); break; } } @@ -108,7 +108,7 @@ namespace UIShare }; loopStack.Push(context); step.CurrentLoopCount = context.LoopCount; - LoggerHelper.InfoWithNotify($"循环开始,共{context.LoopCount}次", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环开始,共{context.LoopCount}次", depth); index++; } @@ -117,7 +117,7 @@ namespace UIShare { if (loopStack.Count == 0) { - LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth: depth); + LoggerHelper.ErrorWithNotify(_systemConfig.Title, "未匹配的循环结束指令", depth: depth); step.Result = 2; index++; continue; @@ -133,7 +133,7 @@ namespace UIShare { // 继续循环:跳转到循环开始后的第一条指令 index = context.StartIndex + 1; - LoggerHelper.InfoWithNotify($"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth); } else { @@ -141,7 +141,7 @@ namespace UIShare loopStack.Pop(); var loopStopwatch = loopStopwatchStack.Peek(); index++; - LoggerHelper.InfoWithNotify($"循环结束,共执行{context.LoopCount}次", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环结束,共执行{context.LoopCount}次", depth); if (depth == 0 && loopStopwatch.IsRunning) { loopStopwatch.Stop(); @@ -168,7 +168,7 @@ namespace UIShare SubSingleStep = true; _scopedContext.SingleStep = false; } - LoggerHelper.InfoWithNotify($"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth); stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken); UpdateCurrentStepResult(step, true, stepSuccess, depth); if (SubSingleStep) @@ -179,7 +179,7 @@ namespace UIShare } else if (step.Method != null) { - LoggerHelper.InfoWithNotify($"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth); await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken); stepSuccess = step.Result == 1; if (step.NGGotoStepID != null && !stepSuccess) @@ -188,7 +188,7 @@ namespace UIShare if (tmp != null) { index = tmp.Index - 2; - LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); } } if (step.OKGotoStepID != null && stepSuccess) @@ -197,7 +197,7 @@ namespace UIShare if (tmp != null) { index = tmp.Index - 2; - LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); } } } @@ -257,7 +257,7 @@ namespace UIShare } else { - LoggerHelper.ErrorWithNotify("程序循环指令未闭合,请检查后重试"); + LoggerHelper.ErrorWithNotify(_systemConfig.Title, "程序循环指令未闭合,请检查后重试"); break; } } @@ -277,7 +277,7 @@ namespace UIShare }; loopStack.Push(context); step.CurrentLoopCount = context.LoopCount; - LoggerHelper.InfoWithNotify($"循环开始({step.Name}),共{context.LoopCount}次", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环开始({step.Name}),共{context.LoopCount}次", depth); index++; } @@ -286,7 +286,7 @@ namespace UIShare { if (loopStack.Count == 0) { - LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth:depth); + LoggerHelper.ErrorWithNotify(_systemConfig.Title, "未匹配的循环结束指令", depth:depth); step.Result = 2; index++; continue; @@ -302,7 +302,7 @@ namespace UIShare { // 继续循环:跳转到循环开始后的第一条指令 index = context.StartIndex + 1; - LoggerHelper.InfoWithNotify($"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth); } else { @@ -310,7 +310,7 @@ namespace UIShare loopStack.Pop(); var loopStopwatch = loopStopwatchStack.Peek(); index++; - LoggerHelper.InfoWithNotify($"循环结束,共执行{context.LoopCount}次", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环结束,共执行{context.LoopCount}次", depth); if (depth == 0 && loopStopwatch.IsRunning) { loopStopwatch.Stop(); @@ -337,7 +337,7 @@ namespace UIShare SubSingleStep = true; _scopedContext.SingleStep = false; } - LoggerHelper.InfoWithNotify($"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth); stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken); UpdateCurrentStepResult(step, true, stepSuccess, depth); if (SubSingleStep) @@ -348,7 +348,7 @@ namespace UIShare } else if (step.Method != null) { - LoggerHelper.InfoWithNotify($"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth); await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken); stepSuccess = step.Result == 1; if (step.NGGotoStepID != null && !stepSuccess) @@ -357,7 +357,7 @@ namespace UIShare if (tmp != null) { index = tmp.Index - 2; - LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); } } if (step.OKGotoStepID != null && stepSuccess) @@ -366,7 +366,7 @@ namespace UIShare if (tmp != null) { index = tmp.Index - 2; - LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); + LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); } } } @@ -408,7 +408,7 @@ namespace UIShare } if (targetType == null) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth: depth); + LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth: depth); step.Result = 2; } @@ -522,7 +522,7 @@ namespace UIShare } catch (Exception ex) { - LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth: depth); + LoggerHelper.WarnWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth: depth); } } } @@ -546,7 +546,7 @@ namespace UIShare if (method == null) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth: depth); + LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth: depth); step.Result = 2; } @@ -562,7 +562,7 @@ namespace UIShare } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth: depth); + LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth: depth); step.Result = 2; } } @@ -600,7 +600,7 @@ namespace UIShare } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth); + LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth); step.Result = 2; return; } @@ -619,7 +619,7 @@ namespace UIShare paraResult = tmp.Item1; if (tmp.Item2 != null) { - LoggerHelper.WarnWithNotify(tmp.Item2); + LoggerHelper.WarnWithNotify(_systemConfig.Title, tmp.Item2); } } @@ -628,19 +628,19 @@ namespace UIShare { if (!returnType.IsArray) { - LoggerHelper.SuccessWithNotify($"输出 [ {outputParam.Name} ] = {returnValue} ({returnType.Name})", depth); + LoggerHelper.SuccessWithNotify(_systemConfig.Title, $"输出 [ {outputParam.Name} ] = {returnValue} ({returnType.Name})", depth); } else { if (returnValue is IEnumerable enumerable) { var elements = enumerable.Cast().Select(item => item?.ToString() ?? "null"); - LoggerHelper.SuccessWithNotify($"输出 [ {outputParam.Name} ] = [ {string.Join(", ", elements)} ] ({returnType.Name})", depth); + LoggerHelper.SuccessWithNotify(_systemConfig.Title, $"输出 [ {outputParam.Name} ] = [ {string.Join(", ", elements)} ] ({returnType.Name})", depth); } } } } - LoggerHelper.SuccessWithNotify($"指令 [ {step.Index} ] 执行成功", depth); + LoggerHelper.SuccessWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行成功", depth); UpdateCurrentStepResult(step, paraResult: paraResult, depth: depth); } catch (OperationCanceledException) @@ -649,7 +649,7 @@ namespace UIShare } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth); + LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth); step.Result = 2; return; } @@ -697,7 +697,7 @@ namespace UIShare step.Result = re ? 1 : 2; if (step.Result == 2) { - LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] NG:条件表达式验证失败", depth: depth); + LoggerHelper.WarnWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] NG:条件表达式验证失败", depth: depth); } } } @@ -705,7 +705,7 @@ namespace UIShare { if (!paraResult) { - LoggerHelper.WarnWithNotify("参数限值校验失败", depth: depth); + LoggerHelper.WarnWithNotify(_systemConfig.Title, "参数限值校验失败", depth: depth); } step.Result = 2; }