Wie füge ich Javascript in das WebBrowser-Steuerelement ein?

81

Ich habe das versucht:

string newScript = textBox1.Text;
HtmlElement head = browserCtrl.Document.GetElementsByTagName("head")[0];
HtmlElement scriptEl = browserCtrl.Document.CreateElement("script");
lblStatus.Text = scriptEl.GetType().ToString();
scriptEl.SetAttribute("type", "text/javascript");
head.AppendChild(scriptEl);
scriptEl.InnerHtml = "function sayHello() { alert('hello') }";

scriptEl.InnerHtml und scriptEl.InnerText geben beide Fehler:

System.NotSupportedException: Property is not supported on this type of HtmlElement.
   at System.Windows.Forms.HtmlElement.set_InnerHtml(String value)
   at SForceApp.Form1.button1_Click(Object sender, EventArgs e) in d:\jsight\installs\SForceApp\SForceApp\Form1.cs:line 31
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Gibt es eine einfache Möglichkeit, ein Skript in den Dom einzufügen?

jsight
quelle

Antworten:

100

Aus irgendeinem Grund funktionierte Richards Lösung auf meiner Seite nicht (insertAdjacentText schlug mit einer Ausnahme fehl). Dies scheint jedoch zu funktionieren:

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");

Diese Antwort erklärt, wie Sie die IHTMLScriptElementSchnittstelle in Ihr Projekt integrieren können.

Atanas Korchev
quelle
1
Cool, ich denke, die Verwendung von IHTMLScriptElement macht die Codeabsicht auf jeden Fall offensichtlicher. Ich frage mich, warum Sie eine Ausnahme haben, aber manchmal können Sie mit COM Interop wetteifern.
ZeroBugBounce
Was ist mit dem Hinzufügen eines Verweises auf eine lokale JS-Datei? Bitte sehen Sie stackoverflow.com/questions/4029602/…
IAmAN00B
Bitte helfen Sie mir dabei. Wie hast du das gemacht. Ich möchte JS über meine C ++ - App in Echtzeit in meine Seite einfügen. Wie soll ich vorgehen?
Johnydep
Gilt dies auch für das Injizieren von JQuery-Dateien?
Gumuruh
50
HtmlDocument doc = browser.Document;
HtmlElement head = doc.GetElementsByTagName("head")[0];
HtmlElement s = doc.CreateElement("script");
s.SetAttribute("text","function sayHello() { alert('hello'); }");
head.AppendChild(s);
browser.Document.InvokeScript("sayHello");

(getestet in .NET 4 / Windows Forms App)

Bearbeiten: Fallproblem im Funktionssatz behoben.

Typpo
quelle
11
Ich habe diese Lösung sehr geschätzt, da sie nicht auf der (wenn auch nützlichen!) IHTMLSCriptElement-Assembly basiert.
Micah Smith
5
@jsight Dies sollte die akzeptierte Antwort sein. Es ist das gleiche wie die aktuelle Antwort, jedoch einfacher und ohne IHTMLSCriptElementAbhängigkeit.
BlueRaja - Danny Pflughoeft
32

Hier ist der einfachste Weg, den ich gefunden habe, nachdem ich daran gearbeitet habe:

string javascript = "alert('Hello');";
// or any combination of your JavaScript commands
// (including function calls, variables... etc)

// WebBrowser webBrowser1 is what you are using for your web browser
webBrowser1.Document.InvokeScript("eval", new object[] { javascript });

Die globale JavaScript-Funktion eval(str)analysiert und führt alles aus, was in str geschrieben ist. Überprüfen Sie w3schools ref hier .

Ilya Rosikhin
quelle
22

In .NET 4 ist dies außerdem noch einfacher, wenn Sie das dynamische Schlüsselwort verwenden:

