Here is an interesting user interface contribution from Eduardo Teixeira of Autodesk:
Question: I am building a Revit add-in using the Revit API.
I would like to add a button for it to an existing out-of-the-box Revit ribbon panel using the Revit API in C#.
I could not find any documentation that shows how to do that.
Is it possible at all?
Answer: Yes, this can be done. I am not certain whether it is officially supported, though. You will have to explore on your own a bit.
The official API is limited. You can however also use functionality from the .NET UI Automation library and from the AdWindows.dll .NET assembly included with Revit, similar to the one provided with AutoCAD.
Here are some previous discussion exploring related issues that might help:
- Pimp my ribbon
- Roll a toggle button
- Enable button in zero document state
- Add non-command button to the ribbon
Response: Thanks for the tip. The article that really helped me was the first one you list. I was able to add a button to the existing out-of-the-box Energy Analysis panel under the Analyze tab.
There are just two simple steps required achieve the desired result:
To add a custom button to the Analyze tab in the Revit Energy Analysis ribbon panel:
- Add a reference to the AdWindows.dll .NET assembly provided with Revit.
- Add the two snippets of source code listed below to the external application implementation:
- In OnStartup, create and add the button.
- Handle the UIElementActivated event.
Adding the References
Add a reference to the AdWindows.dll .NET assembly provided with Revit.
Don't forget to set the copy local flag to false on that.
This will also require references to the .NET WindowsBase and PresentationFramework assemblies, which in turn require PresentationCore and System.Xaml.
Creating and Adding the Button
In OnStartup, localise the existing tab and panel, instantiate a new ribbon button, add it to the tab, and subscribe to the UIElementActivated event.
Here is a simplified version of Eduardo's code set up to run on Jeremy's system and open the browser to display The Building Coder home page:
public Result OnStartup( UIControlledApplication a ) { adWin.RibbonControl ribbon = adWin.ComponentManager.Ribbon; foreach( adWin.RibbonTab tab in ribbon.Tabs ) { if( tab.Id == "Analyze" ) { foreach( adWin.RibbonPanel panel in tab.Panels ) { if( panel.Source.Id == "cea_shr" ) { adWin.RibbonButton button = new adWin.RibbonButton(); button.Name = "TbcButtonName"; //button.Image = image; //button.LargeImage = image; button.Id = "ID_TBC_BUTTON"; button.AllowInStatusBar = true; button.AllowInToolBar = true; button.GroupLocation = Autodesk.Private .Windows.RibbonItemGroupLocation.Middle; button.IsEnabled = true; button.IsToolTipEnabled = true; button.IsVisible = true; button.ShowImage = false; // true; button.ShowText = true; button.ShowToolTipOnDisabled = true; button.Text = "The Building Coder"; button.ToolTip = "Open The Building " + "Coder blog on the Revit API"; button.MinHeight = 0; button.MinWidth = 0; button.Size = adWin.RibbonItemSize.Large; button.ResizeStyle = adWin .RibbonItemResizeStyles.HideText; button.IsCheckable = true; button.Orientation = System.Windows .Controls.Orientation.Vertical; button.KeyTip = "TBC"; adWin.ComponentManager.UIElementActivated += new EventHandler< adWin.UIElementActivatedEventArgs>( ComponentManager_UIElementActivated ); panel.Source.Items.Add( button ); return Result.Succeeded; } } } } return Result.Succeeded; }
As you can see, I am triggering the reaction to the button click by subscribing to the UIElementActivated event. Not sure if this is the correct way of doing it, but it works.
Handling the Event
In the event handler, check that the custom button was actually clicked and act on that, e.g. opening the browser at a specified URL.
void ComponentManager_UIElementActivated( object sender, adWin.UIElementActivatedEventArgs e ) { if( e != null && e.Item != null && e.Item.Id != null && e.Item.Id == "ID_TBC_BUTTON" ) { // Perform the button action // Local file string path = System.Reflection.Assembly .GetExecutingAssembly().Location; path = Path.Combine( Path.GetDirectoryName( path ), "test.html" ); // Internet URL path = "http://thebuildingcoder.typepad.com"; Process.Start( path ); } }
Note that this requires no interaction with the Revit database, so there is no need to worry about a valid API context or transactions or any of that stuff.
Many thanks to Eduardo for sharing this!
Sample Run
Jeremy adds: for your convenience, here is AddButton.zip containing the source code, Visual Studio solution and add-in manifest for my version of this external application.
On my system, however, the button appears in the expected location but is disabled, so no action is triggered:
I am not sure why that happens. Maybe Eduardo or somebody else can help resolve this.
Hi Jeremy, hi Eduardo,
when the button is invoked, you could subsribe to OnIdling event to gain access to the Revit database.
Button disabled: as far as I know, we need to set the AvailabilityClassName property of the RibbonButton...
Ah, I see that Autodesk.Windows.RibbonButton class differs from Autodesk.Revit.UI.RibbonButton class.
Since you are using the first one, there is no AvailabilityClassName property on your button object.
Instead of this, I think there is some sort of "command binding" which manages the visibility.
I just looked over Kean's blog postings but did not found related entries so far.
Since we can get the adWin.RibbonButton from the Revit.UI.RibbonButton via Reflection, there might be a way to cast the first into the second.
Sorry for providing just ideas and suggestions, but maybe that may help you nontheless.
Cheers,
Rudolf
Posted by: Rudolf Honke | February 07, 2013 at 06:57
This will only work on Revit 2014.
Posted by: Eduardo P Teixeira | February 12, 2013 at 18:04
Hi Jeremy
I have been creating various add-ins for Revit and have managed to create a custom Ribbon tab on which to place all the commands/icons.
What I would like to do, but cannot find any information on how to achieve it is to add an existing in-built Revit command onto my custom Ribbon. I want to add the "Modify" command as the first item on my Ribbon.
many thanks
Paul
Posted by: Paul Marsland | May 12, 2014 at 06:13
Dear Paul,
You can create a new custom external command of your own, just like usual.
Within it, you can invoke the existing Revit built-in command using the PostCommand functionality:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.3
Cheers, Jeremy.
Posted by: Jeremy Tammik | May 13, 2014 at 09:07
I installed the DockableDialogs example from Revit 2015 SDK and the "Register Page" button is disabled like the button in this post? Any idea why?
Posted by: ZydecoDigital | May 13, 2014 at 22:57
Class ExternalCommandRegisterPage implements IExternalCommandAvailability which has an IsCommandAvailable method. The implementation forces you to register the dialog when a document isn't loaded.
Posted by: ZydecoDigital | May 14, 2014 at 20:42
Dear ZydecoDigital,
Ours is not to wonder why, ours is but to do or die.
Do you have it working now?
Cheers, Jeremy.
Posted by: Jeremy Tammik | May 16, 2014 at 03:06
Dear Jeremy
thanks you for this valuable blogger
i have problem don't know how to solve
i'm creating two different applications for revit
they both should use the same ribbon and tab
how can i do that
please help in this issue
is this article help???
Posted by: hazem | March 20, 2015 at 12:30