12 KiB
12 KiB
Navisworks 2017 API 使用指南
概述
本指南基于实际项目开发经验,汇总了Navisworks 2017 API的核心用法和最佳实践。重点覆盖COM API的属性操作功能,为插件开发提供实用的参考。
目录
环境配置
必需引用
<!-- 项目文件中的引用 -->
<Reference Include="Autodesk.Navisworks.Api" />
<Reference Include="Autodesk.Navisworks.ComApi" />
<Reference Include="Autodesk.Navisworks.Interop.ComApi" />
<Reference Include="Autodesk.Navisworks.Interop.ComApiAutomation" />
命名空间导入
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Plugins;
using ComApi = Autodesk.Navisworks.Api.Interop.ComApi;
using ComApiBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge;
COM API 基础
COM API 状态对象获取
// 获取COM API状态对象 - 这是所有COM操作的入口点
ComApi.InwOpState10 state = ComApiBridge.State;
.NET 对象与 COM 对象转换
// ModelItem 转换为 COM Path
ComApi.InwOaPath3 comPath = (ComApi.InwOaPath3)ComApiBridge.ToInwOaPath(modelItem);
// ModelItemCollection 转换为 COM Selection
ComApi.InwOpSelection comSelection = ComApiBridge.ToInwOpSelection(modelItems);
属性节点获取
// 获取模型项的属性节点
ComApi.InwGUIPropertyNode2 propertyNode =
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(comPath, false);
属性操作 API
1. 创建用户定义属性
基本创建流程
public static void CreateUserDefinedProperty(ModelItem item, string categoryName,
Dictionary<string, string> properties)
{
// 1. 获取COM API状态对象
ComApi.InwOpState10 state = ComApiBridge.State;
// 2. 转换ModelItem为COM路径
ComApi.InwOaPath3 path = (ComApi.InwOaPath3)ComApiBridge.ToInwOaPath(item);
// 3. 获取属性节点
ComApi.InwGUIPropertyNode2 propertyNode =
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
// 4. 创建属性类别容器
ComApi.InwOaPropertyVec propertyCategory = (ComApi.InwOaPropertyVec)state.ObjectFactory(
ComApi.nwEObjectType.eObjectType_nwOaPropertyVec, null, null);
// 5. 添加具体属性
foreach (var kvp in properties)
{
AddProperty(state, propertyCategory, kvp.Key, kvp.Value, kvp.Key + "_Internal");
}
// 6. 设置用户定义属性 (index=0表示创建新类别)
propertyNode.SetUserDefined(0, categoryName, categoryName + "_Internal", propertyCategory);
}
// 辅助方法:添加单个属性到类别
private static void AddProperty(ComApi.InwOpState10 state,
ComApi.InwOaPropertyVec propertyCategory,
string displayName, string value, string internalName)
{
ComApi.InwOaProperty property = (ComApi.InwOaProperty)state.ObjectFactory(
ComApi.nwEObjectType.eObjectType_nwOaProperty, null, null);
property.name = internalName; // 内部名称
property.UserName = displayName; // 显示名称
property.value = value; // 属性值
propertyCategory.Properties().Add(property);
}
关键参数说明
- index=0: 创建新的用户定义属性类别
- categoryName: 属性类别的显示名称
- internalName: 属性类别的内部名称(建议添加"_Internal"后缀)
2. 修改用户定义属性
查找现有属性索引
private static int FindUserDefinedPropertyIndex(ComApi.InwGUIPropertyNode2 propertyNode,
string categoryName)
{
int index = 0;
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
{
if (attribute.UserDefined && attribute.ClassUserName == categoryName)
{
return index;
}
index++;
}
return -1; // 未找到
}
修改现有属性
public static void UpdateUserDefinedProperty(ModelItem item, string categoryName,
Dictionary<string, string> newProperties)
{
ComApi.InwOpState10 state = ComApiBridge.State;
ComApi.InwOaPath3 path = (ComApi.InwOaPath3)ComApiBridge.ToInwOaPath(item);
ComApi.InwGUIPropertyNode2 propertyNode =
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
// 查找现有属性类别的索引
int existingIndex = FindUserDefinedPropertyIndex(propertyNode, categoryName);
if (existingIndex >= 0)
{
// 创建新的属性集合
ComApi.InwOaPropertyVec newPropertyCategory = (ComApi.InwOaPropertyVec)state.ObjectFactory(
ComApi.nwEObjectType.eObjectType_nwOaPropertyVec, null, null);
// 添加新的属性值
foreach (var kvp in newProperties)
{
AddProperty(state, newPropertyCategory, kvp.Key, kvp.Value, kvp.Key + "_Internal");
}
// 使用现有索引覆盖属性类别
propertyNode.SetUserDefined(existingIndex, categoryName,
categoryName + "_Internal", newPropertyCategory);
}
else
{
// 如果不存在,则创建新的
CreateUserDefinedProperty(item, categoryName, newProperties);
}
}
关键要点
- 使用现有索引: 修改时必须使用找到的现有索引,而不是0
- 完全覆盖:
SetUserDefined会完全替换现有属性,而不是增量更新
3. 删除用户定义属性
计算相对索引
private static int GetUserDefinedPropertyRelativeIndex(ComApi.InwGUIPropertyNode2 propertyNode,
string categoryName)
{
int relativeIndex = 0;
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
{
if (attribute.UserDefined)
{
if (attribute.ClassUserName == categoryName)
{
return relativeIndex;
}
relativeIndex++;
}
}
return -1; // 未找到
}
删除属性类别
public static void RemoveUserDefinedProperty(ModelItem item, string categoryName)
{
ComApi.InwOpState10 state = ComApiBridge.State;
ComApi.InwOaPath3 path = (ComApi.InwOaPath3)ComApiBridge.ToInwOaPath(item);
ComApi.InwGUIPropertyNode2 propertyNode =
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
// 计算用户定义属性的相对索引
int relativeIndex = GetUserDefinedPropertyRelativeIndex(propertyNode, categoryName);
if (relativeIndex >= 0)
{
// 用户定义属性索引从1开始,所以需要+1
int userDefinedIndex = relativeIndex + 1;
// 使用RemoveUserDefined方法完全删除属性类别
propertyNode.RemoveUserDefined(userDefinedIndex);
}
}
关键要点
- 索引从1开始: 用户定义属性的索引从1开始,不是0
- 相对索引: 需要计算在用户定义属性中的相对位置
- 完全删除:
RemoveUserDefined会完全移除属性类别,不留痕迹
4. 读取属性值
使用COM API读取
public static string GetPropertyValueViaCom(ModelItem item, string categoryName,
string propertyName)
{
try
{
ComApi.InwOpState10 state = ComApiBridge.State;
ComApi.InwOaPath3 path = (ComApi.InwOaPath3)ComApiBridge.ToInwOaPath(item);
ComApi.InwGUIPropertyNode2 propertyNode =
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
// 遍历属性类别
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
{
if (attribute.UserDefined && attribute.ClassUserName == categoryName)
{
// 遍历类别中的属性
foreach (ComApi.InwOaProperty property in attribute.Properties())
{
if (property.UserName == propertyName)
{
return property.value?.ToString() ?? "";
}
}
}
}
return ""; // 未找到
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"读取属性失败: {ex.Message}");
return "";
}
}
常见问题与解决方案
1. 属性缓存同步问题
问题: COM API写入属性后,.NET API读取到的仍是旧值。
解决方案:
// 强制刷新文档状态
private static void ForceDocumentRefresh()
{
try
{
var doc = Application.ActiveDocument;
if (doc != null)
{
// 强制刷新文档状态
doc.CurrentSelection.Clear();
Application.DoEvents();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"文档刷新失败: {ex.Message}");
}
}
2. 索引计算错误
问题: 使用错误的索引导致操作失败。
解决方案:
- 创建新属性:使用
index = 0 - 修改现有属性:使用绝对索引(从0开始计数所有属性)
- 删除属性:使用相对索引+1(在用户定义属性中的位置+1)
3. 重复属性类别
问题: 每次操作都创建新的属性类别。
解决方案:
// 始终先检查是否存在现有属性
int existingIndex = FindUserDefinedPropertyIndex(propertyNode, categoryName);
if (existingIndex >= 0)
{
// 修改现有属性
propertyNode.SetUserDefined(existingIndex, categoryName, internalName, newProperties);
}
else
{
// 创建新属性
propertyNode.SetUserDefined(0, categoryName, internalName, newProperties);
}
最佳实践
1. 错误处理
try
{
// COM API 操作
}
catch (System.Runtime.InteropServices.COMException comEx)
{
// 处理COM特定错误
LogManager.WriteLog($"COM API错误: {comEx.Message}");
}
catch (Exception ex)
{
// 处理一般错误
LogManager.WriteLog($"操作失败: {ex.Message}");
}
2. 日志记录
// 详细的操作日志
LogManager.WriteLog($"[属性操作] 开始为 {items.Count} 个模型设置属性");
LogManager.WriteLog($"[属性操作] 类别名称: {categoryName}");
LogManager.WriteLog($"[属性操作] 操作完成,成功: {successCount}, 失败: {failCount}");
3. 批量操作
public static int BatchUpdateProperties(ModelItemCollection items,
string categoryName, Dictionary<string, string> properties)
{
int successCount = 0;
foreach (ModelItem item in items)
{
try
{
UpdateUserDefinedProperty(item, categoryName, properties);
successCount++;
}
catch (Exception ex)
{
LogManager.WriteLog($"处理模型 {item.DisplayName} 时失败: {ex.Message}");
}
}
return successCount;
}
4. 内存管理
// COM对象使用完毕后释放引用
ComApi.InwOaPropertyVec propertyCategory = null;
ComApi.InwOaProperty property = null;
try
{
// 使用COM对象
}
finally
{
// 释放COM对象引用
if (propertyCategory != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(propertyCategory);
}
if (property != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(property);
}
}
API 索引机制总结
| 操作类型 | 索引类型 | 索引值 | 说明 |
|---|---|---|---|
| 创建新属性 | 固定值 | 0 | 始终使用0创建新的用户定义属性 |
| 修改现有属性 | 绝对索引 | 0-n | 在所有属性中的位置(包括系统属性) |
| 删除属性 | 相对索引+1 | 1-n | 在用户定义属性中的位置+1 |
参考资源
官方文档
- Navisworks 2017 SDK 文档(安装目录下的api/documentation文件夹)
- Autodesk Developer Network (ADN)
社区资源
实用工具
- Navisworks Object Model Browser(查看对象结构)
- Visual Studio 调试工具(COM对象检查)
更新日志
v1.0 (2025-06-22)
- 初始版本,基于物流属性管理功能开发经验
- 涵盖COM API属性操作的核心方法
- 包含实际项目中遇到的问题和解决方案
注意: 本指南将持续更新,补充更多API用法和最佳实践。欢迎贡献新的内容和改进建议。