Back to Blog
RevitAPIPythonUser InterfaceSelection

UI Selection Methods in Revit API — Interactive Element Selection

Create interactive Revit applications that respond to user input. Learn single and multiple element selection, custom filters, point picking, and TaskDialog interactions.

Paulo Giavoni

Paulo Giavoni

Engineer & BIM Specialist

5 January 20269 min read
UI Selection Methods in Revit API — Interactive Element Selection

Introduction to UI Selection#

The Revit API offers a robust set of tools to let users select elements interactively instead of collecting them automatically. This is the key difference:

  • FilteredElementCollector (previous article) = Finds elements automatically with code
  • UI Selection (this article) = The user clicks on elements they want to process

When to use interactive selection:

  • The user must choose visually what to modify
  • The selection cannot be automated with filters
  • You want visual confirmation before modifying elements
  • You need flexibility — different users select different things

When to use collectors:

  • The selection criteria are clear and automatable ("all walls on ground floor")
  • You need speed — process hundreds of elements automatically
  • The workflow must be repeatable without manual intervention

This is the third article in a three-part series on Revit API development:

  1. Getting Started with BIM Automation
  2. Element Collection with FilteredElementCollector
  3. UI Selection Methods (this article)

Required Libraries and Setup#

UI selection requires additional libraries compared to automatic collection:

Python
1import clr
2clr.AddReference('RevitAPIUI') # <-- Note: we add UI
3import Autodesk
4from Autodesk.Revit.UI import *
5from Autodesk.Revit.UI.Selection import *
6
7clr.AddReference('RevitServices')
8import RevitServices
9from RevitServices.Persistence import DocumentManager
10
11# Get the current document and UI document
12doc = DocumentManager.Instance.CurrentDBDocument
13uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

Key difference:

  • doc = The Revit model (data)
  • uidoc = The user interface (what the user sees)

All selection methods use uidoc, not doc.


Important Note for Dynamo#

WARNING: Most examples in this article work only in C# add-ins, not in Dynamo.

Dynamo doesn't directly support methods like PickObject() because:

  1. Dynamo is designed for visual programming, not code-based interaction
  2. Dynamo nodes handle input/output differently from add-ins

Alternatives in Dynamo:

  • Use nodes like "Select Model Element" or "Select Model Elements"
  • For advanced selections, create a separate C# add-in
  • For prototyping, use PyRevit (standalone Python framework for Revit)

This article is useful if:

  • You're learning Revit API to create C# add-ins in the future
  • You want to understand how Dynamo selection nodes work internally
  • You use PyRevit or similar frameworks that support uidoc.Selection

1. Basic Element Selection#

1.1 Pick a Single Element#

The PickObject() method is the foundation of element selection in Revit API. It prompts the user to select a single element in the Revit interface.

Python
1try:
2 selected_reference = uidoc.Selection.PickObject(ObjectType.Element, "Select an element")
3 element = doc.GetElement(selected_reference.ElementId)
4 print(f"Selected element: {element.Name}")
5 print(f"Category: {element.Category.Name}")
6 print(f"ID: {element.Id}")
7
8 # Get some basic parameters
9 for param in element.Parameters:
10 print(f"{param.Definition.Name}: {param.AsValueString()}")
11except Exception as e:
12 print(f"Selection cancelled or failed: {str(e)}")

This example not only selects an element but also retrieves and prints various properties and parameters of the selected element.

Exercise: Modify the code to allow selection of a specific category (e.g., only walls). Hint: You'll need to use a custom ISelectionFilter.


1.2 Pick Multiple Elements#

When you need to select multiple elements, the PickObjects() method comes in handy:

Python
1try:
2 selected_references = uidoc.Selection.PickObjects(ObjectType.Element, "Select multiple elements")
3 elements = [doc.GetElement(ref.ElementId) for ref in selected_references]
4
5 category_count = {}
6 for elem in elements:
7 category = elem.Category.Name
8 category_count[category] = category_count.get(category, 0) + 1
9
10 print(f"Selected {len(elements)} elements")
11 for category, count in category_count.items():
12 print(f"{category}: {count}")
13except Exception as e:
14 print(f"Selection cancelled or failed: {str(e)}")