dynamic document = this.browser.Document;
dynamic head = document.GetElementsByTagName("head")[0];
dynamic scriptEl = document.CreateElement("script");
scriptEl.text = ...;
head.AppendChild(scriptEl);
justin.m.chase
quelle
2
Warum sollte jemand dafür Dynamik brauchen? Wenn Sie versuchen, einige Eingaben zu speichern, haben wir seit C # 3.0 eine Typinferenz, sodass var akzeptabel wäre. Sie müssen das DLR nicht aufrufen.
Alimbada
23
Dies ist im Grunde genau der Punkt des dynamischen Schlüsselworts: COM interop. Sie haben hier keine Typinferenz, Sie haben Dokumentation. Da ein IHTMLElement2 beispielsweise nicht über IHtmlElement zugewiesen werden kann und Sie zur Laufzeit nur ein COM-Proxy-Objekt haben. Sie müssen nur wissen, welche Schnittstellen in welche umgewandelt werden sollen. Mit dem dynamischen Schlüsselwort können Sie einen Großteil dieser Cruft reduzieren. Sie wissen, dass die Methode existiert, warum sie in eine Schnittstelle umgewandelt wird? Es ruft nicht genau das DLR auf, sondern generiert nur Code, der weiß, wie man Methoden für COM-Objekte aufruft (in diesem Fall).
justin.m.chase
1
@ justin.m.chase du hast mein Leben gerettet.
Khizar Iqbal
17

Wenn Sie nur Javascript ausführen möchten, ist dies am einfachsten (VB .Net):

MyWebBrowser.Navigate("javascript:function foo(){alert('hello');}foo();")

Ich denke, das würde es nicht "injizieren", aber es wird Ihre Funktion ausführen, wenn Sie danach suchen. (Nur für den Fall, dass Sie das Problem zu kompliziert haben.) Und wenn Sie herausfinden können, wie man Javascript injiziert, fügen Sie dies in den Hauptteil der Funktion "foo" ein und lassen Sie das Javascript die Injektion für Sie durchführen.

Eyal
quelle
10

Der verwaltete Wrapper für das HTML-Dokument implementiert die von Ihnen benötigten Funktionen nicht vollständig. Sie müssen daher in die MSHTML-API eintauchen, um das zu erreichen, was Sie möchten:

1) Fügen Sie einen Verweis auf MSHTML hinzu, der unter COM- Verweisen wahrscheinlich als "Microsoft HTML Object Library" bezeichnet wird .

2) Fügen Sie 'using mshtml;' zu Ihren Namespaces.

3) Holen Sie sich einen Verweis auf das IHTMLElement Ihres Skriptelements:

IHTMLElement iScriptEl = (IHTMLElement)scriptEl.DomElement;

4) Rufen Sie die Methode insertAdjacentText mit dem ersten Parameterwert "afterBegin" auf. Alle möglichen Werte sind hier aufgelistet :

iScriptEl.insertAdjacentText("afterBegin", "function sayHello() { alert('hello') }");

5) Jetzt können Sie den Code in der Eigenschaft scriptEl.InnerText sehen.

Hth, Richard

ZeroBugBounce
quelle
1
Schön ... das zusammen mit den Tipps von korchev funktioniert perfekt. Ich wünschte, ich könnte zwei akzeptierte Lösungen für diese festlegen. :)
jsight
8

Als Folge der akzeptierten Antwort ist dies eine minimale Definition der IHTMLScriptElementSchnittstelle, für die keine zusätzlichen Typbibliotheken erforderlich sind:

