All Resources
GuideSolidWorks API2026-03-21

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

  1. Add references to WindowsFormsIntegration.dll and PresentationFramework.dll
  2. Create a WPF UserControl (TaskPaneControl.xaml) with your UI
  3. In ConnectToSW, call CreateTaskpaneView2 to get a TaskPane view
  4. Create an ElementHost, set Dock = Fill, assign your WPF control as Child
  5. Call DisplayWindowFromHandlex64 with 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:

  1. taskPaneView.DeleteView() — remove from SolidWorks
  2. elementHost.Dispose() — release the WinForms container
  3. Set all references to null
  4. 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.

SolidWorks APIC#WPFAdd-inTaskPaneElementHost