What Command is Executed?
In Revit development, it can be challenging to determine which specific PostableCommandId has been executed. While we can identify which button has been triggered and extract certain constants, correlating these to a specific PostableCommandId remains elusive. The documentation provides a description of PostableCommandId, yet it does not offer a direct method for this correlation.
One potential solution is to create a mapping system by extracting the executed button's Id and binding it to a PostableCommandId. This article explores a method to achieve this by monitoring button executions and building a dictionary to track these commands. By using Autodesk's ComponentManager and RevitCommandId classes, developers can effectively capture and map executed commands, simplifying the monitoring process. Here, I will demonstrate how to extract button IDs and create a command map to efficiently track button executions in Revit.
I believe there are many benefits to tracking which button is executed or which one we need to track. For example, to maintain a clean Revit model, we can allow drafters to sync their model only after certain rules have been met. Even better, we can trigger the execution of specific commands before saving a project.
// run this from any method to monitor buttons executions one time only is needed
Autodesk.Windows.ComponentManager.ItemExecuted += ComponentManager_ItemExecuted;
private Dictionary<string, PostableCommand> IdCommandMap = [];
private void BuildCommandMap()
{
var commands = Enum.GetValues(typeof(PostableCommand)).Cast<PostableCommand>();
foreach (var command in commands)
{
IdCommandMap.Add(
RevitCommandId
.LookupPostableCommandId(command)
.Name,
command
);
}
}
private void ComponentManager_ItemExecuted(
object sender,
Autodesk.Internal.Windows.RibbonItemExecutedEventArgs e
)
{
if (IdCommandMap.TryGetValue(e.Item.Id, out PostableCommand executedCommand))
{
// the Catched command
}
else
{
// command is from an addin " not a built in Revit command"
}
}
One more last thing, if the intention to get buttons details then we can extract using the below example, and using the postcommand we can use the Id property to invoke the button execution.
var tabs = Autodesk.Windows.ComponentManager.Ribbon.Tabs;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < tabs.Count; i++)
{
var tab = tabs[i];
foreach (var panel in tab.Panels)
{
foreach (var button in panel.Source.Items)
{
sb.AppendLine($"Name: {button.Text}");
sb.AppendLine($"id: {button.Id}");
sb.AppendLine($"hotkey: {button.KeyTip}");
sb.AppendLine($"image: {button.LargeImage}");
sb.AppendLine($"large Image: {button.Image}");
}
}
}
Another aspect to consider is how to get the command that was executed before running the IExternalCommand object.
You can do this by registering for the ComponentManager.PreviewExecute
event anywhere in your code. Make sure that this is done correctly.
public class ApplicationBase : IExternalApplication
{
public Result OnStartup(UIControlledApplication application)
{
ComponentManager.PreviewExecute += ComponentManager_PreviewExecute;
return Result.Succeeded;
}
private void ComponentManager_PreviewExecute(object sender, EventArgs e)
{
var ButtonCaller = sender as Autodesk.Windows.RibbonButton;
AppGlobals.ApplicationName = ButtonCaller.Text;
}
}
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class TesterCommand : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
TaskDialog.Show("Executed Command", AppGlobals.ApplicationName);
}
}
Subscribe to my newsletter
Read articles from Moustafa Khalil directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Moustafa Khalil
Moustafa Khalil
I'm Moustafa Khalil El-Sayed, an Egyptian native with a passion for architecture and technology. After completing high school in 1999, I embarked on my journey into architecture, earning my Bachelor's degree in Architecture in 2004. My academic pursuits continued, and I later acquired my Master's degree in Architecture from Wings University. However, my thirst for knowledge extended beyond architectural design, leading me to pursue a degree in Computer Science as well. Driven by a desire to innovate, I began self-teaching computer science, which later empowered me to achieve my Associate degree in Computer Science from the University of the People more easily. Armed with dual expertise in architecture and computer science, I've cultivated a unique skill set that blends creativity with technical acumen. My career has taken me across borders, from Egypt to Oman and the UAE, where I've honed my skills as an architect. As a graduate architect and a proficient .NET BIM Solution Developer, I specialize in translating unique visions into tangible realities. My role extends beyond conventional architectural practices; I leverage technology to streamline processes and enhance project outcomes. My journey into programming began with developing script-based Excel tools to augment project management efforts, notably during the Sharm El Sheikh development. Over time, I expanded my programming prowess to address practical challenges encountered in bridging Revit and AutoCAD within my professional sphere. Several of my applications, born from this evolution, have gained recognition, with some even being featured on the Autodesk website. I am committed to pushing boundaries and continually enriching the intersection of architecture and technology, ensuring that my clients benefit from cutting-edge solutions tailored to their needs.