I donât use the pyRevit hooks, so I donât know how useful my comment will be.
I implement my own listeners if I ever need to hook onto any of the events inside Revit.
I imagine if you want to create a single class or block of code that that listens to multiple events you will have to do it yourself. If that is not the case someone more experienced with the pyRevit hooks can correct me.
Here is an example of a simple class I made that listens for document changes and view changes to streamline the process of syncing asynchronous code with Revit.
I use this specific listener inside of an IUpdater so I can synchronize the database inside the updater as the active document/view changes, or new documents get opened/closed.
import pyevent
from Autodesk.Revit.UI import UIApplication
from Autodesk.Revit.UI.Events import ViewActivatedEventArgs
from Autodesk.Revit.DB.Events import (RevitAPIEventStatus, DocumentOpenedEventArgs,
DocumentClosingEventArgs, DocumentClosedEventArgs)
class ViewChangedListener(object):
def __init__(self, uiapp):
# type: (UIApplication) -> ViewChangedListener
self.view_changed, self._view_changed_caller = pyevent.make_event()
self.register(uiapp)
def register(self, uiapp):
# type: (ViewChangedListener, UIApplication) -> None
uiapp.ViewActivated += self.view_activated_handler
def unregister(self, uiapp):
# type: (ViewChangedListener, UIApplication) -> None
uiapp.ViewActivated -= self.view_activated_handler
def view_activated_handler(self, sender, args):
# type: (ViewChangedListener, object, ViewActivatedEventArgs) -> None
self._view_changed_caller(self, args)
class DocumentOpenedListener(object):
def __init__(self, uiapp):
# type: (UIApplication) -> DocumentOpenHandler
self.opened, self._opened_caller = pyevent.make_event()
self.register(uiapp)
def register(self, uiapp):
# type: (DocumentOpenedListener, UIApplication) -> None
uiapp.Application.DocumentOpened += self.opened_handler
def unregister(self, uiapp):
# type: (DocumentOpenedListener, UIApplication) -> None
uiapp.Application.DocumentOpened -= self.opened_handler
def opened_handler(self, sender, args):
# type: (DocumentOpenedListener, object, DocumentOpenedEventArgs) -> None
self._opened_caller(self, args)
class DocumentClosedListener(object):
def __init__(self, uiapp):
# type: (UIApplication) -> DocumentCloseHandler
self.closing_data = {}
self.closed, self._closed_caller = pyevent.make_event()
self.register(uiapp)
def register(self, uiapp):
# type: (DocumentClosedListener, UIApplication) -> None
uiapp.Application.DocumentClosing += self.closing_handler
uiapp.Application.DocumentClosed += self.closed_handler
def unregister(self, uiapp):
# type: (DocumentClosedListener, UIApplication) -> None
uiapp.Application.DocumentClosing -= self.closing_handler
uiapp.Application.DocumentClosed -= self.closed_handler
@staticmethod
def get_doc_name(doc):
if doc.ProjectInformation:
return doc.ProjectInformation.Name
else:
return doc.Title
def closing_handler(self, sender, args):
# type: (DocumentClosedListener, object, DocumentClosingEventArgs) -> None
doc = args.Document
doc_name = self.get_doc_name(doc)
self.closing_data[str(args.DocumentId)] = doc_name
def closed_handler(self, sender, args):
# type: (DocumentClosedListener, object, DocumentClosedEventArgs) -> None
if args.Status == RevitAPIEventStatus.Failed or args.Status == RevitAPIEventStatus.Cancelled:
self.closing_data.pop(str(args.DocumentId), None)
elif args.Status == RevitAPIEventStatus.Succeeded:
self._closed_caller(self, self.closing_data.pop(str(args.DocumentId), None))
else:
pass
class DocumentListener(object):
def __init__(self, uiapp):
# type: (DocumentListener, UIApplication) -> None
self._opened_listener = DocumentOpenedListener(uiapp)
self._closed_listener = DocumentClosedListener(uiapp)
self._view_changed_listener = ViewChangedListener(uiapp)
# these are events that you can subscribe to
# I.E. document_lister_instance.opened += some_func
self.opened = self._opened_listener.opened
self.closed = self._closed_listener.closed
self.view_changed = self._view_changed_listener.view_changed
def register(self, uiapp):
# type: (DocumentListener, UIApplication) -> None
self._opened_listener.register(uiapp)
self._closed_listener.register(uiapp)
self._view_changed_listener.register(uiapp)
def unregister(self, uiapp):
# type: (DocumentListener, UIApplication) -> None
self._opened_listener.unregister(uiapp)
self._closed_listener.unregister(uiapp)
self._view_changed_listener.unregister(uiapp)
Here is an example of how you could use this to hook into multiple events within the same script.
I donât actually know if this example work to be honest, but it should work. (Iâm not able to test it at the moment.)
Edit: if it isnât clear this example should just have a dialog popup saying âDocument - Openedâ or âDocument - Closedâ. But like I said I couldnât test it.
from Autodesk.Revit.UI import TaskDialog, TaskDialogCommonButtons, TaskDialogResult
def warning_dialog(window_name, main_instruction, main_content):
td = TaskDialog(window_name)
td.TitleAutoPrefix = False
td.AllowCancellation = True
td.MainInstruction = main_instruction
td.MainContent = main_content
td.CommonButtons = TaskDialogCommonButtons.Ok
td.DefaultButton = TaskDialogResult.Ok
return td.Show()
def doc_opened_popup(sender, args):
# type: (object, DocumentOpenedEventArgs) -> None
doc = args.Document
if doc.ProjectInformation:
doc_name = doc.ProjectInformation.Name
else:
doc_name = doc.Title
window_name = "{} - Opened".format(doc_name)
main_instruction = window_name
main_content = main_instruction
td_result = warning_dialog(window_name, main_instruction, main_content)
def doc_closed_popup(sender, args):
# type: (object, str | None) -> None
doc_name = args
window_name = "{} - Opened".format(doc_name)
main_instruction = window_name
main_content = main_instruction
td_result = warning_dialog(window_name, main_instruction, main_content)
dl = DocumentListener(__revit__)
dl.opened += doc_opened_popup
dl.closed += doc_closed_popup