Custom Ribbon Tab

I am still on tour presenting at the Western European DevDays conferences, and with no time for blogging or responding to comments.
In fact, I have almost no time for anything at all except presenting, meeting and discussing with participants during the day, and getting from one city to the next in the evenings.
Right now I am sitting in the airport waiting for a plain to Milano.
Back to Bella Italia, albeit for less than twenty-four hours.

I was hoping to find time to prepare a few blog posts in advance for the coming weeks, when I will be gone on holidays and vacation.
Friday is supposed to be my last working day this year, and I am starting to wonder whether I will be able to just walk away from all the unresolved issues and leave them to lie until next year.

Anyway, in a sleepless hour in between I noticed that Augusto Gonçalves responded once again to a question that has already come up a few times in the past, so his interesting result is well worth while presenting, even if it is not directly useful in the context of the Revit API.
It deals with the frequent question on whether it is possible to add your own ribbon tab to the Revit user interface.

Question: I expect the answer to this is no, but I thought I would at least ask anyway.
Is it possible to create a new ribbon tab in Revit, similar to AutoCAD 2010, or are panels within the Add-Ins tab and items within those panels the only ribbon objects that can be accessed and created from a Revit add-in?

Answer: There is no documented support for this in the Revit API that I am aware of.
There are however a couple of undocumented and unsupported .NET assemblies that can be used to access the Revit ribbon in an unsupported way.
The functionality they provide can even be used to add your own custom panel to the Revit ribbon.
What you cannot do, however, is create the context and data required to invoke a standard Revit external command.
We have implemented a sample that creates an own custom tab and adds it to the Revit ribbon.
It displays a command button which can be used to invoke Revit independent functionality.

The functionality to create a new custom panel and add a command button to it is provided by classes in the Autodesk.Windows namespace.
These classes have no knowledge of Revit and its API, and we have not found any way to access the command data required to invoke an external command and make use of the Revit API from such a button.
As long as you are happy just doing .NET stuff completely independently of Revit, you can make use of this.
This functionality is unsupported, and to be used at your own risk, of course.

In addition to the RevitAPI.dll assembly providing access to the Revit API functionality, we reference two other undocumented .NET assemblies provided by Revit, which also live in the Revit Program folder: AdWindows.dll and UIFramework.dll.
These in turn require us to reference some other .NET framework functionality, so we end up with the following list of references.
As always, we need to remember to set the ‘Copy Local’ flag to ‘False’ on the three assemblies referenced from the Revit folder:

  • AdWindows
  • PresentationCore
  • PresentationFramework
  • RevitAPI
  • System
  • System.Windows.Forms
  • UIFramework
  • WindowsBase

We implement an external application named App which makes use of the ribbon functionality provided by the AdWindows and UIFramework assemblies to add its own custom tab and panel to the existing Revit ribbon.
The custom panel displays one ribbon button which invokes a command.

The command needs to implement the System.Windows.Input.ICommand interface.
Note that this definition is completely independent of the Revit external command interface, and actually that is the main problem with our custom ribbon tab: while we can add a tab with its panel and button invoking a command, this is not a standard Revit command, and we have no way to connect it with Revit or make proper use of the Revit API within the command implementation.
It can be used to invoke Revit-independent functionality.

Here is the definition of the command implementation derived from ICommand and its Execute method, which in turn invokes the Execute method of an external Revit command implementation AddRibbonTab.Command, but supplies it with a null ExternalCommandData instance:


