Here is a guest post by Stephen Hamil of RIBA Enterprises, director of NBS, the national standard specification company in the UK, owned by the Royal Institute of British Architects.
They just released the new version of their Revit plug-in that integrates the Revit design model with the NBS specification model, technical guidance and National BIM Library objects.
Below, Chris and Calum from the NBS software development team give a little insight into some of the API functionality they used when developing this software:
We make use of the IDropHandler interface from the API to allow us to drag drop from the National BIM Library NBL.
That enables us to overwrite the default behaviour of Revit when the user drops a family on a project file.
We start the process by making a call from the web browser to its owning user control:
/// <summary> /// Method called from the web browser /// </summary> public override void ClickDrag( string downloadLink, string strFamilyName ) { if( this.nbsUser.hasLoggedInNBL ) { List<string> dragInfo = new List<string>() { downloadLink, strFamilyName }; // Kick off the drag drop event which Revit // will pick up and custom code will check // if family already entered UIApplication.DoDragDrop( dragInfo, new dropHandler( this ) ); } else { this.SignInToFloatPanel(); } }
We use the Idling event to call into the Revit API from modeless dialogs to modify the database without causing damage.
We have a list of commands to run with an array of objects as their parameters and then run this chunk of code to process them in the Idling event handler:
// If we have commands to process if( CommandsToProcess.Count > 0 ) { try { UIDocument uiDoc = UIApp.ActiveUIDocument; // Get the first command in the list to process CommandToRun command = CommandsToProcess.First(); // Get the delegate that we want to run Delegate FunctionDelegate = command.FunctionToRun; // Make sure we have the lastest UIDocument command.ListOfParameters.Insert( 0, uiDoc ); // Get it's parameters object[] Parameters = command.ListOfParameters.ToArray(); // Invoke our function FunctionDelegate.DynamicInvoke( Parameters ); } catch( Exception ex ) { ErrorLogger.LogError( "Error processing command: " + ex.ToString() ); } finally { // Always Pop the first in the queue CommandsToProcess.RemoveAt( 0 ); } }
We encountered a problem when developing the plugin to work with 2014, due to the Document class method get_Element changing to GetElement.
This was easily handled by the way we structure the plugin and have each version inheriting from the previous; we start off with a generic interface:
public class RevitRibbon : IRevitRibbon
For Revit 2013 and 2014, we inherit the previous RevitRibbon class:
public class RevitRibbon : Revit2012.RevitRibbon public class RevitRibbon : Revit2013.RevitRibbon
This allows us to simply override the one function calling the get_Element method, solving the problem without causing any damage to our existing implementations for Revit 2012 and 2013.
For the Revit 2014 users, we did also look into replacing the modeless dialog by a docking panel, which is a really cool new feature.
Unfortunately, though, we ran out of time for this release. However, we’ll look at this again for version 2.1.
Here is a screen snapshot of it working in a prototype:
A lot of work was put into this and it looks pretty good, really linking the design model in Revit with the specification model in NBS.
Here is some further information on:
Thank you, Stephen, for providing this background information.