Kirk Evans Blog

.NET From a Markup Perspective

Specify the HTML for a Windows Forms Web Browser Control

Specify the HTML for a Windows Forms Web Browser Control

  • Comments 23

Mike asks: How do I specify the HTML for a web browser control from a string?

The answer is fairly simple, yet I could not find a quick reference link anywhere from a Google search. So, here is the set of steps to use the web browser control and set the HTML for the control using a string.

There is no real magic: you just need 2 different libraries. The WebBrowser's Document property returns an object representing the DOM for a web page. However, this DOM does not exist until a page is loaded. Rather than load a URL from a file, use about:blank for the URL to load a blank page. When you call the Navigate method of the browser, the status text becomes "Opening page about:blank..." When the document is finished loading, the status text changes to "Done". You can leverage this event to know that the browser is finished loading the blank page, at which time the DOM is accessible.

If you are not using Visual Studio .NET, see the Microsoft SDK documentation for instructions on the Windows Forms ActiveX Control Importer. This utility is used to create a Windows Forms control based on the type library information in the ActiveX control.

  • Create a new Windows Form project.
  • Open the WYSIWYG designer for Form1. Right-click the Toolbox and choose Customize Toolbox..., and click the COM Components tab.
  • Browse the SYSTEM32 directory for shdocvw.dll.. Click OK to choose this DLL. Click OK to close the dialog. Your project references now shows a reference to AxShDocVw.dll.
  • Right-click the References tab and choose Add Reference... Click the COM tab. Click the Browse button. Navigate to the SYSTEM32 directory and choose mshtml.tlb. Click OK to close the dialog. Your project references now shows a reference to MSHTML.
  • From the Toolbox pane, drag an Explorer component onto Form1. name this control "browser" in the properties pane. Switch to the code view for the form and enter the following code for the form:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using mshtml;

namespace WindowsApplication2
{
	public class Form1 : System.Windows.Forms.Form
	{
		private AxSHDocVw.AxWebBrowser browser;
		private System.ComponentModel.Container components = null;

		public Form1()
		{				
			InitializeComponent();
			string url = "about:blank";
			object o = System.Reflection.Missing.Value;
			browser.Navigate ( url,ref o,ref o,ref o,ref o);
			AxSHDocVw.DWebBrowserEvents2_StatusTextChangeEventHandler handler = 
			  new AxSHDocVw.DWebBrowserEvents2_StatusTextChangeEventHandler 
			  (this.browser_StatusTextChange);
			browser.StatusTextChange += handler;			
		}


		private void browser_StatusTextChange
			(object sender, AxSHDocVw.DWebBrowserEvents2_StatusTextChangeEvent e)
		{
			
			mshtml.HTMLDocument doc = (mshtml.HTMLDocument)this.browser.Document;
			doc.body.innerHTML = "<H1>foo</H1>";
		}

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

		#region Windows Form Designer generated code

		private void InitializeComponent()
		{
			System.Resources.ResourceManager resources = new 
				System.Resources.ResourceManager(typeof(Form1));
			this.browser = new AxSHDocVw.AxWebBrowser();
			((System.ComponentModel.ISupportInitialize)(this.browser)).BeginInit();
			this.SuspendLayout();
			// 
			// browser
			// 
			this.browser.Enabled = true;
			this.browser.Location = new System.Drawing.Point(16, 16);
			this.browser.OcxState = 
				((System.Windows.Forms.AxHost.State)(resources.GetObject("browser.OcxState")));
			this.browser.Size = new System.Drawing.Size(344, 224);
			this.browser.TabIndex = 0;
			// 
			// Form1
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(392, 302);
			this.Controls.AddRange(new System.Windows.Forms.Control[] { this.browser});
			this.Name = "Form1";
			this.Text = "Form1";
			((System.ComponentModel.ISupportInitialize)(this.browser)).EndInit();
			this.ResumeLayout(false);

		}
		#endregion

		[STAThread]
		static void Main() 
		{
			Application.Run(new Form1());
		}

	}
}
 

That's all there is to it. Once the DOM is available, you have access to the body of the HTMLDocument.

  • The ActiveX Control Importer converts type definitions in a COM type library for an ActiveX control into a Windows Forms control...

  • Creating a HTML Viewer Control : Dustin Mihalik's Blog
  • Another quick method:

    browser.Navigate ( "about:<h1>Foo</h1>",ref o,ref o,ref o,ref o);
  • Thank you so much for this code!! It only took 3 hours to find!
  • You are a life saver - I found a lot of snipets of code that sort of did what I wanted, but none of them actually explained why it was written that way. Yours is the first that clearly explained why I had to call "navigate", before then I was only getting exception errors.

    You are one righteous dude!
  • Good stuff mate... I've been looking for something similar for a while then come to the same solution, although without using the textchange event...

    Good on you...
  • Dude u rock!! Thanks for the explanation.. FInally....I do have another question though. Iam using this to make a telnet/mudding application. Once I convert the stream to html and display it How do i get the control to scroll down like a textbox would?
  • Try something like this. It works for some scrollable controls. May or may not work for the browser control. Theoretically, you'd just call ScrollToBottom() each time you add text to the control.

    const int WM_VSCROLL = 0x0115;
    readonly IntPtr SB_BOTTOM = new IntPtr( 7 );

    public void ScrollToBottom()
    {
    System.Windows.Forms.Message msg =
    Message.Create( this.Handle,
    WM_VSCROLL,
    SB_BOTTOM,
    IntPtr.Zero );
    this.DefWndProc( ref msg );
    }
  • Sorry, the example assumes that you've subclassed the browser control. If not, replace "this" with "this.browser" (assuming the naming system above).
  • I tried doing exactly this. But, when the form is opened, it gave exception stating "Exception has been thrown by the target of an invocation". And when I click "OK", it displays the stack with bottom most trace pointing to "System.RuntimeType.CreateInstanceImpl(Boolean publicOnly)"

    I am using Windows 2000 SP4 with IE 6 SP1. I have VStudio 2003 with .NET framework 1.1.

    I have no idea what's happening! Greatly appreciate if anyone can help. Thanks.
  • OK. I was trying this on a form which is an MDI child. When I played around with it, I got a clearer exception on the line where the browser was created (within initComponents). It said "could not instantiate ActiveX control because current thread is not signle-threaded apartment".

    When I tried the same code on a form (not an MDI child) that has the main (like in the above example) it worked!

    Anyone faced this issue? Thanks.
  • I got the answer. I had missed out "[STAThread]" directive above main method declaration.

    Thanks.
  • Thanks!
Page 1 of 2 (23 items) 12
Leave a Comment
  • Please add 7 and 1 and type the answer here:
  • Post
Translate This Page
Search
Archive
Archives