一键导入
acad-palettes-ribbon
PaletteSet dockable palettes, Ribbon API (tabs, panels, buttons), IExtensionApplication
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
PaletteSet dockable palettes, Ribbon API (tabs, panels, buttons), IExtensionApplication
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Corridors, baselines, regions, assemblies, subassemblies, corridor surfaces
Custom subassembly .NET design — CorridorState, SubassemblyGenerator, targets, SATemplate
Stock-subassembly pattern catalog — need→file index, worked DrawImplement recipes, point/link/shape code reference, mined from Autodesk's 120 VB stock subassemblies
Superelevation design, attainment, cross slope, pivot points, lane config
Block definitions, references, attributes, dynamic block properties, exploding
Dimensions — aligned, rotated, arc, radial, angular, ordinate, text overrides
| name | acad-palettes-ribbon |
| description | PaletteSet dockable palettes, Ribbon API (tabs, panels, buttons), IExtensionApplication |
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 is a dockable, floatable container that holds one or more tabbed palettes. Each palette is a WinForms UserControl (or WPF content via ElementHost).
using Autodesk.AutoCAD.Windows;
// GUID must be unique per PaletteSet — used for persistence
private static PaletteSet _paletteSet;
[CommandMethod("SHOWMYPALETTE")]
public void ShowMyPalette()
{
if (_paletteSet == null)
{
_paletteSet = new PaletteSet(
"My Tool Palette", // display name
new Guid("A1B2C3D4-E5F6-7890-ABCD-EF1234567890")); // unique GUID
_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;
// Add a WinForms UserControl as a palette tab
MyUserControl control = new MyUserControl();
_paletteSet.Add("Properties", control);
// Add a second tab
MySecondControl control2 = new MySecondControl();
_paletteSet.Add("Settings", control2);
}
_paletteSet.Visible = true;
}
using System.Windows.Forms.Integration;
// Create a WinForms UserControl that hosts WPF content
UserControl host = new UserControl();
ElementHost elementHost = new ElementHost();
elementHost.Dock = DockStyle.Fill;
elementHost.Child = new MyWpfUserControl(); // WPF UserControl
host.Controls.Add(elementHost);
_paletteSet.Add("WPF Tab", host);
_paletteSet.StateChanged += OnPaletteStateChanged;
_paletteSet.SizeChanged += OnPaletteSizeChanged;
_paletteSet.DockStateChanged += OnDockStateChanged;
_paletteSet.PaletteActivated += OnPaletteActivated;
_paletteSet.PaletteAdded += OnPaletteAdded;
_paletteSet.VisibleChanged += OnVisibleChanged;
_paletteSet.Load += OnPaletteLoad;
Fires when the palette is shown, hidden, rolled up, or unrolled.
private void OnPaletteStateChanged(object sender, PaletteSetStateEventArgs e)
{
// e.NewState is the new PaletteSetState
if (e.NewState == PaletteSetState.Show)
{
// Palette became visible — refresh data
RefreshContent();
}
else if (e.NewState == PaletteSetState.Hide)
{
// Palette was hidden
}
}
Fires when the palette docks or undocks.
private void OnDockStateChanged(object sender, EventArgs e)
{
PaletteSet ps = (PaletteSet)sender;
DockSides currentDock = ps.Dock;
// Adjust layout based on dock state if needed
}
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.
// The GUID in the constructor enables automatic persistence
_paletteSet = new PaletteSet("My Palette",
new Guid("A1B2C3D4-E5F6-7890-ABCD-EF1234567890"));
// Custom state persistence (manual)
_paletteSet.Load += (s, e) =>
{
// Restore custom settings from registry or file
string savedFilter = LoadSetting("PaletteFilter");
if (savedFilter != null)
ApplyFilter(savedFilter);
};
// Save custom state when palette closes
_paletteSet.StateChanged += (s, e) =>
{
if (e.NewState == PaletteSetState.Hide)
SaveSetting("PaletteFilter", GetCurrentFilter());
};
The Ribbon API lives in Autodesk.Windows (referenced via AdWindows.dll). It provides RibbonControl, RibbonTab, RibbonPanel, and various button/control types.
using Autodesk.Windows;
public void CreateRibbonTab()
{
RibbonControl ribbon = ComponentManager.Ribbon;
if (ribbon == null) return;
// Create a new tab
RibbonTab tab = new RibbonTab();
tab.Title = "My Tools";
tab.Id = "MY_TOOLS_TAB";
tab.Name = "My Tools Tab";
// Create a panel
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);
// Make the tab active
tab.IsActive = true;
}
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 "; // trailing space executes immediately
button.CommandHandler = new RibbonCommandHandler();
panelSource.Items.Add(button);
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);
}
}
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;
}
// From embedded resource
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;
}
}
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; // top half executes default, bottom shows dropdown
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);
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;
// Enable or disable auto-labeling
SetAutoLabel(isChecked);
};
panelSource.Items.Add(toggleButton);
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;
// Handle selection change
}
};
panelSource.Items.Add(combo);
Arrange multiple small items in horizontal rows within a panel.
RibbonRowPanel rowPanel = new RibbonRowPanel();
// First row
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);
// Row break — start a new row
rowPanel.Items.Add(new RibbonRowBreak());
// Second row
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);
The application menu (File menu) can be customized by accessing ComponentManager.Ribbon.ApplicationMenu.
RibbonControl ribbon = ComponentManager.Ribbon;
// Add item to application menu
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);
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()
{
// Ribbon may not exist yet at Initialize time — defer
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()
{
// Clean up palette
if (_paletteSet != null)
{
_paletteSet.Visible = false;
_paletteSet = null;
}
// Remove ribbon tab
RibbonControl ribbon = ComponentManager.Ribbon;
if (ribbon != null)
{
RibbonTab tab = ribbon.FindTab("MYPLUGIN_TAB");
if (tab != null)
ribbon.Tabs.Remove(tab);
}
}
}
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.Image or LargeImage should be Freeze()-d for cross-thread access. Non-frozen images throw on the ribbon's render thread.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.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.DocumentBecameCurrent.Visible = true outside a command context -- may require Application.DocumentManager.MdiActiveDocument.LockDocument() if the palette modifies the database on show.IsChecked -- read this property inside the CheckStateChanged handler; the value reflects the new state after the click.acad-palettes -- deep PaletteSet API reference, Tool Palette API, Properties Palette, lifecycle and zero-document stateacad-events-overrules -- IExtensionApplication lifecycle for registering palettes and ribbon at startupacad-editor-input -- command execution via SendStringToExecute triggered by ribbon buttonsacad-blocks -- tool palette block content and block insertion commands from ribbon