| name | acad-palettes |
| description | PaletteSet hosting, WPF AddVisual, events, persistence, Tool Palette API, Properties Palette COM |
AutoCAD Palette APIs
Use this skill when creating custom dockable palettes, choosing between PaletteSet/Tool Palettes/Properties Palette, or handling palette lifecycle with zero-document state.
PaletteSet and Palette
Autodesk.AutoCAD.Windows.PaletteSet is the managed wrapper over AduiPaletteSet. It inherits from Autodesk.AutoCAD.Windows.Window, implements ICollection, and hosts one or more child Palette tabs.
Autodesk.AutoCAD.Windows.Palette is a sealed class wrapping CAdUiPalette. Access its parent via Palette.PaletteSet.
Constructors
Official constructors:
PaletteSet(string name) -- creates an unnamed palette set (no persistence)
PaletteSet(string name, Guid toolID) -- GUID enables automatic state persistence across sessions
Community-reported constructor (not officially documented):
PaletteSet(string name, string cmd, Guid toolID) -- cmd is the command name AutoCAD replays when restoring an open palette on startup. See Gotchas for safety requirements.
Hosting Methods
Palette Add(string name, Control control) -- host a WinForms UserControl
Palette Add(string name, Uri htmlPage) -- host HTML-backed content
Palette AddVisual(string name, Visual control) -- host a WPF visual directly (no ElementHost needed)
Palette AddVisual(string name, Visual control, bool bResizeContentToPaletteSize) -- WPF visual with explicit resize control. When true, the WPF content resizes with the palette. When false, the content retains its natural size.
AddVisual is the preferred approach for WPF content in modern plugins. It avoids the WinForms UserControl + ElementHost wrapper that Add(string, Control) requires.
Example: WinForms Palette Singleton
using System;
using System.Drawing;
using System.Windows.Forms;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
public sealed class SamplePaletteCommands
{
private static readonly Guid PaletteId =
new Guid("E4E1D31A-8B4A-4F47-B10A-3B9E3D5C9E90");
private static PaletteSet _paletteSet;
[CommandMethod("SHOW_SAMPLE_PALETTE")]
public static void ShowSamplePalette()
{
if (_paletteSet == null)
{
_paletteSet = new PaletteSet("Sample Palette", PaletteId)
{
MinimumSize = new Size(320, 220),
KeepFocus = false
};
_paletteSet.Add("General", new SamplePaletteControl());
}
_paletteSet.Visible = true;
}
}
public sealed class SamplePaletteControl : UserControl
{
public SamplePaletteControl()
{
Dock = DockStyle.Fill;
Controls.Add(new Label
{
Dock = DockStyle.Fill,
Text = "Palette content goes here.",
TextAlign = ContentAlignment.MiddleCenter
});
}
}
Example: WPF Palette via AddVisual
using System;
using System.Drawing;
using System.Windows.Controls;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
public sealed class WpfPaletteCommands
{
private static readonly Guid PaletteId =
new Guid("6AB6F5C2-DBCB-48AC-8A55-4620D2D8CBE7");
private static PaletteSet _paletteSet;
[CommandMethod("SHOW_WPF_PALETTE")]
public static void ShowWpfPalette()
{
if (_paletteSet == null)
{
_paletteSet = new PaletteSet("WPF Palette", PaletteId)
{
MinimumSize = new Size(360, 240)
};
var view = new UserControl
{
Content = new TextBlock
{
Text = "WPF content hosted by PaletteSet.AddVisual",
Margin = new System.Windows.Thickness(16)
}
};
_paletteSet.AddVisual("Preview", view, true);
}
_paletteSet.Visible = true;
}
}
Lifecycle and Startup
Application Initialization
Implement IExtensionApplication for initialization and termination. Use assembly-level ExtensionApplication and CommandClass attributes as load-time optimization hints.
Command Context
- Without
CommandFlags.Session -- command runs in document context (tied to current drawing)
- With
CommandFlags.Session -- command runs in application context (survives MDI document switches)
Palette commands often need CommandFlags.Session because they must survive document switches, remain safe with no drawing active, and interact with UI state broader than a single drawing.
Application and DocumentCollection Events
Events relevant to palette hosts:
Application events -- BeginQuit, QuitWillStart, Idle, EnterModal, LeaveModal. Handlers stay active until AutoCAD shuts down or you unregister them.
DocumentCollection events -- DocumentActivated, DocumentCreated, DocumentDestroyed, DocumentToBeDestroyed, DocumentBecameCurrent. Use these instead of trying to infer lifecycle from command strings like OPEN, NEW, CLOSE, QUIT.
Zero-Document State
When no documents are open, AutoCAD exposes only a reduced application surface. Key facts:
DocumentDestroyed is the recommended event for detecting entry into zero-document state
- At the time of the last document closing,
DocumentManager.Count is still 1 during the DocumentDestroyed callback
MdiActiveDocument may be null -- guard all document-dependent code paths
Autoloader
PackageContents.xml flags LoadOnCommandInvocation and LoadOnAutoCADStartup control when your module loads. For command-driven palettes, prefer LoadOnCommandInvocation for startup-performance reasons.
Recommended Pattern
- Implement
IExtensionApplication
- Register application and document-collection events once in
Initialize()
- Unregister them in
Terminate()
- Keep the
PaletteSet as a singleton
- Create the palette lazily on the first command invocation
- Use
CommandFlags.Session when the command must be safe in application context
- Guard every document-dependent code path for zero-document state
Example: Lifecycle Wiring
using System;
using System.Drawing;
using System.Windows.Forms;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using AcApp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
[assembly: ExtensionApplication(typeof(PaletteLifecycleModule))]
[assembly: CommandClass(typeof(PaletteLifecycleModule))]
public sealed class PaletteLifecycleModule : IExtensionApplication
{
private static readonly Guid PaletteId =
new Guid("BB4DEB65-6F0A-4104-B8E9-A69A0B621B3E");
private static PaletteSet _paletteSet;
public void Initialize()
{
AcApp.QuitWillStart += OnQuitWillStart;
AcApp.DocumentManager.DocumentActivated += OnDocumentActivated;
AcApp.DocumentManager.DocumentDestroyed += OnDocumentDestroyed;
}
public void Terminate()
{
AcApp.QuitWillStart -= OnQuitWillStart;
AcApp.DocumentManager.DocumentActivated -= OnDocumentActivated;
AcApp.DocumentManager.DocumentDestroyed -= OnDocumentDestroyed;
}
[CommandMethod("SHOW_LIFECYCLE_PALETTE", CommandFlags.Session)]
public static void ShowPalette()
{
EnsurePalette();
_paletteSet.Visible = true;
}
private static void EnsurePalette()
{
if (_paletteSet != null) return;
_paletteSet = new PaletteSet("Lifecycle Palette", PaletteId)
{
MinimumSize = new Size(300, 200)
};
_paletteSet.Add("Main", new UserControl { Dock = DockStyle.Fill });
_paletteSet.Load += (sender, e) =>
{
};
_paletteSet.StateChanged += (sender, e) =>
{
var activeDoc = AcApp.DocumentManager.MdiActiveDocument;
if (activeDoc != null)
{
activeDoc.Editor.WriteMessage(
$"\nPalette state changed: {e.NewState}");
}
};
}
private static void OnDocumentActivated(object sender,
DocumentCollectionEventArgs e)
{
}
private static void OnDocumentDestroyed(object sender,
DocumentDestroyedEventArgs e)
{
bool enteringZeroDocState = AcApp.DocumentManager.Count == 1;
if (enteringZeroDocState)
{
}
}
private static void OnQuitWillStart(object sender, EventArgs e)
{
}
}
Tool Palette API
The Tool Palette API lives in the Autodesk.AutoCAD.Windows.ToolPalette namespace (AcMgd.dll, AcTcMgd.dll). It is the managed wrapper layer over AcTc* ObjectARX classes -- not the same as PaletteSet.
Runtime Model
Tool palettes are catalog-backed. Your application creates catalog, palette, and tool content once; AutoCAD saves it to ATC files with a path to your module. The Tool Palette framework loads your application when the Tool Palettes window initializes. This is fundamentally different from PaletteSet:
PaletteSet -- direct custom UI host you fully control
- Tool Palette API -- persistent catalog-and-tool framework managed by AutoCAD
When to Use
Use the Tool Palette API when extending the Tool Palettes window with catalog-backed tools, stock-tool behavior, or tool groups. Use PaletteSet for custom dockable UI with buttons, lists, grids, previews, and plugin-specific workflows.
For deeper Tool Palette behavior, Autodesk extension points become COM/ObjectARX oriented. The managed namespace exposes wrappers and interfaces (IAcadTool, IAcadToolContextMenu, IAcadToolDragSource, IAcadToolDropTarget), but the programming model is closer to framework customization than general-purpose dockable UI.
Example: ToolPaletteManager Command
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows.ToolPalette;
using AcApp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
public sealed class ToolPaletteCommands
{
[CommandMethod("TOOLPALETTE_INFO", CommandFlags.Session)]
public static void ToolPaletteInfo()
{
ToolPaletteManager manager = ToolPaletteManager.Manager;
var editor = AcApp.DocumentManager.MdiActiveDocument?.Editor;
if (editor == null) return;
editor.WriteMessage($"\nCatalog path(s): {manager.CatalogPath}");
manager.LoadCatalogs(
CatalogTypeFlags.Catalog | CatalogTypeFlags.StockToolCatalog,
LoadFlags.LoadLinks | LoadFlags.LoadImages);
editor.WriteMessage("\nTool palette catalogs loaded.");
}
}
Properties Palette API
The Properties Palette (Property Inspector) is a COM-based module for inspecting and editing object properties. It is used by the Properties palette, Tool Palettes, Visualization Styles, and other UI hosts.
Capabilities
- Display custom properties for custom objects
- Customize property categorization and editing
- Customize the Properties palette UI
- Display properties for a custom command
- Add custom tabs to the Properties palette
When to Use
Use the Properties Palette API when your custom entities, custom objects, or commands need to participate in the built-in Properties palette. Use PaletteSet when you need a dockable window for your own commands and workflow.
Decision Matrix
| Need | Best Fit | Why |
|---|
| Dockable plugin UI with tabs, forms, WPF views, previews, command buttons | PaletteSet | Official managed host for custom palette windows |
| Host WinForms controls in a palette | PaletteSet.Add(string, Control) | Direct WinForms support |
| Host WPF content in a palette | PaletteSet.AddVisual(...) | Direct WPF visual hosting (no ElementHost) |
| Host HTML content in a palette | PaletteSet.Add(string, Uri) | Official HTML-backed overload |
| Tool catalogs, stock tools, tool groups | Tool Palette API | Framework behind the Tool Palettes feature and ATC-backed catalog model |
| Custom entity/command properties in Properties palette | Properties Palette / Property Inspector APIs | Designed specifically for property inspection and editing |
| Civil 3D-specific custom business UI | Usually PaletteSet | Civil 3D does not have a separate managed custom-palette framework; the host API is AutoCAD |
Gotchas
-
Stable GUID controls state restoration -- giving a PaletteSet a stable Guid is what lets AutoCAD restore persisted window state (docking, size, location) across sessions. Without a GUID (or with a changing one), the palette loses its position every restart. (Community-reported, strong field guidance.)
-
3-arg constructor startup safety -- the community-reported PaletteSet(string name, string cmd, Guid toolID) replays cmd when restoring an open palette on startup. The command must be idempotent, safe in application context, and safe in zero-document or temporary-document startup conditions. (Community-reported.)
-
Restart-docked edge cases -- palettes may show hidden tabs, missing controls, or misbehaving layout only when reopening docked from persisted state. Always test: show palette -> dock -> close AutoCAD -> reopen -> verify visibility, docking, focus, and control interactivity. (Community-reported.)
-
Zero-document guard -- palette code that assumes MdiActiveDocument or a fully available command line must be guarded. During DocumentDestroyed, DocumentManager.Count is still 1 when the last document closes.
-
KeepFocus for interactive controls -- set KeepFocus = true when the palette contains text boxes, combo boxes, or other interactive controls. Without it, focus returns to the drawing editor immediately after clicking inside the palette.
-
MdiActiveDocument null during construction -- the document context is not established until the palette is shown. Defer document access to event handlers or Load, not the constructor.
-
AddVisual resize parameter -- when bResizeContentToPaletteSize is true, the WPF content stretches with the palette. When false, the content keeps its natural size. Default behavior (no bool overload) resizes content to match the palette.
-
Load/Save events are XML-backed -- these fire when AutoCAD persists or restores palette state. Use PalettePersistEventArgs.ConfigurationSection to read/write custom settings alongside the built-in state.
-
Themed icons supersede older icon methods -- use SetThemedIcon(...) or the LightThemedIcon/DarkThemedIcon properties for proper light/dark theme support. Older icon properties do not participate in theme switching.
Related Skills
acad-palettes-ribbon -- practical ribbon API (tabs, panels, buttons, combos) and basic PaletteSet patterns with ElementHost WPF hosting
acad-events-overrules -- application/document events for palette lifecycle management
acad-editor-input -- command execution via SendStringToExecute triggered by palette controls