| name | acad-palettes-ribbon |
| description | PaletteSet dockable palettes, Ribbon API (tabs, panels, buttons), IExtensionApplication |
AutoCAD Palettes and Ribbon
Use this skill when creating dockable tool palettes via PaletteSet, building ribbon tabs and panels, adding ribbon buttons and controls, or registering UI in the IExtensionApplication lifecycle.
PaletteSet
PaletteSet is a dockable, floatable container that holds one or more tabbed palettes. Each palette is a WinForms UserControl (or WPF content via ElementHost).
Creating a PaletteSet
using Autodesk.AutoCAD.Windows;
private static PaletteSet _paletteSet;
[CommandMethod("SHOWMYPALETTE")]
public void ShowMyPalette()
{
if (_paletteSet == null)
{
_paletteSet = new PaletteSet(
"My Tool Palette",
new Guid("A1B2C3D4-E5F6-7890-ABCD-EF1234567890"));
_paletteSet.Style = PaletteSetStyles.ShowPropertiesMenu
| PaletteSetStyles.ShowAutoHideButton
| PaletteSetStyles.ShowCloseButton;
_paletteSet.DockEnabled = DockSides.Left | DockSides.Right;
_paletteSet.MinimumSize = new System.Drawing.Size(250, 200);
_paletteSet.Size = new System.Drawing.Size(350, 600);
_paletteSet.Opacity = 100;
_paletteSet.KeepFocus = true;
MyUserControl control = new MyUserControl();
_paletteSet.Add("Properties", control);
MySecondControl control2 = new MySecondControl();
_paletteSet.Add("Settings", control2);
}
_paletteSet.Visible = true;
}
Adding WPF Content via ElementHost
using System.Windows.Forms.Integration;
UserControl host = new UserControl();
ElementHost elementHost = new ElementHost();
elementHost.Dock = DockStyle.Fill;
elementHost.Child = new MyWpfUserControl();
host.Controls.Add(elementHost);
_paletteSet.Add("WPF Tab", host);
PaletteSet Events
_paletteSet.StateChanged += OnPaletteStateChanged;
_paletteSet.SizeChanged += OnPaletteSizeChanged;
_paletteSet.DockStateChanged += OnDockStateChanged;
_paletteSet.PaletteActivated += OnPaletteActivated;
_paletteSet.PaletteAdded += OnPaletteAdded;
_paletteSet.VisibleChanged += OnVisibleChanged;
_paletteSet.Load += OnPaletteLoad;
StateChanged
Fires when the palette is shown, hidden, rolled up, or unrolled.
private void OnPaletteStateChanged(object sender, PaletteSetStateEventArgs e)
{
if (e.NewState == PaletteSetState.Show)
{
RefreshContent();
}
else if (e.NewState == PaletteSetState.Hide)
{
}
}
DockStateChanged
Fires when the palette docks or undocks.
private void OnDockStateChanged(object sender, EventArgs e)
{
PaletteSet ps = (PaletteSet)sender;
DockSides currentDock = ps.Dock;
}
PaletteSet Persistence
PaletteSet automatically saves and restores its dock state, position, and size between sessions when a GUID is provided. The state is stored in the Windows registry under the AutoCAD profile.
_paletteSet = new PaletteSet("My Palette",
new Guid("A1B2C3D4-E5F6-7890-ABCD-EF1234567890"));
_paletteSet.Load += (s, e) =>
{
string savedFilter = LoadSetting("PaletteFilter");
if (savedFilter != null)
ApplyFilter(savedFilter);
};
_paletteSet.StateChanged += (s, e) =>
{
if (e.NewState == PaletteSetState.Hide)
SaveSetting("PaletteFilter", GetCurrentFilter());
};
Ribbon API
The Ribbon API lives in Autodesk.Windows (referenced via AdWindows.dll). It provides RibbonControl, RibbonTab, RibbonPanel, and various button/control types.
Creating a Ribbon Tab
using Autodesk.Windows;
public void CreateRibbonTab()
{
RibbonControl ribbon = ComponentManager.Ribbon;
if (ribbon == null) return;
RibbonTab tab = new RibbonTab();
tab.Title = "My Tools";
tab.Id = "MY_TOOLS_TAB";
tab.Name = "My Tools Tab";
RibbonPanelSource panelSource = new RibbonPanelSource();
panelSource.Title = "Drawing Tools";
panelSource.Id = "MY_DRAWING_PANEL";
RibbonPanel panel = new RibbonPanel();
panel.Source = panelSource;
tab.Panels.Add(panel);
ribbon.Tabs.Add(tab);
tab.IsActive = true;
}
RibbonButton
RibbonButton button = new RibbonButton();
button.Text = "Create Block";
button.ShowText = true;
button.ShowImage = true;
button.Size = RibbonItemSize.Large;
button.Orientation = System.Windows.Controls.Orientation.Vertical;
button.LargeImage = LoadImage("Images/create_block_32.png");
button.Image = LoadImage("Images/create_block_16.png");
button.CommandParameter = "CREATEBLOCK ";
button.CommandHandler = new RibbonCommandHandler();
panelSource.Items.Add(button);
RibbonCommandHandler
public class RibbonCommandHandler : System.Windows.Input.ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
RibbonButton button = parameter as RibbonButton;
if (button == null) return;
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return;
string cmdName = (string)button.CommandParameter;
doc.SendStringToExecute(cmdName, true, false, true);
}
}
Loading Ribbon Images
using System.Windows.Media.Imaging;
private static BitmapImage LoadImage(string relativePath)
{
string dllPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
string dir = System.IO.Path.GetDirectoryName(dllPath);
string fullPath = System.IO.Path.Combine(dir, relativePath);
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(fullPath, UriKind.Absolute);
image.EndInit();
return image;
}
private static BitmapImage LoadEmbeddedImage(string resourceName)
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
using (var stream = assembly.GetManifestResourceStream(resourceName))
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = stream;
image.CacheOption = BitmapCacheOption.OnLoad;
image.EndInit();
image.Freeze();
return image;
}
}
RibbonSplitButton
A button with a dropdown menu of sub-items.
RibbonSplitButton splitButton = new RibbonSplitButton();
splitButton.Text = "Label";
splitButton.ShowText = true;
splitButton.Size = RibbonItemSize.Large;
splitButton.IsSplit = true;
splitButton.LargeImage = LoadImage("Images/label_32.png");
RibbonButton subItem1 = new RibbonButton();
subItem1.Text = "Label Pipes";
subItem1.CommandParameter = "LABELPIPES ";
subItem1.CommandHandler = new RibbonCommandHandler();
RibbonButton subItem2 = new RibbonButton();
subItem2.Text = "Label Structures";
subItem2.CommandParameter = "LABELSTRUCTURES ";
subItem2.CommandHandler = new RibbonCommandHandler();
splitButton.Items.Add(subItem1);
splitButton.Items.Add(subItem2);
panelSource.Items.Add(splitButton);
RibbonToggleButton
A button that stays pressed to indicate an on/off state.
RibbonToggleButton toggleButton = new RibbonToggleButton();
toggleButton.Text = "Auto Label";
toggleButton.ShowText = true;
toggleButton.Size = RibbonItemSize.Standard;
toggleButton.Image = LoadImage("Images/auto_label_16.png");
toggleButton.CheckStateChanged += (s, e) =>
{
bool isChecked = toggleButton.IsChecked;
SetAutoLabel(isChecked);
};
panelSource.Items.Add(toggleButton);
RibbonCombo
A dropdown combo box in the ribbon.
RibbonCombo combo = new RibbonCombo();
combo.Id = "LAYER_COMBO";
combo.Size = RibbonItemSize.Large;
combo.Width = 180;
combo.ShowImage = false;
combo.Items.Add(new RibbonButton { Text = "Option A", Id = "OPT_A" });
combo.Items.Add(new RibbonButton { Text = "Option B", Id = "OPT_B" });
combo.Items.Add(new RibbonButton { Text = "Option C", Id = "OPT_C" });
combo.CurrentChanged += (s, e) =>
{
RibbonButton selected = combo.Current as RibbonButton;
if (selected != null)
{
string selectedId = selected.Id;
}
};
panelSource.Items.Add(combo);
RibbonRowPanel
Arrange multiple small items in horizontal rows within a panel.
RibbonRowPanel rowPanel = new RibbonRowPanel();
RibbonButton btn1 = new RibbonButton();
btn1.Text = "Zoom Extents";
btn1.ShowText = true;
btn1.Size = RibbonItemSize.Standard;
btn1.CommandParameter = "ZOOM E ";
btn1.CommandHandler = new RibbonCommandHandler();
rowPanel.Items.Add(btn1);
rowPanel.Items.Add(new RibbonRowBreak());
RibbonButton btn2 = new RibbonButton();
btn2.Text = "Regen";
btn2.ShowText = true;
btn2.Size = RibbonItemSize.Standard;
btn2.CommandParameter = "REGEN ";
btn2.CommandHandler = new RibbonCommandHandler();
rowPanel.Items.Add(btn2);
panelSource.Items.Add(rowPanel);
Application Menu
The application menu (File menu) can be customized by accessing ComponentManager.Ribbon.ApplicationMenu.
RibbonControl ribbon = ComponentManager.Ribbon;
ApplicationMenu appMenu = ribbon.ApplicationMenu;
RibbonButton appMenuItem = new RibbonButton();
appMenuItem.Text = "My Custom Export";
appMenuItem.Id = "MY_EXPORT";
appMenuItem.CommandParameter = "MYCUSTOMEXPORT ";
appMenuItem.CommandHandler = new RibbonCommandHandler();
appMenu.MenuContent.Items.Add(appMenuItem);
IExtensionApplication Lifecycle for UI Registration
Register ribbon and palette UI in the IExtensionApplication.Initialize method. The ribbon may not be available immediately at startup, so defer creation if necessary.
public class MyPlugin : IExtensionApplication
{
private static PaletteSet _paletteSet;
public void Initialize()
{
if (ComponentManager.Ribbon != null)
{
CreateRibbon();
}
else
{
ComponentManager.ItemInitialized += OnComponentInitialized;
}
}
private void OnComponentInitialized(object sender, RibbonItemEventArgs e)
{
if (ComponentManager.Ribbon != null)
{
ComponentManager.ItemInitialized -= OnComponentInitialized;
CreateRibbon();
}
}
private void CreateRibbon()
{
RibbonControl ribbon = ComponentManager.Ribbon;
RibbonTab tab = new RibbonTab();
tab.Title = "My Plugin";
tab.Id = "MYPLUGIN_TAB";
RibbonPanelSource panelSource = new RibbonPanelSource();
panelSource.Title = "Tools";
RibbonPanel panel = new RibbonPanel();
panel.Source = panelSource;
RibbonButton paletteBtn = new RibbonButton();
paletteBtn.Text = "Show Palette";
paletteBtn.Size = RibbonItemSize.Large;
paletteBtn.ShowText = true;
paletteBtn.LargeImage = LoadImage("Images/palette_32.png");
paletteBtn.CommandParameter = "SHOWMYPALETTE ";
paletteBtn.CommandHandler = new RibbonCommandHandler();
panelSource.Items.Add(paletteBtn);
tab.Panels.Add(panel);
ribbon.Tabs.Add(tab);
}
public void Terminate()
{
if (_paletteSet != null)
{
_paletteSet.Visible = false;
_paletteSet = null;
}
RibbonControl ribbon = ComponentManager.Ribbon;
if (ribbon != null)
{
RibbonTab tab = ribbon.FindTab("MYPLUGIN_TAB");
if (tab != null)
ribbon.Tabs.Remove(tab);
}
}
}
Gotchas
- PaletteSet GUID must be unique -- reusing a GUID from another PaletteSet causes state corruption and crashes on restore.
ComponentManager.Ribbon may be null during Initialize -- the ribbon loads asynchronously. Always check for null and defer via ComponentManager.ItemInitialized.
CommandParameter needs a trailing space -- without it, the command string is placed on the command line but not executed. The space acts as Enter.
KeepFocus = true on PaletteSet -- required for interactive controls (text boxes, combo boxes) inside palettes. Without it, focus returns to the drawing editor immediately.
- Ribbon images must be frozen -- WPF BitmapImage objects used as
Image or LargeImage should be Freeze()-d for cross-thread access. Non-frozen images throw on the ribbon's render thread.
- PaletteSet content cannot access
MdiActiveDocument directly during construction -- the document context is not established until the palette is shown. Defer document access to event handlers or Load.
SendStringToExecute is asynchronous -- it queues the command; it does not run immediately. Do not assume the command has completed after the call returns.
- Ribbon tabs persist across NETLOAD/NETUNLOAD -- if the plugin is reloaded, duplicate tabs appear. Check for existing tabs by Id before adding.
- PaletteSet minimum size interacts with dock -- when docked, the palette cannot be smaller than
MinimumSize. If MinimumSize is too large, the palette cannot dock into narrow side panels.
RibbonSplitButton.IsSplit = true -- when true, the top portion executes the first item's command and the bottom arrow opens the dropdown. When false, the entire button opens the dropdown.
- ElementHost in PaletteSet -- wrap WPF content in a WinForms UserControl first, then add the UserControl to PaletteSet. Adding an ElementHost directly can cause layout issues.
- Ribbon state after drawing switch -- ribbon tab selection resets when switching documents. Re-activating a custom tab requires handling
DocumentBecameCurrent.
- PaletteSet
Visible = true outside a command context -- may require Application.DocumentManager.MdiActiveDocument.LockDocument() if the palette modifies the database on show.
- RibbonToggleButton
IsChecked -- read this property inside the CheckStateChanged handler; the value reflects the new state after the click.
Related Skills
acad-palettes -- deep PaletteSet API reference, Tool Palette API, Properties Palette, lifecycle and zero-document state
acad-events-overrules -- IExtensionApplication lifecycle for registering palettes and ribbon at startup
acad-editor-input -- command execution via SendStringToExecute triggered by ribbon buttons
acad-blocks -- tool palette block content and block insertion commands from ribbon