This example selects multiple elements and provides a summary of the selected elements by category.

Exercise: Extend the code to calculate and print the total volume of all selected elements that have a volume parameter.


2. Advanced Selection Techniques#

2.1 Selection by Rectangle#

The PickElementsByRectangle() method allows for a more visual selection process, similar to dragging a selection box in the Revit interface:

Python
1try:
2 selected_elements = uidoc.Selection.PickElementsByRectangle("Select elements by rectangle")
3
4 levels = {}
5 for elem_id in selected_elements:
6 elem = doc.GetElement(elem_id)
7 if hasattr(elem, 'Level'):
8 level_name = elem.Level.Name if elem.Level else "No Level"
9 levels[level_name] = levels.get(level_name, 0) + 1
10
11 print(f"Selected {len(selected_elements)} elements")
12 for level, count in levels.items():
13 print(f"Level {level}: {count} elements")
14except Exception as e:
15 print(f"Selection cancelled or failed: {str(e)}")

This example selects elements within a rectangle and organizes them by level, providing a count of elements on each level.


2.2 Pick Box#

The PickBox() method creates a selection box based on two points, which can be useful for defining a 3D region:

Python
1from Autodesk.Revit.DB import BoundingBoxIntersectsFilter, Outline
2
3try:
4 box = uidoc.Selection.PickBox(PickBoxStyle.Enclosing, "Select area")
5 outline = Outline(box.Min, box.Max)
6 bb_filter = BoundingBoxIntersectsFilter(outline)
7
8 collector = FilteredElementCollector(doc).WherePasses(bb_filter)
9 elements = list(collector)
10
11 print(f"Found {len(elements)} elements within the picked box")
12 category_count = {}
13 for elem in elements:
14 category = elem.Category.Name if elem.Category else "No Category"
15 category_count[category] = category_count.get(category, 0) + 1
16
17 for category, count in category_count.items():
18 print(f"{category}: {count}")
19except Exception as e:
20 print(f"Selection cancelled or failed: {str(e)}")

This example uses the picked box to create a bounding box filter, then finds all elements that intersect with this box.


3. Custom Selection Filters#

Custom selection filters allow for fine-grained control over which elements can be selected:

Python
1class CustomFilter(ISelectionFilter):
2 def __init__(self, category_name, parameter_name, parameter_value):
3 self.category_name = category_name
4 self.parameter_name = parameter_name
5 self.parameter_value = parameter_value
6
7 def AllowElement(self, elem):
8 if elem.Category and elem.Category.Name == self.category_name:
9 parameter = elem.LookupParameter(self.parameter_name)
10 if parameter and parameter.AsString() == self.parameter_value:
11 return True
12 return False
13
14 def AllowReference(self, reference, point):
15 return False
16
17try:
18 custom_filter = CustomFilter("Walls", "Comments", "Important")
19 selected_elements = uidoc.Selection.PickObjects(
20 ObjectType.Element,
21 custom_filter,
22 "Select important walls"
23 )
24
25 print(f"Selected {len(selected_elements)} important walls")
26 for ref in selected_elements:
27 elem = doc.GetElement(ref.ElementId)
28 print(f"Wall ID: {elem.Id}, Name: {elem.Name}")
29except Exception as e:
30 print(f"Selection cancelled or failed: {str(e)}")

This example creates a custom filter that only allows selection of walls with a specific comment value.


3.1 Category Filter#

A simpler filter that only allows selection of specific categories:

Python
1class CategoryFilter(ISelectionFilter):
2 def __init__(self, category_names):
3 self.category_names = category_names if isinstance(category_names, list) else [category_names]
4
5 def AllowElement(self, elem):
6 if elem.Category:
7 return elem.Category.Name in self.category_names
8 return False
9
10 def AllowReference(self, reference, point):
11 return False
12
13# Usage: Select only doors and windows
14door_window_filter = CategoryFilter(["Doors", "Windows"])
15selected = uidoc.Selection.PickObjects(
16 ObjectType.Element,
17 door_window_filter,
18 "Select doors or windows"
19)

4. Working with Selected Views#

Retrieving and working with selected views in the project browser:

Python
1def get_selected_views():
2 selected_ids = uidoc.Selection.GetElementIds()
3 selected_views = [
4 doc.GetElement(id) for id in selected_ids
5 if doc.GetElement(id).GetType().Name.startswith("View")
6 ]
7 return selected_views
8
9selected_views = get_selected_views()
10print(f"Selected {len(selected_views)} views")
11
12for view in selected_views:
13 print(f"View Name: {view.Name}, Type: {view.ViewType}")
14
15 # Count visible elements in each view
16 collector = FilteredElementCollector(doc, view.Id).WhereElementIsNotElementType()
17 element_count = collector.GetElementCount()
18 print(f" Visible elements: {element_count}")
19
20 # Check view-specific properties
21 if hasattr(view, 'Scale'):
22 print(f" Scale: 1:{view.Scale}")

5. Point Selection#

Point selection is crucial for many operations, such as creating new elements or measuring distances:

Python
1from Autodesk.Revit.DB import XYZ
2
3def pick_points(prompt, count):
4 points = []
5 for i in range(count):
6 try:
7 point = uidoc.Selection.PickPoint(
8 ObjectSnapTypes.Endpoints,
9 f"{prompt} (Point {i+1}/{count})"
10 )
11 points.append(point)
12 except Exception as e:
13 print(f"Point selection cancelled or failed: {str(e)}")
14 return None
15 return points
16
17def distance_between_points(p1, p2):
18 return p1.DistanceTo(p2)
19
20points = pick_points("Select two points to measure distance", 2)
21if points and len(points) == 2:
22 distance = distance_between_points(points[0], points[1])
23 print(f"Distance between points: {distance:.2f} feet")
24
25 # Create a line element between the two points
26 try:
27 line = Line.CreateBound(points[0], points[1])
28 doc.Create.NewDetailCurve(doc.ActiveView, line)
29 print("Created a detail line between the points")
30 except Exception as e:
31 print(f"Failed to create detail line: {str(e)}")

This example demonstrates how to pick multiple points, calculate the distance between them, and create a detail line.


6. User Interaction with TaskDialog#

Creating interactive dialogs enhances the user experience:

Python
1def create_task_dialog(title, main_instruction, content, commands, verification_text=None):
2 dialog = TaskDialog(title)
3 dialog.MainInstruction = main_instruction
4 dialog.MainContent = content
5
6 for command in commands:
7 dialog.AddCommandLink(command[0], command[1])
8
9 if verification_text:
10 dialog.VerificationText = verification_text
11
12 return dialog
13
14# Usage example
15commands = [
16 (TaskDialogCommandLinkId.CommandLink1, "Option 1: Select walls"),
17 (TaskDialogCommandLinkId.CommandLink2, "Option 2: Select doors"),
18 (TaskDialogCommandLinkId.CommandLink3, "Option 3: Cancel operation")
19]
20
21dialog = create_task_dialog(
22 "Element Selection",
23 "Choose what to select",
24 "Your choice will determine which elements can be selected.",
25 commands,
26 "Remember my choice"
27)
28
29result = dialog.Show()
30
31if result == TaskDialogResult.CommandLink1:
32 print("User chose to select walls")
33 # Proceed with wall selection
34elif result == TaskDialogResult.CommandLink2:
35 print("User chose to select doors")
36 # Proceed with door selection
37elif result == TaskDialogResult.CommandLink3:
38 print("User cancelled the operation")
39
40if dialog.WasVerificationChecked():
41 print("User wants to remember this choice")

7. Face and Edge Selection#

For more precise geometry selection:

