Selecting Elements in Revit API

Selecting elements or geometries is a common requirement in Revit plugins. You might need users to select objects for various purposes: elements for further processing, points for placing families, or surfaces for calculations. All of that is possible by knowing the Selection class.

Accessing the Selection class

The Selection class (from Autodesk.Revit.UI.Selection) is a gateway for retrieving already selected elements, setting new selections, and prompting users to select elements or geometries within your Revit plugins.
C#
var uiApp = commandData.Application;
var uiDoc = uiApp.ActiveUIDocument;
var doc = uiDoc.Document;

var selectionManager = uiDoc.Selection;

Ways to get selected elements

Revit API offers various ways to handle element selection:
Retrieving pre-selected elements:
Get elements that were selected before your method runs
Requesting user selection:
Prompt the user to select elements after your method starts (e.g., after a button click).
Mixed approach:
Retrieve already selected elements, or if no elements are selected, prompt the user for selection.

Retrieving pre-selected elements

To retrieve elements that were manually selected in the model before running your method, use the Selection.GetElementIds.
C#
var selectedElementsIds = selectionManager.GetElementIds();
TaskDialog.Show("Selected Elements", $"Selected elements number: {selectedElementsIds.Count}");

Requesting user selection

To request the user to select elements, you can use a variety of Pick[…] methods:
PickObject and PickObjects: select one or multiple elements of various types
Specify the Element type (Element, PointOnElement, Edge, Face, LinkedElement, Subelement) with the ObjectType enumerator.
PickPoint: select a point.
PickElementsByRectangle: select elements by drawing a rectangle on the screen.
C#
// Picking objects (Elements, geometries) - requesting the user to select
var elementReference = selectionManager.PickObject(ObjectType.Element, "Select element");
var element = doc.GetElement(elementReference);
TaskDialog.Show("Picked Element", $"Element: {element.Name}");

var elementsReferences = selectionManager.PickObjects(ObjectType.Element, "Select elements");
TaskDialog.Show("Picked Elements", $"Elements number: {elementsReferences.Count}");
	
// Picking an edge
Reference edgeRef = selectionManager.PickObject(ObjectType.Edge, "Select an edge");
Edge edge = doc.GetElement(edgeRef.ElementId).GetGeometryObjectFromReference(edgeRef) as Edge;
TaskDialog.Show("Picked Edge", $"Edge length: {edge.ApproximateLength}");

// Picking a point
var xyz = selectionManager.PickPoint(ObjectSnapTypes.Midpoints, "Select a midpoint");
TaskDialog.Show("Picked Point", $"Point coordinates: {xyz}");

// Picking elements by rectangle
var elementsSelected = selectionManager.PickElementsByRectangle("Select elements by rectangle");
var elementNames = string.Join(", ", elementsSelected.Select(e => e.Name));
TaskDialog.Show("Picked Elements by Rectangle", $"Elements: {elementNames}");

Mixed Approach: Retrieving or Requesting Selection

To enhance user experience, you can try to retrieve already selected elements or, if none are selected, prompt the user to make a selection.
C#
// Mixed approach -retrieving the selected elements or, if none are selected, requesting to select
var selectedElementsIds = selectionManager.GetElementIds();
if (selectedElementsIds.Count == 0)
{
	// Use the pick object method to select an element
	var elementsReferences = selectionManager.PickObjects(ObjectType.Element, "Select elements");
	selectedElementsIds = elementsReferences.Select(r => r.ElementId).ToList();
}
TaskDialog.Show("Selected Elements", $"Selected elements number: {selectedElementsIds.Count}");

Applying a Selection Filter

Sometimes, you need to set strict rules for elements available for selection. For example, you might want the user to select only walls of a certain width. In such cases, you can apply a Selection Filter.
To define a Selection Filter, create a class implementing the ISelectionFilter interface. Below are examples of two filters and their usage.
C#
// Applying the selection filter
var wallSelectionFilter = new ElementTypesSelectionFilter(typeof(Wall));
var wallReference = selectionManager.PickObject(ObjectType.Element, wallSelectionFilter, "Select a wall");

var wallAndFloorSelectionFilter = new ElementTypesSelectionFilter(typeof(Wall), typeof(Floor));
var wallOrFloorReference = selectionManager.PickObject(ObjectType.Element, wallAndFloorSelectionFilter, "Select a wall or a floor");

var minimumWidthWallSelectionFilter = new MinimumWidthWallsSelectionFilter(1); // remember - by default, width unit is Feet
var minimumWidthWallReference = selectionManager.PickObject(ObjectType.Element, minimumWidthWallSelectionFilter, "Select a wall with a minimum width of 1 foot");


// SelectionFilter classes
class ElementTypesSelectionFilter : ISelectionFilter
{
	private readonly Type[] allowedTypes;

	public ElementTypesSelectionFilter(params Type[] allowedTypes)
	{
		this.allowedTypes = allowedTypes;
	}

	public bool AllowElement(Element element)
	{
		return allowedTypes.Contains(element.GetType());
	}

	public bool AllowReference(Reference reference, XYZ position)
	{
		return false;
	}
}

class MinimumWidthWallsSelectionFilter : ISelectionFilter
{
	private readonly double minimumWidth;

	public MinimumWidthWallsSelectionFilter(double minimumWidth)
	{
		this.minimumWidth = minimumWidth;
	}

	public bool AllowElement(Element element)
	{
		if (element is Wall wall) return wall.Width >= minimumWidth;
			
		return false;
	}

	public bool AllowReference(Reference reference, XYZ position)
	{
		return false;
	}
}

Setting selection

Finally, if you need to set the selection programmatically within your method, use Selection.SetElementIds.
C#
var wallsIds = new FilteredElementCollector(doc)
.OfClass(typeof(Wall))
.WhereElementIsNotElementType()
.ToElementIds();

selectionManager.SetElementIds(wallsIds);

Setting selection

Use Selection class to:
Retrieve pre-selected elements.
Prompt users to select elements after your method starts.
Combine both approaches for flexibility.
Apply a SelectionFilter to ensure users select elements that meet your criteria.
Set selections programmatically with Selection.SetElementIds.
Do you want to become the Revit Programmer of the Future?