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 a particular case: the command is available to Revit Architecture only and when nothing is selected or some walls, windows or stairs are selected beforehand.
Public Function IsCommandAvailable(ByVal uiApp As UIApplication, ByVal catSet As CategorySet) As Boolean Implements IExternalCommandAvailability.IsCommandAvailable
If uiApp.Application.Product = ProductType.Structure Then
Return False
End If
If uiApp.Application.Product = ProductType.MEP Then
Return False
End If
If catSet.IsEmpty Then
Return True
End If
Dim allCats As Categories = uiApp.ActiveUIDocument.Document.Settings.Categories
Dim cat As Autodesk.Revit.DB.Category = allCats.Item(BuiltInCategory.OST_Walls)
If catSet.Contains(cat) Then
Return True
End If
cat = allCats.Item(BuiltInCategory.OST_Windows)
If catSet.Contains(cat) Then
Return True
End If
cat = allCats.Item(BuiltInCategory.OST_Stairs)
If catSet.Contains(cat) Then
Return True
End If
Return False
End Function
All relevant code has been appended below:
#Region "Namespaces"
Imports System.Text
Imports System.Linq
Imports System.Xml
Imports System.Reflection
Imports System.ComponentModel
Imports System.Collections
Imports System.Collections.Generic
Imports System.Windows
Imports System.Windows.Media.Imaging
Imports System.Windows.Forms
Imports System.IO
Imports Autodesk.Revit.ApplicationServices
Imports Autodesk.Revit.Attributes
Imports Autodesk.Revit.DB
Imports Autodesk.Revit.DB.Events
Imports Autodesk.Revit.DB.Architecture
Imports Autodesk.Revit.DB.Structure
Imports Autodesk.Revit.DB.Mechanical
Imports Autodesk.Revit.DB.Electrical
Imports Autodesk.Revit.DB.Plumbing
Imports Autodesk.Revit.UI
Imports Autodesk.Revit.UI.Selection
Imports Autodesk.Revit.UI.Events
Imports Autodesk.Revit.Collections
Imports Autodesk.Revit.Exceptions
Imports Autodesk.Revit.Utility
Imports RvtApplication = Autodesk.Revit.ApplicationServices.Application
Imports RvtDocument = Autodesk.Revit.DB.Document
#End Region
Public Class CommandEnabler
Implements IExternalCommandAvailability
#Region "IExternalCommandAvailability Members"
Public Function IsCommandAvailable(ByVal uiApp As UIApplication, ByVal catSet As CategorySet) As Boolean Implements IExternalCommandAvailability.IsCommandAvailable
If uiApp.Application.Product = ProductType.Structure Then
Return False
End If
If uiApp.Application.Product = ProductType.MEP Then
Return False
End If
If catSet.IsEmpty Then
Return True
End If
Dim allCats As Categories = uiApp.ActiveUIDocument.Document.Settings.Categories
Dim cat As Autodesk.Revit.DB.Category = allCats.Item(BuiltInCategory.OST_Walls)
If catSet.Contains(cat) Then
Return True
End If
cat = allCats.Item(BuiltInCategory.OST_Windows)
If catSet.Contains(cat) Then
Return True
End If
cat = allCats.Item(BuiltInCategory.OST_Stairs)
If catSet.Contains(cat) Then
Return True
End If
Return False
End Function
#End Region
End Class
Here is the test code:
Function CreateRibbonPanel() As RibbonPanel
Dim panel As RibbonPanel = _cachedUiCtrApp.CreateRibbonPanel("Revit2011x64VBAddinByVS2008")
Dim assemFullName As String = Assembly.GetExecutingAssembly().Location
Dim assemPath As String = Path.GetDirectoryName(assemFullName)
Dim cnt1Panel_grp0_item1Data As PushButtonData = New PushButtonData("cnt1Panel_grp0_item1", "PushButton1", assemFullName, "Revit2011x64VBAddinByVS2008.ExtCmd")
Dim cnt1Panel_grp0_item1 As PushButton = CType(panel.AddItem(cnt1Panel_grp0_item1Data), PushButton)
cnt1Panel_grp0_item1.ToolTip = "A PushButton with the default image."
cnt1Panel_grp0_item1.LargeImage = BmpImageSource("Revit2011x64VBAddinByVS2008.ExtCmd32x32.bmp")
cnt1Panel_grp0_item1.AvailabilityClassName = "Revit2011x64VBAddinByVS2008.CommandEnabler"
Return panel
End Function
Private Function BmpImageSource(ByVal embeddedPath As String) As System.Windows.Media.ImageSource
Dim stream As Stream = Me.GetType().Assembly.GetManifestResourceStream(embeddedPath)
Dim decoder As BmpBitmapDecoder = New System.Windows.Media.Imaging.BmpBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default)
Return decoder.Frames(0)
End Function
If the test application is loaded into Revit Architecture and nothing is selected for example, the command (actually represented by the PushButton) will be available.
If the platform is Revit Structure or only some grids are selected for example, the command (actually represented by the PushButton) will be disabled.
RevitAddinWizard can help implement the IExternalCommandAvailability interface automatically in VB.NET with its Command Enabler in a few seconds and supports all Revit flavors and categories and any combinations of them.
Recent Comments