public class AdskCommandHandler
  : System.Windows.Input.ICommand
{
  string AssemblyName
  {
    get;
    set;
  }
 
  string ClassName
  {
    get;
    set;
  }
 
  public AdskCommandHandler(
    string assemblyName,
    string className )
  {
    AssemblyName = assemblyName;
    ClassName = className;
  }
 
  public event EventHandler CanExecuteChanged;
 
  public bool CanExecute( object a )
  {
    return true;
  }
 
  public void Execute( object a )
  {
    System.Reflection.Assembly assembly
      = System.Reflection.Assembly.LoadFrom(
        AssemblyName );
 
    IExternalCommand command
      = assembly.CreateInstance(
        ClassName ) as IExternalCommand;
 
    Debug.Print(
      "AdskCommandHandler.Execute command invoked: "
      + "assembly {0}, class {1}",
      AssemblyName, ClassName );
 
    ExternalCommandData commandData = null;
    string message = string.Empty;
    ElementSet elements = null;
 
    IExternalCommand.Result r
      = command.Execute( commandData,
        ref message, elements );
  }
}

Here is the OnStartup method of the external application creating the custom ribbon tab.
Note that the RibbonPanel created here is an Autodesk.Windows.RibbonPanel instance, not an Autodesk.Revit one:


public IExternalApplication.Result OnStartup(
  ControlledApplication a )
{
  // create new ribbon button:
 
  RibbonButton button = new RibbonButton();
  button.Text = "My Button";
  button.ShowText = true;
  button.CommandHandler = new AdskCommandHandler(
    "AddRibbonTab.dll", "AddRibbonTab.Command" );
 
  // create new ribbon panel:
 
  RibbonPanelSource source = new RibbonPanelSource();
  source.Title = "My Panel";
  source.Items.Add( button );
 
  RibbonPanel panel = new RibbonPanel();
  panel.Source = source;
 
  // create custom ribbon tab:
 
  RibbonTab tab = new RibbonTab();
  tab.Id = "MY_TAB_ID";
  tab.Title = "My Custom Tab";
  tab.IsVisible = true;
 
  // access Revit ribbon control and add custom tab:
 
  RibbonControl control
    = UIFramework.RevitRibbonControl.RibbonControl;
 
  control.Tabs.Add( tab );
  tab.Panels.Add( panel );
 
  return IExternalApplication.Result.Succeeded;
}

Here is the resulting custom ribbon tab with its panel and command button displayed in Revit MEP 2010:

Custom ribbon tab

Here is the complete
AddRibbonTab source code and Visual Studio solution.

Many thanks to Augusto for exploring and discovering this undocumented functionality and providing the surprising sample code!


Comments

