locked
Unbound .NET WebBrowser control deactivates Windows Form RRS feed

  • Question

  • Hello,

    In a project of mine, I need to work with unbound WebBrowser controls. The goal is to navigate simultaneously to several web pages, using several WebBrowser controls, and showing the individual pages when the user requests them pressing a button, binding the needed WebBrowser control to a container control in the form to display them.

    Problem: Whenever one of the WebBrowser controls loads a page that focuses a control on the page by means of scripting, my Form gets deactivated after document complete if the WebBrowser control is not showing. This only happens with pages that focus an element on load (for example, using onload attribute in body tag but not only).

    Reproduce code (using www.msn.com since this site focusses the search textbox after document complete):

    In a standard new VB Windows Forms Application (with Form1), drop a button (Button1) in the Form1 designer and this code in the code editor:
    Public Class Form1
    
        Private wb As New WebBrowser
    
        Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
    
            wb.Navigate("www.msn.com")
    
        End Sub
    End Class
    

    Expected result from running the Application and pressing Button1:
    The unbound and invisible WebBrowser control loads the msn page, the form Form1 stays activated. (In the real project the browser is to be shown as needed).

    Actual result:
    The WebBrowser control loads the page and after a while (document complete), the form Form1 gets deactivated.

    As far as I could figure out until now, this happens because of page scripts trying to focus on an element of the page. I did a lot of research before posting this problem here but i was unable to find a solution.

    Thank you in  advance,
    Best regards

    Friday, October 23, 2009 6:15 PM

Answers

  • Finally I found a workaround, still a hack, but stable and no side effects so far. Shortly:

    Declare the windows API function EnableWindow and disable the browsers window handle while it is unbound and invisible, then enable it when it is bound and visible.

     

    Declare Function EnableWindow Lib "user32" (ByVal hWnd As IntPtr, ByVal bEnable As Boolean) As Boolean
    
    ' to prevent the webbrowser control from grabbing 
    ' the focus as requested by page scripts 
    EnableWindow(wb.Handle, false)
    
    ' to display the control (page scripts
    ' will be able to grab the focus)
    EnableWindow(wb.Handle, true)
    
    

    • Marked as answer by ifdefdebug Tuesday, August 17, 2010 1:33 PM
    Tuesday, August 17, 2010 1:33 PM

All replies

  •  

    Public Class Form1
        Friend WithEvents wb As WebBrowser
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Label1.Text = "Navigating..."
            wb.Navigate("www.msn.com")
        End Sub
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            wb = New WebBrowser()
            wb.Visible = False
            Me.Controls.Add(wb)
        End Sub
    
        Private Sub wb_DocumentCompleted(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles wb.DocumentCompleted
            Label1.Text = "Complete."
        End Sub
    End Class
    • Marked as answer by ifdefdebug Monday, October 26, 2009 4:12 PM
    • Unmarked as answer by ifdefdebug Tuesday, August 17, 2010 1:33 PM
    Saturday, October 24, 2009 7:37 AM
  • Hello,

    Thank you for your reply, this answers my question since adding the invisible browser to the form's control collection does prevent the form from being deactivated.

    But now there is another problem: whatever control on the form has the focus, will loose the focus on document complete (for pages that focus on one of their own elements). In your example, Button1 had the focus after clicking it, and lost it after document complete. This is a new problem since users are interrupted in their work whenever such a page completes.


    Note: the webbrowser control must be in the form's control collection, when I tried a similar solution (browser invisible and added to the container control - a split panel - where it was supposed to be shown later), the form still got deactivated.
    Monday, October 26, 2009 4:11 PM
  • Hello,

    would calling Button1.Focus() in the document complete event handler be an option for you?
    Monday, October 26, 2009 5:02 PM
  • Hello,

    well I am trying to get things to work with this kind of workaround, but it's difficult because I don't know which control has focus before the invisible webbrowser grabs it...

    Anyway, I have noticed that MS is addressing this issue with the new IProtectFocus interface, introduced for IE7, but minimum OS is Windows Vista and that's not acceptable for me since my solution has to work on XP. And one would have to roll his own .NET wrapper for the webbrowser since the built-in one doesn't implement this.


    Wednesday, October 28, 2009 1:49 PM
  • In my experience, when something needs a lot of workarounds to be done there's a big problem with the design of the application. Think about other options!
    Wednesday, October 28, 2009 8:57 PM
  • You are totally right, and in my case the "big problem" is trying to use a resource (the WebBrowser control) for something (invisibly load a page containing focusing scripts without grabbing the focus) it just can't do. The goal is to load a page invisibly and show it on demand (no problem with that). Those "other options" I may think about are not doing it at all, doing it without the WebBrowser control, or still find a sound way to do it with the WebBrowser control. And of course, refocusing after losing the focus is not a sound way because there would be flickering and racing with user input.

    Thursday, October 29, 2009 10:46 AM

  • The solution was to use csEXWB, "The most complete C# Webbrowser wrapper control" (according to the author), found at the CodeProject website. I removed all features depending on the bundled COM library to obtain a pure c# solution. This controls exposes to .NET everything the COM webbrowser and mshtml have to offer in terms of customization. It allows me to simply turn off script execution - and the focus problem disappeared. This is still a workaround, but since all pages I need to load work fine without script I am done for now.

    PS:
    If the focusing script resides in the body tag's onload event attribute, you can avoid it by editing this attribute in the document complete event handler since the onload event always fires after returning from document complete. This can be done with the .NET WebBrowser and HTMLDocument as well. The problem were focusing scripts embedded in the body's inner html - they are executed on the fly, while the page is loading, and don't wait for document complete. Until now, the only way I found was to disable script execution at all using csEXWB.

    Public Class Form1
        Private wb As New cEXWB
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            wb.Navigate("www.msn.com")
        End Sub
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            
            ' the following two lines somehow initialize the browser,
            ' otherwise navigation would not succeed
            Me.Controls.Add(wb)
            Me.Controls.Remove(wb)
            wb.DownloadScripts = False
    
        End Sub
    
    End Class
    
    • Marked as answer by ifdefdebug Thursday, November 5, 2009 1:23 PM
    • Unmarked as answer by ifdefdebug Tuesday, August 17, 2010 1:20 PM
    Thursday, November 5, 2009 1:15 PM
  • Finally I found a workaround, still a hack, but stable and no side effects so far. Shortly:

    Declare the windows API function EnableWindow and disable the browsers window handle while it is unbound and invisible, then enable it when it is bound and visible.

     

    Declare Function EnableWindow Lib "user32" (ByVal hWnd As IntPtr, ByVal bEnable As Boolean) As Boolean
    
    ' to prevent the webbrowser control from grabbing 
    ' the focus as requested by page scripts 
    EnableWindow(wb.Handle, false)
    
    ' to display the control (page scripts
    ' will be able to grab the focus)
    EnableWindow(wb.Handle, true)
    
    

    • Marked as answer by ifdefdebug Tuesday, August 17, 2010 1:33 PM
    Tuesday, August 17, 2010 1:33 PM
  • Hi ifdefdebug,

    What kind of issues did you have with the unmarked answers? Please provide some guidance in order to allow future readers of this thread to better understand the problem and find their own way out.

    Marcel

    Tuesday, August 17, 2010 5:16 PM
  • Have you had any problems with the lack of RecreateHandle?  I am trying to use cEXWB on a form that is destroyed and recreated using the DivExpress xtraTabbedMdiManager and need to resolve this issue.
    Tuesday, October 19, 2010 3:11 AM