原文链接(The Building Coder: Jeremy Tammik)
我们的目标是在一个新建的族中,对一个Family Instance进行镜像。我们已经讨论过【元素镜像】和【访问一个新建元素】,但是在一个新建的族文档中进行这些操作有些不同。
第一个问题是镜像命令需要一个当前活动视图作为参数。而活动视图在族文档中不是自动呈现的。Joe(译者注:叶雄进)找到了一个解决办法,通过ShowElements方法来曲线实现对当前活动视图的指定。不过这个方法有个副作用:会产生一个不需要的警告消息。所以第二个问题是如何消除这个伴生的警告消息。
正如你接下来将会看到的,你可以使用ShowElements方法来改变当前的活动视图,甚至在族文档和项目文档之间切换。官方的Revit 2011 API不提供任何方式来切换活动视图(译者注:Revit 2012 API弥补了这一缺陷)。
最初的问题是这样的:
【问题】我想要创建一个新族:Profile-Mullion.rfa,插入一些详细的构件,然后沿垂直轴对它们进行镜像。当我试图镜像一个构件的Family Instance时,Revit抛出一个异常:无效的活动视图。我的族文档的活动视图总是为NULL,因为这个族文档是我用Application.NewDocument()在代码中动态创建的。我尝试用代码改变当前动态视图,但是Document.ActiveView属性是只读的。有什么办法可以解决这个问题吗?我还尝试过Mirror(Element, Reference)和Mirror(Element, Line),不过它们都会导致相同的异常。
【解答】指定当前活动视图的思路是:在指定视图的参考平面上创建一条线段(DetailLine)。然后使用ShowElement()方法显示该线段,则Revit会自动切换其活动视图到该线段所在的视图。至于该方法导致的警告对话框,可以使用DialogBoxShowing事件来处理掉。实现代码如下:
Public Shared Function NewFamilySymbol( _
ByVal projectDoc As Document) _
As FamilySymbol
Dim app As Autodesk.Revit.ApplicationServices _
.Application = projectDoc.Application
Dim templateFileName As String _
= "C:\Program Files\Autodesk" _
+ "\Revit Architecture 2011" _
+ "\Content\Imperial Templates" _
+ "\Profile-Mullion.rft"
Dim familyDoc As Document _
= app.NewFamilyDocument(templateFileName)
If familyDoc Is Nothing Then
Dim tdError As New TaskDialog("Error")
tdError.MainInstruction = "Could not find" _
+ " family template: Profile-Mullion.rft"
tdError.MainContent = "Designated path '" _
+ templateFileName + "' is invalid."
tdError.CommonButtons _
= TaskDialogCommonButtons.Close
tdError.Show()
Return Nothing
End If
' Store some elements in the original project
' that we can use later (that are in the
' current ActiveView)
Dim projDocCollector As New _
FilteredElementCollector( _
projectDoc, projectDoc.ActiveView.Id)
Dim projFamInsts As List(Of ElementId) _
= projDocCollector.OfClass( _
GetType(FamilyInstance)) _
.ToElementIds
Dim famDocCollector As New _
FilteredElementCollector(familyDoc)
Dim views As List(Of Element) _
= famDocCollector _
.OfClass(GetType(View)) _
.ToElements
Dim planView As View = Nothing
' Find the default view
For Each v As View In views
If v.Name = "Ref. Level" Then
planView = v
Exit For
End If
Next
Dim fileName As String = Nothing
Dim familyDocTrans As New Transaction( _
familyDoc, "CreateFamilySymbol")
familyDocTrans.Start()
Dim famUIdoc As New UIDocument(familyDoc)
' ... Create FamilyInstances in the familyDoc
' Mirror elements about vertical centerline
Dim origin As New XYZ(0, 0, 0)
Dim pt As New XYZ(0, 1, 0)
Dim vertAxis As Line = app.Create.NewLine( _
origin, pt, True)
Dim detLine As DetailLine = familyDoc _
.FamilyCreate.NewDetailCurve( _
planView, vertAxis)
' Set up event handler to automatically
' click "OK" when the ShowElements dialog
' box appears
CGlobal.SuppressDialogBoxes = True
Try
' Transfer the active view to the
' Family(Document)
famUIdoc.ShowElements(detLine)
familyDoc.Mirror(detailComps, vertAxis)
' Delete the old family instance
familyDoc.Delete(detailComps)
Catch ex As Exception
End Try
' Delete the detail line
familyDoc.Delete(detLine)
' Transfer the active view back to the project
Dim projUIdoc As New UIDocument(projectDoc)
projUIdoc.ShowElements(projFamInsts.Item(0))
' Reset the dialog box event handler
CGlobal.SuppressDialogBoxes = False
familyDocTrans.Commit()
' Define a save path for the new family
If familyDoc.SaveAs(fileSavePath) Then
' Bring the family into the current project
projectDoc.LoadFamily( _
fileSavePath, projectFam)
' Close the family edit,
' do not save changes
familyDoc.Close(False)
' Return Family or FamilySymbol
End Function