using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Autodesk.Navisworks.Api; using NavisApplication = Autodesk.Navisworks.Api.Application; using NavisworksTransport.Core; using NavisworksTransport.Core.Config; using NavisworksTransport.UI.WPF.Collections; using NavisworksTransport.UI.WPF.Models; using NavisworksTransport.Utils; namespace NavisworksTransport.UI.WPF.ViewModels { /// /// 类别设置页签的ViewModel - 基于分层管理页签的设计风格 /// /// 功能特点: /// 1. 参考分层管理页签的布局风格和UI组织方式 /// 2. 将模型选择提示移动到类别属性区域中 /// 3. 提供完整的物流属性设置功能 /// 4. 支持批量属性设置和单个模型编辑 /// 5. 使用MVVM架构和线程安全的UI更新 /// public class ModelSettingsViewModel : ViewModelBase, IDisposable { #region 私有字段和依赖注入 private readonly UIStateManager _uiStateManager; // 选择事件订阅管理器 private SelectionEventSubscription _selectionEventSubscription; // 文档模型集合变化事件订阅标志 private bool _modelsCollectionEventSubscribed; // 资源释放状态标志 private bool _disposed; // 上次模型数量,用于检测模型加载完成 private int _lastModelsCount = -1; #endregion #region 状态字段 private bool _isProcessing; private string _selectedModelsText; private string _selectedCategory; private bool _isTraversable; private int _priority; private double _widthLimit; private double _heightLimit; private double _speedLimit; private bool _isLogisticsOnlyMode; private LogisticsModel _selectedLogisticsModel; private string _selectedCategoryFilter = "全部"; #endregion #region 公共属性 - 使用线程安全的SetProperty方法 /// /// 是否正在处理中 /// public bool IsProcessing { get => _isProcessing; set { if (SetPropertyThreadSafe(ref _isProcessing, value)) { OnPropertyChanged(nameof(IsNotProcessing)); RefreshAllCommands(); } } } /// /// 是否未在处理中 /// public bool IsNotProcessing => !IsProcessing; /// /// 选中模型文本 /// public string SelectedModelsText { get => _selectedModelsText; set => SetPropertyThreadSafe(ref _selectedModelsText, value); } /// /// 可用类别集合 - 使用线程安全集合 /// public ThreadSafeObservableCollection AvailableCategories { get; } = new ThreadSafeObservableCollection(); /// /// 选中的类别 /// public string SelectedCategory { get => _selectedCategory; set { if (SetPropertyThreadSafe(ref _selectedCategory, value)) { OnPropertyChanged(nameof(CanSetLogisticsAttribute)); } } } /// /// 是否可通行 /// public bool IsTraversable { get => _isTraversable; set => SetPropertyThreadSafe(ref _isTraversable, value); } /// /// 优先级列表 - 使用线程安全集合 /// public ThreadSafeObservableCollection PriorityLevels { get; } = new ThreadSafeObservableCollection { 1, 2, 3, 4, 5 }; /// /// 优先级(1-5级,5为最高) /// public int Priority { get => _priority; set => SetPropertyThreadSafe(ref _priority, value); } /// /// 宽度限制(米) /// public double WidthLimit { get => _widthLimit; set => SetPropertyThreadSafe(ref _widthLimit, value); } /// /// 高度限制(米) /// public double HeightLimit { get => _heightLimit; set => SetPropertyThreadSafe(ref _heightLimit, value); } /// /// 限速(米/秒) /// public double SpeedLimit { get => _speedLimit; set => SetPropertyThreadSafe(ref _speedLimit, value); } /// /// 是否可以设置物流属性 /// public bool CanSetLogisticsAttribute => !string.IsNullOrEmpty(SelectedCategory) && !IsProcessing && HasSelectedModels; /// /// 是否可以清除物流属性 /// public bool CanClearLogisticsAttribute => !IsProcessing && HasSelectedModels && HasSelectedModelsWithLogisticsAttributes; /// /// 是否有选中的模型 /// public bool HasSelectedModels { get { try { var document = NavisApplication.ActiveDocument; return document?.CurrentSelection?.SelectedItems?.Count > 0; } catch { return false; } } } /// /// 选中的模型是否包含物流属性 /// public bool HasSelectedModelsWithLogisticsAttributes { get { try { var document = NavisApplication.ActiveDocument; var selectedItems = document?.CurrentSelection?.SelectedItems; if (selectedItems == null || selectedItems.Count == 0) return false; // 检查是否至少有一个选中的模型具有物流属性 foreach (var item in selectedItems) { if (CategoryAttributeManager.HasLogisticsAttributes(item)) { return true; } } return false; } catch { return false; } } } /// /// 物流模型集合 - 使用线程安全集合 /// public ThreadSafeObservableCollection LogisticsModels { get; } = new ThreadSafeObservableCollection(); /// /// 选中的物流模型 /// /// /// 选中的物流模型 /// public LogisticsModel SelectedLogisticsModel { get => _selectedLogisticsModel; set { if (SetPropertyThreadSafe(ref _selectedLogisticsModel, value)) { // 选中Navisworks中对应的模型 SelectModelInNavisworks(value); // 回填属性值到UI LoadModelAttributes(value); // 高亮并聚焦到选中的模型 if (value?.NavisworksItem != null) { FocusOnLogisticsModel(value); } } } } /// /// 可用类别筛选选项 - 从所有可用类别动态获取 /// 注意:不包含"全部","全部"是UI层面的特殊选项 /// public ThreadSafeObservableCollection AvailableCategoryFilters { get; } = new ThreadSafeObservableCollection(); /// /// 当前选中的类别筛选条件 /// public string SelectedCategoryFilter { get => _selectedCategoryFilter; set { if (SetPropertyThreadSafe(ref _selectedCategoryFilter, value)) { // 筛选条件变化时,触发筛选列表刷新 OnPropertyChanged(nameof(FilteredLogisticsModels)); LogManager.Info($"[ModelSettingsViewModel] 物流模型筛选条件已切换为: {value}"); } } } /// /// 筛选后的物流模型列表 /// public System.Collections.Generic.List FilteredLogisticsModels { get { if (SelectedCategoryFilter == "全部" || string.IsNullOrEmpty(SelectedCategoryFilter)) { return new System.Collections.Generic.List(LogisticsModels); } return System.Linq.Enumerable.ToList( System.Linq.Enumerable.Where(LogisticsModels, m => m.Category == SelectedCategoryFilter)); } } /// /// 加载模型属性并回填到UI /// /// 选中的物流模型 /// /// 加载模型属性并回填到UI /// /// 选中的物流模型 private void LoadModelAttributes(LogisticsModel logisticsModel) { if (logisticsModel?.NavisworksItem == null) { // 正常情况:清除选择时传入null,无需处理 return; } // 从Navisworks项中获取物流属性信息 var info = CategoryAttributeManager.GetLogisticsAttributeInfo(logisticsModel.NavisworksItem); if (info == null) { LogManager.Error($"[ModelSettingsViewModel] 异常:列表中的模型 {logisticsModel.Name} 没有物流属性信息!"); return; } // 验证物流类型 if (string.IsNullOrEmpty(info.ElementType)) { LogManager.Error($"[ModelSettingsViewModel] 异常:模型 {logisticsModel.Name} 的ElementType为空!"); return; } // 将类别ID转换为显示名称 string displayName = GetDisplayNameByCategoryId(info.ElementType); if (string.IsNullOrEmpty(displayName)) { LogManager.Error($"[ModelSettingsViewModel] 异常:模型 {logisticsModel.Name} 的ElementType '{info.ElementType}' 无法找到对应的类别!"); return; } if (!AvailableCategories.Contains(displayName)) { LogManager.Error($"[ModelSettingsViewModel] 异常:模型 {logisticsModel.Name} 的类别显示名称 '{displayName}' 不在可用类别中!"); return; } // 验证优先级 if (info.Priority < 1 || info.Priority > 5) { LogManager.Error($"[ModelSettingsViewModel] 异常:模型 {logisticsModel.Name} 的优先级 {info.Priority} 超出有效范围(1-5)!"); return; } // 验证高度限制 if (info.HeightLimit <= 0) { LogManager.Error($"[ModelSettingsViewModel] 异常:模型 {logisticsModel.Name} 的高度限制 {info.HeightLimit} 无效!"); return; } // 验证速度限制 if (info.SpeedLimit <= 0) { LogManager.Error($"[ModelSettingsViewModel] 异常:模型 {logisticsModel.Name} 的速度限制 {info.SpeedLimit} 无效!"); return; } // 验证宽度限制 if (info.WidthLimit <= 0) { LogManager.Error($"[ModelSettingsViewModel] 异常:模型 {logisticsModel.Name} 的宽度限制 {info.WidthLimit} 无效!"); return; } // 所有验证通过,回填属性(使用显示名称) SelectedCategory = displayName; IsTraversable = info.IsTraversable; Priority = info.Priority; HeightLimit = info.HeightLimit; SpeedLimit = info.SpeedLimit; WidthLimit = info.WidthLimit; LogManager.Info($"[ModelSettingsViewModel] 已回填模型属性: {logisticsModel.Name}, 类型: {info.ElementType}, 可通行: {info.IsTraversable}, 优先级: {info.Priority}, 高度: {info.HeightLimit}m, 速度: {info.SpeedLimit}m/s, 宽度: {info.WidthLimit}m"); } /// /// 是否处于仅显示物流模式 /// public bool IsLogisticsOnlyMode { get => _isLogisticsOnlyMode; set { if (SetPropertyThreadSafe(ref _isLogisticsOnlyMode, value)) { // 当开关状态改变时,自动应用可见性设置 ApplyVisibilityMode(); } } } #endregion #region 命令 - 使用统一的Command Pattern public ICommand RefreshSelectionCommand { get; private set; } public ICommand SetLogisticsAttributeCommand { get; private set; } public ICommand ClearLogisticsAttributeCommand { get; private set; } public ICommand RefreshLogisticsModelsCommand { get; private set; } public ICommand ResetToDefaultsCommand { get; private set; } public ICommand ToggleModelVisibilityCommand { get; private set; } #endregion #region 构造函数 - 使用依赖注入和统一架构 public ModelSettingsViewModel(LogisticsControlViewModel mainViewModel = null) : base() { try { // 从配置文件初始化默认值(必须在UI绑定之前完成) var config = ConfigManager.Instance.Current; _selectedModelsText = "请在主界面中选择需要设置的模型"; _selectedCategory = "通道"; _isTraversable = config.Logistics.Traversable; _priority = config.Logistics.Priority; _widthLimit = config.Logistics.WidthLimitMeters; _heightLimit = config.Logistics.HeightLimitMeters; _speedLimit = config.Logistics.SpeedLimitMetersPerSecond; _isLogisticsOnlyMode = false; // 获取UI状态管理器实例和设置主ViewModel引用到基类 _uiStateManager = UIStateManager.Instance; SetMainViewModel(mainViewModel); // 验证关键组件是否正常初始化 if (_uiStateManager == null) { LogManager.Error("UIStateManager初始化失败"); throw new InvalidOperationException("UIStateManager初始化失败"); } // 初始化命令 InitializeCommands(); // 订阅配置变更事件 SubscribeToConfigChanges(); // 订阅Navisworks选择变化事件 - 使用新的选择管理服务 SubscribeToSelectionEvents(); // 订阅文档模型集合变化事件 SubscribeToDocumentModelsEvents(); // 异步初始化 InitializeAsync(); LogManager.Info("ModelSettingsViewModel构造函数执行完成 - 使用统一UI架构"); } catch (Exception ex) { LogManager.Error($"ModelSettingsViewModel构造函数异常: {ex.Message}", ex); UpdateMainStatus("初始化失败,请检查日志"); throw; } } #endregion #region 配置变更处理 /// /// 订阅配置变更事件 /// private void SubscribeToConfigChanges() { try { ConfigManager.Instance.CategoryConfigurationChanged += OnCategoryConfigurationChanged; LogManager.Info("ModelSettingsViewModel 已订阅配置变更事件"); } catch (Exception ex) { LogManager.Error($"订阅配置变更事件失败: {ex.Message}", ex); } } /// /// 取消订阅配置变更事件 /// private void UnsubscribeFromConfigChanges() { try { ConfigManager.Instance.CategoryConfigurationChanged -= OnCategoryConfigurationChanged; LogManager.Info("ModelSettingsViewModel 已取消订阅配置变更事件"); } catch (Exception ex) { LogManager.Warning($"取消订阅配置变更事件时发生异常: {ex.Message}"); } } /// /// 配置变更事件处理 /// private void OnCategoryConfigurationChanged(object sender, Tuple args) { try { var category = args.Item1; var eventArgs = args.Item2; // 处理 Logistics 类别变更 if (category == ConfigCategory.Logistics || category == ConfigCategory.All) { LogManager.Info("收到 Logistics 配置变更通知,正在更新默认属性值..."); var config = ConfigManager.Instance.Current; // 更新默认属性值(仅当用户未选择模型时) SafeExecute(() => { // 如果当前没有选择模型,更新默认值 if (!HasSelectedModels) { IsTraversable = config.Logistics.Traversable; Priority = config.Logistics.Priority; WidthLimit = config.Logistics.WidthLimitMeters; HeightLimit = config.Logistics.HeightLimitMeters; SpeedLimit = config.Logistics.SpeedLimitMetersPerSecond; string source = eventArgs.IsExternalChange ? "外部修改" : "内部更新"; UpdateMainStatus($"默认属性已更新 ({source})"); LogManager.Info($"默认物流属性已更新 - 来源: {source}"); } }); } // 处理自定义类别变更 - 刷新可用类别列表 if (category == ConfigCategory.All) { LogManager.Info("收到配置变更通知,正在更新可用类别列表..."); SafeExecute(() => { // 重新加载自定义类别 CategoryAttributeManager.ReloadCustomCategories(); // 刷新可用类别列表 RefreshAvailableCategories(); string source = eventArgs.IsExternalChange ? "外部修改" : "内部更新"; UpdateMainStatus($"类别列表已更新 ({source})"); LogManager.Info($"可用类别列表已更新 - 来源: {source}, 当前类别数: {AvailableCategories.Count}"); }); } } catch (Exception ex) { LogManager.Error($"处理配置变更事件失败: {ex.Message}", ex); } } /// /// 刷新可用类别列表 /// private void RefreshAvailableCategories() { _uiStateManager.ExecuteUIUpdateAsync(() => { // 保存当前选中的类别 string previousSelectedCategory = SelectedCategory; string previousSelectedFilter = SelectedCategoryFilter; // 清空集合 AvailableCategories.Clear(); AvailableCategoryFilters.Clear(); // 先添加"全部"选项到筛选器 AvailableCategoryFilters.Add("全部"); // 从 CategoryAttributeManager 获取所有可用类别(内置 + 自定义) var allCategories = CategoryAttributeManager.GetAllAvailableCategories().ToList(); foreach (var cat in allCategories) { AvailableCategories.Add(cat.DisplayName); AvailableCategoryFilters.Add(cat.DisplayName); } // 恢复之前的选择(如果仍然存在) if (!string.IsNullOrEmpty(previousSelectedCategory) && AvailableCategories.Contains(previousSelectedCategory)) { SelectedCategory = previousSelectedCategory; } else if (AvailableCategories.Count > 0) { // 默认选择"通道"或第一个类别 SelectedCategory = AvailableCategories.Contains("通道") ? "通道" : AvailableCategories[0]; } // 恢复筛选器选择 if (!string.IsNullOrEmpty(previousSelectedFilter) && AvailableCategoryFilters.Contains(previousSelectedFilter)) { SelectedCategoryFilter = previousSelectedFilter; } else { SelectedCategoryFilter = "全部"; } }).ConfigureAwait(false); } #endregion #region 命令初始化 - 统一的Command Pattern /// /// 初始化命令(使用Command Pattern框架) /// private void InitializeCommands() { SafeExecute(() => { RefreshSelectionCommand = new RelayCommand( async () => await RefreshSelectionAsync(), () => IsNotProcessing); SetLogisticsAttributeCommand = new RelayCommand( async () => await SetLogisticsAttributeAsync(), () => CanSetLogisticsAttribute); ClearLogisticsAttributeCommand = new RelayCommand( async () => await ClearLogisticsAttributeAsync(), () => CanClearLogisticsAttribute); RefreshLogisticsModelsCommand = new RelayCommand( async () => await RefreshLogisticsModelsAsync(), () => IsNotProcessing); ResetToDefaultsCommand = new RelayCommand( async () => await ResetToDefaultsAsync(), () => IsNotProcessing); ToggleModelVisibilityCommand = new RelayCommand( async (model) => await ToggleModelVisibilityAsync(model), (model) => model != null && IsNotProcessing); LogManager.Info("类别设置命令初始化完成 - 使用统一Command Pattern框架"); }, "初始化命令"); } #endregion #region 业务逻辑方法 - 使用统一的UIStateManager /// /// 刷新选择状态 - 使用新的选择管理服务 /// private async Task RefreshSelectionAsync() { // 1. 初始UI状态更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = true; UpdateMainStatus("正在检查模型选择...", -1, true); }); try { // 2. 使用新的选择管理服务获取选择状态(后台线程) var selectionResult = await NavisworksSelectionHelper.GetCurrentSelectionStateAsync(); // 3. 结果UI更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { if (selectionResult.Success) { SelectedModelsText = NavisworksSelectionHelper.FormatSelectionText(selectionResult, "个模型"); UpdateMainStatus("检查完成"); } else { SelectedModelsText = selectionResult.ErrorMessage ?? "检查选择状态失败"; UpdateMainStatus("检查失败"); } // 🔧 修复:刷新所有与选择相关的命令状态(包括清除属性按钮) OnPropertyChanged(nameof(HasSelectedModels)); OnPropertyChanged(nameof(HasSelectedModelsWithLogisticsAttributes)); OnPropertyChanged(nameof(CanSetLogisticsAttribute)); OnPropertyChanged(nameof(CanClearLogisticsAttribute)); }); } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 刷新选择异常: {ex.Message}", ex); // 异常UI更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { SelectedModelsText = "检查选择状态异常"; UpdateMainStatus($"检查失败: {ex.Message}"); }); } finally { // 4. 清理UI状态 await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = false; }); } } /// /// 设置物流属性 - 实现正确的业务逻辑与UI分离模式 /// private async Task SetLogisticsAttributeAsync() { // 1. 初始UI状态更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = true; UpdateMainStatus("正在设置物流属性...", -1, true); }); try { // 2. 业务逻辑执行(必须在主线程上执行,因为包含 Navisworks COM API 调用) var result = NavisworksApiHelper.ExecuteOnUIThread(() => { try { var selectedItems = NavisApplication.ActiveDocument?.CurrentSelection?.SelectedItems; if (selectedItems == null || selectedItems.Count == 0) { return new { Success = false, Count = 0, Message = "请先选择模型元素" }; } // 根据显示名称查找类别ID string categoryId = GetCategoryIdByDisplayName(SelectedCategory); if (string.IsNullOrEmpty(categoryId)) { return new { Success = false, Count = 0, Message = $"无效的物流类别: {SelectedCategory}" }; } int successCount = CategoryAttributeManager.AddLogisticsAttributes( selectedItems, categoryId, isTraversable: IsTraversable, priority: Priority, heightLimit: HeightLimit, speedLimit: SpeedLimit, widthLimit: WidthLimit); return new { Success = true, Count = successCount, Message = $"已为 {successCount} 个元素设置物流属性: {SelectedCategory}" }; } catch (Exception ex) { return new { Success = false, Count = 0, Message = $"设置属性失败: {ex.Message}" }; } }); // 3. 结果UI更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { UpdateMainStatus(result.Message); if (result.Success) { LogManager.Info($"设置物流属性成功: {result.Message}"); } else { LogManager.Warning($"设置物流属性失败: {result.Message}"); } }); // 如果设置成功,异步刷新物流模型列表 if (result.Success) { await RefreshLogisticsModelsAsync(); // 如果当前处于仅显示物流模式,重新应用可见性设置 if (IsLogisticsOnlyMode) { // 重要:ApplyVisibilityMode包含Navisworks API调用,必须在主线程中执行 await _uiStateManager.ExecuteUIUpdateAsync(() => ApplyVisibilityMode()); } } } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 设置物流属性异常: {ex.Message}", ex); // 异常UI更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { UpdateMainStatus($"设置属性出错: {ex.Message}"); }); } finally { // 4. 清理UI状态 await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = false; }); } } /// /// 清除物流属性 - 实现正确的业务逻辑与UI分离模式 /// private async Task ClearLogisticsAttributeAsync() { // 1. 初始UI状态更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = true; UpdateMainStatus("正在清除物流属性...", -1, true); }); try { // 2. 业务逻辑执行(必须在主线程上执行,因为包含 Navisworks COM API 调用) var result = await _uiStateManager.ExecuteUIUpdateAsync(() => { try { var selectedItems = NavisApplication.ActiveDocument?.CurrentSelection?.SelectedItems; if (selectedItems == null || selectedItems.Count == 0) { return new { Success = false, Count = 0, Message = "请先选择模型元素" }; } // 使用CategoryAttributeManager的RemoveLogisticsAttributes方法 int successCount = CategoryAttributeManager.RemoveLogisticsAttributes(selectedItems); return new { Success = successCount > 0, Count = successCount, Message = successCount > 0 ? $"已清除 {successCount} 个元素的物流属性" : "没有找到可清除的物流属性" }; } catch (Exception ex) { return new { Success = false, Count = 0, Message = $"清除属性失败: {ex.Message}" }; } }); // 3. 结果UI更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { UpdateMainStatus(result.Message); if (result.Success) { LogManager.Info($"清除物流属性成功: {result.Message}"); } else { LogManager.Warning($"清除物流属性失败: {result.Message}"); } }); // 如果清除成功,异步刷新物流模型列表 if (result.Success) { await RefreshLogisticsModelsAsync(); // 如果当前处于仅显示物流模式,重新应用可见性设置 if (IsLogisticsOnlyMode) { // 重要:ApplyVisibilityMode包含Navisworks API调用,必须在主线程中执行 await _uiStateManager.ExecuteUIUpdateAsync(() => ApplyVisibilityMode()); } } } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 清除物流属性异常: {ex.Message}", ex); // 异常UI更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { UpdateMainStatus($"清除属性出错: {ex.Message}"); }); } finally { // 4. 清理UI状态 await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = false; }); } } /// /// 刷新物流模型列表 - 实现正确的业务逻辑与UI分离模式 /// private async Task RefreshLogisticsModelsAsync() { // 1. 初始UI状态更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = true; UpdateMainStatus("正在刷新物流模型列表...", -1, true); }); try { // 2. 业务逻辑执行(必须在主线程上执行,因为包含 Navisworks COM API 调用) var result = await _uiStateManager.ExecuteUIUpdateAsync(() => { try { // 直接使用 CategoryAttributeManager 的 API var document = NavisApplication.ActiveDocument; var logisticsItems = CategoryAttributeManager.GetAllLogisticsItems(); var models = new List(); foreach (var item in logisticsItems) { // 直接使用 CategoryAttributeManager 的 API var info = CategoryAttributeManager.GetLogisticsAttributeInfo(item); // 将类别ID转换为显示名称 string categoryId = info?.ElementType ?? "未分类"; string displayName = categoryId; if (categoryId != "未分类") { var categoryDef = CategoryAttributeManager.GetCategoryDefinition(categoryId); if (categoryDef != null) { displayName = categoryDef.DisplayName; } } var model = new LogisticsModel { Name = item.DisplayName ?? "未命名模型", Category = displayName, Attributes = FormatLogisticsAttributes(info), IsVisible = !item.IsHidden, NavisworksItem = item }; models.Add(model); } return new { Success = true, Models = models, Count = models.Count }; } catch (Exception ex) { LogManager.Error($"刷新物流模型列表异常: {ex.Message}", ex); return new { Success = false, Models = new List(), Count = 0 }; } }); // 3. 结果UI更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { LogisticsModels.Clear(); if (result.Success) { foreach (var model in result.Models) { LogisticsModels.Add(model); } // 触发筛选列表刷新 OnPropertyChanged(nameof(FilteredLogisticsModels)); UpdateMainStatus($"已刷新物流模型列表,共 {result.Count} 个模型"); } else { UpdateMainStatus("刷新物流模型列表失败"); } }); LogManager.Info($"已刷新所有物流模型列表,共 {result.Count} 个模型"); } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 刷新物流模型异常: {ex.Message}", ex); // 异常UI更新 await _uiStateManager.ExecuteUIUpdateAsync(() => { LogisticsModels.Clear(); OnPropertyChanged(nameof(FilteredLogisticsModels)); UpdateMainStatus($"刷新列表出错: {ex.Message}"); }); } finally { // 4. 清理UI状态 await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = false; }); } } /// /// 重置为默认值 - 从配置文件读取默认值 /// private async Task ResetToDefaultsAsync() { await _uiStateManager.ExecuteUIUpdateAsync(() => { var config = ConfigManager.Instance.Current; SelectedCategory = "通道"; IsTraversable = config.Logistics.Traversable; Priority = config.Logistics.Priority; WidthLimit = config.Logistics.WidthLimitMeters; HeightLimit = config.Logistics.HeightLimitMeters; SpeedLimit = config.Logistics.SpeedLimitMetersPerSecond; UpdateMainStatus("已重置为默认值(来自配置)"); LogManager.Info($"已重置类别设置为默认值 - 可通行:{IsTraversable}, 优先级:{Priority}, 宽度:{WidthLimit:F1}m, 高度:{HeightLimit:F1}m, 速度:{SpeedLimit:F1}m/s"); }); } /// /// 切换模型可见性 /// private async Task ToggleModelVisibilityAsync(LogisticsModel model) { if (model?.NavisworksItem == null) return; await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = true; }); try { // 重要:Navisworks API 操作必须在主线程中执行,不能在Task.Run中 var newVisibility = !model.IsVisible; // 使用VisibilityHelper来切换单个模型的可见性 var itemCollection = new ModelItemCollection { model.NavisworksItem }; bool success = VisibilityHelper.SetItemsVisibility(itemCollection, !newVisibility); // 更新UI状态 await _uiStateManager.ExecuteUIUpdateAsync(() => { if (success) { model.IsVisible = newVisibility; var action = newVisibility ? "显示" : "隐藏"; UpdateMainStatus($"已{action}模型: {model.Name}"); LogManager.Info($"成功{action}模型: {model.Name}"); } else { UpdateMainStatus($"切换模型可见性失败: {model.Name}"); LogManager.Error($"切换模型可见性失败: {model.Name}"); } }); } catch (Exception ex) { LogManager.Error($"ToggleModelVisibilityAsync异常: {ex.Message}", ex); await _uiStateManager.ExecuteUIUpdateAsync(() => { UpdateMainStatus($"切换可见性异常: {ex.Message}"); }); } finally { await _uiStateManager.ExecuteUIUpdateAsync(() => { IsProcessing = false; }); } } /// /// 在Navisworks中选择对应的模型 /// private void SelectModelInNavisworks(LogisticsModel model) { // 重要:根据示例代码,选择操作必须在主线程中执行,不能在Task.Run中 try { if (model?.NavisworksItem == null) { // 如果没有选中模型,清除Navisworks选择 bool success = NavisworksSelectionHelper.SetModelSelection((ModelItem)null); if (success) { LogManager.Info("已清除Navisworks选择"); } else { LogManager.Warning("清除Navisworks选择失败"); } } else { // 选择指定的模型项 bool success = NavisworksSelectionHelper.SetModelSelection(model.NavisworksItem); if (success) { LogManager.Info($"已在Navisworks中选择模型: {model.Name}"); } else { LogManager.Warning($"在Navisworks中选择模型失败: {model.Name}"); } } } catch (Exception ex) { LogManager.Error($"在Navisworks中选择模型失败: {ex.Message}", ex); } } #endregion // 选择状态格式化方法已移至NavisworksSelectionHelper中 #region 场景加载完成事件处理 /// /// 订阅场景加载完成事件 /// private void SubscribeToDocumentModelsEvents() { try { var document = NavisApplication.ActiveDocument; if (document?.Models != null && !_modelsCollectionEventSubscribed) { document.Models.SceneLoaded += OnSceneLoaded; document.Models.CollectionChanged += OnModelsCollectionChanged; _modelsCollectionEventSubscribed = true; LogManager.Info("[ModelSettingsViewModel] 已订阅SceneLoaded和CollectionChanged事件"); } } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 订阅SceneLoaded事件失败: {ex.Message}", ex); } } /// /// 取消场景加载完成事件 /// private void UnsubscribeFromDocumentModelsEvents() { try { if (_modelsCollectionEventSubscribed) { var document = NavisApplication.ActiveDocument; if (document?.Models != null) { document.Models.SceneLoaded -= OnSceneLoaded; document.Models.CollectionChanged -= OnModelsCollectionChanged; } _modelsCollectionEventSubscribed = false; LogManager.Info("[ModelSettingsViewModel] 已取消订阅SceneLoaded和CollectionChanged事件"); } } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 取消订阅SceneLoaded事件失败: {ex.Message}", ex); } } /// /// 场景加载完成事件处理器 /// private async void OnSceneLoaded(object sender, EventArgs e) { // 如果已经释放,直接返回 if (_disposed) return; try { var document = NavisApplication.ActiveDocument; var modelsCount = document?.Models?.Count ?? 0; LogManager.Info($"[ModelSettingsViewModel] 场景加载完成,当前模型数量: {modelsCount}"); // 更新上次模型数量 _lastModelsCount = modelsCount; // 注意:不在 SceneLoaded 事件中直接刷新物流模型列表 // 因为 SceneLoaded 事件可能在模型完全加载之前触发 // 刷新逻辑移到 OnModelsCollectionChanged 中处理 } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 处理场景加载完成事件异常: {ex.Message}", ex); } } /// /// 模型集合变化事件处理器 - 用于检测文档加载完成 /// private async void OnModelsCollectionChanged(object sender, EventArgs e) { // 如果已经释放,直接返回 if (_disposed) return; try { var document = NavisApplication.ActiveDocument; var currentModelsCount = document?.Models?.Count ?? 0; // 检测模型数量从 0 变为 >0,表示文档已加载完成 if (_lastModelsCount == 0 && currentModelsCount > 0) { LogManager.Info($"[ModelSettingsViewModel] 检测到文档加载完成(模型数量: {_lastModelsCount} -> {currentModelsCount})"); // 刷新物流模型列表 await RefreshLogisticsModelsAsync(); } // 更新上次模型数量 _lastModelsCount = currentModelsCount; } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 处理模型集合变化事件异常: {ex.Message}", ex); } } #endregion #region 选择事件处理 /// /// 订阅Navisworks选择变化事件 - 使用新的选择管理服务 /// private void SubscribeToSelectionEvents() { try { // 使用新的选择管理服务订阅选择变化事件 _selectionEventSubscription = NavisworksSelectionHelper.SubscribeToSelectionChanges( OnSelectionChangedAsync, _uiStateManager); LogManager.Info("[ModelSettingsViewModel] 已通过NavisworksSelectionHelper订阅选择变化事件"); } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 订阅选择事件失败: {ex.Message}", ex); } } /// /// 取消订阅Navisworks选择变化事件 - 使用新的选择管理服务 /// private void UnsubscribeFromSelectionEvents() { try { // 通过Dispose方法取消订阅 _selectionEventSubscription?.Dispose(); _selectionEventSubscription = null; LogManager.Info("[ModelSettingsViewModel] 已通过NavisworksSelectionHelper取消订阅选择变化事件"); } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 取消选择事件订阅失败: {ex.Message}", ex); } } /// /// 选择变化事件处理器 - 使用新的选择管理服务 /// private async Task OnSelectionChangedAsync(SelectionStateResult selectionResult) { // 如果已经释放,直接返回 if (_disposed) return; try { // 更新物流属性相关的选择状态(使用新的选择结果) await UpdateModelSelectionStateAsync(selectionResult); LogManager.Debug($"[ModelSettingsViewModel] 选择状态已更新: {selectionResult.Count}个项目"); } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 处理选择变化事件异常: {ex.Message}", ex); } } /// /// 更新模型选择状态 - 使用新的选择管理服务 /// private async Task UpdateModelSelectionStateAsync(SelectionStateResult selectionResult = null) { // 如果已经释放,直接返回 if (_disposed) return; try { // 如果没有提供选择结果,则获取当前选择状态 if (selectionResult == null) { selectionResult = await NavisworksSelectionHelper.GetCurrentSelectionStateAsync(); } // UI更新 - 使用新的选择管理服务格式化选择文本 if (selectionResult.Success) { SelectedModelsText = NavisworksSelectionHelper.FormatSelectionText(selectionResult, "个模型"); } else { SelectedModelsText = selectionResult.ErrorMessage ?? "检查选择状态异常"; } // 🔧 修复:刷新所有与选择相关的命令状态(包括清除属性按钮) OnPropertyChanged(nameof(HasSelectedModels)); OnPropertyChanged(nameof(HasSelectedModelsWithLogisticsAttributes)); OnPropertyChanged(nameof(CanSetLogisticsAttribute)); OnPropertyChanged(nameof(CanClearLogisticsAttribute)); LogManager.Debug($"[ModelSettingsViewModel] 模型选择状态已更新: 成功={selectionResult.Success}, 数量={selectionResult.Count}"); } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 更新模型选择状态异常: {ex.Message}", ex); SelectedModelsText = "检查选择状态异常"; } } #endregion #region 辅助方法 /// /// 异步初始化 /// private async void InitializeAsync() { try { await _uiStateManager.ExecuteUIUpdateAsync(() => { // 初始化物流类别(包括内置和自定义类别) AvailableCategories.Clear(); AvailableCategoryFilters.Clear(); // 先添加"全部"选项到筛选器 AvailableCategoryFilters.Add("全部"); // 从 CategoryAttributeManager 获取所有可用类别(内置 + 自定义) var allCategories = CategoryAttributeManager.GetAllAvailableCategories(); foreach (var category in allCategories) { AvailableCategories.Add(category.DisplayName); AvailableCategoryFilters.Add(category.DisplayName); } // 设置默认选择 if (AvailableCategories.Count > 0 && AvailableCategories.Contains("通道")) { SelectedCategory = "通道"; } else if (AvailableCategories.Count > 0) { SelectedCategory = AvailableCategories[0]; } // 设置默认筛选器为"全部" SelectedCategoryFilter = "全部"; }); // 注意:不在初始化时刷新选择状态和物流模型列表 // 刷新会在以下情况自动触发: // 1. 选择状态 - 通过 NavisworksSelectionHelper 的选择变化事件自动刷新 // 2. 物流模型列表 - 通过 Models.CollectionChanged 事件在文档加载后自动刷新 // 🔧 确保初始化完成后所有Command状态正确 await _uiStateManager.ExecuteUIUpdateAsync(() => { RefreshAllCommands(); UpdateMainStatus("类别设置已就绪"); }); } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 初始化失败: {ex.Message}"); await _uiStateManager.ExecuteUIUpdateAsync(() => { UpdateMainStatus("初始化失败,请检查日志"); }); } } /// /// 应用可见性模式 /// private void ApplyVisibilityMode() { SafeExecute(() => { if (IsLogisticsOnlyMode) { ShowLogisticsOnlyInternal(); } else { // 取消"仅显示物流元素",退出隔离模式 if (VisibilityHelper.ExitIsolation()) { // 更新物流模型列表中的可见性状态 foreach (var model in LogisticsModels) { model.IsVisible = true; } UpdateMainStatus("已恢复可见性状态"); LogManager.Info("[UI-ModelSettings] 退出隔离模式,恢复可见性状态"); } else { // 没有隔离状态,显示全部 VisibilityHelper.ShowAllItems(); UpdateMainStatus("已显示全部元素"); LogManager.Info("[UI-ModelSettings] 没有隔离状态,显示全部"); } } }, "应用可见性模式", runOnUIThread: true); } /// /// 内部方法:仅显示物流元素 /// private void ShowLogisticsOnlyInternal() { try { LogManager.Info("[UI-ModelSettings] 开始仅显示物流元素"); var document = NavisApplication.ActiveDocument; if (document == null || document.Models == null) { LogManager.Warning("[UI-ModelSettings] 没有活动文档"); UpdateMainStatus("没有活动文档"); return; } var logisticsItems = CategoryAttributeManager.GetAllLogisticsItems(); if (logisticsItems == null || logisticsItems.Count == 0) { LogManager.Info("[UI-ModelSettings] 没有找到物流元素"); UpdateMainStatus("未找到物流元素"); return; } LogManager.Info($"[UI-ModelSettings] 找到 {logisticsItems.Count} 个物流元素"); // 进入隔离模式(自动保存当前状态) bool success = VisibilityHelper.EnterIsolation(logisticsItems); if (success) { // 更新物流模型列表中的可见性状态 foreach (var model in LogisticsModels) { model.IsVisible = true; } LogManager.Info($"[UI-ModelSettings] 成功隔离显示物流元素"); UpdateMainStatus($"仅显示物流元素 ({logisticsItems.Count} 个物流节点)"); } else { LogManager.Error("[UI-ModelSettings] 进入隔离模式失败"); UpdateMainStatus("操作失败"); } } catch (Exception ex) { LogManager.Error($"[UI-ModelSettings] 仅显示物流元素失败:{ex.Message}"); UpdateMainStatus($"操作失败:{ex.Message}"); } } /// /// 根据显示名称获取类别ID /// /// 类别显示名称 /// 类别ID,如果未找到返回null private string GetCategoryIdByDisplayName(string displayName) { if (string.IsNullOrEmpty(displayName)) return null; // 从所有可用类别中查找 var allCategories = CategoryAttributeManager.GetAllAvailableCategories(); foreach (var category in allCategories) { if (category.DisplayName == displayName) { return category.Id; } } // 如果没找到匹配,直接返回显示名称(可能是旧数据或其他情况) return displayName; } /// /// 根据类别ID获取显示名称 /// /// 类别ID /// 类别显示名称,如果未找到返回null private string GetDisplayNameByCategoryId(string categoryId) { if (string.IsNullOrEmpty(categoryId)) return null; // 从所有可用类别中查找 var allCategories = CategoryAttributeManager.GetAllAvailableCategories(); foreach (var category in allCategories) { if (category.Id.Equals(categoryId, StringComparison.OrdinalIgnoreCase)) { return category.DisplayName; } } // 如果没找到匹配,直接返回类别ID(可能是旧数据或其他情况) return categoryId; } /// /// 格式化物流属性为显示字符串 /// private string FormatLogisticsAttributes(LogisticsAttributeInfo info) { if (info == null) return "无属性"; // 简单格式化:可通行、优先级、限制等 return $"可通行: {(info.IsTraversable ? "是" : "否")}, " + $"优先级: {info.Priority}, " + $"高度限制: {info.HeightLimit}m, " + $"速度限制: {info.SpeedLimit}m/s"; } private void RefreshAllCommands() { OnPropertyChanged(nameof(CanSetLogisticsAttribute)); OnPropertyChanged(nameof(CanClearLogisticsAttribute)); OnPropertyChanged(nameof(HasSelectedModels)); OnPropertyChanged(nameof(HasSelectedModelsWithLogisticsAttributes)); // 🔧 强制WPF重新查询所有Command的CanExecute状态 System.Windows.Input.CommandManager.InvalidateRequerySuggested(); } /// /// 聚焦到物流模型 /// public void FocusOnLogisticsModel(LogisticsModel logisticsModel) { if (logisticsModel?.NavisworksItem == null) return; try { // 聚焦到模型(斜上方60度视角) ViewpointHelper.FocusOnModelItem(logisticsModel.NavisworksItem, ViewpointHelper.ViewpointStrategy.ModelFocus); UpdateMainStatus($"已聚焦到物流模型: {logisticsModel.Name}"); LogManager.Info($"聚焦到物流模型: {logisticsModel.Name}, 类别: {logisticsModel.Category}"); } catch (Exception ex) { LogManager.Error($"聚焦到物流模型失败: {ex.Message}", ex); UpdateMainStatus($"聚焦失败: {ex.Message}"); } } #endregion #region 向后兼容性接口 /// /// 向后兼容:提供UIStateManager访问接口 /// public UIStateManager UIStateManager => _uiStateManager; /// /// 验证ViewModel状态是否正常 /// public bool IsValidState() { return _uiStateManager != null && AvailableCategories != null && LogisticsModels != null && PriorityLevels != null; } /// /// 获取ViewModel状态信息 /// public string GetStateInfo() { return $"UIStateManager: {(_uiStateManager != null ? "已初始化" : "未初始化")}, " + $"可用类别数量: {AvailableCategories?.Count ?? 0}, " + $"物流模型数量: {LogisticsModels?.Count ?? 0}"; } /// /// 释放资源 /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// 释放资源的具体实现 /// /// 是否正在释放托管资源 protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { try { // 取消选择事件订阅 UnsubscribeFromSelectionEvents(); // 取消文档模型集合事件订阅 UnsubscribeFromDocumentModelsEvents(); // 取消配置变更事件订阅 UnsubscribeFromConfigChanges(); LogManager.Info("[ModelSettingsViewModel] 资源清理完成"); } catch (Exception ex) { LogManager.Error($"[ModelSettingsViewModel] 资源清理失败: {ex.Message}"); } } _disposed = true; } } #endregion } }