29 responses to “Custom Ribbon Tab”

  1. Jeremy,
    Good luck with your trip.
    If the PushButton text is long, for example “My External Command” (hypothetical example), how can I place it on two lines just like it is shown in the “Structural Settings” Command in the “Manage” tab.
    Regards,
    Nadim

  2. Dear Nadim,
    There is no support for this in the Revit API. You may be able to somehow use some Revit independent API to access the ribbon buttons and modify their content. If you succeed with that, please let us know. Thank you!
    Cheers, Jeremy.

  3. Thanks Jeremy,
    Is there any support for having a default button in the PullDownButton?
    I mean by that when hte pulldownbutton looks like two parts, the upper partclicks on of the pushbuttons in the list, and the bottom part gives the menu of pushbuttons added to this pulldownbutton.
    Example: Revit UI has alot of examples on this, like, Wall pulldownbutton (Home tab), ElementProperties pulldownbutton ( the default is the Instance Properties)
    Regards,
    Nadim,

  4. Dear Nadim,
    As far as I know, the Revit API currently does not provide this possibility. As said before, the SDK Ribbon sample demonstrates everything that can be done with ribbons through the Revit API. I don’t know whether it might be possible to use some Revit independent API to access the ribbon buttons and modify their behaviour like you describe. If you succeed with that, please let us know. Thank you!
    Cheers, Jeremy.

  5. TypePad HTML Email
    Thanks Jeremy,
    I guess Ill wait until these features are added to the API.
    Regards,
    Nadim

  6. Hi Jeremy,
    I have similar questions regarding the Ribbon Panel in Revit API, and will really appreciate if you could take a look at them:
    1) Is it possible to create a PullButton (B) inside another PullButton (A)and add couple of other PushButtons (a,b,c…)? (like A->B->(a,b,c…));
    2) I notice in your example, you have a “Press F1 for More Help” text line with a horizontal separator from the above button. So how to create a horizontal separator inside the PullButton? All I got from the API guide is the vertical separator for the Ribbon Panel(ribbonPanel.AddSeparator()).
    3) Currently Revit API only allows to stack 3 or less buttons, is there anyway to override that?
    Thank you!
    Happy New Year!
    Wei

  7. Dear Wei,
    Happy New Year to you too!
    1. Not as far as I know.
    2. The horizontal separator is in the tooltip that Revit has automatically created and displayed, not in the button.
    3. Not as far as I know.
    Cheers, Jeremy.

  8. Hi Jeremy,
    Thanks for the reply. It seems that Revit wants to keep the panels simple and tidy:)
    Anyways, I found something funny! When I created some (3+) ribbon panels with 1-tier pulldown buttons within the same C# project, and built them as add-in to the Revit program, it surprisingly became some 2-tier pulldown buttons because the panels took too much space and automatically contracted into pulldown button! Does Revit have some implicit rule on how big a panel should be? I know the panel images can’t exceed 32×32 pixels, but how could we actually configure these dimensions?
    Another question that has been bothering me is about the schedules/quantities. Shared parameters are very useful in the Revit program, and I tend to use them across different schedules/quantities or material takeoffs. However, is there any chance that we could link different schedules/quantities like we did in relational database (e.g. the Access or even the GIS program)based on specific shared parameter? Or could we make use of Revit API to manipulate those schedules/quantities tables as we did in Excel, say fill in a field in the table using functions?

  9. Sorry for being so wordy, but it’s kind of difficult to describe the problem. I really want to post some image to make things more explicit but obviously TypePad won’t let me.
    Thanks for answering my questions!

  10. Dear Wei,
    I really cannot say anything about the automatic reconfiguration that you describe.
    Regarding the schedules, we do not have any access at all to those in the Revit API as of yet.
    Cheers, Jeremy.

  11. Dear Wei,
    No problem at all, and sorry for the typepad limitations!
    Cheers, Jeremy.

  12. Sergey Avatar
    Sergey

    Hi Jeremy
    problem is – when opening family document for edit (“Edit family”) and then closing it – panel dissapeared
    i didn’t founded the way to recreate it again
    mb you know the solution for such situation?

  13. Dear Sergey,
    Nope, sorry, I have not heard of that problem before. Congratulations on finding something new :-)
    In 2010, there was some discussion on the topic of greyed out commands now and then, which I summarised in
    http://thebuildingcoder.typepad.com/blog/2009/06/rfa-version-grey-commands-family-context-and-rdb-link.html#2
    Cheers, Jeremy.

  14. Sergey Avatar
    Sergey

    thx Jeremy Tammik
    by it’s sad finding..
    by problem not in greyed out commands.. problem that tab missing after such Edit family manipulation..
    seems that we need to move to standard Add-it panel :( it’s sad, because of we have some nesting panels in our tab
    Jeremy, thx anyway

  15. Dear Sergey,
    Oh, now I understand. You are talking about your own custom panel that you added yourself.
    That is completely unsupported, so I would absolutely expect that to cause problems!
    Who knows what Revit does in the background. Maybe it regenerates all panels regularly as it sees fit. Not knowing about your custom panel, that would of course be obliterated by the Revit panel regeneration.
    I am not surprised, nor should you be.
    Cheers, Jeremy.

  16. Sergey Avatar
    Sergey

    Dear Jeremy
    sorry, my question was not clear
    yes, i was talking about custom panel
    thx

  17. Jinsol Avatar
    Jinsol

    Hello,
    I’ve been also looking for same solution you asked. Do you have any progress about this? or just forget about it and leave the tab as it is.

  18. Mohammad El Charfa Avatar
    Mohammad El Charfa

    Hi,
    Thanks for the great blog, but I am having a little issue with getting the application instance since the commanddata is null. How did ya’ll overcome that?
    Thanks,

  19. Dear Mohammad,
    Thank you for your query and your ADN case 1261390 [ExternalCommandData]. Please only use one of the channels in future, preferably the ADN DevHelp online one, since that will guarantee you an answer from anyone on the team and also ensure that the information is tracked in our internal knowledge base and can be easily hooked up with requests and wish list items.
    As stated in the blog post above, this method is not officially supported by the API and we cannot offer any help through ADN for these kind of workarounds.
    The Revit API only supports plug-ins adding entries to the existing Add-Ins and Analyse tabs in the Revit user interface.
    Still, the null value that I provide in the sample above can be improved upon, as demonstrated by Guy Robinson on his blog. I mentioned his posts on this topic in
    http://thebuildingcoder.typepad.com/blog/2009/12/create-a-real-revit-ribbon-tab.html
    http://thebuildingcoder.typepad.com/blog/2010/01/custom-ribbon-tab-context-switch.html
    I repeat that creating your own tab in the Revit ribbon is not officially supported, so you are making use of this functionality at your own risk and we cannot provide you with any support whatsoever in this area if you run into problems.
    Cheers, Jeremy.

  20. Nishant Avatar
    Nishant

    Error 1 The type name ‘Result’ does not exist in the type ‘Autodesk.Revit.UI.IExternalCommand’ E:_Software Development\Revit Plugins\RoomRenumbering1.4\Source\Commands.cs 133 30 RoomRenumbering
    Error 2 ‘Autodesk.Revit.UI.IExternalApplication’ does not contain a definition for ‘Result’ E:_Software Development\Revit Plugins\RoomRenumbering1.4\Source\Commands.cs 514 39 RoomRenumbering
    Hii i am getting the above errors.. Please help.

  21. Dear Nishant,
    It looks to me as if you are referring to the wrong version of the Revit API assemblies. For instance, you may be trying to compile a Revit 2011 or 2012 add-in with the Revit 2010 API assemblies or vice versa.
    Cheers, Jeremy.

  22. Nishant Avatar
    Nishant

    Thanks for the reply. Actually i am very new to revit development. All i know is that i am using Revit 2011.
    1) I want a separate button on the ribbon for the element renumbering add-in of the month. Could you please guide me as to how to go about it with respect to your code ?
    The add-in works fine otherwise.
    2) I want to add support for pipes but can’t find the built in category. Help me regarding this if u can.
    Thanks.

  23. Nishant Avatar
    Nishant

    Hi jeremy. I am still stuck with my above mentioned problems. Please help if u can.
    Thanks.

  24. Dear Nishant,
    So you are having problems trying compiling the room renumbering plugin of the month?
    As I said above, off-hand it looks to me as if you have some kind of version problem.
    Have you ever compiled any other Revit add-in of your own?
    If so, you should be able to solve this.
    If not, I suggest working through the ‘My First Revit Plug-in’ tutorial:
    http://thebuildingcoder.typepad.com/blog/2011/05/my-first-revit-plug-in.html
    I hope this helps resolve the issue. Good luck!
    Cheers, Jeremy.

  25. Dear Sir,
    I want to assign a shortcut key for this custom Tab.
    For example, Alt + H —> Home.
    I have tried this, but still in confusion. Please help me.
    Thankyou,
    Jayshree.

  26. mgibbons@hobbs-black.com Avatar
    mgibbons@hobbs-black.com

    Hi Jeremy,
    I have copied over the code to make my own ribbon tab, but it comes up with one error: “Error 1: The type or namespace name ‘Windows’ does not exist in the namespace ‘System’ (are you missing an assembly reference?)” Which reference file do I need?
    thanks!
    Mark

  27. Dear Mark,
    They are listed above in the one and only bullet list in the answer.
    Cheers, Jeremy.

  28. dear jeremy,
    when i use the above code on revit 2014
    it doesn’t work due to many cross references
    can you help

  29. Dear Jeremy,
    When I use the above code on revit 2015 it doesn’t work too.
    Thanks.

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading