Thursday, December 06, 2012

C# - WebBrowser Control

1. Introduction to WebBrowser Control

The "Dotnet WebBrowser Control" provides the capability of browsing the web pages to your application. You can also display your own HTML content through the web browser control. That means you can generate all fancy report and display that in a web browser control. In this article, I will show how can you design simple browsing window (When you are browsing using this sample, Do not provide any personal information. This is just a sample that demonstrates the use of WebBrowser control ). At the end, I will show how do you display the user content and hook button click in the user content to the c# methods.


2. About the sample

The screen shot of the sample is shown below:



The user will type the web address in the Address Bar. To navigate to the typed web address, they should click the Go button. The stop and reload to the same job as every browser is doing today. When the sample is navigating and consuming the web content, the progress bar shows how much the current load content is progressed. The information bar shows what part of the page content is currently getting loaded. When you run the sample you may notice for fully downloading a page, there may be multiple navigation start and end and each denotes that to fully construct the page the sample download the content from the different location. OK, let us start developing the sample.


3. Designing the Web Browser using Visual Studio

The browser we are going to create is composed of ToolStrip, StatusStrip, and the WebBrowser control. First, the toolbar is created and then the required controls on the toolbars are placed. This step is shown in the below video:


Video 1: Setting up the toolbar
In the video, you will not see the buttons for user content. We will add that later. Next, we should add the StatusStrip control to the sample application form. Once the status control is added, a Progress bar and a label for displaying the information are placed in the StatusStrip control. This is shown in the below video:
 Video 2: Setting up the status bar.
Finally, we added the WebBrowser control to our sample. Note that when you place the WebBrowser control on the form, it automatically occupies the entire free area in which it is dropped.
Video 3: Place the WebBrowser control.
Tags for coding: //WEB_BR, //WEB_CS
WEB_BR: Coding shows some basic WebBrowser supports
WEB_CS: Coding shows displaying the user content and handling the control events from those scripts

4. WebBrowser basic actions

WebBrowser control provides rich functionalities and in this sample, we will see only the basic actions like loading a web page, stopping the current page load and refreshing the page load.
1) In the Go button click handler, we take the web address provided in the Address box and navigate to that page. In the meantime, we display the status text "Loading". The Navigate method will absorb the content from the web address specified by the user and displays that in WebBrowser control.
private void btnGo_Click(object sender, EventArgs e)
{
    //Web_BR 01: Navigate to the URL
    Browser.Navigate(txtTBURL.Text);
    Status_Information.Text = "Loading...";
}
2) Canceling the page load as well as refreshing the loaded/partly loaded page content are straight forward. We should simply call the corresponding methods in the WebBrowser control to do so. Below are the handler functions for Stop and Reload buttons
private void btnStop_Click(object sender, EventArgs e)
{
    //Web_BR 02: Stop Loading the Page
    Browser.Stop();
}

private void btnReload_Click(object sender, EventArgs e)
{
    //Web_BR 03: Refresh the Page
    Browser.Refresh();
}

5. Designing Status Information for WebBrowser Control

When we load a web page on a browser; say IE; to fully load the document, the browser has to navigate to different web locations. Say, for example, the website having a lot of YouTube videos and review about the video (Page’s own content is review) also contains a FaceBook like a page on the same page. When we browse to that website, the browser will load the review content of the video from the page itself, then it navigates to the YouTube and FaceBook to get other required information. So, to load a document completely, the browser should navigate to three web addresses even though the user specifies only one address in the address bar of the sample browser.
When the browser is navigating to a different site for loading some portion of the document, we will get two events namely "Navigating Event" and "Navigated Event". The first event says that the navigation is about to start and the second event says, navigation is completed. When the web page document is fully loaded, we get the "DocumentCompleted Event".
We handled all the three events to display the status information:
private void frmWebBrowser_Load(object sender, EventArgs e)
{
    //Web_BR 04: Hide the visibility of the status bar
    Status_PB.Visible = false;
}

private void Browser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
    //Web_BR 06: Provide some information about the current navaigation
    Status_PB.Visible = true;
    Status_Information.Text = "Navigating " + e.Url.ToString() + " for " + e.TargetFrameName;
}

private void Browser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
    //Web_BR 07: Provide some information about the current navaigation
    Status_Information.Text = "Navigated..";
}

private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    //Web_BR 08: Provide some information about the current navaigation
    Status_PB.Visible = false;
    Status_Information.Text = "Web Page Loaded";
}
Note that we hide the progress in the status bar during the form load. And, we enable that when the Browser starts its first navigation for the page. Once we receive the "doumentcompleted event", we again disable the progress bar. Below given video shows loading the web page in our browser sample:
Video 4: Sample in Action: Navigate to a Page

6. Create Plain custom HTML for WebBrowser Control

When we click the custom button 1 from the tool strip, the browser loads custom script 1 as shown below. We access this HTML button shown in the below picture from the C# code and hook the click event of this button to the c# method.
The ToolStrip of our browser sample application is modified to include two more buttons and each button loads two different user content in the web browser control. The below video shows adding these two buttons to the ToolStrip control:
Video 5: Modify ToolStrip Control
Once the buttons are added, using the Visual Studio IDE, the custom web content (Shown in the Picture Above) is created. The formatted content of the IDE created HTML page is given below:
<html >
 <head>
   <title>Button Click by ID</title>
 </head>
 <body>The button placed below is a html button. The button is accessed by C# and a handler method(in C#) is provided at runtime
   <input id='BtnTest' style='z-index: 100; left: 8px; width: 102px; position: absolute;top:60px' type='button' value='button'/>
 </body>
