Community Pick: Many members of our community have endorsed this article.
Editor's Choice: This article has been selected by our editors as an exceptional contribution.

Handling WebBrowser DHTML events in your .Net Application

Wayne Taylor (webtubbs)
CERTIFIED EXPERT
Published:

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 [i]assembly[/i] 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...OR...

2. Make the [i]class[/i] 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
                      ....

Open 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

Open 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>

Open in new window

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

Open 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

Open 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

Open 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

Open 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

Open in new window

4
7,565 Views
Wayne Taylor (webtubbs)
CERTIFIED EXPERT

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.