none
Focus issues with System.Windows.Controls.WebBrowser RRS feed

  • Question

  • I've been encountering several issues that deal with keyboard focus when it comes to the both the new WPF WebBrowser control that was released with SP1 as well as the Windows Forms WebBrowser in certain situations where they are hosted within the WindowsFormHost and the ElementHost controls respectively.

    The main issue seems to come when focus is lost due to a popup window or some other meaningful dialog window. When focus returns to the original Window/Form which is hosting the WebBrowser control, the keyboard focus seems to be stuck somewhere without a programmatic a way to get it back onto the WebBrowser control. I have noticed however that clicking the mouse back somewhere within the document being displayed in the WebBrowser control seems to regain focus.

    To reproduce this with the code that is posted below follow these steps:
    1. Run Form2 as the main application form
    2. Once the first form opens try pressing Ctrl+N to open a new browser window
    3. After the new browser window opens close it so that focus naturally returns to Form2
    4. Attempt to open a new browser window again using Ctrl+N
    Expected Results: The new window browser window should open just like in step 2.

    Actual Results: The new browser window does not open and no indication shows that the command key is being recognized by the application.


    Form2.cs

    using System; 
    using System.Windows.Forms; 
     
    namespace WindowsFormsApplication1 
        public partial class Form2 : Form 
        { 
            public Form2() 
            { 
                InitializeComponent(); 
     
                System.Windows.Controls.WebBrowser w = new System.Windows.Controls.WebBrowser(); 
                w.Name = "webBrowser1"
     
                System.Windows.Controls.DockPanel d = new System.Windows.Controls.DockPanel(); 
                d.LastChildFill = true
                d.Children.Add(w); 
     
                elementHost1.Child = d; 
     
                w.Navigate(new Uri("http://www.google.com")); 
            } 
        } 
     


    Form2.Designer.cs


    namespace WindowsFormsApplication1 
        partial class Form2 
        { 
            /// <summary> 
            /// Required designer variable. 
            /// </summary> 
            private System.ComponentModel.IContainer components = null
     
            /// <summary> 
            /// Clean up any resources being used. 
            /// </summary> 
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
            protected override void Dispose(bool disposing) 
            { 
                if(disposing && (components != null)) 
                { 
                    components.Dispose(); 
                } 
                base.Dispose(disposing); 
            } 

            #region Windows Form Designer generated code 
     
            /// <summary> 
            /// Required method for Designer support - do not modify 
            /// the contents of this method with the code editor. 
            /// </summary> 
            private void InitializeComponent() 
            { 
                this.elementHost1 = new System.Windows.Forms.Integration.ElementHost(); 
                this.SuspendLayout(); 
                //  
                // elementHost1 
                //  
                this.elementHost1.Dock = System.Windows.Forms.DockStyle.Fill; 
                this.elementHost1.Location = new System.Drawing.Point(0, 0); 
                this.elementHost1.Name = "elementHost1"
                this.elementHost1.Size = new System.Drawing.Size(562, 337); 
                this.elementHost1.TabIndex = 0; 
                this.elementHost1.Text = "elementHost1"
                this.elementHost1.Child = null
                //  
                // Form2 
                //  
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
                this.ClientSize = new System.Drawing.Size(562, 337); 
                this.Controls.Add(this.elementHost1); 
                this.Name = "Form2"
                this.Text = "Form2"
                this.ResumeLayout(false); 
     
            } 

            #endregion 
     
            private System.Windows.Forms.Integration.ElementHost elementHost1; 
        } 


    What I've tried so far

    I've tried this same senario using a WPF RichTextBox in place of the WPF WebBrowser control and by implementing the KeyDown event on the RickTextBox so that the F9 key opens another window. This was an attempt to show whether it was the ElementHost control which was causing the problem, however it appears that the example with the RichTextBox works just fine.

    I've tried another senario using the WPF WebBrowser inside of a WPF window to see if this issue only occurs in cases where we are using Windows Forms and WPF in interop senarios. I found that if I use WPF WebBrowser and WPF Window with no interop that the problem does seem to go away. Although at the same time I found out that interestingly if I use the a WPF application with a WPF Window but using the WindowsFormsHost to host the Windoes Form WebBrowser that I actually end up with a similar issue show in the example above except for the roles of Windoes Forms and WPF have switched.

    To rule out the WindowsFormsHost in the case above I did a simlar test by using the Windows Forms RichTextBox in place of the Windows Forms WebBrowser control and confirmed that there was no issue.

    To make sure that this issue isn't purely a WebBrowser issue I set up two cases where I use a Form to host the Windows Forms WebBrowser control and a WPF Window to host the WPF WebBrowser control. Interestingly the WinForm Form/WinForm WebBrowser cases seems to work just fine but the WPF Window/WPF WebBrowser case exibits the issue when using the Ctrl+N command however when setup with the F9 KeyDown command to open another WPF window.

    After seeing the difference between the F9 command and the Ctrl+N command behavior I tried a few other cases to test the WPF/WPF case out. In one test I tried just switching the window to another existing window that I had open to see if when I returned whether I would the proper focus and I did. Next I tried using the SHIFT+Left_Click combination on one the links instead of using Ctrl+N and uppon return to the page keyboard focus did indeed seem to be lost.

    In light of the above findings I realized that the F9 key method with the RichTextBox probably didn't show much as it seems that only commands from within the WebBrowser control which spawn a new window seem to exibit this problem. I did however go back and test the WinForm/WPF case and found that any way of changing focus from the Form causes the same focus issue unlike with the WPF Window/WPF Browser and WPF Window /WinForm Browser case.

    Conclusion

    So from my tests so far it seems that using the ElementHost control to host the WPF WebBrowser or by using the WPF WebBrowser in all cases results in the issue of focus for which I haven't found any way to programatically resolve. More specifically it appears that that with the WinForm From/WPF WebBrowser case that any way of diverting the focus from the Form causes the focus issue whereas within the all of the cases involving a WPF Window that the focus issue only seems to happen when windows are spawned from internal commands that come from within the WebBrowser. Somehow in all of this mess using Windows Form with a Windows Form Web Browser seems to be able to work without issue in all of the cases tested thusfar, although unfortunately this is not an option for the project that I'm working on.

    Can anybody explain what I'm experiencing here and even better give some suggestions on some workarounds that I could implement to get around this issue?
    Wednesday, October 22, 2008 1:52 AM

