Як вводити Javascript в елемент керування WebBrowser?


81

Я спробував це:

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 і scriptEl.InnerText видають помилки:

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)

Чи є простий спосіб ввести скрипт у дім?

Відповіді:


101

З якоїсь причини рішення Річарда не спрацювало з мого боку (insertAdjacentText не вдалося за винятком). Однак, схоже, це працює:

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

Ця відповідь пояснює, як додати IHTMLScriptElementінтерфейс до вашого проекту.


1
Класно, я думаю, що використання IHTMLScriptElement у будь-якому випадку робить намір коду більш очевидним. Мені цікаво, чому ви отримали виняток, але іноді це найкраще з COM-взаємодією.
ZeroBugBounce

А як щодо додавання посилання на локальний файл js? Будь ласка, див. Stackoverflow.com/questions/4029602/…
IAmAN00B

Будь ласка, допоможіть мені в цьому. Як ти це зробив. Я хочу ввести JS на мою сторінку в режимі реального часу через мою програму C ++. Як мені це робити.
Johnydep

це застосовне і до введення файлу jquery?
gumuruh

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

(протестовано в .NET 4 / Windows Forms App)

Редагувати: Виправлена ​​проблема з регістром у наборі функцій.


12
Я оцінив це рішення, оскільки воно не покладається на (хоч і корисно!) Збірку IHTMLSCriptElement.
Micah Smith

6
@jsight Це має бути прийнятою відповіддю. Це те саме, що і поточна відповідь, але простіше і без IHTMLSCriptElementзалежності.
BlueRaja - Danny Pflughoeft

32

Ось найпростіший спосіб, який я знайшов після роботи над цим:

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

Те, що робить глобальна функція JavaScript eval(str), - це синтаксичний аналіз та виконання того, що написано в str. Перевірте посилання w3schools тут .


22

Крім того, у .NET 4 це ще простіше, якщо ви використовуєте динамічне ключове слово:

dynamic document = this.browser.Document;
dynamic head = document.GetElementsByTagName("head")[0];
dynamic scriptEl = document.CreateElement("script");
scriptEl.text = ...;
head.AppendChild(scriptEl);

2
Навіщо комусь для цього потрібна динаміка? Якщо ви намагаєтеся зберегти певний текст, ми маємо умовивід типу, оскільки C # 3.0, тому var буде прийнятним. Немає необхідності починати виклик DLR.
алімбада

23
Це в основному саме суть динамічного ключового слова: взаємодія COM. Ви насправді тут не маєте виводу типу, у вас є документація. Оскільки IHTMLElement2 не можна призначити з IHtmlElement, наприклад, і під час виконання у вас просто є COM-об'єкт проксі-сервера. Ви просто повинні знати, які інтерфейси в які вкласти. Динамічне ключове слово допомагає скоротити велику кількість цієї сутності. Ви знаєте, метод існує, навіщо вкидати його в якийсь інтерфейс? Він точно не `` викликає DLR '', він просто генерує код, який знає, як викликати метод на COM-об'єктах (у цьому випадку).
justin.m., покупка

1
@ justin.m.chase ти врятував мені життя.
Хізар Ікбал

17

Якщо все, що ви дійсно хочете, це запустити javascript, це було б найпростіше (VB .Net):

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

Я припускаю, що це не "введе" його, але воно запустить вашу функцію, якщо це те, що ви шукаєте. (Про всяк випадок, якщо ви занадто ускладнили проблему.) І якщо ви зможете зрозуміти, як вводити в javascript, помістіть це в тіло функції "foo" і дозвольте javascript зробити ін'єкцію за вас.


10

Керована обгортка для документа HTML не реалізує повністю необхідну вам функціональність, тому вам потрібно зануритися в API MSHTML, щоб виконати те, що ви хочете:

1) Додайте посилання на MSHTML, яке буде називатися "бібліотека об'єктів Microsoft HTML" під посиланнями COM .

2) Додайте 'using mshtml;' до ваших просторів імен.

3) Отримайте посилання на елемент IHTMLElement вашого сценарію:

IHTMLElement iScriptEl = (IHTMLElement)scriptEl.DomElement;

4) Викличте метод insertAdjacentText із першим значенням параметра "afterBegin". Усі можливі значення перелічені тут :

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

5) Тепер ви зможете побачити код у властивості scriptEl.InnerText.

Hth, Річард


1
Приємно ... це разом із порадами Корчева працює чудово. Я би хотів, щоб я міг встановити два прийнятих рішення щодо цього. :)
jsight

8

Як продовження прийнятої відповіді , це мінімальне визначення IHTMLScriptElementінтерфейсу, яке не вимагає включення додаткових бібліотек типів:

