public static List<FamilyInstance> GetFilteredNestedFamilyInstances(
string familyFileNameFilter,
string typeNameFilter,
Document familyDocument,
bool caseSensitiveFiltering)
{
// Following good SOA practices, verify the
// incoming data can be worked with.
ValidateFamilyDocument( familyDocument ); // Throws an exception if not a family doc
// The filters can be null
List<FamilyInstance> oResult
= new List<FamilyInstance>();
FamilyInstance oFamilyInstanceCandidate;
FamilySymbol oFamilySymbolCandidate;
List<Family> oMatchingNestedFamilies
= new List<Family>();
List<FamilyInstance> oAllFamilyInstances
= new List<FamilyInstance>();
bool bFamilyFileNameFilterExists = true;
bool bTypeNameFilterExists = true;
// Set up some fast-to-test boolean values, which will be
// used for short-circuit Boolean evaluation later.
if( string.IsNullOrEmpty( familyFileNameFilter ) )
{
bFamilyFileNameFilterExists = false;
}
if( string.IsNullOrEmpty( typeNameFilter ) )
{
bTypeNameFilterExists = false;
}
// Unfortunately detecting nested families in a family document requires iterating
// over all the elements in the document, because the built-in filtering mechanism
// doesn't work for this case. However, families typically don't have nearly as many
// elements as a whole project, so the performance hit shouldn't be too bad.
// Still, the fastest performance should come by iterating over all elements in the given
// family document exactly once, keeping subsets of the family instances found for
// later testing against the nested family file matches found.
ElementClassFilter fFamilyClass = new ElementClassFilter( typeof( Family ) );
ElementClassFilter fFamInstClass = new ElementClassFilter( typeof( FamilyInstance ) );
LogicalOrFilter f = new LogicalOrFilter( fFamilyClass, fFamInstClass );
FilteredElementCollector collector = new FilteredElementCollector( familyDocument );
collector.WherePasses( f );
foreach( Element e in collector )
{
// See if this is a family file nested into the current family document.
Family oNestedFamilyFileCandidate = e as Family;
if( oNestedFamilyFileCandidate != null )
{
// Must ask the "Element" version for it's name, because the Family object's
// name is always the empty string.
if( !bFamilyFileNameFilterExists
|| FilterMatches( oNestedFamilyFileCandidate.Name,
familyFileNameFilter, caseSensitiveFiltering ) )
{
// This is a nested family file, and either no valid family file name filter was
// given, or the name of this family file matches the filter.
oMatchingNestedFamilies.Add( oNestedFamilyFileCandidate );
}
}
else
{
// This element is not a nested family file definition, see if it's a
// nested family instance.
oFamilyInstanceCandidate
= e as FamilyInstance;
if( oFamilyInstanceCandidate != null )
{
// Just add the family instance to our "all" collection for later testing
// because we may not have yet found all the matching nested family file
// definitions.
oAllFamilyInstances.Add( oFamilyInstanceCandidate );
}
}
} // End iterating over all the elements in the family document exactly once
// See if any matching nested family file definitions were found. Only do any
// more work if at least one was found.
foreach( Family oMatchingNestedFamilyFile
in oMatchingNestedFamilies )
{
// Count backwards through the all family instances list. As we find
// matches on this iteration through the matching nested families, we can
// delete them from the candidates list to reduce the number of family
// instance candidates to test for later matching nested family files to be tested
for( int iCounter = oAllFamilyInstances.Count - 1;
iCounter >= 0; iCounter-- )
{
oFamilyInstanceCandidate
= oAllFamilyInstances[iCounter];
#if _2010
oFamilySymbolCandidate
= oFamilyInstanceCandidate.ObjectType
as FamilySymbol;
#endif // _2010
ElementId id = oFamilyInstanceCandidate.GetTypeId();
oFamilySymbolCandidate = familyDocument.GetElement( id )
as FamilySymbol;
if( oFamilySymbolCandidate.Family.UniqueId
== oMatchingNestedFamilyFile.UniqueId )
{
// Only add this family instance to the results if there was no type name
// filter, or this family instance's type matches the given filter.
if( !bTypeNameFilterExists
|| FilterMatches( oFamilyInstanceCandidate.Name,
typeNameFilter, caseSensitiveFiltering ) )
{
oResult.Add( oFamilyInstanceCandidate );
}
// No point in testing this one again,
// since we know its family definition
// has already been processed.
oAllFamilyInstances.RemoveAt( iCounter );
}
} // Next family instance candidate
} // End of for each matching nested family file definition found
return oResult;
}