Hosting WPF Controls in SolidWorks TaskPane
Embed a WPF UserControl inside a SolidWorks TaskPane using the ElementHost bridge. Includes the keyboard input workaround essential for text fields to work — a solution not documented in official SolidWorks API docs.
Why WPF in SolidWorks
SolidWorks add-ins traditionally use Windows Forms for UI. But WPF offers significant advantages:
- Data binding — two-way binding eliminates manual UI updates
- MVVM pattern — clean separation of UI and business logic
- Modern controls — richer styling, animations, and layout options
- Scalable rendering — vector-based, looks sharp on high-DPI displays
The challenge: SolidWorks TaskPane expects a Windows Forms handle (HWND), not a WPF visual. The ElementHost control bridges this gap.
The ElementHost Bridge
ElementHost is a Windows Forms control that can host WPF content. It provides the HWND that SolidWorks needs, while rendering your WPF UserControl inside.
// Create your WPF UserControl
var taskPaneControl = new TaskPaneControl();
// Wrap in ElementHost
var elementHost = new ElementHost
{
Dock = DockStyle.Fill,
Child = taskPaneControl
};
// Create TaskPane and display the host
var taskPane = swApp.CreateTaskpaneView2("", "MyAddin");
taskPane.DisplayWindowFromHandlex64(
elementHost.Handle.ToInt64());Step by Step
- Add references to
WindowsFormsIntegration.dllandPresentationFramework.dll - Create a WPF UserControl (
TaskPaneControl.xaml) with your UI - In
ConnectToSW, callCreateTaskpaneView2to get a TaskPane view - Create an
ElementHost, setDock = Fill, assign your WPF control asChild - Call
DisplayWindowFromHandlex64with the ElementHost's handle
The Keyboard Problem
This is the most painful gotcha in SolidWorks add-in development.
When your WPF TextBox is inside an ElementHost inside a SolidWorks TaskPane, keyboard input does not work. You can click the TextBox, see the cursor, but typing does nothing. Keys are swallowed by SolidWorks' message loop before they reach your WPF control.
This affects all text input — TextBox, ComboBox (editable), RichTextBox. Non-text controls (buttons, sliders, checkboxes) work fine.
The Workaround
Handle PreviewKeyDown on the UserControl and manually insert characters into the focused TextBox:
private void TaskPaneControl_PreviewKeyDown(
object sender, KeyEventArgs e)
{
var textBox = Keyboard.FocusedElement as TextBox;
if (textBox == null) return;
string charToInsert = null;
// Letters A-Z with Shift/CapsLock handling
if (e.Key >= Key.A && e.Key <= Key.Z)
{
bool isShift = (Keyboard.Modifiers & ModifierKeys.Shift) != 0;
bool isCaps = Console.CapsLock;
bool isUpper = isShift ^ isCaps;
char c = (char)('A' + (e.Key - Key.A));
charToInsert = isUpper ? c.ToString()
: c.ToString().ToLower();
}
// Numbers, space, punctuation
else if (e.Key >= Key.D0 && e.Key <= Key.D9)
charToInsert = ((int)(e.Key - Key.D0)).ToString();
else if (e.Key == Key.Space) charToInsert = " ";
else if (e.Key == Key.OemPeriod) charToInsert = ".";
else if (e.Key == Key.OemMinus) charToInsert = "-";
if (charToInsert != null)
{
int caret = textBox.CaretIndex;
if (textBox.SelectionLength > 0)
{
textBox.Text = textBox.Text.Remove(
textBox.SelectionStart,
textBox.SelectionLength);
caret = textBox.SelectionStart;
}
textBox.Text = textBox.Text.Insert(
caret, charToInsert);
textBox.CaretIndex = caret + charToInsert.Length;
e.Handled = true;
}
}This workaround manually maps key codes to characters and inserts them at the cursor position, handling selection replacement, Shift, and CapsLock.
Cleanup
Proper disposal order in DisconnectFromSW is critical to avoid COM leaks:
taskPaneView.DeleteView()— remove from SolidWorkselementHost.Dispose()— release the WinForms container- Set all references to
null GC.Collect()+GC.WaitForPendingFinalizers()— force COM RCW cleanup
COM Registration
Your add-in class needs [ComRegisterFunction] and [ComUnregisterFunction] attributes to register with SolidWorks via the registry:
var keyPath = @"SOFTWARE\SolidWorks\AddIns\{"
+ t.GUID.ToString() + "}";
using var key = Registry.LocalMachine.CreateSubKey(keyPath);
key.SetValue("Title", "MyAddin");
key.SetValue("Description", "My SolidWorks Add-in");Set the HKCU key value to 1 to load at SolidWorks startup, or 0 for manual loading.