Revit On Startup (Internal macros)

For follow up looking for a way to run a command once an addin is loaded into Revit or Navis Works. It is possible through the revit macros- still searching for an API version:

From: http://boostyourbim.wordpress.com/2013/01/06/using-module_startup-to-run-macro-code-when-revit-starts/

January 6, 2013


Using Module_Startup to run macro code when Revit starts

Filed under: Error Handling, PerformanceAdviser — harrymattison @ 10:00 am

In previous posts, I have recommended staying away from this code that Revit creates in your macro file. Now I will explain a situation when we need to get into it.



private void Module_Startup(object sender, EventArgs e)

{

}The short summary is that code in Module_Startup runs automatically when Revit starts. It can be useful for subscribing to events, registering updaters for Dynamic Model Update, and for using the FailureDefinition.CreateFailureDefinition which is why it is relevant to this series of posts on PerformanceAdviser.



While working on a code sample to run a custom rule with the Performance Adviser, I ran the macro and Revit threw this exception:







The RevitAPI.chm help file tells us more about this restriction of FailureDefinition.CreateFailureDefinition:



The newly created FailureDefinition will be added to the FailureDefinitionRegistry. Because FailureDefinition could only be registered when Revit starting up, this function cannot be used after Revit has already started. Throws InvalidOperationException if invoked after Revit start-up is completed.



So we can’t start Revit normally and then, in the middle of our Revit session, run a macro that registers a FailureDefinition. Therefore we need a way to do this registration when Revit starts.



The Revit API Wiki provides the solution:



The Module_Startup method is called when a module loads and Module_Shutdown is called when a module unloads. For Application-level macro modules, Module Startup is called when Revit starts



So I move the code that calls CreateFailureDefinition from my RunRoomRule macro into Module_Startup. (RunRoomRule will be discussed in its own upcoming post). My Module_Startup now looks like this:



private void Module_Startup(object sender, EventArgs e)

{

// Get the one instance of PerformanceAdviser in the Application

PerformanceAdviser pa = PerformanceAdviser.GetPerformanceAdviser();



// Create an instance of the RoomNotEnclosed rule class. Calling the RoomNotEnclosed() constructor is what calls CreateFailureDefinition.

RoomNotEnclosed roomNotEnclosed = new RoomNotEnclosed();



// Add this roomNotEnclosed rule to the PerformanceAdviser

pa.AddRule( roomNotEnclosed.Id, roomNotEnclosed );

}But when I compile my macro code I get the same exception shown in the screenshot above! Why? Because, in addition to Module_Startup running when Revit starts, it is also called when the macro project is rebuilt.



This creates a bit of a puzzle. I need to move the code to Module_Startup to only have it run when Revit starts. But to do this I need to compile the macro in the middle of my Revit session. But compiling the code in the middle of the Revit session fails because it calls Module_Startup.



The way out of this situation is to add try/catch handling of this exception. I have written about try/catch before and noted that, in general, for this blog I am not going to catch every exception that might occur. But here I have no choice. The exception that occurs during compilation needs to be caught so that compilation can succeed. On startup, the exception will not occur because at that time it will be legal to call CreateFailureDefinition.



The final code is:



private void Module_Startup(object sender, EventArgs e)

{

try

{

// Get the one instance of PerformanceAdviser in the Application

PerformanceAdviser pa = PerformanceAdviser.GetPerformanceAdviser();



// Create an instance of the RoomNotEnclosed rule class

RoomNotEnclosed roomNotEnclosed = new RoomNotEnclosed();



// Add this roomNotEnclosed rule to the PerformanceAdviser

pa.AddRule( roomNotEnclosed.Id, roomNotEnclosed );

}

// Need to catch this exception because otherwise Revit will throw every time this is compiled because

// Module_Startup and Module_Shutdown are called when the macro project is compiled.

// And because the macro project will compile in the middle of the Revit session, calling RoomNotEnclosed()

// will throw because it calls CreateFailureDefinition

catch (Autodesk.Revit.Exceptions.ApplicationException)

{}

}

(In my initial code I was catching the InvalidOperationException which is the specific sub-class of Autodesk.Revit.Exceptions.ApplicationException that is thrown by CreateFailureDefinition. But there is also another exception to deal with, an ArgumentException that occurs when the failure definition id has already been used to register an existing failure definition. ApplicationException is the parent class of both InvalidOperationException and ArgumentException, so catching ApplicationException takes care of both cases)



Comments

Popular posts from this blog

Powerpoint countdown and current time in slides VBA

Revit area plans adding new types and references (Gross and rentable)