[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; }
}

Отже, повний код всередині похідного класу управління WebBrowser виглядатиме так:

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

8

Я вважаю, що найпростішим методом введення Javascript у HTML-документ WebBrowser Control із c # є виклик методу "execScript" із кодом, який буде введено як аргумент.

У цьому прикладі код javascript вводиться і виконується в глобальному масштабі:

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

Якщо ви хочете затримати виконання, вводьте функції та викликайте їх після:

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

Це справедливо для елементів керування Windows Forms та WPF WebBrowser.

Це рішення не є крос-браузерним, оскільки "execScript" визначається лише в IE та Chrome. Але питання полягає в елементах керування Microsoft WebBrowser, і IE підтримується єдиним.

Щоб дійсний метод перехресного браузера вводив код JavaScript, створіть об’єкт Функції з новим ключовим словом. Цей приклад створює анонімну функцію з введеним кодом і виконує її (javascript реалізує закриття, і функція має доступ до глобального простору без локального змінного забруднення).

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

Звичайно, ви можете затримати виконання:

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

Сподіваюся, це допоможе


7

це рішення за допомогою 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);

2
Оскільки це ресурс спільноти, його відповідь все ще корисна іншим (як і мені). +1 за еквівалент mshtml, врятував мені запитання.
Kyeotic

1
Для кожного, хто знайде це, видаліть 'class' з останнього рядка ((HTMLHeadElement)head).appendChild((IHTMLDOMNode)scriptObject);.
Kyeotic

1
Чи є така відповідь, яку можуть отримати адміністратори? Наведені вище всі насправді помиляються. Цей запізнився, але насправді це найбільш правильна відповідь.
justin.m., покупка

2

Я використовував це: D

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

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

Тоді ви можете виконати і отримати результат за допомогою:

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

Я сподіваюся бути корисним


2

Ось приклад VB.Net, якщо ви намагаєтеся отримати значення змінної всередині сторінки, завантаженої в елемент керування WebBrowser.

Крок 1) Додайте посилання на COM у своєму проекті до бібліотеки об’єктів Microsoft HTML

Крок 2) Далі, додайте цей код VB.Net до свого Form1, щоб імпортувати бібліотеку mshtml:
Імпортує mshtml

Крок 3) Додайте цей код VB.Net над рядком "Public Class Form1":
<System.Runtime.InteropServices.ComVisibleAttribute (True)>

Крок 4) Додайте елемент керування WebBrowser до свого проекту

Крок 5) Додайте цей код VB.Net до своєї функції Form1_Load:
WebBrowser1.ObjectForScripting = Me

Крок 6) Додайте цей підпункт VB.Net, який додасть функцію "CallbackGetVar" до Javascript веб-сторінки:

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

Крок 7) Додайте таку підгрупу VB.Net, яку потім буде шукати Javascript при виклику:

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

Крок 8) Нарешті, щоб викликати зворотний виклик Javascript, додайте цей код VB.Net при натисканні кнопки або де завгодно:

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

Крок 9) Якщо вас здивує, що це працює, можливо, ви захочете прочитати функцію Javascript "eval", використовувану в кроці 6, яка саме це робить можливим. Він візьме рядок і визначить, чи існує змінна з цим ім’ям, і, якщо так, повертає значення цієї змінної.


1

Ви завжди можете використовувати властивість "DocumentStream" або "DocumentText". Для роботи з документами HTML я рекомендую HTML Agility Pack .


Приємна порада ... Я впевнений, що lib колись стане в нагоді.
jsight

1

я використовую це:

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

0

Що ви хочете зробити, це використовувати Page.RegisterStartupScript (ключ, сценарій):

Детальніше див. Тут: http://msdn.microsoft.com/en-us/library/aa478975.aspx

По суті, ви створюєте свій рядок javascript, передаєте його цьому методу та надаєте йому унікальний ідентифікатор (у випадку, якщо ви спробуєте зареєструвати його двічі на сторінці)

EDIT: Це те, що ви називаєте тригером щасливим. Не соромтеся це робити. :)


4
ASP.Net не має багато спільного з сценарієм елемента керування WebBrowser у додатку winforms.
jsight

Я, мабуть, прочитав би так само і дав ту саму неправильну відповідь
Grank

0

Якщо вам потрібно ввести цілий файл, ви можете використовувати це:

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

Не забудьте імпортувати System.IO, щоб використовувати StreamReader. Сподіваюся, це допоможе.


Я знаю, що на це було відповідено за 3 дні до року тому, але чи зможете ви використати це для розміщення файлу в input type="file"розділі?
Кріс Хоббс,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.