关于uidoc.PostRequestForElementTypePlacement()调用结构墙/楼板放置的问题
解决Revit API中PostRequestForElementTypePlacement触发建筑构件而非结构构件的问题
嘿,这个问题我之前做Revit二次开发时也踩过坑,咱们一步步来拆解解决:
一、直接触发结构墙/楼板的放置功能
其实uidoc.PostRequestForElementTypePlacement()的行为完全由你传入的ElementType决定——你之前大概率是传入了建筑墙/楼板的类型,所以才会触发建筑构件的放置逻辑。只要传入对应的结构构件类型,就能直接调用结构墙/楼板的原生放置流程。
举个结构墙的代码示例:
using Autodesk.Revit.DB; using Autodesk.Revit.UI; public void PlaceStructuralWall(UIDocument uidoc) { Document doc = uidoc.Document; // 筛选项目中的结构墙类型 var structuralWallType = new FilteredElementCollector(doc) .OfClass(typeof(WallType)) .Cast<WallType>() .FirstOrDefault(wt => wt.Kind == WallKind.Structural); if (structuralWallType != null) { // 传入结构墙类型,直接触发结构墙放置流程 uidoc.PostRequestForElementTypePlacement(structuralWallType); } else { TaskDialog.Show("提示", "项目中未找到结构墙类型"); } }
结构楼板的逻辑类似,只要筛选StructuralFloorType而非普通建筑楼板类型即可:
var structuralFloorType = new FilteredElementCollector(doc) .OfClass(typeof(FloorType)) .Cast<FloorType>() .FirstOrDefault(ft => ft.FloorType == FloorType.Structural);
二、放置后修改Structural参数的方案
如果因为某些限制,你必须先通过建筑构件流程放置,再修改为结构构件,那要注意:PostRequestForElementTypePlacement()是异步执行的——它只是向Revit发送一个放置请求,要等用户完成交互后才会生成构件。所以你不能在调用方法后立刻修改,得通过事件监听来捕获构件创建的时机。
最常用的是Idling事件(Revit空闲时触发),示例代码如下:
public void PlaceWallAndSetStructural(UIDocument uidoc) { Document doc = uidoc.Document; UIApplication app = uidoc.Application; // 标记是否在等待用户完成放置 bool isWaitingForPlacement = true; // 记录放置前的墙数量,用于精准筛选新增的墙 int preWallCount = new FilteredElementCollector(doc) .OfClass(typeof(Wall)) .Count(); // 发送建筑墙放置请求 var architecturalWallType = new FilteredElementCollector(doc) .OfClass(typeof(WallType)) .Cast<WallType>() .FirstOrDefault(wt => wt.Kind == WallKind.Architectural); if (architecturalWallType == null) return; uidoc.PostRequestForElementTypePlacement(architecturalWallType); // 注册Idling事件,监听构件创建 app.Idling += (sender, args) => { if (!isWaitingForPlacement) return; // 获取本次放置新增的墙 var newWalls = new FilteredElementCollector(doc) .OfClass(typeof(Wall)) .Cast<Wall>() .Skip(preWallCount) .ToList(); if (newWalls.Any()) { // 开启事务修改参数(Revit API要求修改必须在事务内) using (Transaction trans = new Transaction(doc, "设置为结构墙")) { trans.Start(); foreach (Wall wall in newWalls) { // 修改Structural参数(BuiltInParameter对应值1代表true) Parameter structuralParam = wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT); if (structuralParam != null && !structuralParam.IsReadOnly) { structuralParam.Set(1); } } trans.Commit(); } // 停止监听,避免重复触发或内存泄漏 isWaitingForPlacement = false; app.Idling -= (sender, args); } }; }
小提示
- 用
Skip(preWallCount)筛选新增构件比用创建时间更可靠,能避免误修改旧构件。 - 所有对Revit模型的修改操作,必须包裹在
Transaction事务中执行,这是API的硬性规则。
内容的提问来源于stack exchange,提问作者Jan Buijs
相关产品推荐
相关产品推荐

