One main focus of the Revit 2013 API features is better support for add-in integration. This includes the possibility for an add-in to replace an existing Revit command with its own implementation. Note that you cannot call an existing command, just replace it entirely.
Such a command replacement is demonstrated in a very simple form by the DisableCommand SDK sample, which disables a command by replacing its implementation with a simple popup message.
A slightly more complex example is given by the UIAPI SDK sample, which implements and installs an alternative command binding for the Design Model command to start up a new family freshly created from the conceptual mass template and display its 3D view.
These are the steps to replace a built-in Revit command:
- Determine the RevitCommandId to replace by examining the journal file and searching for the name of the original command.
- Create an AddInCommandBinding for this command id.
- Provide an alternate implementation for the command binding.
List of all Revit Command Ids
To simplify the first step, Victor Chekalin aka Виктор Чекалин now presents a list of all Revit command ids,
In Victor's own words:
I'm learning the ability to replace a Revit command with my own add-in implementation. To replace a command, I must know CommandId of the command which I want to replace. The help tells me I can find a CommandId in the journal file. So the Revit SDK help doesn't contains full list of CommandIds. I have decided to correct this mistake and create that list.
I thought this information will be useful for you and other developers and send you the list of all command ids in both text and Excel format.
Question: Wow! How did you create this list?
Answer: It is my little secret how I've got it. Joke :-)
At first I thought the commands must be described somewhere. I searched for the text 'ID_EXPORT_IFC' (the command name from the Dev Days Online – Revit 2013 API) in all files at the Revit Program folder. So I found the UIFramework.dll file. I opened this file in the text editor and saw XML data containing command descriptions.
Next steps were very easy. I saved this part of the UIFramework.dll file to the XML file and read the XML data:
private IEnumerable<InternalCommandDef> ReadCommandsFromFile() { using( var streamReader = File.OpenText( @"C:\Users\ChekalinVV" + "\Documents\Revit\Revit2013SDK" + "\RevitUICommands.xml" ) ) { using( var reader = XmlReader.Create( streamReader ) ) { while( reader.Read() ) { if( reader.Name.Equals( "Command" ) ) { InternalCommandDef commandDef = new InternalCommandDef(); if( reader.MoveToAttribute( "Path" ) ) commandDef.Path = reader.Value; if( reader.MoveToAttribute( "CommandId" ) ) commandDef.CommandId = reader.Value; yield return commandDef; } } } } }
Retrieve get CommandId info for each command and write it to the text file:
using( var textFile = File.CreateText( @"C:\Users\ChekalinVV\Documents\Revit" + "\Revit2013SDK\RevitUICommands.txt" ) ) { foreach( var command in commands ) { RevitCommandId commandId = RevitCommandId .LookupCommandId( command.CommandId ); if( commandId == null ) continue; command.CanHaveBinding = commandId.CanHaveBinding; command.Id = commandId.Id; textFile.WriteLine( "{0}\t{1}\t{2}\t{3}", command.CommandId, command.Path, command.Id, command.CanHaveBinding ); /* It is just a joke if( !commandId.HasBinding && commandId.CanHaveBinding ) { var commandBinding = App.ControlledApplication .CreateAddInCommandBinding(commandId); commandBinding.Executed += OnCommandExecute; } */ } } }
It is not necessary to get full CommandId properties, but I wanted to retrieve the CanHaveBinding property for all commands. As I can see only two commands cannot have binding: Undo and Redo commands. Although I try to bind ID_APP_EXIT command (just for test because it was the first command I found in the journal files). It binds without any errors but doesn't work.
Very many thanks to Victor for this interesting research and the useful comprehensive list!
Hi Jeremy, hi Victor,
after reading the command IDs, I assume they can be used with UI Automation.
For example,
ID_ANNOTATIONS_DIMENSION_ALIGNED
can be found in the status bar text in this screen shot:
http://thebuildingcoder.typepad.com/.a/6a00e553e1689788330147e270f039970b-popup
So after *knowing* all command IDs, we could also *invoke* all commands:
http://thebuildingcoder.typepad.com/blog/2011/01/ribbon-spying-and-ui-automation.html
Cheers,
Rudi
Posted by: Rudolf Honke | June 21, 2012 at 05:34
Hi Jeremy,
I really doubt if overwriting existing functions should be done at all.
There are cases in which a plugin can affect the behaviour of the whole application, e.g. when using RegisterFailuresProcessor().
In the worst case, it may be that one of your installed plugins suppresses all warnings and errors, avoiding you from performing the needed error solution even manually.
When overwriting existing functions, it may be that the user doesn't even know that he uses a replacement function, depending on the documentation you shipped with your plugin.
Cheers,
Rudolf
Posted by: Rudolf Honke | June 21, 2012 at 06:18
You can also get a listing of all the Command_Ids from the keyboardshortcuts.xml file ")
Posted by: Phillip Miller | June 21, 2012 at 16:16
Hi, Rudolf.
I haven't seen this post before. Thanks for link. I think that information should useful for me.
Regards, Victor.
Posted by: Account Deleted | June 21, 2012 at 23:12
Hello, Phillip.
Where can I get the keyboardshortcuts.xml file? I cann't find it anywhere.
Posted by: Account Deleted | June 21, 2012 at 23:13
Hi Victor.
First you need to activate the keyboards shortcuts through the Revit UI by going to ribbon -> View -> User Interface -> keyboard shortcuts.
Add a shortcut and that will create the shortcuts file. I hope that helps.
Posted by: Phillip Miller | June 22, 2012 at 02:37
Dear Rudi,
Yes, very reasonable doubts indeed. Please take heed.
Cheers, Jeremy.
Posted by: Jeremy Tammik | June 28, 2012 at 03:08
Hi Jeremy,
Is invoking a command in this manner a recommended approach?
Thanks,
Dan
Posted by: Dan Tartaglia | June 28, 2012 at 09:41
Dear Dan,
There is currently no recommended approach to invoke a command. The Revit API does not support it at all. All you can do at the moment is replace a built-in Revit command with your own implementation. Everything else is unsupported and not recommended.
Cheers, Jeremy.
Posted by: Jeremy Tammik | June 28, 2012 at 09:55
Hi..Jeremy..
I am creating commandBinding() for revit "CreateSimilar" functionality. But I am not able to get orginal behaviour of "Create Similar" after removing Executed event from the document. How can i acheive this?
Thanks
Posted by: sangsen | July 17, 2012 at 03:02
You realize that the Excel sheet also exposes all internal Debugging commands? That is actually very handy.
Posted by: Martin Taurer | August 04, 2012 at 10:14
Dear Martin,
Thank you for pointing this out. Nope, I did not realise that.
Why do you find them handy, please? What do you use them for?
Thank you!
Cheers, Jeremy.
Posted by: Jeremy Tammik | August 15, 2012 at 06:37
Dear Sangsen,
Have you tried using UIApplication.RemoveAddInCommandBinding?
Cheers, Jeremy.
Posted by: Jeremy Tammik | August 15, 2012 at 07:37
On a semi-related note, I'm trying to identify the commands associated with Detail Lines for creating custom keyboard shortcuts. Modifying the commands for Contextual Tabs>Draw works for Filled Regions, Floors, etc. but does not seem to work for Detail Lines. Any idea where else to look?
Is there any way to get the command id associated with a particular button?
Posted by: Mark | August 23, 2012 at 12:38
Dear Mark,
I would have expected them to be in there.
If not, have you looked in the journal file?
Cheers, Jeremy.
Posted by: Jeremy Tammik | August 23, 2012 at 12:44
Doesn't seem to have "Edit Family" either which I really need.
Posted by: Michael | August 24, 2013 at 17:58
Dear Michael,
I guess they thought that you can do more with the EditFamily API method, and using OpenAndActivateDocument to navigate.
Or there were other internal reasons for not exposing such a complicated command :-)
Cheers, Jeremy.
Posted by: Jeremy Tammik | August 26, 2013 at 09:20
What if you were looking to have a warning dialog and then proceed with the originally requested command.
So you could use the commandBinding then run a eventhandler to show the dialog, could you then have the original command run after the user clicks OK on the warning box?
or is that a different process than commandbinding? Is there a process to catch when standard Revit commands are run and do things alongside the command?
Posted by: Drew | September 04, 2014 at 18:40
found it:
AddInCommandBinding.BeforeExecuted Event
Posted by: Drew | September 04, 2014 at 23:16
Cheeky question, but is there an updated list of internal commands for 2015? I am not sure what assembly reference I need for the InternalCommandDef so I haven't managed to get it working to try to get the data myself.
Posted by: DJ | November 07, 2014 at 19:52