更新了版本,删掉2个测试按钮
This commit is contained in:
parent
cddb7de71e
commit
531e07f25d
142
CHANGELOG.md
142
CHANGELOG.md
@ -1,5 +1,147 @@
|
||||
# NavisworksTransport 变更日志
|
||||
|
||||
## [0.7.0] - 2025-08-18
|
||||
|
||||
### 🎯 分层管理功能完整实现 - WPF架构重构与线程安全解决方案
|
||||
|
||||
#### 核心功能突破
|
||||
|
||||
**🔥 分层管理页签 - 全新WPF实现**
|
||||
|
||||
- **WPF UI架构重构**
|
||||
- 完全使用WPF替代WinForms,实现现代化用户界面
|
||||
- 采用MVVM架构模式,实现业务逻辑与UI分离
|
||||
- 集成ThreadSafeObservableCollection确保跨线程集合操作安全
|
||||
- 使用RelayCommand实现统一的命令模式
|
||||
|
||||
- **分层预览功能**
|
||||
- 实现智能楼层分析,支持按楼层和按自定义属性分层
|
||||
- 支持1级、2级、3级、全部四种遍历深度选择
|
||||
- 提供实时预览结果,显示分层名称、对象数量、估算文件大小
|
||||
- 缓存机制优化,避免重复分析提升性能
|
||||
|
||||
- **分层保存功能**
|
||||
- 批量导出功能,支持一键保存所有分层到指定目录
|
||||
- 智能文件命名:项目名_分层名_时间戳格式
|
||||
- 支持NWD导出选项配置(嵌入纹理、阻止对象属性导出等)
|
||||
- 完整的进度显示和错误处理机制
|
||||
|
||||
- **保存当前选择项功能**
|
||||
- 支持多选节点的智能导出
|
||||
- 包含子节点选项,完整保存节点层次结构
|
||||
- 自动生成默认文件名,支持多选节点描述
|
||||
- 智能可见性控制,只导出相关项目
|
||||
|
||||
#### 重大技术突破
|
||||
|
||||
**🔧 Navisworks API线程安全解决方案**
|
||||
|
||||
- **根本问题解决**:修复了分层保存时程序崩溃的线程安全问题
|
||||
- 发现Navisworks API(COM组件)必须在主UI线程(STA线程)中执行
|
||||
- 对比分析"保存当前选择项"(成功)vs"分层保存"(崩溃)的线程差异
|
||||
- 使用`System.Windows.Application.Current.Dispatcher.Invoke()`确保API调用线程安全
|
||||
|
||||
- **API调用模式修复**:
|
||||
```csharp
|
||||
// ❌ 问题代码:后台线程调用导致崩溃
|
||||
document.ExportToNwd(outputPath, exportOptions);
|
||||
|
||||
// ✅ 修复代码:确保主线程执行
|
||||
Dispatcher.Invoke(() => {
|
||||
document.ExportToNwd(outputPath, exportOptions);
|
||||
});
|
||||
```
|
||||
|
||||
- **线程状态诊断**:
|
||||
- 添加线程状态检查(STA/MTA)和日志记录
|
||||
- 实现线程安全的异常处理机制
|
||||
- 建立完整的API调用最佳实践
|
||||
|
||||
#### 业务逻辑架构
|
||||
|
||||
**🔧 SimplifiedModelSplitterManager - 轻量级分层管理器**
|
||||
|
||||
- **核心功能模块**:
|
||||
- 楼层检测和分析:集成FloorDetector实现智能楼层识别
|
||||
- 属性分组:支持按自定义属性进行模型分组
|
||||
- 预览生成:提供分层预览结果,包含项目统计和元数据
|
||||
- 批量导出:支持多分层同时导出,完整的错误处理
|
||||
|
||||
- **性能优化**:
|
||||
- 双重缓存策略:分层结果缓存和深度控制缓存
|
||||
- 智能可见性控制:只操作顶级节点,避免全模型遍历
|
||||
- 内存管理:大量模型项时自动垃圾回收
|
||||
|
||||
#### UI架构技术细节
|
||||
|
||||
**🔧 LayerManagementViewModel - MVVM架构实现**
|
||||
|
||||
- **线程安全UI更新**:
|
||||
- 集成UIStateManager实现安全的跨线程UI更新
|
||||
- 使用ThreadSafeObservableCollection避免集合操作异常
|
||||
- 实现SetPropertyThreadSafe方法确保属性更新安全
|
||||
|
||||
- **Command模式应用**:
|
||||
- AnalyzeFloorsCommand:楼层分析命令
|
||||
- PreviewSplitCommand:分层预览命令
|
||||
- ExecuteSplitCommand:分层保存命令
|
||||
- SaveSelectedItemsCommand:选择项保存命令
|
||||
|
||||
- **异步操作管理**:
|
||||
- 正确的业务逻辑与UI分离模式
|
||||
- 四步骤异步操作:初始UI更新→业务逻辑执行→结果UI更新→状态清理
|
||||
- 完善的异常处理和状态恢复机制
|
||||
|
||||
#### API使用方法文档更新
|
||||
|
||||
**📚 线程安全章节补充**
|
||||
|
||||
- **实际案例记录**:将此次线程安全问题解决方案完整记录
|
||||
- **最佳实践模式**:提供线程安全的Navisworks API调用模式
|
||||
- **常见问题对照表**:线程问题症状、原因、解决方案
|
||||
- **代码示例**:完整的线程安全API调用示例
|
||||
|
||||
#### 技术架构成果
|
||||
|
||||
**架构质量提升**
|
||||
|
||||
- **完整MVVM实现**:ViewModels、Views、Models分离,代码结构清晰
|
||||
- **线程安全保障**:解决COM API线程安全问题,确保稳定性
|
||||
- **异常处理完善**:多层次异常处理,优雅降级机制
|
||||
- **性能优化显著**:缓存机制和智能算法,处理大模型性能提升
|
||||
|
||||
**用户体验改进**
|
||||
|
||||
- **现代化界面**:WPF界面美观且响应流畅
|
||||
- **操作简化**:一键预览、一键导出,操作门槛降低
|
||||
- **反馈完善**:实时进度显示、详细状态提示
|
||||
- **容错能力强**:异常情况自动恢复,不影响其他功能
|
||||
|
||||
### 验证结果 ✅
|
||||
|
||||
- ✅ 分层预览功能完全正常,支持多种分层策略
|
||||
- ✅ 分层保存功能稳定运行,无崩溃问题
|
||||
- ✅ 保存当前选择项功能完善,支持多选节点
|
||||
- ✅ 线程安全问题彻底解决,API调用稳定
|
||||
- ✅ WPF UI响应流畅,用户体验良好
|
||||
- ✅ 所有功能完整测试通过,系统稳定性达标
|
||||
|
||||
### 技术文档更新
|
||||
|
||||
- ✅ `NavisworksAPI使用方法.md` 补充线程安全章节
|
||||
- ✅ 记录实际问题解决过程和技术方案
|
||||
- ✅ 提供完整的最佳实践代码示例
|
||||
- ✅ 建立线程安全问题诊断和解决流程
|
||||
|
||||
### 开发里程碑
|
||||
|
||||
- **分层管理功能**:从概念到完整实现,涵盖预览、保存、选择项导出
|
||||
- **WPF架构重构**:完全现代化的UI架构和MVVM模式
|
||||
- **线程安全解决**:深入理解COM API特性,建立稳定的调用模式
|
||||
- **技术文档完善**:经验总结和最佳实践,为后续开发铺路
|
||||
|
||||
---
|
||||
|
||||
## [0.6.0] - 2025-08-17
|
||||
|
||||
### 🎯 UI架构重构重大突破 - 线程安全与稳定性全面提升
|
||||
|
||||
@ -1 +1 @@
|
||||
0.6.0
|
||||
0.7.0
|
||||
@ -275,7 +275,176 @@ public void ExportSelectedNodes(List<ModelItem> selectedItems, string filePath)
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 常用属性和方法速查
|
||||
## 8. 线程安全 - 关键重要
|
||||
|
||||
### 8.1 Navisworks API 线程安全要求
|
||||
|
||||
**核心原则:所有 Navisworks API 调用必须在主 UI 线程(STA 线程)中执行**
|
||||
|
||||
```csharp
|
||||
// ❌ 错误:在后台线程中调用 Navisworks API
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var document = Application.ActiveDocument; // 可能崩溃
|
||||
document.ExportToNwd(path, options); // 会崩溃
|
||||
});
|
||||
|
||||
// ✅ 正确:使用 Dispatcher.Invoke 确保主线程执行
|
||||
await Task.Run(() =>
|
||||
{
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var document = Application.ActiveDocument;
|
||||
document.ExportToNwd(path, options); // 安全执行
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 8.2 实际案例:分层导出修复
|
||||
|
||||
**问题场景**:`SimplifiedModelSplitterManager.ExportLayerToNwd` 方法通过后台线程调用时崩溃
|
||||
|
||||
```csharp
|
||||
// ❌ 问题代码:导致崩溃
|
||||
public bool ExportLayerToNwd(...)
|
||||
{
|
||||
var document = NavisApplication.ActiveDocument;
|
||||
document.ExportToNwd(outputPath, exportOptions); // 后台线程崩溃
|
||||
}
|
||||
```
|
||||
|
||||
**修复方案**:使用 Dispatcher.Invoke 包装所有 API 调用
|
||||
|
||||
```csharp
|
||||
// ✅ 修复代码:线程安全
|
||||
public bool ExportLayerToNwd(...)
|
||||
{
|
||||
bool exportResult = false;
|
||||
Exception exportException = null;
|
||||
|
||||
// 确保在主线程中执行所有 Navisworks API 调用
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var document = NavisApplication.ActiveDocument;
|
||||
|
||||
// 保存可见性状态
|
||||
var originalVisibilityState = SaveCurrentVisibilityState(document);
|
||||
|
||||
try
|
||||
{
|
||||
// 隐藏不需要的项目
|
||||
var itemsToHide = GetItemsToHide(...);
|
||||
document.Models.SetHidden(itemsToHide, true);
|
||||
|
||||
// 创建导出选项
|
||||
var exportOptions = new NwdExportOptions
|
||||
{
|
||||
ExcludeHiddenItems = true,
|
||||
EmbedXrefs = false,
|
||||
PreventObjectPropertyExport = false
|
||||
};
|
||||
|
||||
// 在主线程中安全执行导出
|
||||
document.ExportToNwd(outputPath, exportOptions);
|
||||
exportResult = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 恢复可见性状态
|
||||
RestoreVisibilityState(document, originalVisibilityState);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exportException = ex;
|
||||
}
|
||||
});
|
||||
|
||||
if (exportException != null)
|
||||
throw exportException;
|
||||
|
||||
return exportResult;
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 线程安全检查和诊断
|
||||
|
||||
```csharp
|
||||
// ✅ 检查当前线程状态
|
||||
var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState();
|
||||
LogManager.Info($"当前线程状态: {apartmentState}"); // 应该是 STA
|
||||
|
||||
if (apartmentState != System.Threading.ApartmentState.STA)
|
||||
{
|
||||
LogManager.Warning("警告:不在STA线程中,API调用可能失败");
|
||||
}
|
||||
|
||||
// ✅ 验证是否在主线程中
|
||||
bool isMainThread = System.Windows.Application.Current.Dispatcher.CheckAccess();
|
||||
if (!isMainThread)
|
||||
{
|
||||
LogManager.Warning("警告:不在主线程中,需要使用Dispatcher.Invoke");
|
||||
}
|
||||
```
|
||||
|
||||
### 8.4 常见线程安全问题和解决方案
|
||||
|
||||
| 问题场景 | 症状 | 解决方案 |
|
||||
|---------|------|---------|
|
||||
| 后台线程调用 API | 程序崩溃,无错误信息 | 使用 `Dispatcher.Invoke()` |
|
||||
| Command.ExecuteAsync() | Task 中的 API 调用崩溃 | 在 Task 内部使用 Dispatcher |
|
||||
| 异步方法调用 API | 间歇性崩溃 | 检查执行线程,确保主线程 |
|
||||
| Timer 中调用 API | 定时器触发时崩溃 | Timer 回调使用 Dispatcher |
|
||||
|
||||
### 8.5 最佳实践模式
|
||||
|
||||
```csharp
|
||||
// ✅ 推荐模式:安全的异步 Navisworks API 调用
|
||||
public async Task<bool> SafeNavisworksOperationAsync()
|
||||
{
|
||||
// 1. 后台准备数据
|
||||
var preparedData = await Task.Run(() =>
|
||||
{
|
||||
// 在后台线程中进行数据准备(不涉及 Navisworks API)
|
||||
return PrepareDataSafely();
|
||||
});
|
||||
|
||||
// 2. 主线程执行 API 调用
|
||||
bool result = false;
|
||||
await System.Windows.Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
// 所有 Navisworks API 调用都在主线程中
|
||||
var document = Application.ActiveDocument;
|
||||
result = document.SomeNavisworksOperation(preparedData);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ✅ 推荐模式:批量 API 操作
|
||||
public void BatchNavisworksOperations(List<ModelItem> items)
|
||||
{
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var document = Application.ActiveDocument;
|
||||
|
||||
// 批量操作,避免多次线程切换
|
||||
var itemCollection = new ModelItemCollection();
|
||||
foreach (var item in items)
|
||||
{
|
||||
itemCollection.Add(item);
|
||||
}
|
||||
|
||||
// 一次性完成所有操作
|
||||
document.Models.SetHidden(itemCollection, true);
|
||||
document.CurrentSelection.CopyFrom(itemCollection);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 常用属性和方法速查
|
||||
|
||||
### ModelItem 常用属性
|
||||
- `HasGeometry` - 是否有几何体
|
||||
@ -301,16 +470,19 @@ public void ExportSelectedNodes(List<ModelItem> selectedItems, string filePath)
|
||||
- `SetRequired(ModelItemCollection items, bool required)` - 设置必需状态
|
||||
- `RootItemDescendantsAndSelf` - 所有根项目的后代
|
||||
|
||||
## 9. 错误避免指南
|
||||
## 10. 错误避免指南
|
||||
|
||||
1. **不要使用不存在的API**:如 `SearchCondition.HasAncestor`
|
||||
2. **避免深度递归**:使用内置的 `DescendantsAndSelf` 代替手写递归
|
||||
3. **批量操作**:使用 `ModelItemCollection` 进行批量设置,而不是逐个操作
|
||||
4. **正确的命名空间**:确保引用 `using Autodesk.Navisworks.Api;`
|
||||
5. **异常处理**:文件操作和API调用要适当处理异常
|
||||
6. **资源清理**:隐藏操作后要恢复原始状态
|
||||
1. **线程安全是第一要务**:所有 Navisworks API 调用必须在主 UI 线程中执行
|
||||
2. **不要使用不存在的API**:如 `SearchCondition.HasAncestor`
|
||||
3. **避免深度递归**:使用内置的 `DescendantsAndSelf` 代替手写递归
|
||||
4. **批量操作**:使用 `ModelItemCollection` 进行批量设置,而不是逐个操作
|
||||
5. **正确的命名空间**:确保引用 `using Autodesk.Navisworks.Api;`
|
||||
6. **异常处理**:文件操作和API调用要适当处理异常
|
||||
7. **资源清理**:隐藏操作后要恢复原始状态
|
||||
8. **线程状态检查**:在关键操作前验证线程状态(STA)
|
||||
9. **Dispatcher 模式**:后台线程中需要调用 API 时,始终使用 Dispatcher.Invoke
|
||||
|
||||
## 10. 参考官方示例
|
||||
## 11. 参考官方示例
|
||||
|
||||
强烈建议查看以下官方示例了解更多用法:
|
||||
- `SearchComparisonPlugIn.cs` - 搜索性能对比
|
||||
|
||||
@ -13,6 +13,10 @@
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<TabControl Grid.Row="0" Name="MainTabControl" Margin="5">
|
||||
<TabItem Header="分层管理" Name="LayerManagementTab">
|
||||
<ContentControl x:Name="LayerManagementContent"/>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="类别设置" Name="ModelSettingsTab">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Margin="10">
|
||||
@ -213,10 +217,6 @@
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="分层管理" Name="LayerManagementTab">
|
||||
<ContentControl x:Name="LayerManagementContent"/>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="系统管理" Name="SystemManagementTab">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Margin="10">
|
||||
|
||||
@ -408,9 +408,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
public ICommand BrowseOutputDirectoryCommand { get; private set; }
|
||||
public ICommand SaveSelectedItemsCommand { get; private set; }
|
||||
public ICommand CancelOperationCommand { get; private set; }
|
||||
public ICommand TestExportCommand { get; private set; }
|
||||
public ICommand DiagnosticCommand { get; private set; }
|
||||
public ICommand SimpleSaveCommand { get; private set; }
|
||||
public ICommand TestExportToNwdCommand { get; private set; }
|
||||
|
||||
#endregion
|
||||
@ -503,18 +501,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
CancelOperationCommand = new RelayCommand(CancelOperation, () => IsProcessing);
|
||||
|
||||
TestExportCommand = new RelayCommand(
|
||||
async () => await TestExportAsync(),
|
||||
() => IsNotProcessing);
|
||||
|
||||
DiagnosticCommand = new RelayCommand(
|
||||
async () => await RunDiagnosticAsync(),
|
||||
() => IsNotProcessing);
|
||||
|
||||
SimpleSaveCommand = new RelayCommand(
|
||||
async () => await SimpleSaveAsync(),
|
||||
() => IsNotProcessing);
|
||||
|
||||
TestExportToNwdCommand = new RelayCommand(
|
||||
async () => await TestExportToNwdAsync(),
|
||||
() => IsNotProcessing);
|
||||
@ -1231,11 +1221,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
LogManager.Info($"[LayerManagementViewModel] 已重新选择 {originalSelection.Count} 个目标节点");
|
||||
|
||||
// 创建导出选项 - 只导出可见项目
|
||||
// 创建导出选项 - 使用用户配置的参数
|
||||
var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions();
|
||||
exportOptions.ExcludeHiddenItems = true; // 只导出可见项目(选中节点及其子项)
|
||||
exportOptions.EmbedXrefs = false;
|
||||
exportOptions.PreventObjectPropertyExport = false;
|
||||
exportOptions.EmbedXrefs = EmbedXrefs;
|
||||
exportOptions.PreventObjectPropertyExport = PreventObjectPropertyExport;
|
||||
|
||||
LogManager.Info($"[LayerManagementViewModel] SaveSelectedItems导出选项: EmbedXrefs={exportOptions.EmbedXrefs}, PreventObjectPropertyExport={exportOptions.PreventObjectPropertyExport}");
|
||||
|
||||
LogManager.Info("[LayerManagementViewModel] 开始调用ExportToNwd API");
|
||||
|
||||
@ -1356,123 +1348,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试导出功能 - 使用简化模式,避免崩溃
|
||||
/// </summary>
|
||||
private async Task TestExportAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info("[LayerManagementViewModel] 开始简化测试导出");
|
||||
|
||||
// 1. 简单状态更新
|
||||
IsProcessing = true;
|
||||
|
||||
// 2. 获取保存路径
|
||||
string saveFilePath = null;
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var saveDialog = new Microsoft.Win32.SaveFileDialog
|
||||
{
|
||||
Title = "测试导出 - 选择保存位置",
|
||||
Filter = "Navisworks文件 (*.nwd)|*.nwd",
|
||||
DefaultExt = "nwd",
|
||||
FileName = $"测试导出_{DateTime.Now:yyyyMMdd_HHmmss}.nwd"
|
||||
};
|
||||
|
||||
if (saveDialog.ShowDialog() == true)
|
||||
{
|
||||
saveFilePath = saveDialog.FileName;
|
||||
}
|
||||
});
|
||||
|
||||
if (string.IsNullOrEmpty(saveFilePath))
|
||||
{
|
||||
LogManager.Info("[LayerManagementViewModel] 用户取消了测试导出");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 使用SimplifiedModelSplitterManager进行基础测试导出
|
||||
bool exportResult = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try
|
||||
{
|
||||
LogManager.Info($"[LayerManagementViewModel] 开始测试导出到: {saveFilePath}");
|
||||
|
||||
// 使用最简单的导出测试,不使用复杂的分层逻辑
|
||||
exportResult = PerformSimpleExportTest(saveFilePath);
|
||||
|
||||
LogManager.Info($"[LayerManagementViewModel] TestBasicExport调用完成,结果: {exportResult}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[LayerManagementViewModel] 测试导出异常: {ex.Message}", ex);
|
||||
errorMessage = ex.Message;
|
||||
exportResult = false;
|
||||
}
|
||||
|
||||
// 4. 简单的结果显示
|
||||
if (exportResult)
|
||||
{
|
||||
if (File.Exists(saveFilePath))
|
||||
{
|
||||
var fileInfo = new FileInfo(saveFilePath);
|
||||
MessageBox.Show(
|
||||
$"测试导出成功!\n\n文件路径: {saveFilePath}\n文件大小: {fileInfo.Length / 1024} KB\n创建时间: {fileInfo.CreationTime}\n\n这说明基础导出功能正常工作!",
|
||||
"测试导出结果", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("测试导出操作完成,但文件不存在。", "测试导出结果", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show($"测试导出失败!\n\n错误信息: {errorMessage}\n\n请检查日志了解详细信息。",
|
||||
"测试导出结果", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
LogManager.Info("[LayerManagementViewModel] 简化测试导出完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[LayerManagementViewModel] 测试导出过程异常: {ex.Message}", ex);
|
||||
MessageBox.Show($"测试导出过程异常: {ex.Message}", "测试导出错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 5. 简单的状态清理
|
||||
IsProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示测试导出结果消息框
|
||||
/// </summary>
|
||||
private void ShowTestExportResult(bool isSuccess, string message, string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (isSuccess)
|
||||
{
|
||||
var successMessage = $"测试导出成功!\n\n{message}\n\n文件位置: {filePath}";
|
||||
MessageBox.Show(successMessage, "测试导出结果", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorMessage = $"测试导出失败!\n\n{message}\n\n请检查日志了解详细错误信息。";
|
||||
MessageBox.Show(errorMessage, "测试导出结果", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
}));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[LayerManagementViewModel] 显示测试导出结果失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行环境诊断 - 检查Navisworks API环境
|
||||
@ -1616,207 +1492,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最简单的保存方法 - 直接保存当前模型
|
||||
/// </summary>
|
||||
private async Task SimpleSaveAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info("[LayerManagementViewModel] 开始简单保存");
|
||||
|
||||
// 1. 简单状态更新
|
||||
IsProcessing = true;
|
||||
|
||||
// 2. 获取保存路径
|
||||
string saveFilePath = null;
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var saveDialog = new Microsoft.Win32.SaveFileDialog
|
||||
{
|
||||
Title = "保存当前模型",
|
||||
Filter = "Navisworks文件 (*.nwd)|*.nwd",
|
||||
DefaultExt = "nwd",
|
||||
FileName = $"当前模型_{DateTime.Now:yyyyMMdd_HHmmss}.nwd"
|
||||
};
|
||||
|
||||
if (saveDialog.ShowDialog() == true)
|
||||
{
|
||||
saveFilePath = saveDialog.FileName;
|
||||
}
|
||||
});
|
||||
|
||||
if (string.IsNullOrEmpty(saveFilePath))
|
||||
{
|
||||
LogManager.Info("[LayerManagementViewModel] 用户取消了保存操作");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 最简单的保存操作 - 在主UI线程中直接执行,避免线程问题
|
||||
bool saveResult = false;
|
||||
string errorMessage = "";
|
||||
|
||||
try
|
||||
{
|
||||
LogManager.Info($"[LayerManagementViewModel] 开始保存到: {saveFilePath}");
|
||||
|
||||
// 获取当前文档
|
||||
var document = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||
if (document == null)
|
||||
{
|
||||
errorMessage = "没有活动文档";
|
||||
saveResult = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info($"[LayerManagementViewModel] 当前文档: {document.FileName ?? "未命名"}");
|
||||
LogManager.Info($"[LayerManagementViewModel] 模型数量: {document.Models?.Count ?? 0}");
|
||||
|
||||
// 最基本的保存调用 - 在主线程中执行
|
||||
document.SaveFile(saveFilePath, Autodesk.Navisworks.Api.DocumentFileVersion.Current);
|
||||
|
||||
saveResult = true;
|
||||
LogManager.Info($"[LayerManagementViewModel] SaveFile调用完成");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[LayerManagementViewModel] 保存异常: {ex.Message}", ex);
|
||||
errorMessage = ex.Message;
|
||||
saveResult = false;
|
||||
}
|
||||
|
||||
// 4. 简单的结果显示 - 避免复杂的UI更新
|
||||
if (saveResult)
|
||||
{
|
||||
if (File.Exists(saveFilePath))
|
||||
{
|
||||
var fileInfo = new FileInfo(saveFilePath);
|
||||
MessageBox.Show(
|
||||
$"保存成功!\n\n文件路径: {saveFilePath}\n文件大小: {fileInfo.Length / 1024} KB\n创建时间: {fileInfo.CreationTime}",
|
||||
"保存结果", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("保存操作完成,但文件不存在。", "保存结果", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show($"保存失败!\n\n错误信息: {errorMessage}\n\n这可能说明基础的Navisworks API调用有问题。",
|
||||
"保存结果", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
LogManager.Info("[LayerManagementViewModel] 简单保存完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[LayerManagementViewModel] 简单保存异常: {ex.Message}", ex);
|
||||
MessageBox.Show($"保存过程异常: {ex.Message}", "保存错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 5. 简单的状态清理
|
||||
IsProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行最简单的导出测试 - 只选择前几个模型项
|
||||
/// </summary>
|
||||
private bool PerformSimpleExportTest(string saveFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info("[LayerManagementViewModel] 开始执行简单导出测试");
|
||||
|
||||
// 获取当前文档
|
||||
var document = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||
if (document?.Models?.Count == 0)
|
||||
{
|
||||
LogManager.Error("[LayerManagementViewModel] 没有活动文档或模型");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 保存当前选择状态
|
||||
var originalSelection = new List<ModelItem>();
|
||||
foreach (ModelItem item in document.CurrentSelection.SelectedItems)
|
||||
{
|
||||
originalSelection.Add(item);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 清空当前选择
|
||||
document.CurrentSelection.Clear();
|
||||
|
||||
// 获取根节点的前5个子项进行测试
|
||||
int itemCount = 0;
|
||||
|
||||
LogManager.Info($"[LayerManagementViewModel] 模型数量: {document.Models.Count}");
|
||||
|
||||
// 遍历所有模型的根项
|
||||
foreach (Model model in document.Models)
|
||||
{
|
||||
if (itemCount >= 5) break;
|
||||
|
||||
var rootItem = model.RootItem;
|
||||
LogManager.Info($"[LayerManagementViewModel] 处理模型: {model.FileName},根项: {rootItem.DisplayName}");
|
||||
|
||||
foreach (ModelItem child in rootItem.Children)
|
||||
{
|
||||
if (itemCount >= 5) break;
|
||||
|
||||
try
|
||||
{
|
||||
document.CurrentSelection.Add(child);
|
||||
LogManager.Info($"[LayerManagementViewModel] 已选择项目 #{itemCount + 1}: {child.DisplayName}");
|
||||
itemCount++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[LayerManagementViewModel] 跳过无效项目: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (itemCount == 0)
|
||||
{
|
||||
LogManager.Error("[LayerManagementViewModel] 没有找到可用的模型项");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogManager.Info($"[LayerManagementViewModel] 已选择 {itemCount} 个模型项,开始导出");
|
||||
|
||||
// 直接导出选择的项目,使用最基本的API
|
||||
document.SaveFile(saveFilePath, Autodesk.Navisworks.Api.DocumentFileVersion.Current);
|
||||
|
||||
LogManager.Info("[LayerManagementViewModel] 简单导出测试完成");
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 恢复原始选择
|
||||
document.CurrentSelection.Clear();
|
||||
foreach (ModelItem item in originalSelection)
|
||||
{
|
||||
try
|
||||
{
|
||||
document.CurrentSelection.Add(item);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[LayerManagementViewModel] 恢复选择项时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[LayerManagementViewModel] 简单导出测试异常: {ex.Message}", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试ExportToNwd API - 专门的导出API
|
||||
@ -1992,11 +1668,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
document.CurrentSelection.Add(targetItem);
|
||||
LogManager.Info($"[LayerManagementViewModel] 已选择目标节点: {targetItem.DisplayName}");
|
||||
|
||||
// 创建导出选项 - 只导出可见项目
|
||||
// 创建导出选项 - 使用用户配置的参数
|
||||
var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions();
|
||||
exportOptions.ExcludeHiddenItems = true; // 只导出可见项目(目标节点及其子项)
|
||||
exportOptions.EmbedXrefs = false;
|
||||
exportOptions.PreventObjectPropertyExport = false;
|
||||
exportOptions.EmbedXrefs = EmbedXrefs;
|
||||
exportOptions.PreventObjectPropertyExport = PreventObjectPropertyExport;
|
||||
|
||||
LogManager.Info($"[LayerManagementViewModel] TestExportToNwd导出选项: EmbedXrefs={exportOptions.EmbedXrefs}, PreventObjectPropertyExport={exportOptions.PreventObjectPropertyExport}");
|
||||
|
||||
LogManager.Info("[LayerManagementViewModel] 开始调用ExportToNwd API");
|
||||
|
||||
|
||||
@ -177,6 +177,11 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
|
||||
IsChecked="{Binding EmbedXrefs}"
|
||||
Margin="0,0,0,5"
|
||||
ToolTip="将外部引用和纹理数据嵌入到导出的NWD文件中"/>
|
||||
<TextBlock Text="⚠️ 注意:嵌入纹理数据可能导致导出失败或程序崩溃,建议在小模型上测试"
|
||||
Style="{StaticResource StatusTextStyle}"
|
||||
Foreground="#FFFF6600"
|
||||
FontStyle="Italic"
|
||||
Margin="0,0,0,8"/>
|
||||
<CheckBox Content="阻止导出对象特性"
|
||||
IsChecked="{Binding PreventObjectPropertyExport}"
|
||||
Margin="0,0,0,5"
|
||||
@ -302,15 +307,6 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
|
||||
Command="{Binding DiagnosticCommand}"
|
||||
ToolTip="检查Navisworks API环境和线程状态"
|
||||
Background="#FFFFD700"/>
|
||||
<Button Content="简单保存"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Command="{Binding SimpleSaveCommand}"
|
||||
ToolTip="直接保存当前模型为NWD"
|
||||
Background="#FFAAFFAA"/>
|
||||
<Button Content="测试导出"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Command="{Binding TestExportCommand}"
|
||||
ToolTip="导出5个模型项验证基础功能"/>
|
||||
<Button Content="复杂导出测试"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Command="{Binding TestExportToNwdCommand}"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user