using UIShare.UIViewModel; using UIShare.GlobalVariable; using Common.Attributes; using Logger; using Microsoft.IdentityModel.Logging; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Xml; using Model; using static UIShare.UIViewModel.ParameterVM; using UIShare.ViewModelBase; using NLog; namespace TestingModule.ViewModels { public class CommandTreeViewModel:NavigateViewModelBase { #region 属性 private string _SearchText; public string SearchText { get => _SearchText; set => SetProperty(ref _SearchText, value); } private ObservableCollection _instructionTree = new(); public ObservableCollection InstructionTree { get => _instructionTree; set => SetProperty(ref _instructionTree, value); } public ProgramVM Program { get => _ScopedContext.Program; set { if (_ScopedContext.Program != value) { _ScopedContext.Program = value; RaisePropertyChanged(); } } } public ObservableCollection Assemblies { get => _ScopedContext.Assemblies; set { if (_ScopedContext.Assemblies != value) { _ScopedContext.Assemblies = value; RaisePropertyChanged(); } } } private ObservableCollection _subPrograms = new(); public ObservableCollection SubPrograms { get => _subPrograms; set => SetProperty(ref _subPrograms, value); } private Dictionary _treeNodeMap = new(); public Dictionary TreeNodeMap { get => _treeNodeMap; set => SetProperty(ref _treeNodeMap, value); } private Dictionary _xmlDocumentCache = new(); public Dictionary XmlDocumentCache { get => _xmlDocumentCache; set => SetProperty(ref _xmlDocumentCache, value); } #endregion public ICommand LoadedCommand { get; set; } public ICommand SearchEnterCommand { get; set; } public ICommand TreeDoubleClickCommand { get; set; } public ICommand ReloadCommand { get; set; } private ScopedContext _ScopedContext { get; set; } private readonly SystemConfig _systemConfig; private readonly GlobalInfo _globalInfo; public CommandTreeViewModel(IContainerProvider containerProvider, ScopedContext scopedContext, SystemConfig systemConfig, GlobalInfo globalInfo) : base(containerProvider) { _ScopedContext = scopedContext; _systemConfig = systemConfig; _globalInfo = globalInfo; LoadedCommand = new DelegateCommand(Loaded); SearchEnterCommand = new DelegateCommand(Search); TreeDoubleClickCommand = new DelegateCommand(TreeDoubleClick); ReloadCommand = new DelegateCommand(Reload); } #region 委托命令 private void Reload() { LoadAllAssemblies(); LoadSubPrograms(); LoadInstructionsToTreeView(); } private void TreeDoubleClick(object obj) { if (!_globalInfo.IsAdmin) return; if(obj is InstructionNodeVM Node) { if(Node.Children.Count == 0) { int index = _ScopedContext.SelectedStep?.Index >= 0 ? _ScopedContext.SelectedStep.Index : -1; if (Node.Tag is MethodInfo method) { AddMethodToProgram(method, index); } else if(Node.Tag is string tag) { switch (tag) { case "循环开始": AddLoopStartStep(index); break; case "循环结束": AddLoopEndStep(index); break; } } else if(Node.Tag is SubProgramItemVM subProgram) { AddSubProgramToProgram(subProgram, index); } } } } private void Search() { } private void Loaded() { LoadAllAssemblies(); LoadSubPrograms(); LoadInstructionsToTreeView(); } #endregion #region 加载指令 /// /// 加载指定目录下的所有DLL /// private void LoadAllAssemblies() { Assemblies.Clear(); foreach (var dllPath in Directory.GetFiles(_systemConfig.DLLFilePath, "*.dll")) { try { var assembly = Assembly.LoadFile(dllPath); Assemblies.Add(assembly); // 加载对应的XML注释文件 (项目没有用到) //string xmlPath = Path.ChangeExtension(dllPath, ".xml"); //if (File.Exists(xmlPath)) //{ // try // { // XmlDocument xmlDoc = new XmlDocument(); // xmlDoc.Load(xmlPath); // _xmlDocumentCache[assembly.FullName!] = xmlDoc; // } // catch (Exception xmlEx) // { // LoggerHelper.WarnWithNotify($"加载XML注释失败: {Path.GetFileName(xmlPath)} - {xmlEx.Message}"); // } //} } catch (Exception ex) { LoggerHelper.WarnWithNotify($"无法加载程序集 {Path.GetFileName(dllPath)}: {ex.Message}"); } } } // 子程序加载方法 private void LoadSubPrograms() { SubPrograms.Clear(); if (!Directory.Exists(_systemConfig.SubProgramFilePath)) { Directory.CreateDirectory(_systemConfig.SubProgramFilePath); return; } foreach (var filePath in Directory.GetFiles(_systemConfig.SubProgramFilePath, "*.adp")) { try { SubPrograms.Add(new SubProgramItemVM { Name = Path.GetFileNameWithoutExtension(filePath), FilePath = filePath }); } catch (Exception ex) { LoggerHelper.WarnWithNotify($"加载子程序错误: {filePath} - {ex.Message}"); } } } /// /// 加载指令集到TreeView /// private void LoadInstructionsToTreeView() { InstructionTree.Clear(); var controlRootNode = new InstructionNodeVM { Name = "系统指令", Tag = "ControlRoot" }; InstructionTree.Add(controlRootNode); // 循环开始 controlRootNode.Children.Add(new InstructionNodeVM { Name = "循环开始", Tag = "循环开始" }); // 循环结束 controlRootNode.Children.Add(new InstructionNodeVM { Name = "循环结束", Tag = "循环结束" }); // ---------------------- // 子程序 根节点 // ---------------------- var subProgramRoot = new InstructionNodeVM { Name = "子程序", Tag = "SubProgramRoot" }; InstructionTree.Add(subProgramRoot); foreach (var subProgram in SubPrograms) { subProgramRoot.Children.Add(new InstructionNodeVM { Name = subProgram.Name, Tag = subProgram, }); } // ---------------------- // 动态 DLL 指令 // ---------------------- foreach (var assembly in Assemblies) { List validTypes = new List(); try { var types = assembly.GetTypes().Where(t => t.IsPublic && !t.IsNested && (t.IsClass || t.IsValueType) && (!t.IsAbstract || t.IsSealed) && t.GetCustomAttribute() != null); foreach (var type in types) { if (type.GetCustomAttribute()?.Browsable == false) continue; var allMethods = new HashSet(); GetPublicMethods(type, allMethods); if (allMethods.Count > 0) validTypes.Add(type); } } catch (Exception ex) { LoggerHelper.ErrorWithNotify($"加载类型错误: {assembly.FullName} - {ex.Message}"); } if (validTypes.Count > 0) { var assemblyNode = new InstructionNodeVM { Name = assembly.GetName().Name, Tag = assembly }; InstructionTree.Add(assemblyNode); TreeNodeMap[assembly] = assemblyNode; foreach (var type in validTypes) { //拦截没有在设备列表中的设备类型 //if (SystemConfig.Instance.DeviceList.Where(x=>x.Remark==type.Name).ToList().Count==0 && type.FullName.Contains("DeviceCommand.Device")) //{ // continue; //} var typeNode = new InstructionNodeVM { Name = type.Name, Tag = type, }; assemblyNode.Children.Add(typeNode); TreeNodeMap[type] = typeNode; var allMethods = new HashSet(); GetPublicMethods(type, allMethods); foreach (var method in allMethods) { if (method.IsSpecialName) continue; if (method.DeclaringType == typeof(object)) continue; string[] ignoreMethods = { "GetType", "ToString", "Equals", "GetHashCode" }; if (ignoreMethods.Contains(method.Name)) continue; if (method.GetCustomAttribute()?.Browsable == false) continue; if (type.IsAbstract && type.IsSealed && !method.IsStatic) continue; var parameters = method.GetParameters(); var paramText = string.Join(", ", parameters.Select(p => $"{p.ParameterType.Name} {p.Name}")); var methodNode = new InstructionNodeVM { Name = $"{method.Name}({paramText})", Tag = method, }; typeNode.Children.Add(methodNode); TreeNodeMap[method] = methodNode; } } } } } #endregion #region 辅助方法 /// /// 递归获取类型的所有公共方法(包括继承的方法),但跳过被重写的方法 /// /// 要处理的目标类型 /// 存储方法的集合 private void GetPublicMethods(Type type, HashSet methods) { // 获取当前类型的所有公共方法(包括继承的) var allMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly) .Where(m => !m.IsSpecialName && m.DeclaringType != typeof(object)) .ToList(); // 按方法签名分组 var groupedMethods = allMethods .GroupBy(m => new { m.Name, Parameters = string.Join(",", m.GetParameters().Select(p => p.ParameterType.FullName)) }); foreach (var group in groupedMethods) { // 从组中选择声明类型最接近当前类型(即继承层次最深)的方法 MethodInfo? selectedMethod = null; int minDepth = int.MaxValue; foreach (var method in group) { // 计算声明类型的深度 int depth = 0; Type? current = type; Type declaringType = method.DeclaringType!; while (current != null && current != declaringType) { depth++; current = current.BaseType; } // 如果找到声明类型且在继承链上 if (current == declaringType) { if (selectedMethod == null || depth < minDepth) { selectedMethod = method; minDepth = depth; } } } if (selectedMethod != null) { methods.Add(selectedMethod); } } } #endregion #region 指令添加 private void AddMethodToProgram(MethodInfo method, int insertIndex = -1) { try { var newStep = new StepVM { Name = method.Name, StepType = "方法", Method = new MethodVM { FullName = method.DeclaringType?.FullName, Name = method.Name } }; // 添加输入参数 foreach (var param in method.GetParameters()) { newStep.Method.Parameters.Add(new ParameterVM { Name = param.Name!, Type = param.ParameterType, Category = ParameterCategory.Input }); } // 添加输出参数(返回值) Type returnType = method.ReturnType; if (returnType == typeof(Task)) { // 不添加输出参数(无返回值) } else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>)) { // 提取实际返回类型(如 Task -> bool) Type actualType = returnType.GetGenericArguments()[0]; newStep.Method.Parameters.Add(new ParameterVM { Name = "Result", Type = actualType, // 使用实际类型 Category = ParameterCategory.Output }); } else if (returnType != typeof(void)) { // 同步方法正常添加 newStep.Method.Parameters.Add(new ParameterVM { Name = "Result", Type = returnType, Category = ParameterCategory.Output }); } // 添加到程序 if(_ScopedContext.SelectedStepList == "主程序") { if(insertIndex >= 0 && insertIndex <= Program.StepCollection.Count) Program.StepCollection.Insert(insertIndex, newStep); else Program.StepCollection.Add(newStep); } else { if (insertIndex >= 0 && insertIndex <= Program.ErrorStepCollection.Count) Program.ErrorStepCollection.Insert(insertIndex, newStep); else Program.ErrorStepCollection.Add(newStep); } } catch (Exception ex) { LoggerHelper.ErrorWithNotify($"添加方法失败: {method.Name} - {ex.Message}"); } } private void AddSubProgramToProgram(SubProgramItemVM subProgram, int insertIndex = -1) { try { var newStep = new StepVM { Name = subProgram.Name, StepType = "子程序" }; var jsonstr = File.ReadAllText($"{subProgram.FilePath}"); var tmp = JsonConvert.DeserializeObject(jsonstr); if (tmp != null) { newStep.SubProgram = tmp; } // 添加到程序 if (_ScopedContext.SelectedStepList == "主程序") { if (insertIndex >= 0 && insertIndex <= Program.StepCollection.Count) Program.StepCollection.Insert(insertIndex, newStep); else Program.StepCollection.Add(newStep); } else { if (insertIndex >= 0 && insertIndex <= Program.ErrorStepCollection.Count) Program.ErrorStepCollection.Insert(insertIndex, newStep); else Program.ErrorStepCollection.Add(newStep); } } catch (Exception ex) { LoggerHelper.ErrorWithNotify($"添加子程序失败: {subProgram.Name} - {ex.Message}"); } } private void AddLoopStartStep(int insertIndex = -1) { var newStep = new StepVM { Name = "循环开始", StepType = "循环开始", LoopCount = 1, Method = new() { Parameters = [new() { Name = "循环次数", Type = typeof(int), Category = ParameterCategory.Input }] } }; // 添加到程序 if (_ScopedContext.SelectedStepList == "主程序") { if (insertIndex >= 0) Program.StepCollection.Insert(insertIndex, newStep); else Program.StepCollection.Add(newStep); } else { if (insertIndex >= 0) Program.ErrorStepCollection.Insert(insertIndex, newStep); else Program.ErrorStepCollection.Add(newStep); } } private void AddLoopEndStep(int insertIndex = -1) { // 查找最近的未匹配循环开始 StepVM? lastUnmatchedLoopStart = null; for (int i = Program.StepCollection.Count - 1; i >= 0; i--) { if (Program.StepCollection[i].StepType == "循环开始") { bool isMatched = Program.StepCollection.Any(s => s.StepType == "循环结束" && s.LoopStartStepId == Program.StepCollection[i].ID); if (!isMatched) { lastUnmatchedLoopStart = Program.StepCollection[i]; break; } } } var newStep = new StepVM { Name = "循环结束", StepType = "循环结束", LoopStartStepId = lastUnmatchedLoopStart?.ID }; // 添加到程序 if (_ScopedContext.SelectedStepList == "主程序") { if (insertIndex >= 0) Program.StepCollection.Insert(insertIndex, newStep); else Program.StepCollection.Add(newStep); } else { if (insertIndex >= 0) Program.ErrorStepCollection.Insert(insertIndex, newStep); else Program.ErrorStepCollection.Add(newStep); } } #endregion } }