using PdmSwPlugin.Common.Entity.Pdm; using SolidWorks.Interop.sldworks; using SolidWorks.Interop.swconst; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace PdmSwPlugin.Common.Util.Pdm { public class BomTreeReader { public BomTreeReader() { factory = LimitedConcurrencyLevelTaskSchedulerMsn.Factory; } public TaskFactory factory; /// /// 全部BOM的平铺List /// public ConcurrentQueue CacheList { get; private set; } = new ConcurrentQueue(); /// /// 插件展示的TreeBom /// public ConcurrentQueue TreeList { get; private set; } = new ConcurrentQueue(); /// /// 每次刷新时的缓存 /// private ConcurrentDictionary BomInfoCache { get; set; } private CancellationTokenSource CancellationSwitch { get; set; } public event EventHandler SingleCompleted; private int bomOrder = 0; /// /// 多线程从打开的根文档中读取BOM信息 /// /// 树型BOM列表 public void GetBomsFromDocAsync(ModelDoc2 sldDoc) { bomOrder = 0; if (sldDoc == null) { return; } int drawingType = sldDoc.GetType(); Configuration activeConfiguration = sldDoc.GetActiveConfiguration() as Configuration; if (activeConfiguration == null) { return; } CustomPropertyUtil.ClearAllCustomProperties(sldDoc); Component2 rootComponent = activeConfiguration.GetRootComponent3(false); string path = rootComponent.GetPathName(); BomInfo bomInfo = GetBomInfoFromDoc(rootComponent); PdmBom bom = ConcatCacheBom(bomInfo, 0, null, rootComponent); // ConcatBom 可能会返回null,说明这是个模拟件 if (bom == null) { return; } BomInfoCache[rootComponent.GetPathName()] = bomInfo; CacheList.Enqueue(bom); TreeList.Enqueue(bom); SingleCompleted?.Invoke(this, bom); bom.children = new ObservableCollection(); // 这里放个1,多线程说不准,就扣的快了 CountdownEvent counter = new CountdownEvent(1); // counter.Add 要在每个子任务前执行,不能放到子任务中进行!!! // 防止任务数太少,来不及增加计数导致直接Wait结束 counter.TryAddCount(); factory.StartNew(() => { GetChildrenBomAsync(bom, rootComponent, 0, bom.children, counter); }); counter.Wait(); counter.Dispose(); } /// /// 多线程递归获取子BOM /// /// private void GetChildrenBomAsync(PdmBom parent, Component2 parentComponent, int level, Collection children, CountdownEvent counter) { try { if (parentComponent == null) { parent.modules = new ObservableCollection(); return; } object[] childrenComponents = parentComponent.GetChildren(); if (childrenComponents == null) { parent.modules = new ObservableCollection(); return; } // 计算每个子料数量的缓存 Dictionary numCache = new Dictionary(); List modules = new List(); int order = -1; foreach (object child in childrenComponents) { Component2 childComponent = child as Component2; ModelDoc2 childDoc = childComponent.GetModelDoc2(); // 清楚格式不对的属性 CustomPropertyUtil.ClearAllCustomProperties(childDoc); string childPath = childComponent.GetPathName(); PdmBom bom = null; if (BomInfoCache.ContainsKey(childPath)) { BomInfo info = BomInfoCache[childPath]; bom = ConcatCacheBom(info, level + 1, parent, childComponent); // 就算有缓存,也要把新bom的treeId更新了,id在这里不一定唯一,tree是唯一的 bom.treeId = Guid.NewGuid().ToString(); } else { BomInfo info = GetBomInfoFromDoc(childComponent); if (info == null) { // 可能会返回null,说明这是个模拟件,直接跳过 continue; } BomInfoCache[childPath] = info; bom = ConcatCacheBom(info, level + 1, parent, childComponent); } if (!bom.lost) { // // 如果bom没有丢失,处理子料 if (bom.drawingType == (int)swDocumentTypes_e.swDocASSEMBLY) { bom.children = new ObservableCollection(); counter.TryAddCount(); factory.StartNew(() => { GetChildrenBomAsync(bom, childComponent, bom.level, bom.children, counter); }); } else { bom.modules = new ObservableCollection(); } } // 列表缓存 bom.order = ++order; CacheList.Enqueue(bom); modules.Add(bom); SingleCompleted?.Invoke(this, bom); // 丢没丢都要处理数量 if (numCache.ContainsKey(bom.name)) { numCache[bom.name].quantity++; } else { numCache[bom.name] = bom; children.Add(bom); } } if (modules != null && modules.Count > 0) { parent.modules = new ObservableCollection(modules.OrderBy(e => e.name).ToList()); return; } parent.modules = new ObservableCollection(); } finally { counter.Signal(); if (level == 0) counter.Signal(); } } public List Refresh(SldWorks swApp, ModelDoc2 doc) { if (swApp == null || doc == null) { return null; } CacheList = new ConcurrentQueue(); TreeList = new ConcurrentQueue(); BomInfoCache = new ConcurrentDictionary(); GetBomsFromDocAsync(doc); return TreeList.OrderBy(e => e.name).ToList(); ; } /// /// 从WEB获取与Component2对应的数据库中的物料信息 /// /// /// private static BomInfo GetBomInfoFromDoc(Component2 component) { ModelDoc2 doc = component.GetModelDoc2(); // 直接用文件名,以免 SolidWorks 因为有多个相同文件而把 Name2 加了 -N 的后缀名 string childPath = component.GetPathName(); string childName = Path.GetFileNameWithoutExtension(childPath); if (ModelUtil.Is_Mn(childName)) { // 如果是个模拟件,直接跳过了 return null; } BomInfo bomInfo; // id先用uuid填充 if (doc == null || string.IsNullOrEmpty(childPath) || !File.Exists(childPath)) { bomInfo = new BomInfo { id = Guid.NewGuid().ToString(), doc = doc, lost = true, suppressed = component.IsSuppressed(), lightWeight = (component.GetSuppression2() == (int)swComponentSuppressionState_e.swComponentLightweight), }; return bomInfo; } int drawingType = doc.GetType(); bomInfo = new BomInfo { id = Guid.NewGuid().ToString(), doc = doc, drawingType = drawingType, properties = CustomPropertyUtil.GetCustomProperties(doc, true), d3FilePath = childPath, }; return bomInfo; } /// /// 拼接WEB中BomInfo信息和本地图纸中的Pdmbom信息 /// /// /// /// /// private static PdmBom ConcatCacheBom(BomInfo info, int level, PdmBom parent, Component2 component) { if (info == null) return null; //if (component.IsHidden(true)) //{ // info.isHidden = true; //} PdmBom bom = new PdmBom { BomInfo = info, treeId = info.id, level = level, quantity = 1, parent = parent, component = component, isHidden = component.IsHidden(true) }; // 封装Bom信息 bom.Init(); return bom; } } }