All replies

  • Well, I can explain what you're experiencing: normal WPF/hwnd interop. This behaviour is pretty standard when using hwnds together with WPF. The interop between the two technologies works as far as positioning and display is concerned, but unfortunately these focus issues have always existed and nobody has managed to fix them. This is why, in my opinion, WPF/hwnd interop cannot be used in production applications.

    Hopefully someone from Microsoft will be able to suggest a workaround that might help you in this individual case. Unfortunately I can't.
    Controls for WPF and Windows Forms at http://www.divelements.co.uk
    Wednesday, October 22, 2008 8:37 AM
  • Based off of what you said about this specifically being an ActiveX issue I started looking for other cases where this might be happening. So far I've found the following information around on the web.

    ActiveX Controls don't treat Focus the same
    Blog post about using WebBrowser and HTML editor in Visual FoxPro by Calvin Hsia which may explain similar behavior.
    http://blogs.msdn.com/calvin_hsia/archive/2005/07/22/441895.aspx

    Walkthrough: Hosting an ActiveX Control in Windows Presentation Foundation
    General guide on how to host ActiveX controls in WPF, no explanation of the interop problems mentioned by Tim Dawson.
    http://msdn.microsoft.com/en-us/library/ms742735.aspx

    WPF Interoperability - Supporting Keyboard Navigation
    This page is Part 3 of an 8 part article on WPF Interoperability which gives clues on how keyboard specific commands are handled.
    http://www.ddj.com/windows/197003872?pgno=3

    So far nothing new as far as a workaround but I still have my hopes.




    Wednesday, October 22, 2008 1:47 PM
  • Below are some additional resource on this issue around on the web.

    Enabling Flash in the .NET 2.0 WebBrowser control
    When a .NET 2.0 application uses the System.Windows.Forms.WebBrowser control to load a page which contains a Flash movie, the movie may fail to respond to mouse events.
    http://www.trinet.co.uk/kb.asp?kbid=000046

    Hidden WebBrowser stealing focus
    Every time a timer event triggers it to perform a m_WebBrowser.Navigate() I get that classic IE 'click' and it steals the focus from the user's current application
    http://www.msnewsgroups.net/group/microsoft.public.dotnet.languages.csharp/topic26082.aspx

    WebBrowser Control active element doesn't regain focus after ALT+TABbing to another app and back

    Another MSDN post which seems to describe the same issue.
    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/c6f83ce5-1525-4d31-8c14-05e8a301d92a/
    Tuesday, October 28, 2008 12:55 AM
  • I could reproduce this issue in pure Windows Forms application using the following code:

    public partial class FocusDemoForm : Form
    {
        public FocusDemoForm()
        {
            InitializeComponent();
            WebBrowser w = new WebBrowser();
            w.Dock = DockStyle.Fill;
            this.Controls.Add(w);
            w.Navigate("http://www.google.com");
        }
    }

    If you move the focus to the search TextBox, and press CTRL+N to open new browser window, and close it, the focus should move back to the search TextBox, but unfortunately, it doesn't work consistently.

    Could you please elaborate your specific usage scenario, so we can start working out solution from there. I don't think there is a generic solution to this type of focus issue when mixing  up many usage scenarios together.

    Thanks
    Tuesday, October 28, 2008 4:55 AM
  • Thanks for responding Marco, below I'll described more specifically our setup.

    Our Usage Scenario

    Our current usage scenario is that we have an MDI environment set up in a Windows Forms application where child forms (also Windows Forms) all contain a single ElementHost control docked to fill the form. Each form's ElementHost control then hosts a custom WPF control that inherits indirectly through a common base class from UserControl. We have several of these custom controls of which each inherit from our base UserControl class which we are calling BaseModule. The specific case we have been having problems with is when our BaseModule contains a WindowsFormsHost control which then in turn hosts a Windows Forms WebBrowser control. Generally the focus issues we have seen so far is that the the focus doesn't seem to be set properly upon initial load but more importantly that when we loose focus from this window - as described in my first post - the focus does not return properly and no programatic move we have made so far has been able to properly regain that focus.

    Other than the obvious reason of creating a more simplistic test case for diagnostic purposes, I created the embedded code example in order to show that these issues exist regardless of the double nesting of the ElementHost and the WindowsFormsHost which I'm aware is unsupported according to the documentation. My assumption is that if I can figure out how to solve the same issues in the more simple cases itterated in my first post that I may be able to apply the same techniques to our actual production setup and if not then I'm open to the various options that we have for removing the double nesting.


    The Pure WinForms Example

    In an interesting note about your test case which I've also tried, I noticed that the keyboard commands still work when the child browser window is closed however the text box is no longer focused as you mentioned. Also interesting is that after opening a second child browser using Ctrl+N after closing the first and then also closing the second child window focus seems to magically return to the search text box.
    Wednesday, October 29, 2008 2:48 AM
  • This method works for me:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            WindowsFormsHost host = new WindowsFormsHost();
            WebBrowser webBrowser = new WebBrowser();
            host.Child = webBrowser;
            elementHost1.Child = host;

            webBrowser.Navigate(new Uri("http://www.google.com"));
            this.Activated += delegate
            {
                Console.WriteLine(this.ActiveControl);
                if (webBrowser.Document != null)
                {
                    if (this.ActiveControl == elementHost1 && webBrowser.Document.ActiveElement != null)
                    {
                        webBrowser.Document.ActiveElement.Focus();
                    }
                }
            };
        }
    }

    Note that I use Windows Forms' WebBrowser here, because WPF version of it is far from complete and lack of interoperability with HTML content.

    Thanks
    Friday, October 31, 2008 6:09 AM
  • I tested the methodology suggested above by Marco Zhou to respond to the Form's Activated event in order to set force focus back to the WebBrowser.Document.ActiveElement. Below are my results for the different UI framework combinations.


    A. Window (WinForms) / WebBrowser (WinForms) - Pure WinForms

    As described previously this pure WinForms case normally results in correct key command focus but visual focus with the blinking cursor seems flakey in that only after using Ctrl+N twice and closing the corresponding dialogs does the original window regain visual focus.

    Results after implementing the suggested re-focusing on form activation seem to correct the focus in all cases tested so far including using Ctrl+N, swaping windows with Alt+tab, and so on.


    B. Window (WPF) / WebBrowser (WinForms)

    In this case using we don't have the Windows.Forms.Form.ActiveControl property available so I just assumed in my tests that the web browser was the last control that was focused and attempt to call WebBrowser.Document.ActiveElement.Focus() when the Window.Activated event fires. Unfortunately this doesn't seem to improve our situation at all and also causes the same pop-under issue described above. One interesting thing that I found is that if I instead call Focus on the WebBrowser directly and then to call WebBrowser.Document.ActiveElement.Focus() it seems that the keyboard focus works the first time and the second time the child window is closed but not subsequently.


    C. Window (WinForms) / WebBrowser (WinForms) - Double nesting of WindowsFormsHost within an ElementHost

    Although this type of composition isn't officially supported I think it is important to point out issues with this type of composition in order to help either prove that it will work for some needs or otherwise show exactly why it isn't supported.

    Results after implementing the suggested modifications to regain focus showed that just as in the Pure WinForms example that focusing the ActiveElement within the Forms Activated event seems to correct the known issues.

    One important difference however between this case and the Pure WinForms is that after minimizing the main window it appears focus is lost and does not regain focus using the prescribed solution. After going back and testing I can confirm that the Pure WinForms case this doesn't seem to be a problem at all.


    Conclusion

    So far it appears that the solution suggested by Marco Zhou works except for test case C from above when minimizing the window and then maximizing it, and for test case B where it appears that this solution doesn't appear to remedy the situation at all.

    Both of these case are of interest to me as I try to get to the bottom of these focus issues however the issue in test case C applies directly to what we are doing currently in our project. Any discussion on either case I think will benefit us as well as other readers who may come accross this topic.

    Another important aspect that is missing here is an explanation of why this type of workaround is needed in the first place, espeicaly in test case A where we would expect the WebBrowser control to behave the same as every other Windows Forms control with respect to focus.
    Wednesday, November 5, 2008 2:11 AM
  • After experimenting around a little more with Test Case B from above I found this combination of Focus() calls that seems to at least allow me to regain keyboard command focus to the WebBrowser itself however it doesn't appear that after the second attempt that the keyboard focus is recaptured with respect to the actual element within the document. In my case the element I've been attempting to focus is the search text box at www.google.com which I believe has the id="q".

    To reproduce the behavior I'm describing with the following code follow the following steps:
    1. Start the application so that the main window is open to the google search page.
    2. Click in the search text box in order to assign focus.
    3. Press Ctrl+N to open a child browser window.
    4. Close the resulting window (notice focus has returned to the search text box of the original window by the blinking cursor)
    5. Press Ctrl+N again to once again open a child browser window.
    6. Close the resulting window again.

    Expected Result:
    We expect the same result as witnessed directly after completing step 4 where visual focus is restored to the text box noticable by the blinking cursor. Also subsequent attempts to issue the new window command via Ctrl+N should continue to work.

    Actual Result:
    It appears that Ctrl+N still works however visual keyboard focus is not restored to the ActiveElement. By typing we can confirm that indeed the key events do not produce text in the text box as they would have directly after step 4.


    Window3.xaml
    <Window x:Class="FocusTest.Window3" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:swf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" 
        Title="Window3" Height="308" Width="515"
        <DockPanel LastChildFill="True"
            <WindowsFormsHost Name="windowsFormsHost1"
                <swf:WebBrowser x:Name="webBrowser1"></swf:WebBrowser> 
            </WindowsFormsHost> 
        </DockPanel> 
    </Window> 
     

    Window3.xaml.cs
    using System; 
    using System.Windows; 
    using System.Windows.Input; 
     
    namespace FocusTest 
        public partial class Window3 : Window 
        { 
            public Window3() 
            { 
                InitializeComponent(); 
     
                webBrowser1.Navigate(new Uri("http://www.google.com")); 
     
                this.Activated += delegate 
                { 
                    Console.WriteLine(FocusManager.GetFocusedElement(this)); 
                    if(webBrowser1.Document != null
                    { 
                        windowsFormsHost1.Focus(); 
                        webBrowser1.Focus(); 
                        webBrowser1.Document.ActiveElement.Focus(); 
                    } 
                }; 
            } 
        } 
     

    Note that also with Test Case B that it appears the the minimizing and maximizing test tried in Test Case C also seems to be an issue here.

    using System; 
    using System.Windows; 
    using System.Windows.Input; 
     
    namespace FocusTest 
        public partial class Window3 : Window 
        { 
            public Window3() 
            { 
                InitializeComponent(); 
     
                webBrowser1.Navigate(new Uri("http://www.google.com")); 
     
                this.Activated += delegate 
                { 
                    Console.WriteLine(FocusManager.GetFocusedElement(this)); 
                    if(webBrowser1.Document != null
                    { 
                        windowsFormsHost1.Focus(); 
                        webBrowser1.Focus(); 
                        webBrowser1.Document.ActiveElement.Focus(); 
                    } 
                }; 
            } 
        } 


    Wednesday, November 5, 2008 2:33 AM
  • Recently as part of a hotfix for .NET Framework Microsoft has a released a fix for keyboard focus issues with regard to the web browser control. If I find any improvement for the issues I've been describing here after installing this update I'll post my feedback back here.

    List of changes and fixed issues in the .NET Framework 3.5 Service Pack 1
    http://support.microsoft.com/kb/951847

    FIX: An ActiveX control will not receive keyboard navigation events when you use a System.Windows.Forms.WebBrowser control to host Web pages
    http://support.microsoft.com/kb/946102/

    I guess it would be too much to ask to have a Microsoft representative speak up and help out identifying whether the issues I'm describing are related to the bugs that were corrected in this hotfix.
    Thursday, February 26, 2009 5:25 PM
  • I found this thread quite informative so I thought I'd post what's working for me after similar experiments.

    My situation is a bit different from kainhart's in that I have a WPF Window with the WPF WebBrowser control inside.

    My problem was that I was unable to force focus to go to the browser control when my window first showed up. Yet I was able to send focus there by tabbing around the window. Debugging into WPF source I see that the tab handling for the WebBrowser class will trigger the OLEIVERB_UIACTIVATE wheras plain old Focus() will not. This seems to be the key for me.

    So I handled the LoadComplete event and in there forced a TabInto() on the browser control.  Here's my C++/CLI. m_webBrowser is the WebBrowser control...

    void MyHtmlView::OnLoadCompleted( CLR::Object^ /*sender*/, NavigationEventArgs^ /*e*/ )
    {
    	using namespace System::Windows::Interop;
    
    	// Set the dialog's initial focus to the Browser control.
    
    	// Stop sinking this event since we only want to redirect
    	// the focus once, when the dialog initially comes up.
    
    	m_webBrowser->LoadCompleted -= gcnew LoadCompletedEventHandler( this, &MyHtmlView::OnLoadCompleted );
    
    	// Use TabInto instead of m_webBrowser->Focus() b/c Focus() will not trigger 
    	// an OLEIVERB_UIACTIVATE on the IE ActiveX control but tabbing will.
    	// See WebBrowser.cs in WPF code.
    
    	IKeyboardInputSink^ inputSink = static_cast<IKeyboardInputSink^>(m_webBrowser);
    	inputSink->TabInto( gcnew TraversalRequest( FocusNavigationDirection::First ) );
    }
    
    • Proposed as answer by wwdavep Friday, June 7, 2013 4:47 PM
    Wednesday, October 14, 2009 2:29 PM
  • Thanks for sharing. I'll see if I can do something similar as a workaround in our app. Currently we are doing something the equivalent to a SendKeys and sending the Tab key to the app however this creates issues for the Visual Studio Debugger and we would like to at least replace this workaround with one that is better if we can't find a more complete solution. I think your workaround might be just what we are looking for.
    Wednesday, October 14, 2009 10:36 PM