Web Browser/Content in a C# Application

April 28, 2008 at 7:22 am Leave a comment

One of the most powerful development tools I’ve come across is using a dynamic
HTML type user interface for my C# applications. Not for the entire application
(like Microsoft Money), but frequently rich mixed content needs to be delivered
to the user and an embedded web browser is powerful.

Embedding just a web browser into an app is okay, but to use it as a responsive
user interface to your C# application is where the real power lies.

Note: Don’t get overwhelmed by the number of steps here. Each step is built upon
the previous but made so you can stop anywere and use what you’ve got up to that point.

Step 1: Get Internet Explorer Into Your App

  1. Create a new Windows Form
  2. Add the SHDocVw Web Browser COM Custom Control to your “Windows Forms”
    1. Right Click on the Toolbox
    2. Choose “Customize Toolbox…”
    3. Select and Add “Microsoft Web Browser”
  3. Draw the new control onto your form (Global icon)

These steps are necessary as the OCX control requires state information that
VS.NET automatically handles and includes in the projects resource file.
Step 2: Using the Web Browser

Since the Web Browser object is compatible with IE 3 to IE 6 and is based on
COM, it is a bit more complicated to use than a .NET component. Here is some
code on how to navigate.
Note: I will call my axWebBrowser control on a form “webMain”.


private void Navigate(string url)
{
    object o = System.Reflection.Missing.Value;
    webMain.Navigate(url, ref o, ref o, ref o, ref o);
}

The System.Reflection.Missing.Value object provides a null reference for an
optional/missing parameter. Much like in VB you can make passing some parameters
optional. Ex: Function MyFunc(url as String, Optional OtherInfo as String)

Handling the Web Browsers events requires knowing what to look for. Here is an
example of the status text change event:


using AxSHDocVw;

webMain.StatusTextChange += new DWebBrowserEvents2_StatusTextChangeEventHandler(webMain_StatusTextChange);

private void webMain_StatusTextChange(object sender, DWebBrowserEvents2_StatusTextChangeEvent e)
{
    Console.WriteLine(”webMain Status Text: ” + e.text);
}

This is all that is need just to use the browser to navigate to a web site.

Step 3: Access the IE Document Object Module (DOM)

Knowledge of Internet Explorer’s Document Object Model (IE DOM) from here
on is very useful.

Now my favorite part is in creating DHTML (Dynamic HTML) at run time and feeding
this to the browser control to make my own custom UI and display rich dynamic
content. We need access to the Microsoft HTML object library then know which
properties to line up.

  1. Right Click on References in the Solutions View
  2. Choose “Add Reference…”
  3. Go to the COM Tab
  4. Select and add “Microsoft HTML Object Library”

Note: There are a lot of items avalible in the mshtml library. Use the
references below to get more info on them.

Now let’s get the body of the web document.


using mshtml;

private HTMLDocument document
{get {return (HTMLDocument) webMain.Document;}}

private HTMLBody body
{get {return (HTMLBody) document.body;}}

Note: The web browser is a generic content container and by default is
not initialized to an HTML container so you must first load some HTML content
before attempting to access the document or body properties. The easiest way to
do this is:


