Description
If you want to enhance the user experience in a Revit Add-in then you might want to better customize operations to meet the user’s expectations. Selection is an important feature that allows the user to dynamically interact with his Revit Model. But selections can be targeted.
In this article I will present you how to create a custom selection filter that will allow users to only select a certain type of element from the Revit model
Revit API
The ISelectionFilter interface provided from the Revit API provides us the ability to filter objects during a selection operation. This interface exposes two methods that return a bool, we must return true if we want to add the element to the selection, otherwise we must return false.
To create a custom selection filter we must simply create a class that will implement this interface.
When the user selects elements from Revit all the elements that are within a selection tool pass through this filter and only those that pass this validation are highlighted and added to the selection.
public interface ISelectionFilter { bool AllowElement(DB.Element elem); bool AllowReference(Reference reference, DB.XYZ position); }
To actually use this selection filter we must first invoke the selection method. This is location in our active UIDocument and the method that I am going to use in this example is called PickElementsByRectangle. This selection type prompts the user to select multiple elements by drawing a rectangle which pass a customer filter.
public IList<Element> PickElementsByRectangle( ISelectionFilter selectionFilter )
Creating the custom filter
One important thing to mention here is that in this example we will create the filter to keep only doors. We will leverage the BuiltInCategory of these elements, this means that for each element we must determine it’s BuiltInCategory and for doors this is BuiltInCategory.OST_Doors.
Each element in Revit has a Category property, but this is of Category type, not a BuiltInCategory :
Getting the BuiltInCategory from a category is pretty straight forward. The actual BuiltInCategory value is stored as the category’s id and making the conversion is made like :
BuiltInCategory builtInCategory = (BuiltInCategory)category.Id.IntegerValue;
And now the actual code
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); if (builtInCategory == BuiltInCategory.OST_Doors) return true; return false; } public bool AllowReference(Reference reference, XYZ position) { return false; } private int GetCategoryIdAsInteger(Element element) { return element?.Category?.Id?.IntegerValue ?? -1; } } }
try { var elements = uiApp.ActiveUIDocument.Selection.PickElementsByRectangle(new SelectionFilterDoor(), "Select Doors"); } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { //handle exception } catch (ForbiddenForDynamicUpdateException) { //handle exception } catch (Exception) { //handle exception }
Now, when you invoke this selection the user will see only the doors highlighted: