Gonzalo JL /YouTube
My First Revit Addin. Part 2

My First Revit Addin. Part 2

14 September 2026 · 13'31" · Watch on YouTube ↗

revit api, revit, c#, bim, visual studio, addin, youtube


In this second episode we break down the code line by line, understanding each method, making modifications and exploring the Revit API docs.

1. Understanding the code of a Revit addin

In the previous article, we configured Visual Studio, generated our first DLL file, and created the .addin manifest to load an addin into Revit. The command appeared in the interface and worked correctly.

Now it’s time to understand what the code actually does.

Copying and pasting is enough to get started, but if we want to modify an addin, expand it, or create one from scratch, we need to understand what happens on each line. Let’s analyse the basic structure of a Revit external command and how it interacts with the model.


2. Using and namespaces

The first lines of the file are these, where we declare the four namespaces we are going to use:

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.Attributes;

Autodesk.Revit.DB and Autodesk.Revit.Attributes belong to RevitAPI.dll, while Autodesk.Revit.UI and Autodesk.Revit.UI.Selection belong to RevitAPIUI.dll.

When we add references to the Revit DLLs, as we did in the first lesson, Visual Studio gains access to thousands of classes. The using statements tell Visual Studio which namespaces we want to work with and prevent us from having to write full paths constantly.

For example, notice that if we write Document inside Execute(), we don’t get an error. However, as soon as we remove the namespace that tells Visual Studio where to look for that class, Document and several other classes that also belong to Autodesk.Revit.DB produce errors and are marked in red. This clearly shows the dependency and the need to declare namespaces.

If we didn’t declare the namespace, we would have to tell Visual Studio where to look every time we use a class. For example, to declare Document, we would have to write: Autodesk.Revit.DB.Document.

As you can see, this greatly simplifies reading and writing code.

Namespaces also help prevent conflicts between classes with the same name belonging to different libraries.


3. The class and IExternalCommand

The following block usually has this structure:

[Transaction(TransactionMode.Manual)]
public class Class1 : IExternalCommand

There are two important concepts here.

[Transaction] attribute

The line inside the brackets is an attribute.

[Transaction(TransactionMode.Manual)]

It tells Revit how it should manage the transactions of the command. In this case, we use Manual, which means that the addin will be responsible for opening and closing transactions in the code.

Later, we’ll see why this is required when modifying the model.


The class

public class Class1 : IExternalCommand

public

This is the access modifier. Revit needs to be able to access this class in order to execute the command. If it isn’t public, the addin cannot be loaded.

class

Defines a class, which is essentially a template for creating objects.

Class1

This is simply the name of the class. In real projects, it is good practice to use descriptive names.

: IExternalCommand

This is the key element.

IExternalCommand is an interface from the Revit API. Implementing it tells Revit that this class is a command that can be executed from the interface.

Without it, Revit wouldn’t know that it should treat the class as an addin.

Whenever you come across a class or an interface you don’t recognise, you can look it up in revitapidocs.com. It is a community-built browser of the Revit API, and it is far easier to navigate than the official reference.


4. The Execute() method

Inside the class we find the heart of the addin:

public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements)

When the user clicks the command inside Revit, this method is executed automatically.

commandData

This is the most important parameter.

Through it, we can access:

It is the gateway to the Revit environment.


message

This is a string that we can modify if an error occurs.

If the command fails, Revit will display this message to the user in a dialog box.


elements

This allows us to specify which elements should be highlighted on screen if the command fails.

It is useful in more complex addins to help the user locate the problem.


5. The startup ritual

The first lines inside Execute() are repeated in practically every addin:

UIApplication uiapp = commandData.Application;
Document doc = uiapp.ActiveUIDocument.Document;

Here we obtain:

The Document object represents the model database: it contains elements, families, parameters, and all the information in the project.


6. Selecting elements

First, we declare an empty variable of type Reference:

Reference pickedref;

Reference is the class Revit uses to represent references to elements in the model.

Then we access the selection system:

Selection sel = uiapp.ActiveUIDocument.Selection;

And ask the user to select an element:

pickedref = sel.PickObject(
    ObjectType.Element,
    "Please select a group");

What does PickObject() do?

This method:

In this case, we use:

ObjectType.Element

This allows us to select any element in the model. If the user presses ESC, the method throws an exception.


7. Getting the actual element

When we use PickObject(), we don’t get the element directly. We get a Reference. A Reference is simply a reference to the element, not the element itself.

To retrieve the actual object, we use:

Element elem = doc.GetElement(pickedref);

GetElement() searches the document for the element associated with that reference.


8. Casting to Group

Now we convert the generic element into a group:

Group? group = elem as Group;

The API returns an Element, but we know that we expect a group.

The as operator attempts to convert the object:

That’s why we use:

Group?

The ? indicates that the variable can contain null. It doesn’t stop the user from selecting something incorrect, such as a wall or a door: in that case group is simply null, and the code still has to deal with it.


9. Selecting a point

Next, we ask the user to select a point in the model:

XYZ point = sel.PickPoint(
    "Please pick a point to place group");

Difference between PickObject() and PickPoint()

PickObject()

Returns a Reference to an element.

PickPoint()

Returns an XYZ, which represents a coordinate in 3D space. Here, we don’t need to know which element exists at that point, only its position.


10. Transactions

To modify the Revit model, we must work inside a transaction.

Transaction trans = new Transaction(doc);

trans.Start("Lab");

doc.Create.PlaceGroup(point, group?.GroupType);

trans.Commit();

The sequence is always the same:

  1. Start a transaction
  2. Make changes
  3. Commit with Commit()

Why do transactions exist?

Revit needs to precisely control which changes are made to the model.

If an error occurs during execution:

Each transaction also becomes an entry in Revit’s undo history.


11. Placing the group

The line that actually modifies the model is:

doc.Create.PlaceGroup(point, group?.GroupType);

Here:

The ?. operator avoids a NullReferenceException on this line when group is null, but PlaceGroup() then receives null and fails anyway. That’s why this version of the addin breaks if you select something that isn’t a group: the proper fix is to filter the selection so only groups can be picked.


12. Command result

Finally:

return Result.Succeeded;

This tells Revit that the command completed successfully.

If we return:

Result.Failed

or

Result.Cancelled

Revit will automatically undo the changes made during the transaction.


Conclusion

The basic structure of a Revit addin always follows the same pattern:

Although the example is simple, it introduces many of the fundamental concepts of the Revit API:

Understanding this foundation properly makes it much easier to develop more complex addins in the future.

If you want to go deeper, Autodesk’s Revit API Developer’s Guide is the official reference behind everything we have seen here.