private void Form1_Load(object sender, System.EventArgs e)
{
    // Goto a blank HTML page
    Navigate(”about:blank”);

    // Wait for the document to load
    while (body == null) Application.DoEvents();
     Step 4: Trapping IE DOM Events

Okay so now we have a Web Browser control showing our custom content.  How do we
interact with the content we’re showing to the use?  We need to trap
the HTML events.


using System.Runtime.InteropServices;

private void Form1_Load(object sender, System.EventArgs e)
{
    // … Other Previous Code Here

    // Set the handler for several DHTML events
    document.onclick = this;
    document.onmouseover = this;
    document.onmouseout = this;
}

// The default COM Interop method [DispId(0)]
public void DefaultMethod()
{
    HTMLWindow2 win = (HTMLWindow2) document.parentWindow;   Step 5: Putting it All Together - Make a Wrapper Custom Control

Okay, we now have all the tools we need to make everything work together.
I highly recommend making your own web browser custom control wrapper to make
working with the browser easier.  Here is the basic wrapper that I made and use
on everything.  This is great for spiffy message boxes, rich content on your
forms, etc.  Be sure to have the correct references.

Note: You will have to remove/delete the Web Browser control off the custom
control, put it back on manually, and rename it to webMain in order for VS.NET to
include the correct OCX state and licensing.

When put on a form, this custom control can appear and act much like a regular
label.  It defaults to the basic color and font of other controls.  Have fun!


using System;
using mshtml;
using System.Windows.Forms;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace CoadTools
{
    #region Delegates
    public delegate void WebBrowserElementEventHandler(object sender, mshtml.IHTMLEventObj e);
    #endregion

    /// &ltsummary>
    /// Noah Coad’s IE Web Browser Custom Control Wrapper
    /// </summary>
    public class WebBrowser : System.Windows.Forms.UserControl
    {
        #region Control Components
        private System.Windows.Forms.Panel pnlWeb;
        private AxSHDocVw.AxWebBrowser webMain;

        /// &ltsummary> Required designer variable. </summary>
        private System.ComponentModel.Container components = null;
        #endregion

        #region Enumerators
        public enum ieScrollBars {None, Always, Auto};
        #endregion

        #region Event Handler Declarations
        public event WebBrowserElementEventHandler WebBrowserElementEvent;
        #endregion

        #region Constructor(s)
        public WebBrowser()
        {
            InitializeComponent();

            // Go to the blank page, initializes the WebBrowser control to handle HTML documents.
            Navigate(”about:blank”, true);

            // Wait for the control to initialize to HTML and load the blank page.
            while (body == null) {Application.DoEvents();}

            // Set default properties for the control to appear like a generic label control.
            pnlWeb.BorderStyle = BorderStyle.None;
            //ScrollBars = ScrollBars.none;
            this.Text = “”;
            this.HTML = “”;
            body.style.font = “8.25pt Microsoft Sans Serif, 10pt Verdana”;
            body.style.margin = “0″;
            body.style.borderStyle = “none”;
            body.style.background = “buttonface”;
            ScrollBars = ieScrollBars.None;
        }

        #endregion

        #region Component Designer generated code
        /// &ltsummary> 
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if (disposing) if (components != null) components.Dispose();
            base.Dispose(disposing);
        }

        /// &ltsummary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(WebBrowser));
            this.pnlWeb = new System.Windows.Forms.Panel();
            this.webMain = new AxSHDocVw.AxWebBrowser();
            this.pnlWeb.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.webMain)).BeginInit();
            this.SuspendLayout();
            // 
            // pnlWeb
            // 
            this.pnlWeb.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
            this.pnlWeb.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                                                                                                 this.webMain});
            this.pnlWeb.Dock = System.Windows.Forms.DockStyle.Fill;
            this.pnlWeb.Name = “pnlWeb”;
            this.pnlWeb.Size = new System.Drawing.Size(150, 150);
            this.pnlWeb.TabIndex = 1;
            // 
            // webMain
            // 
            this.webMain.ContainingControl = this;
            this.webMain.Dock = System.Windows.Forms.DockStyle.Fill;
            this.webMain.Enabled = true;
            this.webMain.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject(”webMain.OcxState”)));
            this.webMain.Size = new System.Drawing.Size(146, 146);
            this.webMain.TabIndex = 0;
            // 
            // WebBrowser
            // 
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                                                                                    this.pnlWeb});
            this.Name = “WebBrowser”;
            this.pnlWeb.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.webMain)).EndInit();
            this.ResumeLayout(false);

        }
        #endregion

        #region Public Control Properties
        // Sets the scroll bars of body of the document.
        /// &ltsummary>
        /// Special Internet Explorer BODY.Scroll Property
        /// </summary>
        [DefaultValue(ieScrollBars.None)]
        [Description("Internet Explorer's BODY.Scroll Property")]
        public ieScrollBars ScrollBars
        {
            get
            {
                if (body.scroll.Equals(”yes”)) return ieScrollBars.Always;
                if (body.scroll.Equals(”auto”)) return ieScrollBars.Auto;
                return ieScrollBars.None;
            }
            set
            {
                if (value == ieScrollBars.Auto) body.scroll = “auto”;
                if (value == ieScrollBars.None) body.scroll = “no”;
                if (value == ieScrollBars.Always) body.scroll = “yes”;
            }
        }

        [DefaultValue(BorderStyle.None)]
        public BorderStyle BorderStyle
        {
            get {return pnlWeb.BorderStyle;}
            set {pnlWeb.BorderStyle = value;}
        }

        #endregion

        #region Public HTML Properties

        [Browsable(false)]  // Do not show in the properties box
        public HTMLDocument document
        { get {return (HTMLDocument) webMain.Document;} }

        [Browsable(false)]  // Do not show in the properties box
        public HTMLBody body
        { get {return (HTMLBody) document.body;} }

        // Document Body’s innerText
        [DefaultValue("")] // Let the properties box know the default value
        [Browsable(true)]  // Do show in the properties box
        [Description("Internet Explorer's BODY.innerText Property")]
        public override string Text
        {
            get {return body.innerText;}
            set {body.innerText = value;}
        }

        // Document Body’s innerHTML
        [DefaultValue("")]
        [Description("Internet Explorer's BODY.innerHTML Property")]
        public string HTML
        {
            get {return body.innerHTML;}
            set {body.innerHTML = value;}
        }

        #endregion

        #region COM Event Handler for WebBrowser HTML Elements
        // COM Event Handler for HTML Element Events
        [DispId(0)]
        public void DefaultMethod()
        {
            // Call the custom Web Browser HTML event 
            WebBrowserElementEvent(this, document.parentWindow.@event);
        }
        #endregion

        #region Public Methods
        /// &ltsummary>
        /// Navigates to a web page, defaults to waiting for the page to load before continuing.
        /// </summary>
        /// &ltparam name=”url”>The URL to be redirected to</param>
        public void Navigate(string url)
        { Navigate(url, true); }

        /// &ltsummary>
        /// Navigates to a web page
        /// </summary>
        /// &ltparam name=”url”>The URL to be redirected to</param>
        /// &ltparam name=”wait”>Wait for the page to load before continuing</param>
        public void Navigate(string url, bool wait)
        {
            // Creates the null missing value object
            object o = System.Reflection.Missing.Value;

            // Resets the browser to an empty container, cleaning the slate
            if (wait) webMain.Navigate(null, ref o, ref o, ref o, ref o);

            // Wait until the browser is empty
            if (wait) while (document != null) {Application.DoEvents();}

            // Go to the new URL
            webMain.Navigate(url, ref o, ref o, ref o, ref o);

            if (wait) while (document.body == null) {Application.DoEvents();}
            //if (wait) while (webMain.Busy) {Application.DoEvents();}
        }

        #endregion
    }
}

