FilteredElementCollector allows you to access all kinds of Elements in Revit projects – model elements, families, geometries, views – based on specific criteria.
Long chains of FilteredElementCollector methods can be daunting. But don’t worry – breaking them down clarifies a lot. Actually, most cases can be resolved with the image below.
📌 TLDR – Summary Upfront:
Typical FilteredElementCollector
C#
var elements = new FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_Walls) // or OfClass(typeof(Wall))
.WhereElementIsNotElementType() // or WhereElementIsElementType()
.ToElements()
.Cast<Wall>() //optional
.Where(wall => wall.Width > 1); //optional
Let’s break it down.
Constructor
Initialize the collector for a document.
You can also limit the collector to elements visible in a specific view.
C#
var collector = new FilteredElementCollector(doc);
var collectorForView = new FilteredElementCollector(doc, viewId);
OfCategory or OfClass
•
OfCategory: Filters elements by a specific category (BuiltInCategory members).
•
OfClass: Filters elements by their API class.
These methods are often interchangeable. For example, Wall has both category and specific class.
C#
.OfCategory(BuiltInCategory.OST_Walls)
.OfClass(typeof(Wall))
But some model elements have no specific classes. For example, instances of Columns and Beams share the same class: FamilyInstance. To distinguish between them, use the OfCategory method.
C#
.OfClass(typeof(FamilyInstance) //gets all FamilyInstances, including Columns and Beams
.OfCategory(BuiltInCategory.OST_StructuralColumns) //gets only Columns
.OfCategory(BuiltInCategory.OST_StructuralFraming) //gets only Beams
Element Types vs Instances
Understanding the difference between Element Types and Element Instances is crucial.
•
Element Types: Definitions or templates of elements (e.g., a family type)
•
Element Instances: Actual elements placed in the project (e.g., several columns inserted into the model).
Use:
•
WhereElementIsElementType to get types
•
WhereElementIsNotElementType to get instances
C#
var columnTypes = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_StructuralColumns).WhereElementIsElementType().ToElements(); //gets 10 Column Family Types (e.g., M_Concrete_Rectangular-Column 300 x 450 mm, UC-Universal Column-Column 203x203x46UC)
var columnInstances = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_StructuralColumns).WhereElementIsNotElementType().ToElements(); //gets 3 instances of M_Concrete_Rectangular-Column 300 x 450 mm columns inserted into the model
🛈
When classes are specific for types (e.g., WallType), using WhereElementIsElementType() isn’t required. However, including it makes your code clearer and more robust.
Retrieving Elements
Convert the collector to a list of Elements using ToElements() or ElementIds using ToElementIds().
C#
var collector = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).WhereElementIsNotElementType(); // a collector
var familyInstances = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).WhereElementIsNotElementType().ToElements(); // a list of Elements.
Casting to a specific class
To have a list of specific elements (e.g., Walls) – instead of generic Elements returned by ToElements() – you need to cast them.
C#
var walls = new FilteredElementCollector(doc)
.OfClass(typeof(Wall))
.WhereElementIsNotElementType()
.ToElements()
.Cast<Wall>();
Now, you can access properties and methods specific to the class. Which is helpful for…
Further filtering with Where()
To further filter elements based on their properties, you can use LINQ’s Where() method.
C#
// collecting walls wider than 1 feet
var wideWalls = new FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_Walls)
.WhereElementIsNotElementType()
.ToElements()
.Cast<Wall>()
.Where(wall => wall.Width > 1);
// getting a specific family type
var familySymbols = new FilteredElementCollector(doc)
.OfClass(typeof(FamilySymbol))
.WhereElementIsElementType()
.Cast<FamilySymbol>();
string familyName = "Test Family";
string familyTypeName = "Test Family Type";
var specificFamilySymbol = familySymbols
.FirstOrDefault(symbol => symbol.FamilyName == familyName && symbol.Name == familyTypeName);
Examples
🛈
Some crucial model elements, like Columns or Beams (Structural Framings), have no specific classes. Their types are FamilySymbols and their instances are FamilyInstances.
C#
var columnTypes = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_StructuralColumns).WhereElementIsElementType().ToElements().Cast<FamilySymbol>();
var columnInstances = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_StructuralColumns).WhereElementIsNotElementType().ToElements().Cast<FamilyInstance>();
var columnFamilyType = new FilteredElementCollector(doc).OfClass(typeof(FamilySymbol)).ToElements().Cast<FamilySymbol>().Where(symbol => symbol.FamilyName == „Square Column” && symbol.Name == „40 x 40”);
var wallTypes = new FilteredElementCollector(doc).OfClass(typeof(WallType)).ToElements().Cast<WallType>();
var wideWallInstances = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).WhereElementIsNotElmentType().ToElements().Cast<Wall>().Where(wall => wall.Width > 1);