Handling WebBrowser DHTML events in your .Net Application

AID: 3718
  • Status: Published

7770 points

  • Bywebtubbs
  • TypeTips/Tricks
  • Posted on2010-09-17 at 18:19:55
Awards
  • Community Pick
  • Experts Exchange Approved

Introduction


When many people think of the WebBrowser control, they immediately think of a control which allows the viewing and navigation of web pages. While this is true, it's also very useful for displaying your own custom User Interface (UI). Those members that have used QuickEE will have seen it in action - it is the basis of the Question View pane.

In this article, I will explain how you can raise events from the WebBrowsers DHTML document, and have them handled by your application.  For instance, a user might click an HTML <button> object and your application program can then take action to handle that click.


Setting it up


The interaction between the DHTML and you application is handled by the Component Object Model (COM), so before you can handle the events you need to ensure the class holding your client code is COM-visible.  There are two methods for achieving this.  Make either your assembly or a class visble to COM interactions.

1

Make your assembly COM-Visible

One option is to make your entire assembly visible to COM by going to the Assembly Information dialog (Project > [AppName] Properties > Application tab > Assembly Information) and ensure the "Make assembly COM-Visible" checkbox is checked:

COM-Visible-Assembly.png
  • 20 KB
  • COM-Visible Assembly
COM-Visible Assembly

...OR...
2

Make the class COM-Visible

The second (and recommended) method is to make just the parent class COM-visible. The parent class in most cases will be the Form's class that contains the WebBrowser control. This is done by adding the ComVisibleAttribute to the class....

<System.Runtime.InteropServices.ComVisible(True)> _
Public Class Form1
....
                                    
1:
2:
3:

Select allOpen in new window


Now that you have done one of the above, you also need to inform the WebBrowser control which object will be handling the DHTML events. This is done by setting the ObjectForScripting property of the WebBrowser to the parent class. Because this property is not available at design time, you need to set it at run time, generally in the Forms Load event....
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        WebBrowser1.ObjectForScripting = Me
    End Sub
                                    
1:
2:
3:

Select allOpen in new window


To make debugging of your application easier, it is recommended that you do not suppress the WebBrowser's scripting errors. This is done by ensuring the WebBrowsers ScriptErrorsSuppressed property is set to False.


Adding the Document to your WebBrowser


QuickEE uses Extensible Stylesheet Language Transformations (XSLT) to transform an XML document to HTML, however you can use whatever method you desire. For the purposes of this article, we will use simple HTML and add it to the WebBrowser control with its DocumentText property.

Before adding the HTML to the WebBrowser, it's important to know how to raise the events to be handled by your application. This is done by calling the DHTML window.external object, along with the name and arguments of the appropriate routine in your application.

Here's an example:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<htm>
    <body>
        <button onclick="window.external.SimpleCall()">Call an application routine from script</button><br />
        <button onclick="window.external.ParameterCall(99, 'some text')">Call an application routine from script, with parameters</button><br />
        <br />
        <input type="text" value="Some text" id="txtTest"/><br />
        <button onclick="window.external.ReferenceCall('txtTest')">Call an application routine from script, sending an elements ID</button><br />
        <br />
        Reference the calling element<input type="checkbox" Checked="Checked" value="test" onclick="window.external.ReferenceCall2(this)"/>
    </body>
</html>
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:

Select allOpen in new window


If your HTML is stored in a String variable, you add it to your WebBrowser control like this....
WebBrowser1.DocumentText = HTMLstring
                                    
1:

Select allOpen in new window



Handling the Script calls in your code


Now that you have your WebBrowser set up with the right properties and a document, it's time to add the routines to your application. As mentioned earlier, the WebBrowsers parent class needs to be COM-visible. The reason for this is it will contain the routines which are called by the window.external object of the browser's DOM.

The first two calls ('SimpleCall' and 'ParameterCall') are easy to handle....
    Public Sub SimpleCall()
        MsgBox("Simple Call")
    End Sub

    Public Sub ParameterCall(ByVal i As Integer, ByVal s As String)
        MsgBox(String.Format("i = {0}, s = {1}", i, s))
    End Sub
                                    
1:
2:
3:
4:
5:
6:
7:

Select allOpen in new window


Note how each of the routines has a declaration context of "Public".  That is equied to make these routines visible to COM.

The third call ('ReferenceCall') requires some special handling because it references an element within the HTML Document.  This code obtains an element object from an ID and displays its value in a message box:
    Public Sub ReferenceCall(ByVal cid As String)
        Dim c As HtmlElement = WebBrowser1.Document.GetElementById(cid)
        MsgBox(c.GetAttribute("value"))
    End Sub
                                    
1:
2:
3:
4:

Select allOpen in new window


The fourth call ('ReferenceCall2') passes the element which raised the event. It requires special handling because it passes an MSHTML object. This requires adding a reference to your project (to Microsoft.mshtml, which is located under the .Net tab of the Add Reference dialog)
    Public Sub ReferenceCall2(ByVal c As Object)
        MsgBox(CType(c, mshtml.IHTMLInputElement).checked)
    End Sub
                                    
1:
2:
3:

Select allOpen in new window



Conclusion


