Selecting and Picking Elements in Revit API

Selecting elements or geometries in your plugin is possible with the Selection class.
📌 TLDR – Summary Upfront:
Use Selection class to:
➡️
Get currently selected elements ​with Selection.GetElementIds().
➡️
Prompt the user to select elements with various Pick[…] methods (PickObject, PickObjects, PickPoint, …).
➡️
Set selected elements programmatically with Selection.SetElementIds().
The Selection Filter allows you to set additional rules for Elements to select.

Accessing the Selection class

The Selection class (from Autodesk.Revit.UI.Selection) allows 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

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 selected 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}");

Convenient Mixed Approach: Retrieving or Requesting Selection

To enhance user experience, you can 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

You might need to set strict rules for elements available for selection (for example, selecting only walls of a certain width). In such cases, 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

You can also set the selection programmatically within your method with Selection.SetElementIds.
C#
var wallsIds = new FilteredElementCollector(doc)
.OfClass(typeof(Wall))
.WhereElementIsNotElementType()
.ToElementIds();

selectionManager.SetElementIds(wallsIds);