Skip to content

events

Revit events handler management.

Attributes

mlogger = get_logger(__name__) module-attribute

REGISTERED_HANDLERS = {} module-attribute

HANDLER_UNREGISTERER = FuncAsEventHandler(unregister_exec_handlers, purge=False) module-attribute

HANDLER_UNREGISTERER_EXTEVENT = UI.ExternalEvent.Create(HANDLER_UNREGISTERER) module-attribute

Classes

FuncAsEventHandler(handler_func, purge=True)

Bases: IExternalEventHandler

Turns a function into an event handler.

Source code in pyrevitlib/pyrevit/revit/events.py
def __init__(self, handler_func, purge=True):
    self.name = 'FuncAsEventHandler'
    self.handler_group_id = None
    self.handler_func = handler_func
    self.purge = purge

Attributes

name = 'FuncAsEventHandler' instance-attribute
handler_group_id = None instance-attribute
handler_func = handler_func instance-attribute
purge = purge instance-attribute

Functions

Execute(uiapp)
Source code in pyrevitlib/pyrevit/revit/events.py
def Execute(self, uiapp):
    if self.handler_func and self.handler_group_id:
        self.handler_func(self.handler_group_id)
        if self.purge:
            self.handler_group_id = self.handler_func = None
GetName()
Source code in pyrevitlib/pyrevit/revit/events.py
def GetName(self):
    return self.name

Functions

create_handler(handler_func, handler_args_type)

Source code in pyrevitlib/pyrevit/revit/events.py
def create_handler(handler_func, handler_args_type):
    return framework.EventHandler[handler_args_type](handler_func)

add_handler(event_name, handler_func)

Source code in pyrevitlib/pyrevit/revit/events.py
def add_handler(event_name, handler_func):
    event_handler = None

    if event_name == 'doc-changed':
        event_handler = \
            create_handler(handler_func, DB.Events.DocumentChangedEventArgs)
        HOST_APP.app.DocumentChanged += event_handler

    elif event_name == 'doc-closed':
        event_handler = \
            create_handler(handler_func, DB.Events.DocumentClosedEventArgs)
        HOST_APP.app.DocumentClosed += event_handler

    elif event_name == 'doc-opened':
        event_handler = \
            create_handler(handler_func, DB.Events.DocumentOpenedEventArgs)
        HOST_APP.app.DocumentOpened += event_handler

    elif event_name == 'view-activated':
        event_handler = \
            create_handler(handler_func, UI.Events.ViewActivatedEventArgs)
        HOST_APP.uiapp.ViewActivated += event_handler

    elif event_name == 'selection-changed':
        if HOST_APP.is_older_than(2023):
            mlogger.error("Not available in this Revit Version")
            return
        event_handler = \
            create_handler(handler_func, UI.Events.SelectionChangedEventArgs)
        HOST_APP.uiapp.SelectionChanged += event_handler

    return event_handler

remove_handler(event_name, event_handler)

Source code in pyrevitlib/pyrevit/revit/events.py
def remove_handler(event_name, event_handler):
    if event_name == 'doc-changed':
        HOST_APP.app.DocumentChanged -= event_handler

    elif event_name == 'doc-closed':
        HOST_APP.app.DocumentClosed -= event_handler

    elif event_name == 'doc-opened':
        HOST_APP.app.DocumentOpened -= event_handler

    elif event_name == 'view-activated':
        HOST_APP.uiapp.ViewActivated -= event_handler

    elif event_name == 'selection-changed':
        if HOST_APP.is_older_than(2023):
            mlogger.error("Not available in this Revit Version")
            return
        HOST_APP.uiapp.SelectionChanged -= event_handler

register_handler(event_name, handler_func, handler_group_id)

Source code in pyrevitlib/pyrevit/revit/events.py
def register_handler(event_name, handler_func, handler_group_id):
    if handler_group_id not in REGISTERED_HANDLERS:
        REGISTERED_HANDLERS[handler_group_id] = {}
    event_handler = add_handler(event_name, handler_func)
    if event_handler:
        REGISTERED_HANDLERS[handler_group_id][event_name] = event_handler

