The interface IExternalCommandAvailability can be implemented to enable or disable Revit external commands (IExternalCommand) through setting the AvailabilityClassName Property of their associated buttons if applicable. Both PushButton and ToggleButton and their data classes have the property.
It is not mandatory though and by default commands will be available to any documents and element selections.
The IExternalCommandAvailability has a single method IsCommandAvailable() and it needs to be implemented. If the associated command (button actually) is supposed to deal with the situation that the derivative of the IExternalCommandAvailability specifies, true needs to be returned, otherwise false.
Let’s look at some particular cases to make the picture a bit clearer.
Some commands are supposed to run on the platform of Revit Architecture only, what the method IsCommandAvailable of the interface IExternalCommandAvailability should look like?
Here it is:
public bool IsCommandAvailable(UIApplication uiApp, CategorySet catSet)
{
if (uiApp.Application.Product == ProductType.Structure) return false;
if (uiApp.Application.Product == ProductType.MEP) return false;
}
What about some other commands only work with walls, windows, or stairs?
Checking the CategorySet argument to see if it contains the OST_Walls, OST_Windows, or OST_Stairs category is the way to go:
public bool IsCommandAvailable(UIApplication uiApp, CategorySet catSet)
{
Categories allCats = uiApp.ActiveUIDocument.Document.Settings.Categories;
Category cat = allCats.get_Item(BuiltInCategory.OST_Walls);
if (catSet.Contains(cat)) return true;
cat = allCats.get_Item(BuiltInCategory.OST_Windows);
if (catSet.Contains(cat)) return true;
cat = allCats.get_Item(BuiltInCategory.OST_Stairs);
if (catSet.Contains(cat)) return true;
return false;
}
Ok, now another a bit complicated situation: the command is available to Revit Architecture only, and when nothing is selected or, some walls, windows or stairs are selected beforehand.
Similar way but with some more checking branches:
public bool IsCommandAvailable(UIApplication uiApp, CategorySet catSet)
{
if (uiApp.Application.Product == ProductType.Structure) return false;
if (uiApp.Application.Product == ProductType.MEP) return false;
if (catSet.IsEmpty) return true;
Categories allCats = uiApp.ActiveUIDocument.Document.Settings.Categories;
Category cat = allCats.get_Item(BuiltInCategory.OST_Walls);
if (catSet.Contains(cat)) return true;
cat = allCats.get_Item(BuiltInCategory.OST_Windows);
if (catSet.Contains(cat)) return true;
cat = allCats.get_Item(BuiltInCategory.OST_Stairs);
if (catSet.Contains(cat)) return true;
return false;
}
All relevant including some testing code has been appended below:
#region Namespaces
using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.IO;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.UI.Events;
using Autodesk.Revit.Collections;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.Utility;
using RvtApplication = Autodesk.Revit.ApplicationServices.Application;
using RvtDocument = Autodesk.Revit.DB.Document;
#endregion
namespace RevitAddinCSProject
{
public class CommandEnabler : IExternalCommandAvailability
{
#region IExternalCommandAvailability Members
public bool IsCommandAvailable(UIApplication uiApp, CategorySet catSet)
{
if (uiApp.Application.Product == ProductType.Structure) return false;
if (uiApp.Application.Product == ProductType.MEP) return false;
if (catSet.IsEmpty) return true;
Categories allCats = uiApp.ActiveUIDocument.Document.Settings.Categories;
Category cat = allCats.get_Item(BuiltInCategory.OST_Walls);
if (catSet.Contains(cat)) return true;
cat = allCats.get_Item(BuiltInCategory.OST_Windows);
if (catSet.Contains(cat)) return true;
cat = allCats.get_Item(BuiltInCategory.OST_Stairs);
if (catSet.Contains(cat)) return true;
return false;
}
#endregion
}
}
public void AddRibbonItemsToRibbonPanel(RibbonPanel panel)
{
string assemFullName = Assembly.GetExecutingAssembly().Location;
string assemPath = Path.GetDirectoryName(assemFullName);
PushButtonData cnt1Panel_grp0_item1Data = new PushButtonData("cnt1Panel_grp0_item1", @"PushButton1", assemFullName, "RevitAddinCSProject.ExtCmd");
PushButton cnt1Panel_grp0_item1 = panel.AddItem(cnt1Panel_grp0_item1Data) as PushButton;
cnt1Panel_grp0_item1.ToolTip = @"A PushButton with the default image.";
cnt1Panel_grp0_item1.LargeImage = BmpImageSource(@"RevitAddinCSProject.Resources.ExtCmd.bmp");
cnt1Panel_grp0_item1.AvailabilityClassName = "RevitAddinCSProject.CommandEnabler";
panel.AddSeparator();
PushButtonData cnt1Panel_grp0_item3Data = new PushButtonData("cnt1Panel_grp0_item3", @"PushButton2", assemFullName, "RevitAddinCSProject.ExtCmd1");
PushButton cnt1Panel_grp0_item3 = panel.AddItem(cnt1Panel_grp0_item3Data) as PushButton;
cnt1Panel_grp0_item3.ToolTip = @"A PushButton with a new image.";
cnt1Panel_grp0_item3.LargeImage = BmpImageSource(@"RevitAddinCSProject.Resources.BigA.bmp");
}
public static System.Windows.Media.ImageSource BmpImageSource(string embeddedPath)
{
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedPath);
var decoder = new System.Windows.Media.Imaging.BmpBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
return decoder.Frames[0];
}
If the test application is loaded into Revit Architecture and nothing is selected for example, the command (actually represented by the left PushButton in the following panel) will be available:
If the platform is Revit Structure or only some grids are selected for example, the command (actually represented by the left PushButton in the following panel) will be disabled:
RevitAddinWizard can help implement the IExternalCommandAvailability interface automatically with its Command Enabler in a few seconds and supports all Revit flavors and categories and any combinations of them.
Links to some related articles:
Use RevitAddinWizard to Create IUpdater Derivatives of Revit API
Implement IFailuresPreprocessor of Revit API
Use RevitAddinWizard to Implement IFailuresPreprocessor of Revit API
Implement An IFailuresProcessor of Revit API
Use RevitAddinWizard to Implement IFailuresProcessor of Revit API
Command Availability And Revit Flavors/Categories of Revit API
Use RevitAddinWizard to Implement IExternalCommandavailability of Revit API
Implement ISelectionFilter of Revit API
Use RevitAddinWizard to Implement ISelectionFilter of Revit API
Recent Comments