When building Revit add-ins that require user input, you often want to restrict which elements the user can select. The Revit API ISelectionFilter interface lets you intercept each element as it passes through the selection tool and allow or reject it based on any condition.
ISelectionFilter
Implement this interface and pass it to PickElementsByRectangle (or other selection methods). Every element the cursor touches is tested by AllowElement — only those returning true are highlighted and added to the final list:
// ISelectionFilter — implement to control which elements the user can select
public interface ISelectionFilter
{
// Return true to allow the element into the selection
bool AllowElement(Element elem);
// Return true to allow a reference (face, edge) — return false if not needed
bool AllowReference(Reference reference, XYZ position);
}Creating the Filter
Each element in Revit has a Category property, but its type is Category — not BuiltInCategory. The built-in category integer value is stored as the category's element ID, so castingcategory.Id.IntegerValue to BuiltInCategory gives you the enum for comparison:
// Door-only selection filter using BuiltInCategory
internal sealed class SelectionFilterDoor : ISelectionFilter
{
public bool AllowElement(Element elem)
{
if (elem is null) return false;
if (!(elem is FamilyInstance)) return false;
BuiltInCategory builtInCategory = (BuiltInCategory)GetCategoryIdAsInteger(elem);
return builtInCategory == BuiltInCategory.OST_Doors;
}
public bool AllowReference(Reference reference, XYZ position)
{
return false;
}
private int GetCategoryIdAsInteger(Element element)
{
return element?.Category?.Id?.IntegerValue ?? -1;
}
}Invoking the Selection
The selection method is on UIDocument.Selection. Wrap it in a try/catch — the user pressing Escape throws an OperationCanceledException and is a normal exit path:
// Invoke the selection — wrap in try/catch for user cancellation
try
{
IList<Element> doors = uiApp.ActiveUIDocument.Selection
.PickElementsByRectangle(new SelectionFilterDoor(), "Select Doors");
// doors contains only FamilyInstances of category OST_Doors
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
// user pressed Escape — expected, handle gracefully
}
catch (ForbiddenForDynamicUpdateException)
{
// selection called from a dynamic updater context
}
catch (Exception ex)
{
TaskDialog.Show("Error", ex.Message);
}