unregister_handler(event_name, handler_func, handler_group_id)

Source code in pyrevitlib/pyrevit/revit/events.py
def unregister_handler(event_name, handler_func, handler_group_id):
    if handler_group_id in REGISTERED_HANDLERS \
            and event_name in REGISTERED_HANDLERS[handler_group_id]:
        event_handler = REGISTERED_HANDLERS[handler_group_id].pop(event_name)
        remove_handler(event_name, event_handler)

unregister_exec_handlers(handler_group_id)

Source code in pyrevitlib/pyrevit/revit/events.py
def unregister_exec_handlers(handler_group_id):
    if handler_group_id in REGISTERED_HANDLERS:
        for event_name, handler_func in \
                REGISTERED_HANDLERS[handler_group_id].items():
            unregister_handler(event_name, handler_func, handler_group_id)

delayed_unregister_exec_handlers(handler_group_id)

Source code in pyrevitlib/pyrevit/revit/events.py
def delayed_unregister_exec_handlers(handler_group_id):
    HANDLER_UNREGISTERER.handler_group_id = handler_group_id
    HANDLER_UNREGISTERER_EXTEVENT.Raise()

handle(*args)

Source code in pyrevitlib/pyrevit/revit/events.py
def handle(*args): #pylint: disable=no-method-argument
    def decorator(function):
        def wrapper(*args, **kwargs):
            return function(*args, **kwargs)
        for event_name in args:
            register_handler(event_name, wrapper, EXEC_PARAMS.exec_id)
        return wrapper
    return decorator

stop_events()

Source code in pyrevitlib/pyrevit/revit/events.py
def stop_events():
    if EXEC_PARAMS.exec_id in REGISTERED_HANDLERS:
        if HOST_APP.has_api_context:
            unregister_exec_handlers(EXEC_PARAMS.exec_id)
        else:
            # request underegister from external event
            delayed_unregister_exec_handlers(EXEC_PARAMS.exec_id)

execute_in_revit_context(func, *args, **kwargs)

Execute a function in Revit API context using ExternalEvent.

Use this helper when calling Revit API from modeless dialogs, background threads, or any non-Revit context where direct API access would raise InvalidOperationException.

The function executes asynchronously - it returns immediately and the function runs when Revit is idle.

Parameters:

Name Type Description Default
func

Function to execute in Revit context

required
*args

Positional arguments to pass to the function

()
**kwargs

Keyword arguments to pass to the function

{}
Example
# Simple function call
execute_in_revit_context(transaction_function, doc, element_id)

# From modeless dialog button click
def on_button_click(sender, args):
    execute_in_revit_context(
        modify_elements,
        selected_ids,
        parameter_name="Comments",
        value="Updated"
    )
Note

This function does not return values from the executed function. For return values, use callbacks or shared mutable objects.

Source code in pyrevitlib/pyrevit/revit/events.py
def execute_in_revit_context(func, *args, **kwargs):
    """
    Execute a function in Revit API context using ExternalEvent.

    Use this helper when calling Revit API from modeless dialogs,
    background threads, or any non-Revit context where direct API
    access would raise InvalidOperationException.

    The function executes asynchronously - it returns immediately
    and the function runs when Revit is idle.

    Args:
        func: Function to execute in Revit context
        *args: Positional arguments to pass to the function
        **kwargs: Keyword arguments to pass to the function

    Example:
        ```python
        # Simple function call
        execute_in_revit_context(transaction_function, doc, element_id)

        # From modeless dialog button click
        def on_button_click(sender, args):
            execute_in_revit_context(
                modify_elements,
                selected_ids,
                parameter_name="Comments",
                value="Updated"
            )
        ```

    Note:
        This function does not return values from the executed function.
        For return values, use callbacks or shared mutable objects.
    """
    _HANDLER.func = func
    _HANDLER.args = args
    _HANDLER.kwargs = kwargs
    _EXTERNAL_EVENT.Raise()