As you can see, handling the DHTML events in your application is reasonably easy. Obviously you can do much more with this, especially with the addition of the MSHTML reference.  In QuickEE, I use this technique to provide a feature-rich UI and it's easy to do something similar in your own applications.


Full Project Code

<System.Runtime.InteropServices.ComVisible(True)> _
Public Class Form1

    Private HTMLstring As String = "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">" & _
    "<html>" & _
    "<body>" & _
    "<button onclick=""window.external.SimpleCall()"">Call an application routine from script</button><br />" & _
    "<button onclick=""window.external.ParameterCall(99, 'some text')"">Call an application routine from script, with parameters</button><br />" & _
    "<br />" & _
    "<input type=""text"" value=""Some text"" id=""txtTest""/><br />" & _
    "<button onclick=""window.external.ReferenceCall('txtTest')"">Call an application routine from script, sending an elements ID</button><br />" & _
    "<br/>" & _
    "Reference the calling element<input type=""checkbox"" Checked=""Checked"" onclick=""window.external.ReferenceCall2(this)""/>" & _
    "</body>" & _
    "</html>"

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        WebBrowser1.ObjectForScripting = Me
        WebBrowser1.ScriptErrorsSuppressed = False

        WebBrowser1.DocumentText = HTMLstring
    End Sub

    Public Sub SimpleCall()
        MsgBox("Simple Call")
    End Sub

    Public Sub ParameterCall(ByVal i As Integer, ByVal s As String)
        MsgBox(String.Format("i = {0}, s = {1}", i, s))
    End Sub

    Public Sub ReferenceCall(ByVal cid As String)
        Dim c As HtmlElement = WebBrowser1.Document.GetElementById(cid)
        MsgBox(c.GetAttribute("value"))
    End Sub
    Public Sub ReferenceCall2(ByVal c As Object)
        MsgBox(CType(c, mshtml.IHTMLInputElement).checked)
    End Sub

End Class
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:

Select allOpen in new window

    Asked On
    2010-09-17 at 18:19:55ID3718
    Tags

    VB.Net

    ,

    .Net

    ,

    WebBrowser

    ,

    DHTML

    Topic

    Microsoft Visual Basic.Net

    Views
    2501

    Comments

    Add your Comment

    Please Sign up or Log in to comment on this article.

    Join Experts Exchange Today

    Gain Access to all our Tech Resources

    Get personalized answers

    Ask unlimited questions

    Access Proven Solutions

    Search 3.2 million solutions

    Read In-Depth How-To Guides

    1000+ articles, demos, & tips

    Watch Step by Step Tutorials

    Learn direct from top tech pros

    And Much More!

    Your complete tech resource

    See Plans and Pricing

    30-day free trial. Register in 60 seconds.

    Loading Advertisement...

    Top Visual Basic.NET Experts

    1. CodeCruiser

      1,541,075

      Genius

      8,400 points yesterday

      Profile
      Rank: Genius
    2. kaufmed

      303,871

      Wizard

      500 points yesterday

      Profile
      Rank: Genius
    3. Idle_Mind

      230,817

      Guru

      2,010 points yesterday

      Profile
      Rank: Savant
    4. nepaluz

      192,076

      Guru

      0 points yesterday

      Profile
      Rank: Sage
    5. PaulHews

      161,438

      Guru

      520 points yesterday

      Profile
      Rank: Genius
    6. BuggyCoder

      150,598

      Guru

      0 points yesterday

      Profile
      Rank: Sage
    7. JamesBurger

      123,179

      Master

      0 points yesterday

      Profile
      Rank: Sage
    8. emoreau

      112,211

      Master

      0 points yesterday

      Profile
      Rank: Genius
    9. Masteraco

      102,128

      Master

      0 points yesterday

      Profile
      Rank: Wizard
    10. TheLearnedOne

      80,982

      Master

      0 points yesterday

      Profile
      Rank: Savant
    11. Dhaest

      63,803

      Master

      2,000 points yesterday

      Profile
      Rank: Genius
    12. MlandaT

      53,803

      Master

      2,100 points yesterday

      Profile
      Rank: Genius
    13. wdosanjos

      53,796

      Master

      0 points yesterday

      Profile
      Rank: Genius
    14. mlmcc

      53,048

      Master

      0 points yesterday

      Profile
      Rank: Savant
    15. RolandDeschain

      41,679

      10 points yesterday

      Profile
      Rank: Sage
    16. srosebabu

      31,025

      2,000 points yesterday

      Profile
      Rank: Guru
    17. mas_oz2003

      28,400

      0 points yesterday

      Profile
      Rank: Genius
    18. sedgwick

      27,350

      0 points yesterday

      Profile
      Rank: Genius
    19. jacko72

      26,596

      0 points yesterday

      Profile
      Rank: Genius
    20. tommyBoy

      25,850

      0 points yesterday

      Profile
      Rank: Genius
    21. dlmille

      22,160

      0 points yesterday

      Profile
      Rank: Genius
    22. imnorie

      21,664

      1,600 points yesterday

      Profile
      Rank: Genius
    23. Cluskitt

      21,418

      0 points yesterday

      Profile
      Rank: Wizard
    24. robert_schutt

      20,440

      0 points yesterday

      Profile
      Rank: Guru
    25. navneethegde

      20,332

      0 points yesterday

      Profile
      Rank: Wizard

    Hall Of Fame