In the post "Adding a form to your addin." we created a simple form/window. But there are problems with those windows. They are never a part of Inventor and therefore always in the way of your Inventor screen or the other way around. (They are in front or at the back of your Inventor Window.) A dockable window can help in those situations.

You can also create dockable windows for aesthetic reasons. It's how Autodesk is also making its commands look and feel.

In the Inventor API help, you will find an example of creating a dockable window. But that example is only valid for Winforms. (Although even that example is not complete.) In this tutorial, I have chosen to create a WPF form. The dockable windows you can create with the Inventor API don't work out of the box with WPF forms. In this post of the tutorial, I will turn the form we created in the post "Adding a form to your addin." into a dockable window/form. That looks something like this:

The dockable window will be created when we start Inventor. therefore we start by changing the "StandardAddInServer". We need to add the following method:

Private Sub CreateDockableWindow(inventor As Inventor.Application)
    Dim mySearchForm As New MySearchForm(inventor)

    Dim userInterfaceMgr As UserInterfaceManager = inventor.UserInterfaceManager
    Dim dockableWindow = userInterfaceMgr.DockableWindows.Add(
        Guid.NewGuid().ToString(),
        "MyDockableWindow InternalName",
        "My dockable window")

    DockableWindowChildAdapter.AddWPFWindow(dockableWindow, mySearchForm)
End Sub

In fact, nothing interesting is done here. The WPF form and the dockable window are created here. But binding the 2 together is done in another class. But this method "CreateDockableWindow" needs to be called. We can do that in the method "Activate". That will look like this.

Public Sub Activate(AddInSiteObject As ApplicationAddInSite, FirstTime As Boolean) Implements ApplicationAddInServer.Activate
    Try

        ' initialize the rule class
        _myButton = New MyButton(AddInSiteObject.Application)

        ' initialize the dockable window
        CreateDockableWindow(AddInSiteObject.Application)
    Catch ex As Exception

        ' Show a message if any thing goes wrong.
        MessageBox.Show($"{ex.Message}{System.Environment.NewLine}{System.Environment.NewLine} {ex.StackTrace}")

        If (ex.InnerException IsNot Nothing) Then
            MessageBox.Show($"Inner exception message: {ex.InnerException.Message}")
        End If

    End Try
End Sub

(The complete code of the "StandardAddInServer" class and the entire solution can be found on GitHub)

Now the more interesting class "DockableWindowChildAdapter". The problem with WPF forms combined with dockable windows is the following:
"Textboxes in WFP application do not receive most keyboard input. The only keys which seem to work are the control keys and the spacebar. You can also highlight, copy and paste to text boxes, but you can't type characters." and
"This is a side-effect of modifying the window structure of Dockable Windows." (source) What that exactly means is above my pay grade but smarter people than me have found a solution. I just joined several ideas into 1 class. The code in this class could also be added to the "StandardAddInServer" directly but then we could not reuse the code that easily.  the class looks like this:

Imports Inventor

Public Module DockableWindowChildAdapter
    '''
    ''' https://forums.autodesk.com/t5/inventor-forum/dockable-window-with-wpf-controls-don-t-receive-keyboard-input/td-p/9115997
    ''' 
    Private Const DLGC_WANTARROWS As UInt32 = &H1
    Private Const DLGC_WANTTAB As UInt32 = &H2
    Private Const DLGC_WANTALLKEYS As UInt32 = &H4
    Private Const DLGC_HASSETSEL As UInt32 = &H8
    Private Const DLGC_WANTCHARS As UInt32 = &H80
    Private Const WM_GETDLGCODE As UInt32 = &H87

    Private _dockableWindow As DockableWindow

    Public Sub AddWPFWindow(dockableWindow As DockableWindow, window As Window)
        _dockableWindow = dockableWindow

        window.WindowStyle = WindowStyle.None
        window.WindowState = WindowState.Maximized
        window.ResizeMode = ResizeMode.NoResize
        window.Show()

        Dim win As Window = Window.GetWindow(window)
        Dim wih = New Interop.WindowInteropHelper(win)
        Dim hWnd As IntPtr = wih.EnsureHandle()

        _dockableWindow.AddChild(hWnd)

        Interop.HwndSource.FromHwnd(hWnd).AddHook(AddressOf WndProc)
    End Sub

    Public Function WndProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr
        If (msg = WM_GETDLGCODE) Then

            handled = True
            Return New IntPtr(DLGC_WANTCHARS Or DLGC_WANTARROWS Or DLGC_HASSETSEL Or DLGC_WANTTAB Or DLGC_WANTALLKEYS)
        End If
        Return IntPtr.Zero
    End Function
End Module

You should be able to run Inventor now and find the docked window.

Skills:

Autodesk Inventor, Vault, Git, C#, vb, .net, php HTML, css, js

Education:

University computer science.
HBO Mechanical engineer.
MBO Fine mechanics.

Experience:

Programmer and Mechanical engineer at Kelvion
(2016 - 20..)

Mechanical engineer at Strukton
(2009 - 2016)

Mechanical engineer at RDG-engineering
(2007 - 2009)

CNC Programmer at VMC
(2005 - 2007)

volunteer at Taizé
(2007)

Certifications:

Objectgeoriënteerd analyseren en ontwerpen, Objectgeoriënteerd programmeren in Java, Webapplicaties: de clientkant, Databases, Security Aware Programmer, Web Security Specialist