WPF Interoperability with Windows Forms and Office 2007

Keith encountered some interesting behavior while trying to build a Custom Task Pane hosting a WPF control in VSTO to use in Excel.  (See my post on "Using WPF With VSTO & Office 2007").

"I click the search textbox and it appears to have focus... but, when I start typing, text goes into the active cell and not the textbox..."

Throwing together a simple control I experienced the same behavior:

Test Addin - Input Focus Non-Activated

Notice that the second TextBox contains the cursor, however the Task Pane "Test Addin" is not highlighted as if it's currently activated, which looks like this:

Test Addin - Input Focus Activated

So what's going on here?  Essentially it appears that the ElementHost is never getting a notification from the WPF message loop that a child control has taken input focus.  Excel is also "greedy" on handling keyboard input if a Task Pane or other control does not have input focus.  Reading this "Windows Forms and WPF Interoperability Input Architecture" MSDN article, it states:

In Windows Forms, keyboard messages are routed to the window handle of the control that has focus. In the ElementHost control, these messages are routed to the hosted element. To accomplish this, the ElementHost control provides an HwndSource instance. If the ElementHost control has focus, the HwndSource instance routes most keyboard input so that it can be processed by the WPF InputManager class.

So lets give the ElementHost focus!  Using the new Routed Event architecture we can have our ElementHost be notified anytime any WPF element that inherits from UIElement has been clicked.  I chose to use a Tunneling strategy to handle the MouseDown event.  The third argument "true" of the AddHandler method says that we want to be notified of ALL MouseDown events, even if another control handles the event and prevents it from continuing on.  You can read about Routed Events (Tunneling & Bubbling) in Adam Nathan's WPF Unleashed book, chapter 3.  (Freely available to download from Time Sneath's blog.)

using Forms = System.Windows.Forms;

 

private ElementHost m_ElementHost;

private CustomTaskPane m_Pane;

private Forms.UserControl m_UserControl;

 

private void ThisAddIn_Startup(Object sender, System.EventArgs e)

{

    m_ElementHost = new ElementHost();

    m_ElementHost.Child = new UserControl2();

    m_ElementHost.Child.AddHandler(

        UIElement.PreviewMouseDownEvent,

        new RoutedEventHandler(PreviewMouseDown_Event),

        true

    );

    m_ElementHost.Dock = Forms.DockStyle.Fill;

    m_UserControl = new Forms.UserControl();

    m_UserControl.Controls.Add(m_ElementHost);

    m_Pane = this.CustomTaskPanes.Add(m_UserControl, "Test Addin");

    m_Pane.Visible = true;

}

 

private void PreviewMouseDown_Event(Object sender, RoutedEventArgs e)

{

    m_ElementHost.Focus();

}

Figure 3.9 (taken from Adam's book) shows the element hierarchy.

WPF Element Hierarchy 

Using this same strategy you could handle only giving the ElementHost, and therefore the Task Pane, focus when say just a TextBox is clicked or got focus, or a Button clicked or got focus.  However I thought using UIElement was a bit more succinct.  Hope that helps!

Published Monday, September 03, 2007 3:15 PM by Joe
Filed under: , ,

Comments

# re: WPF Interoperability with Windows Forms and Office 2007

Monday, September 03, 2007 6:28 PM by Keith Pelletier

Joe... one word: luscious. Buttery even. Worked perfectly. You're a legend. Thanks so much.

Keith

# re: WPF Interoperability with Windows Forms and Office 2007

Monday, September 03, 2007 11:21 PM by Joe

Glad that helped.  =]

Joe

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Powered by Community Server (Non-Commercial Edition), by Telligent Systems