Several people have asked about how to activate their custom add-in panel items when Revit is in zero document state, i.e. when no document has been opened in the Revit user interface:
For an external command, it is no big deal: if you set both its transaction mode and regeneration option to Manual, it will appear in the Revit ribbon panel under Add-Ins > External > External Tools and also be available in zero document state:
However, as you can see, all of the panels defined by external applications are disabled in this state.
Here is the code of an initial version of the external application ZeroDocPanel creating the right-most ribbon panel and push button that you see above and which is disabled in zero document state:
[Transaction( TransactionMode.Manual )] [Regeneration( RegenerationOption.Manual )] class App : IExternalApplication { public const string Caption = "Zero Doc Panel"; public const string Caption2 = "Zero Doc Button"; static string _path = System.Reflection.Assembly .GetExecutingAssembly().Location; public Result OnStartup( UIControlledApplication a ) { RibbonPanel p = a.CreateRibbonPanel( Caption ); PushButton b = p.AddItem( new PushButtonData( Caption2, Caption2, Path.GetDirectoryName( _path ), "ZeroDocPanel.Command" ) ) as PushButton; b.ToolTip = "This is the zero doc panel button tooltip"; return Result.Succeeded; } public Result OnShutdown( UIControlledApplication a ) { return Result.Succeeded; } }
This leads to the following question:
Question: I want to enable the ribbon items in a panel defined by my external application in zero document state. How can I achieve that, please?
In the Revit API help file RevitAPI.chm, I see a statement saying that "The push button will be disabled when there is no active document unless availability class of that button returns true". Could you please elaborate on this?
Answer: Yes, this statement is correct. Buttons defined by an external application are disabled by default in zero document state. If you provide an appropriate external command availability class implementation and return true, they will be enabled. Have you tried this?
We discussed the availability class in the presentation of the RevitAddInUtility, and also touched on it briefly when looking at the Revit 2011 product GUIDs, the add-in manifest tags, and the pipe to conduit converter
Besides being applied to external commands, you can also use the PushButton AvailabilityClassName property to control visibility of individual buttons.
By the way, you have to read the documentation of the IExternalCommandAvailability interface pretty carefully. One of the statements it makes is "This interface should share the same assembly with add-in External Command".
Let's enhance the external application presented above to enable its panel in zero document state. As said, we need to implement the IExternalCommandAvailability interface. Here is a very trivial implementation that simply always returns true:
public class Availability : IExternalCommandAvailability { public bool IsCommandAvailable( UIApplication a, CategorySet b ) { return true; } }
Here is the enhanced code of the ZeroDocPanel external application making use of the command availability class:
[Transaction( TransactionMode.Manual )] [Regeneration( RegenerationOption.Manual )] class App : IExternalApplication { public const string Caption = "Zero Doc Panel"; public const string Caption2 = "Zero Doc Button"; static string _path = System.Reflection.Assembly .GetExecutingAssembly().Location; public Result OnStartup( UIControlledApplication a ) { PushButtonData d = new PushButtonData( Caption2, Caption2, _path, "ZeroDocPanel.Command" ); d.AvailabilityClassName = "ZeroDocPanel.Availability"; RibbonPanel p = a.CreateRibbonPanel( Caption ); PushButton b = p.AddItem( d ) as PushButton; b.ToolTip = "This is the zero doc panel button tooltip"; //b.AvailabilityClassName // = "ZeroDocPanel.Availability"; return Result.Succeeded; } public Result OnShutdown( UIControlledApplication a ) { return Result.Succeeded; } }
One important thing to note is that the AvailabilityClassName property must be set on the PushButtonData instance before adding the push button to the panel, i.e. before calling the AddItem method with the PushButtonData information.
Setting this property afterwards will have no effect!
Alternatively, one can set the AvailabilityClassName property on the resulting PushButton instance itself after it has been added.
And, as said, the command availability class and external command implementation must live in the same .NET assembly. In our case, both of them and the external application implementation as well all share the same assembly.
Here is the ZeroDocPanel external application showing its activated push button in zero document state:
Here is ZeroDocPanel.zip containing the entire source code and Visual Studio solution implementing this add-in.
Addendum: As Arnošt points out in his comment below, the Transaction attribute shown above is unnecessary and will be ignored. I discuss this issue in more detail in an updated note on external application attributes, and removed the attribute in the zip file above.
Hi Jeremy !
Is there any possibility to enable my PushButtons in Views of ViewType.Schedule ?
Thanks,
Rudolf
Posted by: Rudolf Honke | February 18, 2011 at 06:05
Dear Rudolf,
Nope, sorry, not that I know of.
Cheers, Jeremy.
Posted by: Jeremy Tammik | February 19, 2011 at 10:31
FYI: The transaction attribute (e.g. TransactionMode.manual) is only applicable to external commands, not applications. It should be treated as an addin declaration error but since it is harmless it is quietly ignored. (It could be treated as an error in the future though.)
Posted by: Arnošt Löbel | February 22, 2011 at 16:20
Hi Jeremy,
Thank you for all your help in the past two years:)
I am still having problems with enabling custom command buttons. I have implemented Availability Class and done as you said here (I have also inserted AvailabilityClassName tag in *.addin file). Command Buttons are enabled, as is External Tools button, but only on app start up. It goes back to disabled state as soon as I open some project.
Thanks again, wish you all the best.
Posted by: Marko | September 23, 2011 at 04:38
It's ok now, my .addin file was bad.
Thanks
Posted by: Marko | September 29, 2011 at 05:36
Dear Marko,
Thank you very much for your appreciation, I am ever so glad I was able to help in the past.
Congratulations on solving your current problem!
I actually tried to answer to your previous comment, but something went wrong with the system here, and it did not show up.
Here is what I wanted to say:
There are only two possibilities: there is something wrong with your availability class implementation and behaviour, or you are running in some state which disables all external commands:
http://thebuildingcoder.typepad.com/blog/2009/06/rfa-version-grey-commands-family-context-and-rdb-link.html#2
I would try removing the availability class and all references to it, and see whether the buttons are displayed normally again then.
Anyway, now you resolved it, and the comments are working again as well.
Oh, and I also tried to email you an answer, but was told that "Delivery has failed to these recipients or groups..." Tant pis. :-)
Cheers, Jeremy.
Posted by: Jeremy Tammik | September 29, 2011 at 06:24
Jeremy,
I am having a difficult time finding any documentation regarding availability of a textbox during a zero document state. Every time my textbox event is fired it seems like the event is getting the active document or document (which none are open). In my textbox event and subsequent functions there are no calls to acquire the UI. Where am I going wrong?
Matt
Posted by: Matt | November 11, 2012 at 18:27
Dear Matt,
Thank you, interesting issue. Never heard of it before.
Could you please submit an ADN DevHelp Online case for that and supply a sample add-in demonstrating the problem, preferably a complete Visual Studio solution so that we can compile, install and reproduce the problem our end with one single click?
Then we can research the issue and forward to the development team if need be. Thank you!
Cheers, Jeremy.
Posted by: Jeremy Tammik | November 12, 2012 at 03:00
Jeremy,
Does this only work for buttons on the Add-Ins tab? I can't seem to make it work for my own tab. After I load Revit 2013 and click on my tab I get "Revit cannot run availability command "name i gave". Contact the provider..."
In the detail section it says "System.TypeLoadException while creating instance of 'name' in 'my dll path.' Thanks.
Posted by: Mike | October 16, 2013 at 22:40
Dear Mike,
I would expect the availability class to work in the same manner for all buttons.
Cheers, Jeremy.
Posted by: Jeremy Tammik | October 17, 2013 at 09:49
Jeremy,
I figured out the problem. I didn't realize the importance of the string name "ZeroDocPanel.Availability". After I input my app's namespace plus .Availability, it worked. Thanks again.
Posted by: Mike | October 18, 2013 at 20:25
Dear Mike,
That makes sense, a lot! Congratulations on fixing it!
Cheers, Jeremy.
Posted by: Jeremy Tammik | October 22, 2013 at 05:28
Hi Jeremy
Is there a way to Enable Ribbon Items while been in a PromptForFamilyInstancePlacement command?.
Thanks.
Posted by: Fm2 | January 08, 2014 at 16:42
Dear Fm2,
In brief, no. Sorry.
Cheers, Jeremy.
Posted by: Jeremy Tammik | January 10, 2014 at 06:47