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.