# 分层预览中自定义预览的分层实现逻辑分析 ## 概述 本文档详细分析NavisworksTransport插件中分层预览功能的实现逻辑,特别是自定义预览的分层机制、节点遍历深度控制和界面交互方式。 ## 核心架构分析 ### 1. 节点遍历深度控制机制 #### 深度选择界面设计 系统在UI层提供了灵活的深度控制选项: ```csharp // LayerManagementViewModel.cs - 深度选项定义 public ThreadSafeObservableCollection DepthOptions { get; } = new ThreadSafeObservableCollection { "1级", "2级", "3级", "4级", "5级", "全部" }; ``` #### 深度值转换逻辑 界面选择通过`CurrentDepthValue`属性转换为具体的遍历参数: ```csharp public int CurrentDepthValue { get { switch (SelectedDepth) { case "1级": return 1; case "2级": return 2; case "3级": return 3; case "4级": return 4; case "5级": return 5; case "全部": return 0; // 0表示无限深度 default: return 1; } } } ``` #### 核心遍历算法 **主遍历方法**:`GetItemsByDepthUnified(int maxDepth)` ```csharp private ModelItemCollection GetItemsByDepthUnified(int maxDepth) { // 深度为0表示包含所有级别 if (maxDepth <= 0) { result.AddRange(document.Models.RootItemDescendantsAndSelf); return result; } // 精确深度控制:从文档的根模型开始遍历 foreach (Model model in document.Models) { if (model.RootItem != null && maxDepth >= 1) { // 添加第一级节点(模型根的直接子节点) foreach (ModelItem firstLevelItem in model.RootItem.Children) { result.Add(firstLevelItem); // 递归添加更深层次的节点 AddChildrenToDepth(firstLevelItem, result, 2, maxDepth); } } } } ``` **递归遍历方法**:`AddChildrenToDepth()` ```csharp private void AddChildrenToDepth(ModelItem parentItem, ModelItemCollection result, int currentDepth, int maxDepth) { if (currentDepth > maxDepth || parentItem?.Children == null) return; foreach (ModelItem child in parentItem.Children) { result.Add(child); // 如果还没有达到最大深度,继续遍历子项 if (currentDepth < maxDepth) { AddChildrenToDepth(child, result, currentDepth + 1, maxDepth); } } } ``` ### 2. 分层预览处理流程 #### 预览触发链路 ``` 用户界面操作 └── LayerManagementViewModel.PreviewSplitAsync() ├── 生成SplitConfiguration(包含MaxDepth参数) └── SimplifiedModelSplitterManager.PreviewSplit(config) ├── GetAllModelItems(config.MaxDepth) │ └── GetItemsByDepthUnified(maxDepth) // 深度控制核心 ├── PreviewSplitByAttribute(allItems, config, strategy) │ └── strategy.GroupItems() // 按选定策略分组 └── 返回List ``` #### 分层策略处理 **支持的分层策略**: - `BySmartFloorDetection`:智能楼层检测分层 - `ByFloorAttribute`:基于楼层属性分层 - `ByZoneAttribute`:基于分区属性分层 - `BySubSystemAttribute`:基于子系统属性分层 **分层处理核心方法**:`PreviewSplitByAttribute()` ```csharp private List PreviewSplitByAttribute( ModelItemCollection items, SplitConfiguration config, IGroupingStrategy strategy) { // 属性分组阶段 (35-70%) var groups = strategy.GroupItems(items, config); // 生成预览结果阶段 (70-85%) foreach (var group in groups.Values) { var previewResult = new SplitPreviewResult { LayerName = SanitizeLayerName(group.GroupName), ItemCount = group.Items.Count, EstimatedFileSize = EstimateFileSize(group.Items.Count), Status = "就绪", Items = new ModelItemCollection() // 关键:保存分组的模型项 }; // 添加模型项到集合中(用于后续的隔离显示) if (group.Items != null && group.Items.Count > 0) { previewResult.Items.AddRange(group.Items); } results.Add(previewResult); } } ``` ### 3. 数据结构设计 #### 预览结果数据模型 **SplitPreviewItem类**(已具备选择保存功能): ```csharp public class SplitPreviewItem : INotifyPropertyChanged { public string LayerName { get; set; } // 分层名称 public int ObjectCount { get; set; } // 对象数量 public string EstimatedSize { get; set; } // 预估文件大小 public string Status { get; set; } // 状态信息 // 重要:已存在的选择保存功能 private bool _isSelectedForSave = true; public bool IsSelectedForSave { get; set; } // 是否选中用于保存,默认true // 关联的模型项集合(用于隔离显示功能) public ModelItemCollection Items { get; set; } = new ModelItemCollection(); } ``` #### UI数据绑定 **ViewModel中的集合管理**: ```csharp // 预览结果集合 public ThreadSafeObservableCollection SplitPreviewResults { get; } // 当前选中的预览项 public SplitPreviewItem SelectedPreviewResult { get; set; } // 控制预览列表显示 public bool ShowPreviewResults { get; set; } ``` ### 4. 可见性控制机制 #### 参考实现:SaveSelectedItemsAsync方法 系统已有完整的节点隔离显示逻辑,核心步骤: **1. 收集需要保持可见的节点** ```csharp var nodesToKeepVisible = new HashSet(); foreach (var selectedItem in originalSelection) { // 添加选中节点本身 nodesToKeepVisible.Add(selectedItem); // 添加所有祖先节点,确保选中节点的路径可见 var current = selectedItem.Parent; while (current != null) { nodesToKeepVisible.Add(current); current = current.Parent; } // 如果启用了包含子节点选项,添加所有子节点 if (IncludeChildNodes) { var childItems = selectedItem.DescendantsAndSelf.Where(x => x != selectedItem); foreach (ModelItem child in childItems) { nodesToKeepVisible.Add(child); } } } ``` **2. 智能隐藏策略** ```csharp // 收集所有顶级节点 var allTopLevelItems = new List(); foreach (Model model in document.Models) { foreach (ModelItem topLevelItem in model.RootItem.Children) { allTopLevelItems.Add(topLevelItem); } } // 决定哪些顶级分支需要隐藏 var itemsToHide = new ModelItemCollection(); foreach (ModelItem topLevelItem in allTopLevelItems) { bool shouldKeepTopLevel = false; // 检查这个顶级节点或其任何子节点是否需要保持可见 if (nodesToKeepVisible.Contains(topLevelItem)) { shouldKeepTopLevel = true; } else { // 检查是否有任何选中节点是这个顶级节点的后代 foreach (var selectedItem in originalSelection) { var current = selectedItem; while (current != null) { if (current == topLevelItem) { shouldKeepTopLevel = true; break; } current = current.Parent; } if (shouldKeepTopLevel) break; } } // 如果这个顶级节点不需要保持可见,则隐藏它 if (!shouldKeepTopLevel) { itemsToHide.Add(topLevelItem); } } ``` **3. 执行可见性操作** ```csharp // 执行隐藏操作 if (itemsToHide.Count > 0) { document.Models.SetHidden(itemsToHide, true); } // 操作完成后恢复所有项目可见性 var allItems = new ModelItemCollection(); foreach (Model model in document.Models) { foreach (ModelItem item in model.RootItem.Children) { allItems.Add(item); } } if (allItems.Count > 0) { document.Models.SetHidden(allItems, false); } ``` ## 深度遍历使用场景分析 ### 遍历深度对分层效果的影响 | 深度级别 | 遍历范围 | 适用场景 | 性能特点 | |----------|----------|----------|----------| | 1级 | 只包含模型根节点的直接子节点 | 粗粒度分层,适合大型模型的快速概览 | 处理速度最快,内存占用最小 | | 2级 | 包含二级子节点 | 中等粒度分层,平衡详细度与性能 | 适中的处理时间和内存使用 | | 3-5级 | 包含更深层次的节点结构 | 细粒度分层,适合详细分析 | 处理时间较长,内存占用较大 | | 全部 | 包含所有层级的节点 | 最详细的分层分析 | 处理时间最长,内存占用最大 | ### 深度设置的实际应用 **楼层分析场景**: - 1-2级:适合按建筑主要结构分层 - 3-5级:适合按房间或具体构件分层 - 全部:适合最详细的构件级别分析 **系统分析场景**: - 较低深度:按主要系统分类(如电气、暖通、给排水) - 较高深度:按具体设备或管线分层 ## 缓存机制 系统实现了分层结果的缓存机制,提高重复操作的性能: ```csharp // 生成缓存键 string cacheKey = GenerateCacheKey(config); // 检查缓存 List cachedResults = GetFromCache(config.Strategy, cacheKey); if (cachedResults != null && cachedResults.Count > 0) { return cachedResults; // 直接返回缓存结果 } // 处理完成后保存到缓存 SaveToCache(config.Strategy, cacheKey, previewResults); ``` ## 总结 NavisworksTransport的分层预览功能具备以下关键特性: 1. **灵活的深度控制**:支持1-5级精确遍历和无限深度选项 2. **完善的数据结构**:`SplitPreviewItem`已包含选择保存和模型项关联功能 3. **成熟的可见性控制**:基于`SaveSelectedItemsAsync`的参考实现 4. **多样的分层策略**:支持楼层、分区、子系统等多种分层方式 5. **高效的缓存机制**:避免重复计算,提升用户体验 系统架构设计合理,为后续的功能扩展(如选择性保存、单独显示等)提供了良好的基础。