Ok, in this part, let’s look at how to subscribe document events to all documents both existing and coming ones.
To achieve this seemingly simple goal, a few other factors have to be involved such as document collection (Application.Documents), Application events, and UIApplication events. And the subscription needs to happen in an external application rather than an external command which we have talked about in the previous post.
It is obvious to take into account the document collection of the Revit Application as we need to loop through them to subscribe events or unsubscribe them when necessary, but it is not obvious for the other two, Application events, and UIApplication events. A simple question may just arise, what particular events of the two classes to use and how?
In terms of the UIApplication events, the ViewActivated is a must and the ApplicationClosing is optional; in terms of the Application events, the DocumentCreated and DocumentOpened are necessary and the DocumentClosing is good to use.
The ViewActivated is the only entry point in the UIApplication for us to hook the document event handlers into the Application and the Document world as only at this moment a document is about to be created and the event argument provides access to the Document and in turn the Revit Application. So we forward the event subscription from the UIControlledApplication to the Application object in the callback of the ViewActivated event. The ApplicationClosing can be used to unsubscribe document events when the Revit Application is going to quit, and we do not really have to worry about it since the whole application will be disposed anyway.
The DocumentCreated and DocumentOpened events need to be used to monitor when a new document has been created or opened so as for our programs to subscribe events to it. When the DocumentClosing event is broadcasting, we can unsubscribe events to the document but it’s not absolutely necessary as the whole document and any of its events will be destroyed anyway.
Here is the whole document event subscriber class:
public class DocEventSubscriber
{
private UIControlledApplication _uiCtrApp;
private static RvtApplication _app;
private static bool _registered;
public DocEventSubscriber(UIControlledApplication app)
{
_uiCtrApp = app;
_registered = false;
_uiCtrApp.ViewActivated += UIAppEvent_ViewActivated_Handler;
_uiCtrApp.ApplicationClosing += UIAppEvent_ApplicationClosing_Handler;
}
public static void SubscribeForApplication(RvtApplication app)
{
app.DocumentOpened += AppEvent_DocumentOpened_Handler;
app.DocumentCreated += AppEvent_DocumentCreated_Handler;
app.DocumentClosing += AppEvent_DocumentClosing_Handler;
}
public static void UnsubscribeForApplication(RvtApplication app)
{
foreach (RvtDocument doc in app.Documents)
{
UnsubscribeFromDoc(doc);
}
app.DocumentOpened -= AppEvent_DocumentOpened_Handler;
app.DocumentCreated -= AppEvent_DocumentCreated_Handler;
app.DocumentClosing -= AppEvent_DocumentClosing_Handler;
}
public static void SubscribeToDoc(RvtDocument doc)
{
doc.DocumentClosing += DocEventHandlers1.DocEvent_DocumentClosing_Handler;
doc.DocumentPrinted += DocEventHandlers1.DocEvent_DocumentPrinted_Handler;
doc.DocumentPrinting += DocEventHandlers1.DocEvent_DocumentPrinting_Handler;
doc.DocumentSaved += DocEventHandlers1.DocEvent_DocumentSaved_Handler;
doc.DocumentSavedAs += DocEventHandlers1.DocEvent_DocumentSavedAs_Handler;
doc.DocumentSaving += DocEventHandlers1.DocEvent_DocumentSaving_Handler;
doc.DocumentSavingAs += DocEventHandlers1.DocEvent_DocumentSavingAs_Handler;
doc.ViewPrinted += DocEventHandlers1.DocEvent_ViewPrinted_Handler;
doc.ViewPrinting += DocEventHandlers1.DocEvent_ViewPrinting_Handler;
}
public static void UnsubscribeFromDoc(RvtDocument doc)
{
doc.DocumentClosing -= DocEventHandlers1.DocEvent_DocumentClosing_Handler;
doc.DocumentPrinted -= DocEventHandlers1.DocEvent_DocumentPrinted_Handler;
doc.DocumentPrinting -= DocEventHandlers1.DocEvent_DocumentPrinting_Handler;
doc.DocumentSaved -= DocEventHandlers1.DocEvent_DocumentSaved_Handler;
doc.DocumentSavedAs -= DocEventHandlers1.DocEvent_DocumentSavedAs_Handler;
doc.DocumentSaving -= DocEventHandlers1.DocEvent_DocumentSaving_Handler;
doc.DocumentSavingAs -= DocEventHandlers1.DocEvent_DocumentSavingAs_Handler;
doc.ViewPrinted -= DocEventHandlers1.DocEvent_ViewPrinted_Handler;
doc.ViewPrinting -= DocEventHandlers1.DocEvent_ViewPrinting_Handler;
}
public static void UIAppEvent_ViewActivated_Handler(Object sender, EventArgs args)
{
ViewActivatedEventArgs specArgs = args as ViewActivatedEventArgs;
if (!_registered) // Only subscribing once!
{
_app = specArgs.Document.Application;
SubscribeForApplication(_app);
_registered = true;
}
}
public static void UIAppEvent_ApplicationClosing_Handler(Object sender, EventArgs args)
{
ApplicationClosingEventArgs specArgs = args as ApplicationClosingEventArgs;
if (_app != null && _registered)
{
UnsubscribeForApplication(_app);
_registered = false;
}
}
public static void AppEvent_DocumentCreated_Handler(Object sender, EventArgs args)
{
DocumentCreatedEventArgs specArgs = args as DocumentCreatedEventArgs;
SubscribeToDoc(specArgs.Document);
}
public static void AppEvent_DocumentOpened_Handler(Object sender, EventArgs args)
{
DocumentOpenedEventArgs specArgs = args as DocumentOpenedEventArgs;
SubscribeToDoc(specArgs.Document);
}
public static void AppEvent_DocumentClosing_Handler(Object sender, EventArgs args)
{
DocumentClosingEventArgs specArgs = args as DocumentClosingEventArgs;
UnsubscribeFromDoc(specArgs.Document);
}
}
With the subscriber, it is very straightforward and reliable to subscribe document events in an external application:
public Result OnStartup(UIControlledApplication uiApp)
{
_cachedUiCtrApp = uiApp;
try
{
// …
// Subscribe events to all documents in the whole Revit session.
DocEventSubscriber docEventScrscipber = new DocEventSubscriber(_cachedUiCtrApp);
return Result.Succeeded;
}
catch (Exception ex)
{
MessageBox.Show( ex.ToString() );
return Result.Failed;
}
}
All these can be done automatically by the RevitAddinWizard in a moment.
In the part 3, we will demonstrate how to use the RevitAddinWizard to create document event handlers, the subscriber, and any relevant registration code.
Links to some related articles:
Manage Revit Application Events of Revit API
Use RevitAddinWizard to Add Revit Application Event Handlers of Revit API
Implement Revit FailuresProcessing Event Hanlders of Revit API
Use RevitAddinWizard to Implement Revit FailuresProcessing Event Hanlders of Revit API
Manage Revit UIApplication Events
Manage Revit Document Events of Revit API - 3 Document Event Handler of RevitAddinWizard
Recent Comments