I have a form containing a web browser control. This browser control will load some HTML from disk and display it. I want to be able to have a button in the HTML access C# code in my form.
For example, a button in the HTML might call the Close() method on the form.
Target platform: C# and Windows Forms (any version)
Look at the WebBrowser.ObjectForScripting property. Managed to get Google Maps talking to a windows forms application using this.
I've implemeted this in a few applications in the past, here's how: (NB: the example below is not production ready and should be used as a guide only).
First create a normal .NET class (public) that contains public methods that you wish to call from Javasvcipt running in your web browser control.
Most importantly it must be decorated with the ComVisible(true)] attribute from the System.Runtime.InteropServices namespace (Javascript in IE is COM based). It can be called anything, I've called it "External" to make things clearer.
using System.Runtime.InteropServices;
[ComVisible(true)]
public class External
{
private static MainWindow m_mainWindow = null;
public External(MainWindow mainWindow)
{
m_mainWindow = mainWindow;
}
public void CloseApplication()
{
m_mainWindow.Close();
}
public string CurrentDate(string format)
{
return DateTime.Now.ToString(format);
}
}
Next in the .NET form containing your web browser control create an instance of the COMVisible class, then set the web browser controls ObjectForScripting to that instance:
private void MainWindow_Load(object sender, EventArgs e)
{
m_external = new External(this);
browserControl.ObjectForScripting = m_external;
}
Finally, in your Javascript running in the web browser control, you access the .NET methods via the window.external object. In this case window.external actually references (indirectly via a COM interop wrapper) the "External" object created above:
// Javascript code
function CloseButton_Click()
{
if (window.external)
{
window.external.CloseApplication();
}
}
Be aware that calls from Javascript to .NET pass through the COM interop layer and so querying of the default interface, marshalling of parameters etc must occur. In other words it can be relatively SLOW, so do some performance testing if you plan to make multiple calls for example from within a loop.
Also, just for future reference, calling Javascript code from .NET is simpler, just use the Document.InvokeScript method:
browserControl.Document.InvokeScript("jScriptFunction", new object[] { "param1", 2, "param2" });
All you have to do is add an event handler for the WebBrowser's Navigating event.
This event gets fired before the browser navigates to the next page. It allows you to interrupt the process and do whatever you want, including cancelling the navigation and calling into your code.
Pretty easy to use. The only caveat I've come across is that you can't view the PostData -- see my question here: PostData Question
Here's some sample code:
private void MyMethod()
{
// do something
}
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
MyMethod();
e.Cancel = true;
}
This is possible, but I haven't done it in .NET.
A few years back I had a C++ application that hosted a web browser control (ActiveX). From the HTML in the control, it was possible to call 'out' to the ActiveX control and get it to do things.
The same should be possible in .NET, although HTML DOM/JavaScript won't know about C#. But if you wrap your .NET functionality in a COM object, you should be able to call methods on the COM/ActiveX objects which will in-turn call your C# code.
Hope this helps.
I did this several years ago, and blogged about it here:
http://matthewskelton.wordpress.com/2007/04/21/calling-javascript-from-c/
Specifically, you can use Type.InvokeMember()
to call JavaScript from C#.