Invoke C# code from JavaScript in a Document in a WebBrowser
What you need to do is set the ObjectForScripting
property on the web browser control to an object containing the C# methods you want to call from JavaScript. Then you can access that object from JavaScript using window.external
. The only thing to watch out for is that the object has to have the [ComVisibleAttribute(true)]
attribute. I've used this successfully for several years.
Here's a page with documenation and a simple example: http://msdn.microsoft.com/en-us/library/a0746166.aspx
Here's the example from the link (I haven't tried this code):
using System;
using System.Windows.Forms;
using System.Security.Permissions;
[PermissionSet(SecurityAction.Demand, Name="FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class Form1 : Form
{
private WebBrowser webBrowser1 = new WebBrowser();
private Button button1 = new Button();
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
public Form1()
{
button1.Text = "call script code from client code";
button1.Dock = DockStyle.Top;
button1.Click += new EventHandler(button1_Click);
webBrowser1.Dock = DockStyle.Fill;
Controls.Add(webBrowser1);
Controls.Add(button1);
Load += new EventHandler(Form1_Load);
}
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.AllowWebBrowserDrop = false;
webBrowser1.IsWebBrowserContextMenuEnabled = false;
webBrowser1.WebBrowserShortcutsEnabled = false;
webBrowser1.ObjectForScripting = this;
// Uncomment the following line when you are finished debugging.
//webBrowser1.ScriptErrorsSuppressed = true;
webBrowser1.DocumentText =
"<html><head><script>" +
"function test(message) { alert(message); }" +
"</script></head><body><button " +
"onclick=\"window.external.Test('called from script code')\">" +
"call client code from script code</button>" +
"</body></html>";
}
public void Test(String message)
{
MessageBox.Show(message, "client code");
}
private void button1_Click(object sender, EventArgs e)
{
webBrowser1.Document.InvokeScript("test",
new String[] { "called from client code" });
}
}
How to inject Javascript in WebBrowser control?
For some reason Richard's solution didn't work on my end (insertAdjacentText failed with an exception). This however seems to work:
HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0];
HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
element.text = "function sayHello() { alert('hello') }";
head.AppendChild(scriptEl);
webBrowser1.Document.InvokeScript("sayHello");
This answer explains how to get the IHTMLScriptElement
interface into your project.
Invoke a script in WebBrowser, and wait for it to finish running (synchronized)
using async/await you can wait until the script is executed without blocking the UI.
public async void AMethod()
{
string script =
@"<script>
function Script_A() {
Script_B();
window.external.Completed(); //call C#: CallbackObject's Completed method
}
function Script_B(){
alert('in script');
}
</script>";
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
webBrowser1.ObjectForScripting = new CallbackObject(tcs);
//Ensure DocumentText is loaded before invoking "InvokeScript",
//by extension method "SetDocumentTextAsync" (below)
await webBrowser1.SetDocumentTextAsync(script);
webBrowser1.Document.InvokeScript("Script_A");
await tcs.Task;
MessageBox.Show("Script executed");
}
[ComVisible(true)]
public class CallbackObject
{
TaskCompletionSource<bool> _tcs = null;
public CallbackObject(TaskCompletionSource<bool> tcs)
{
_tcs = tcs;
}
public void Completed()
{
_tcs.TrySetResult(true);
}
}
public static class BrowserExtensions
{
public static Task SetDocumentTextAsync(this WebBrowser wb, string html)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
WebBrowserDocumentCompletedEventHandler completedEvent = null;
completedEvent = (sender, e) =>
{
wb.DocumentCompleted -= completedEvent;
tcs.SetResult(null);
};
wb.DocumentCompleted += completedEvent;
wb.ScriptErrorsSuppressed = true;
wb.DocumentText = html;
return tcs.Task;
}
}
How to inject Javascript in WebBrowser control
Does this work?
private void WebBrowser_LoadCompleted
(object sender,
System.Windows.Navigation.NavigationEventArgs e)
{
var webBrowser = sender as WebBrowser;
var document
= webBrowser.Document as mshtml.HTMLDocument;
var ahref
= document.getElementsByTagName("A").Cast<mshtml.IHTMLElement>().First();
ahref.setAttribute(
"onmouseenter",
"javascript:alert('Hi');", 1);
}
You need is Microsoft.mshtml
(the .net API and not MS office one) reference.
Also please see this code for WPF webbrowser control that uses ObjectForScripting
property of WebBrowser
which can help you in injecting javascript...
http://blogs.msdn.com/b/wpf/archive/2011/05/27/how-does-wpf-webbrowser-control-handle-window-external-notify.aspx
Let me know if this helps.
Invoke Javascript Test Click in Web Browser control
[EDITED]
What I said below was incorrect. Your syntax is correct, webBrowser2.Document.InvokeScript("TestClick")
should do the same job as webBrowser2.InvokeScript("TestClick")
. I'll try your code and get back here.
I think the correct syntax should be this:
webBrowser2.Document.InvokeScript("TestClick()");
Note ()
after TestClick
.
Or you could rather do:
webBrowser2.InvokeScript("TestClick");
[EDITED]
There's something wrong with the HTML originally loaded into the WB, maybe you should include it with your question. The following is just a copy of your code (besides this.webBrowser2.DocumentText
) and it does work, TestClick
gets invoked.
private void Form1_Load(object sender, EventArgs e)
{
this.webBrowser2.DocumentText = "<body><div id=flls><button onclick='alert(true)'>go</button></div></body>";
this.webBrowser2.DocumentCompleted += webBrowser2_DocumentCompleted;
}
void webBrowser2_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
HtmlElement head = webBrowser2.Document.GetElementsByTagName("head")[0];
HtmlElement testScript = webBrowser2.Document.CreateElement("script");
IHTMLScriptElement element = (IHTMLScriptElement)testScript.DomElement;
element.text = "function simulate(g,c){var e=extend(defaultOptions,arguments[2]||{});var b,f=null;for(var d in eventMatchers){if(eventMatchers[d].test(c)){f=d;break}}if(!f){throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported')}if(document.createEvent){b=document.createEvent(f);if(f=='HTMLEvents'){b.initEvent(c,e.bubbles,e.cancelable)}else{b.initMouseEvent(c,e.bubbles,e.cancelable,document.defaultView,e.button,e.pointerX,e.pointerY,e.pointerX,e.pointerY,e.ctrlKey,e.altKey,e.shiftKey,e.metaKey,e.button,g)}g.dispatchEvent(b)}else{e.clientX=e.pointerX;e.clientY=e.pointerY;var a=document.createEventObject();b=extend(a,e);g.fireEvent('on'+c,b)}return g}function extend(a,c){for(var b in c){a[b]=c[b]}return a}var eventMatchers={HTMLEvents:/^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,MouseEvents:/^(?:click|dblclick|mouse(?:down|up|over|move|out))$/};var defaultOptions={pointerX:0,pointerY:0,button:0,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false,bubbles:true,cancelable:true};function TestClick(){simulate(document.getElementById('flls').firstChild,'click')};";
head.AppendChild(testScript);
webBrowser2.Document.InvokeScript("TestClick");
}
Calling a Javascript function in the C# webBrowser control
Can you specify what failed?
My sample below consists of a form with a WebBrowser and a Button.
The object called y in the end has the sentence "i did it!". So with me it works.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
webBrowser1.DocumentText = @"<html><head>
<script type='text/javascript'>
function doIt() {
alert('hello again');
return 'i did it!';
}
</script>
</head><body>hello!</body></html>";
}
private void button1_Click(object sender, EventArgs e)
{
object y = webBrowser1.Document.InvokeScript("doIt");
}
}
Calling javascript object method using WebBrowser.Document.InvokeScript
The example in the documentation does NOT include the parenthesis.
private void InvokeScript()
{
if (webBrowser1.Document != null)
{
HtmlDocument doc = webBrowser1.Document;
String str = doc.InvokeScript("test").ToString() ;
Object jscriptObj = doc.InvokeScript("testJScriptObject");
Object domOb = doc.InvokeScript("testElement");
}
}
Try
Document.InvokeMethod("obj.method");
Note that you can pass arguments if you use HtmlDocument.InvokeScript Method (String, Object[]).
Edit
Looks like you aren't the only one with this issue: HtmlDocument.InvokeScript - Calling a method of an object . You can make a "Proxy function" like the poster of that link suggests. Basically you have a function that invokes your object's function. It's not an ideal solution, but it'll definitely work. I'll continue looking to see if this is possible.
Another post on same issue: Using WebBrowser.Document.InvokeScript() to mess around with foreign JavaScript . Interesting solution proposed by C. Groß on CodeProject:
private string sendJS(string JScript) {
object[] args = {JScript};
return webBrowser1.Document.InvokeScript("eval",args).ToString();
}
You could make that an extension method on HtmlDocument and call that to run your function, only using this new function you WOULD include parenthesis, arguments, the whole nine yards in the string you pass in (since it is just passed along to an eval).
Looks like HtmlDocument does not have support for calling methods on existing objects. Only global functions. :(
Related Topics
Creating a PDF from a Rdlc Report in the Background
ASP.NET MVC Get Textbox Input Value
When Using Iis Express No CSS Applied on a Remote Pc
How to Access Winform Textbox Control from Another Class
Is There Really Any Way to Uniquely Identify Any Computer at All
How to Find Multiple Occurrences with Regex Groups
Why Doesn't Include Have Any Effect
How Can a Metro App in Windows 8 Communicate with a Backend Desktop App on the Same MAChine
What Does Synchronizationcontext Do
How to Write Fast Colored Output to Console
How to Get the HTML Output of a Usercontrol in .Net (C#)
Using C# to Dynamically Generate CSS Files
Datacontract Xml Serialization and Xml Attributes
Performance Tests of Serializations Used by Wcf Bindings