[ComImport, ComVisible(true), Guid(@"3050f28b-98b5-11cf-bb82-00aa00bdce0b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
[TypeLibType(TypeLibTypeFlags.FDispatchable)]
public interface IHTMLScriptElement
{
    [DispId(1006)]
    string text { set; [return: MarshalAs(UnmanagedType.BStr)] get; }
}

Ein vollständiger Code in einer vom WebBrowser-Steuerelement abgeleiteten Klasse würde also folgendermaßen aussehen:

protected override void OnDocumentCompleted(
    WebBrowserDocumentCompletedEventArgs e)
{
    base.OnDocumentCompleted(e);

    // Disable text selection.
    var doc = Document;
    if (doc != null)
    {
        var heads = doc.GetElementsByTagName(@"head");
        if (heads.Count > 0)
        {
            var scriptEl = doc.CreateElement(@"script");
            if (scriptEl != null)
            {
                var element = (IHTMLScriptElement)scriptEl.DomElement;
                element.text =
                    @"function disableSelection()
                    { 
                        document.body.onselectstart=function(){ return false; }; 
                        document.body.ondragstart=function() { return false; };
                    }";
                heads[0].AppendChild(scriptEl);
                doc.InvokeScript(@"disableSelection");
            }
        }
    }
}
Uwe Keim
quelle
8

Ich glaube, die einfachste Methode zum Einfügen von Javascript in ein WebBrowser Control-HTML-Dokument aus c # besteht darin, die "execScript" -Methode mit dem als Argument einzufügenden Code aufzurufen.

In diesem Beispiel wird der Javascript-Code im globalen Bereich eingefügt und ausgeführt:

var jsCode="alert('hello world from injected code');";
WebBrowser.Document.InvokeScript("execScript", new Object[] { jsCode, "JavaScript" });

Wenn Sie die Ausführung verzögern möchten, fügen Sie Funktionen ein und rufen Sie sie anschließend auf:

var jsCode="function greet(msg){alert(msg);};";
WebBrowser.Document.InvokeScript("execScript", new Object[] { jsCode, "JavaScript" });
...............
WebBrowser.Document.InvokeScript("greet",new object[] {"hello world"});

Dies gilt für Windows Forms- und WPF-WebBrowser-Steuerelemente.

Diese Lösung ist nicht browserübergreifend, da "execScript" nur in IE und Chrome definiert ist. Die Frage bezieht sich jedoch auf Microsoft WebBrowser-Steuerelemente, und nur der IE wird unterstützt.

Erstellen Sie für eine gültige browserübergreifende Methode zum Einfügen von Javascript-Code ein Funktionsobjekt mit dem neuen Schlüsselwort. In diesem Beispiel wird eine anonyme Funktion mit injiziertem Code erstellt und ausgeführt (Javascript implementiert Schließungen und die Funktion hat Zugriff auf den globalen Raum ohne lokale variable Verschmutzung).

var jsCode="alert('hello world');";
(new Function(code))();

Natürlich können Sie die Ausführung verzögern:

var jsCode="alert('hello world');";
var inserted=new Function(code);
.................
inserted();

Ich hoffe es hilft

Santiago
quelle
7

Dies ist eine Lösung mit mshtml

IHTMLDocument2 doc = new HTMLDocumentClass();
doc.write(new object[] { File.ReadAllText(filePath) });
doc.close();

IHTMLElement head = (IHTMLElement)((IHTMLElementCollection)doc.all.tags("head")).item(null, 0);
IHTMLScriptElement scriptObject = (IHTMLScriptElement)doc.createElement("script");
scriptObject.type = @"text/javascript";
scriptObject.text = @"function btn1_OnClick(str){
    alert('you clicked' + str);
}";
((HTMLHeadElementClass)head).appendChild((IHTMLDOMNode)scriptObject);
Camilo Sanchez
quelle
2
Da dies eine Community-Ressource ist, ist seine Antwort für andere (wie mich) immer noch nützlich. +1 für mshtml-Äquivalent, hat mir eine Frage gespeichert.
Kyeotic
1
Für alle, die dies finden, entfernen Sie 'Klasse' aus der letzten Zeile, sollte lesen, dass ((HTMLHeadElement)head).appendChild((IHTMLDOMNode)scriptObject);Sie sonst Fehler erhalten.
Kyeotic
1
Gibt es überhaupt eine Antwort, die von Admins beworben werden kann? Die darüber liegenden sind in Wirklichkeit alle falsch. Dieser war ein Spätankömmling, ist aber wirklich die richtigste Antwort.
justin.m.chase
2

Ich habe das benutzt: D.

HtmlElement script = this.WebNavegador.Document.CreateElement("SCRIPT");
script.SetAttribute("TEXT", "function GetNameFromBrowser() {" + 
"return 'My name is David';" + 
"}");

this.WebNavegador.Document.Body.AppendChild(script);

Dann können Sie ausführen und das Ergebnis erhalten mit:

string myNameIs = (string)this.WebNavegador.Document.InvokeScript("GetNameFromBrowser");

Ich hoffe hilfreich zu sein

Oscar David Diaz Fortaleché
quelle
2

Hier ist ein VB.Net-Beispiel, wenn Sie versuchen, den Wert einer Variablen innerhalb einer in ein WebBrowser-Steuerelement geladenen Seite abzurufen.

Schritt 1) ​​Fügen Sie der Microsoft HTML Object Library eine COM-Referenz in Ihrem Projekt hinzu

Schritt 2) Fügen Sie als Nächstes diesen VB.Net-Code zu Form1 hinzu, um die mshtml-Bibliothek zu importieren:
Importiert mshtml