Python
1# Select a face
2try:
3 face_ref = uidoc.Selection.PickObject(ObjectType.Face, "Select a face")
4 element = doc.GetElement(face_ref.ElementId)
5 face = element.GetGeometryObjectFromReference(face_ref)
6
7 print(f"Selected face from: {element.Name}")
8 print(f"Face area: {face.Area:.2f} sq ft")
9except Exception as e:
10 print(f"Face selection failed: {str(e)}")
11
12# Select an edge
13try:
14 edge_ref = uidoc.Selection.PickObject(ObjectType.Edge, "Select an edge")
15 element = doc.GetElement(edge_ref.ElementId)
16 edge = element.GetGeometryObjectFromReference(edge_ref)
17
18 print(f"Selected edge from: {element.Name}")
19 print(f"Edge length: {edge.ApproximateLength:.2f} ft")
20except Exception as e:
21 print(f"Edge selection failed: {str(e)}")

8. Setting Pre-Selection#

You can also programmatically set the current selection:

Python
1from Autodesk.Revit.DB import ElementId
2from System.Collections.Generic import List
3
4# Collect all walls
5walls = FilteredElementCollector(doc).OfClass(Wall).ToElements()
6
7# Create a list of ElementIds
8wall_ids = List[ElementId]([wall.Id for wall in walls])
9
10# Set the selection
11uidoc.Selection.SetElementIds(wall_ids)
12
13print(f"Pre-selected {len(wall_ids)} walls")

9. Complete Example: Interactive Element Editor#

Here's a comprehensive example that combines multiple selection techniques:

Python
1class ElementEditor:
2 def __init__(self, doc, uidoc):
3 self.doc = doc
4 self.uidoc = uidoc
5
6 def run(self):
7 # Step 1: Show dialog to choose action
8 dialog = TaskDialog("Element Editor")
9 dialog.MainInstruction = "What would you like to do?"
10 dialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Edit single element")
11 dialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink2, "Edit multiple elements")
12 dialog.AddCommandLink(TaskDialogCommandLinkId.CommandLink3, "Edit elements in area")
13
14 result = dialog.Show()
15
16 if result == TaskDialogResult.CommandLink1:
17 self.edit_single()
18 elif result == TaskDialogResult.CommandLink2:
19 self.edit_multiple()
20 elif result == TaskDialogResult.CommandLink3:
21 self.edit_in_area()
22
23 def edit_single(self):
24 try:
25 ref = self.uidoc.Selection.PickObject(ObjectType.Element, "Select element to edit")
26 element = self.doc.GetElement(ref.ElementId)
27 self.show_element_info(element)
28 except:
29 print("Selection cancelled")
30
31 def edit_multiple(self):
32 try:
33 refs = self.uidoc.Selection.PickObjects(ObjectType.Element, "Select elements to edit")
34 elements = [self.doc.GetElement(ref.ElementId) for ref in refs]
35 for elem in elements:
36 self.show_element_info(elem)
37 except:
38 print("Selection cancelled")
39
40 def edit_in_area(self):
41 try:
42 elements = self.uidoc.Selection.PickElementsByRectangle("Draw rectangle to select")
43 for elem_id in elements:
44 elem = self.doc.GetElement(elem_id)
45 self.show_element_info(elem)
46 except:
47 print("Selection cancelled")
48
49 def show_element_info(self, element):
50 print(f"\n--- {element.Name} ---")
51 print(f"ID: {element.Id}")
52 print(f"Category: {element.Category.Name if element.Category else 'N/A'}")
53
54# Run the editor
55editor = ElementEditor(doc, uidoc)
56editor.run()

Conclusion#

This guide covers a wide range of Revit API selection methods, from basic element picking to advanced filtered selections and user interactions. The key to mastering Revit API selection is practice and experimentation.

Remember:

  • Use custom filters to limit what users can select
  • Always wrap selections in try-except blocks for graceful cancellation handling
  • Combine selection methods with FilteredElementCollector for powerful workflows
  • Provide clear prompts to guide users

What's Next?#

This concludes our three-part series on Revit API development:

  1. Getting Started with BIM Automation — Fundamentals and key concepts
  2. Element Collection with FilteredElementCollector — Finding elements programmatically
  3. UI Selection Methods — Interactive user selection (this article)

Questions or Feedback?

I'd love to hear your thoughts on this article. Reach out directly and let's start a conversation.

Follow me on LinkedIn for more BIM tips and updates