Step 6: Using the Custom Web Browser Control
Here is a simple form and way to use the control above. Enjoy!


using System;
using mshtml;
using CoadTools;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WebBrowserTutorial
{
    /// &ltsummary> Test Container for CoadTools.WebBrowser </summary>
    public class frmWebTest : System.Windows.Forms.Form
    {
        private CoadTools.WebBrowser webMain;
        private System.ComponentModel.Container components = null;

        public frmWebTest()
        { InitializeComponent(); }

        protected override void Dispose( bool disposing )
        {
            if (disposing) if (components != null) components.Dispose();
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code
        /// &ltsummary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.webMain = new CoadTools.WebBrowser();
            this.SuspendLayout();
            // 
            // webMain
            // 
            this.webMain.Dock = System.Windows.Forms.DockStyle.Fill;
            this.webMain.HTML = “webBrowser1″;
            this.webMain.Name = “webMain”;
            this.webMain.Size = new System.Drawing.Size(234, 102);
            this.webMain.TabIndex = 0;
            // 
            // frmWebTest
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(234, 102);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                                                                                    this.webMain});
            this.Name = “frmWebTest”;
            this.Text = “Web Browser Test”;
            this.Load += new System.EventHandler(this.frmWebTest_Load);
            this.ResumeLayout(false);

        }
        #endregion

        /// &ltsummary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        { Application.Run(new frmWebTest()); }

        private void frmWebTest_Load(object sender, System.EventArgs e)
        {
            webMain.WebBrowserElementEvent += new WebBrowserElementEventHandler(webMain_HTMLEvent);
            webMain.HTML = “&ltbr>&ltbr>&ltcenter>&ltspan style=’font: bold 10pt verdana; color: darkgreen;’>Hello World</span></center>”;
            webMain.document.onclick = webMain;
        }

        private void webMain_HTMLEvent(object sender, mshtml.IHTMLEventObj e)
        {
            Console.WriteLine(”HTML Object: ” + e.srcElement + “, Type: ” + e.type);
        }
    }
}

This concludes the test form for experimenting with the above Web Browser control.

Console.WriteLine(”Object: ” + win.@event.srcElement + “, Type: ” + win.@event.type);

}

// Now you have full access to the body of a blank HTML page.

body.innerText = “Hello World”;

}

Advertisements

Entry filed under: c-sharp. Tags: , .

Windows Server 2003 IIS and Scripting interview questions How to collapse and expand rows of a datagrid using C#, ASP.NET, and Javascript.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Trackback this post  |  Subscribe to the comments via RSS Feed


April 2008
M T W T F S S
    Jun »
 123456
78910111213
14151617181920
21222324252627
282930  

%d bloggers like this: