Dockable Window with WPF controls, don't receive keyboard input

Dockable Window with WPF controls, don't receive keyboard input

Anonymous
Not applicable
4,434 Views
7 Replies
Message 1 of 8

Dockable Window with WPF controls, don't receive keyboard input

Anonymous
Not applicable

I've built a C# based plugin that works in AutoCAD, Revit, Navisworks and Inventor. The plugin creates a dockable "window" in each application to host it's WPF content. This works great in all applications except for Inventor.

 

In Inventor, I am forced to create a Windows Form that contains a single ElementHost who's child is set to the plugin's main content. This is then placed inside an Inventor DockableWindow using AddChild.

 

Here's the problem: 

Textboxes in my WFP application do not receive most keyboard input. The only keys which seem to work are control keys and spacebar. I can highlight, copy and paste fine from the textboxes, but I cannot type characters (the typing caret is present).

 

I've read about people with similar issues and many of them mention ElementHost.EnableModelessKeyboardInterop. However this will not work for me, because EnableModelessKeyboardInterop expects a WPF window, while my plugin only contains a UserControl.

 

Another interesting thing is that the plugin work fine in Inventor 2015-2017. Only version 2018 and higer experience the no-keyboard-input issue.

 

Any help with this would be greatly appreciated.

Accepted solutions (1)
4,435 Views
7 Replies
Replies (7)
Message 2 of 8

Xun.Zhang
Alumni
Alumni

Hi @Anonymous,

It seems a regression to me, will contact project team for a better understanding then.


Xun
Message 3 of 8

HideoYamada
Advisor
Advisor

Hi,

 

Today I encountered same trouble and found this post.

I tried to add WPF Window to DockablwWindow's child directly, and it works, but this issue still laies.

(Of course, EnableModelessKeyboardInterop was used.)

 

Now I have reported this issue to the Inventor beta forum.

 

=====

Freeradical

 Hideo Yamada

=====
Freeradical
 Hideo Yamada
https://www.freeradical.jp
0 Likes
Message 4 of 8

JarFu
Autodesk
Autodesk

@HideoYamada @Anonymous, thanks your feedback and sorry for the inconvenience. This is a tech limitation, we need additional handling in the plugin. Our developer will put more details about resolution here later. 



Jar Fu
SW Engineer
Inventor QA
Autodesk, Inc.
0 Likes
Message 5 of 8

HelmesHe
Autodesk
Autodesk
Accepted solution

Hi @Anonymous,

 

This is a know issue when ElementHost in Windows Forms.

WPF TextBox not accepting Input when in ElementHost in Window Forms 

 

And it is a side-effect after we modifying the window structure of Dockable Windows.

 

There is no such issue if we directly add the WPF control into the Dockable Window. This could be done by creating a HwndSource object to wrap the WPF control and pass its Handle property to AddChild.

 

If that could not be done, then please follow the solution in the above post or what is done in an Inventor add-in:

 

    public partial class KeyParameterPaletteForm: CommonForm
    {
        …
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            //Configure this form, so that, the form can work well with dockable window
            DockableWindowChildAdapter.SetDockableWindowChildEventHook(this);
        }
    }

    public static class DockableWindowChildAdapter
    {
        private const UInt32 DLGC_WANTARROWS = 0x0001;
        private const UInt32 DLGC_WANTTAB = 0x0002;
        private const UInt32 DLGC_WANTALLKEYS = 0x0004;
        private const UInt32 DLGC_HASSETSEL = 0x0008;
        private const UInt32 DLGC_WANTCHARS = 0x0080;
        private const UInt32 WM_GETDLGCODE = 0x0087;

        /// <summary>
        /// Enable the event for the structure WPF >> WINFORM >> ELEMENTHOST >> CONTROL
        /// Some event cannot be sent to the CONTROL, set hook for the control
        /// http://stackoverflow.com/questions/835878/wpf-textbox-not-accepting-input-when-in-elementhost-in-window-forms
        /// </summary>
        public static void SetDockableWindowChildEventHook(Form childForm)
        {
            if (childForm == null || childForm.Controls == null || childForm.Controls.Count <= 0)
                return;

            foreach (var control in childForm.Controls)
            {
                var elementHost = control as ElementHost;
                if (elementHost == null || elementHost.Child == null)
                    continue;

                HwndSource visualSourceObject = HwndSource.FromVisual(elementHost.Child) as HwndSource;
                if (visualSourceObject == null)
                    continue;

                visualSourceObject.AddHook(new HwndSourceHook(ChildHwndSourceHook));
            }
        }


        /// <summary>
        /// Handle the key press event from parent window
        /// </summary>
        private static IntPtr ChildHwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg != WM_GETDLGCODE)
                return IntPtr.Zero;

            handled = true;
            return new IntPtr(DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL | DLGC_WANTTAB | DLGC_WANTALLKEYS);
        }
    }

 

 

 



Helmes He

Senior Software Engineer
Message 6 of 8

HideoYamada
Advisor
Advisor

Hello,

 

Referring to Helmes's post, I have written following code. This works well for me.

 

public void Activate(ApplicationAddInSite addInSiteObject, bool firstTime)
{
    // Setup my WPF Window.
    var wpfWindow = new WpfWindow();
    wpfWindow.WindowStyle = System.Windows.WindowStyle.None;
    wpfWindow.ResizeMode = System.Windows.ResizeMode.NoResize;
    wpfWindow.Visibility = System.Windows.Visibility.Visible;

    // Get WPF Window's handle.
    var helper = new WindowInteropHelper(wpfWindow);
    helper.EnsureHandle();
    var handle = helper.Handle;

    // Create Dockable Window.
    var dockableWindow = InventorApplication.UserInterfaceManager.DockableWindows.Add(System.Guid.NewGuid().ToString(), "Test", "Test");
    dockableWindow.AddChild(handle);

    // Set key hook.
    HwndSource.FromHwnd(handle).AddHook(WndProc);
}

private const UInt32 DLGC_WANTARROWS = 0x0001;
private const UInt32 DLGC_WANTTAB = 0x0002;
private const UInt32 DLGC_WANTALLKEYS = 0x0004;
private const UInt32 DLGC_HASSETSEL = 0x0008;
private const UInt32 DLGC_WANTCHARS = 0x0080;
private const UInt32 WM_GETDLGCODE = 0x0087;

private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == WM_GETDLGCODE)
    {
        handled = true;
        return new IntPtr(DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL | DLGC_WANTTAB | DLGC_WANTALLKEYS);
    }
    return IntPtr.Zero;
}

 

=====

Freeradical

 Hideo Yamada

=====
Freeradical
 Hideo Yamada
https://www.freeradical.jp
Message 7 of 8

HideoYamada
Advisor
Advisor

I forgot to write the line initializing the variable 'InventorApplication'.

public void Activate(ApplicationAddInSite addInSiteObject, bool firstTime)
{
    InventorApplication = addInSiteObject.Application;
    ...

// In my actual code, it will be initialized by my own middle ware 🙂

 

=====
Freeradical
 Hideo Yamada
https://www.freeradical.jp
Message 8 of 8

JarFu
Autodesk
Autodesk

Glad to know it works! 😊



Jar Fu
SW Engineer
Inventor QA
Autodesk, Inc.