</html>
In the above script, we gave an Id (BtnTest) to the “input” control. In addition, the control type is specified as a button. Notice that we don’t provide handler now. At runtime, the browser sample will get this button from the loaded HTML content, and dynamically specifies the handler to the button click. Video 6 shows creating and formatting the HTML shown above using the visual studio IDE. 
Video 6: Creating the HTML content for the browser
Note that we changed the double quotes as single quotes and this will avoid formatting the HTML content when we assign it as a string to the WebBrowser control later.

7. Hooking the event at runtime

1) In the above script, the HTML designer not aware of which function to be called and that is decided at the runtime. The first thing we should do is adding a private flag customDoc1. This flag will be set when the WebBrowser control is loading the user HTML script.
//Web_CS 01: Declare boolean tag for document 1 and 2
private bool customDoc1 = false;
2) In the button click handler (For the first user script), we assigned the above-created user content 1 to the web browser control by setting the "DocumentText Property".
//Web_CS 02: Place the Html document with a button having proper Id
private void btnUser1_Click(object sender, EventArgs e)
{
    //Setting this property will load the document and raise document completed
    Browser.DocumentText = "<html ><head><title>Button Click by ID</title></head><body>The button placed below is a html button. The button is accessed by C# and a handler method(in C#) is provided at runtime<input id='BtnTest' style='z-index: 100; left: 8px; width: 102px; position: absolute;top:60px' type='button' value='button'/></body></html>";
    customDoc1 = true;
}
3) As we specified the new content for the WebBrowser control (By setting the DocumentText), the browser will load the content and fires the Document Completed event once the load is fully done. In the event handler, we get the HTML button by its id and store that as "HtmlElement". Then we do provide the event handler to its click event using the delegate "HtmlElementEventHandler". Finally, we reset the boolean flag customDoc1 to false.
//Web_CS 03: Get the Html button from the loaded document
//           Script. Then attach the C# method as click handler
if (customDoc1 == true)
{
    //03.1 : Get html Element
    HtmlElement btnElem = Browser.Document.GetElementById("BtnTest");

    //03.2 : Hook the C# method to the event
    if (btnElem != null)
        btnElem.Click += new HtmlElementEventHandler(Html_test_button_Hanlder);
    //03.3 : Reset the Tag
    customDoc1 = false;
}
4) The handler function for the html button click is shown below:
//Web_CS 04: Create a button handler for Html Button
void Html_test_button_Hanlder(object sender, HtmlElementEventArgs evArg)
{
    MessageBox.Show("Click event of the Script button Handled");
}
In this section, we created an HTML content with a button in it. Then the HTML content is loaded into the WebBrowser control. Once the user content is loaded completely, we get the HTML button instance from the loaded document and attached c-sharp method as click event handler. In this case, the HTML document designer not aware of the c-sharp handler. In some cases, the HTML script knows which function to call on the c-sharp code library. In that case, they (The script developer) do provide the click handler during the HTML design itself. We see that in the next section.

8. Setting the click handler from External source

Look at the second custom script shown below:
<html >
      <head>
         <title>Button Click Hooked to External Method of C#</title>
      </head>
      <body>The scripting person knows which c# function to call. So the well known c# method is tied in the OnClick Attribute
          <input style='z-index: 100; left: 8px; width: 102px; position: absolute;top: 44px'
          type='button' onclick='window.external.ShowMessageE()'  value='button'/>
      </body>
</html>
In this script, the input button is not specified with the id. In the OnClick event, the handler function external.ShowMessageE is specified as an event handler. The external here specifies that the function ShowMessageE() is available from the external source. In our case, the external source is C# as the WebBrowser control is going to load it.
1) In the WebBrowser sample, first, we included the required namespace. This is to make the class "HtmlSupportingMethods" that we are going to implement soon as a COM visible class.
//Web_CS 05: Declare the required namespace
using System.Runtime.InteropServices;
2) In the button click the second user content is specified as the "DocumentText". This document is loaded just the same way we loaded the first script. The only difference is, here we used the verbatim string (@stringcontent) to retain the format of the string as it is.
//Web_CS 06: Set the Html as document content of the browser control.
private void btnUser2_Click(object sender, EventArgs e)
{
    string htmldoc = @"<html >
    <head>
    <title>Button Click Hooked to External Method of C#</title>
    </head>
    <body>The scripting person knows which c# function to call. So the well known c# method is tied in the OnClick Attrubite<input
            style='z-index: 100; left: 8px; width: 102px; position: absolute;top: 44px'
            type='button' onclick='window.external.ShowMessageE()'  value='button'/>
    </body>
    </html>";

    //Setting this property will load the document and raise document completed
    Browser.DocumentText = htmldoc;
}
3) The class HtmlSupportingMethods contains only one public method, which is accessed by our custom script 2 as Window.external.ShowMessageE(). As this method is accessed by the external scripting world, we mark the class as COM compatible by declaring the class with the "[ComVisible(true)] Attribute" 
//Web_CS 07: External scripting methods. This class is set with the ComVisible attribute
//           as it's methods are going to be accessed by the html document content that
//           will be loaded by the Web Browser control
[ComVisible(true)]
public class HtmlSupportingMethods
{
    public void ShowMessageE()
    {
        MessageBox.Show("External Method Accessed");
    }
}
4) There is one final step. How does the content loaded on the WebBrowser control knows where should it get the External Source? We should link the C# HtmlSupportingMethods with the HTML script. We do that in the form load as shown below:
//Web_CS 08: Set the Scripting Object. This should a com visible object
Browser.ObjectForScripting = new HtmlSupportingMethods();
The browser sample in action can be found in the below video. The video shows both the user HTML document and hooking the HTML button click to C# code.
Video 7: Testing the scripting support
Source Code: Download

No comments:

Post a Comment

Leave your comment(s) here.

Like this site? Tell it to your Firend :)