In this section, we list all loaded families and family instances in the current document.
Each family defines a set of types, also called symbols.
To list them, we retrieve all the objects wrapping standard families and types loaded and available in the current model.
Let's first see how we can get all family objects and try to determine their category.
Add a new module named Labs3
to the project and a standard command class
implementation Lab3_1_StandardFamiliesAndTypes
to it:
using System; using System.Collections; using WinForms = System.Windows.Forms; using Autodesk.Revit; using Autodesk.Revit.Elements; using Autodesk.Revit.Parameters; using Autodesk.Revit.Symbols; namespace Labs { public class Lab3_1_StandardFamiliesAndTypes : IExternalCommand { public IExternalCommand.Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements ) { return IExternalCommand.Result.Succeeded; } } }
Public Class Lab3_1_StandardFamiliesAndTypes Implements IExternalCommand Public Function Execute( _ ByVal commandData As ExternalCommandData, _ ByRef message As String, _ ByVal elements As ElementSet) _ As IExternalCommand.Result _ Implements Autodesk.Revit.IExternalCommand.Execute Return IExternalCommand.Result.Succeeded End Function End Class
Unlike previous versions of Revit where we had to iterate through all the elements in Revit and create a list of family elements, from Revit 2009 onwards, we can use the element filtering mechanism to filter out all the family elements. This not only reduces the number of lines of code required to achieve the same result, but also has tremendous performance advantage as compared to previous releases. Insert the following lines of code to the class implementation to create a list of family elements using the filtering mechanism.
Application app = commandData.Application; Document doc = app.ActiveDocument; // // get all family elements in current document: // List<Element> families = new List<Element>(); Filter filterFamily = app.Create.Filter.NewTypeFilter( typeof( Family ) ); doc.get_Elements( filterFamily, families ); string sMsg = "Standard families already loaded in this model:"; foreach( Family f in families ) { // Get its category name; notice that the Category property is not // implemented for the Family class; use FamilyCategory instead; // notice that that is also not always implemented; in that case, // use the workaround demonstrated below, looking at the contained // family symbols' category: sMsg += "\r\n Name=" + f.Name + "; Category=" + ( ( null == f.Category ) ? "?" : f.Category.Name ) + "; FamilyCategory=" + ( ( null == f.FamilyCategory ) ? "?" : f.FamilyCategory.Name ); } LabUtils.InfoMsg( sMsg );
' Element iteration done with element filtering functionality in Revit 2009 Dim doc As Revit.Document = commandData.Application.ActiveDocument Dim elementList As New List(Of Revit.Element) Dim filterType As Filter = commandData.Application.Create.Filter.NewTypeFilter(GetType(Family)) Dim nRetVal As Integer = doc.Elements(filterType, elementList) Dim sMsg As String = "Standard Families already loaded in this model are:" Dim f As Family For Each f In elementList ' get its category name; notice that the category property is ' not implemented for the Family class. use FamilyCategory ' instead, which is also not always implemented: Dim catName As String If f.Category Is Nothing Then catName = "?" Else catName = f.Category.Name End If Dim famCatName As String If f.FamilyCategory Is Nothing Then famCatName = "?" Else famCatName = f.FamilyCategory.Name End If sMsg += vbCrLf & " Name=" & f.Name _ & "; Category=" & catName _ & "; FamilyCategory=" & famCatName Next MsgBox(sMsg)
Compile the project, adjust the ini file and run the command. As we can see from the message box, all the categories are listed as "?", showing that this property is not implemented for family class.
Because the Category
property is not implemented for family
objects, and it is often useful to determine a family instance's category,
the Revit API has defined an additional property FamilyCategory
to query it. Unfortunately, the value of this property is defined in the
content, and some legacy content does not specify a value for it,
so even this property does not always reliably return the value you
might expect.
In order to reliably determine a family's category, we can retrieve the contained symbols or types and determine their category. The following code demonstrates this and also reports all types available in each family, displaying one message box per family. Add the following between the previous loop and the return statement:
// Loop through the collection of families, and now look at // the child symbols (types) as well. These symbols can be // used to determine the family category. foreach( Family f in families ) { string catName; bool first = true; // Loop all contained symbols (types) foreach( FamilySymbol symb in f.Symbols ) { // you can determine the family category from its first symbol. if( first ) { first = false; catName = symb.Category.Name; sMsg = "Family: Name=" + f.Name + "; Id=" + f.Id.Value.ToString() + "; Category=" + catName + "\r\nContains Types:"; } sMsg += "\r\n " + symb.Name + "; Id=" + symb.Id.Value.ToString(); } // Show the symbols for this family and allow user to proceed // to the next family (OK) or cancel (Cancel) sMsg += "\r\nContinue?"; if( !LabUtils.QuestionMsg( sMsg ) ) { break; } }
' Let's do a similar loop, but now get all the child symbols (types) as well. ' These symbols can also be used to determine the category: For Each f In elementList Dim catName As String Dim first As Boolean = True Dim symb As FamilySymbol 'Loop all contained symbols (types) For Each symb In f.Symbols ' Determine the category via first symbol If first Then first = False If (symb.Category Is Nothing) Then catName = "?" ' Still happens for *some* Symbols (Profiles?) Else catName = symb.Category.Name End If sMsg = "Family: Name=" & f.Name & "; Id=" & f.Id.Value.ToString & "; Category=" & catName & vbCrLf & "Contains Types:" End If sMsg += vbCrLf & " " & symb.Name & "; Id=" & symb.Id.Value.ToString Next ' Show the symbols for this family and allow user to procede to the next family (OK) or cancel (Cancel) If MsgBox(sMsg, MsgBoxStyle.OkCancel) = MsgBoxResult.Cancel Then Exit For End If Next
Now a valid category name is reported for all families. The looping continues displaying all types contained in each family in one message box each as long as you click 'OK'. Click 'Cancel' to terminate.
next previous home copyright © 2007-2009 jeremy tammik, autodesk inc. all rights reserved.