Schritt 3) Fügen Sie diesen VB.Net-Code über Ihrer Zeile "Public Class Form1" hinzu:
<System.Runtime.InteropServices.ComVisibleAttribute (True)>

Schritt 4) Fügen Sie Ihrem Projekt ein WebBrowser-Steuerelement hinzu

Schritt 5) Fügen Sie diesen VB.Net-Code zu Ihrer Form1_Load-Funktion hinzu:
WebBrowser1.ObjectForScripting = Me

Schritt 6) Fügen Sie dieses VB.Net-Sub hinzu, das eine Funktion "CallbackGetVar" in das Javascript der Webseite einfügt:

Public Sub InjectCallbackGetVar(ByRef wb As WebBrowser)
    Dim head As HtmlElement
    Dim script As HtmlElement
    Dim domElement As IHTMLScriptElement

    head = wb.Document.GetElementsByTagName("head")(0)
    script = wb.Document.CreateElement("script")
    domElement = script.DomElement
    domElement.type = "text/javascript"
    domElement.text = "function CallbackGetVar(myVar) { window.external.Callback_GetVar(eval(myVar)); }"
    head.AppendChild(script)
End Sub

Schritt 7) Fügen Sie das folgende VB.Net-Sub hinzu, nach dem das Javascript beim Aufrufen sucht:

Public Sub Callback_GetVar(ByVal vVar As String)
    Debug.Print(vVar)
End Sub

Schritt 8) Um den Javascript-Rückruf aufzurufen, fügen Sie diesen VB.Net-Code hinzu, wenn eine Taste gedrückt wird oder wo immer Sie möchten:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    WebBrowser1.Document.InvokeScript("CallbackGetVar", New Object() {"NameOfVarToRetrieve"})
End Sub

Schritt 9) Wenn Sie überrascht sind, dass dies funktioniert, sollten Sie sich über die in Schritt 6 verwendete Javascript-Funktion "eval" informieren, die dies ermöglicht. Es wird eine Zeichenfolge verwendet, um festzustellen, ob eine Variable mit diesem Namen vorhanden ist, und in diesem Fall wird der Wert dieser Variablen zurückgegeben.

sh0ber
quelle
1

Sie können jederzeit eine "DocumentStream" - oder "DocumentText" -Eigenschaft verwenden. Für die Arbeit mit HTML-Dokumenten empfehle ich ein HTML Agility Pack .

TcKs
quelle
Netter Tipp ... Ich bin mir sicher, dass lib irgendwann nützlich sein wird.
jsight
1

ich benutze das:

webBrowser.Document.InvokeScript("execScript", new object[] { "alert(123)", "JavaScript" })
ZRT
quelle
0

Sie möchten Page.RegisterStartupScript (Schlüssel, Skript) verwenden:

Weitere Informationen finden Sie hier: http://msdn.microsoft.com/en-us/library/aa478975.aspx

Grundsätzlich erstellen Sie Ihre Javascript-Zeichenfolge, übergeben sie an diese Methode und geben ihr eine eindeutige ID (falls Sie versuchen, sie zweimal auf einer Seite zu registrieren).

EDIT: Dies ist, was Sie Trigger glücklich nennen. Fühlen Sie sich frei, es zu tun. :) :)

mattlant
quelle
4
ASP.Net hat nicht viel mit der Skripterstellung des WebBrowser-Steuerelements in einer Winforms-App zu tun.
Jsight
Ich hätte wahrscheinlich den gleichen Weg
unterlesen
0

Wenn Sie eine ganze Datei einfügen müssen, können Sie Folgendes verwenden:

With Browser.Document
   Dim Head As HtmlElement = .GetElementsByTagName("head")(0)
   Dim Script As HtmlElement = .CreateElement("script")
   Dim Streamer As New StreamReader(<Here goes path to file as String>)
   Using Streamer
       Script.SetAttribute("text", Streamer.ReadToEnd())
   End Using
   Head.AppendChild(Script)
   .InvokeScript(<Here goes a method name as String and without parentheses>)
End With

Denken Sie daran, zu importieren, System.IOum die zu verwenden StreamReader. Ich hoffe das hilft.

Pablo
quelle
Ich weiß, dass dies vor 3 Tagen vor einem Jahr beantwortet wurde, aber können Sie damit eine Datei in einen input type="file"Abschnitt einfügen?
Chris Hobbs