Làm thế nào để đưa Javascript vào kiểm soát WebBrowser?


81

Tôi đã thử cái này:

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 và scriptEl.InnerText đều mắc lỗi:

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)

Có cách nào dễ dàng để đưa một tập lệnh vào dom không?

Câu trả lời:


101

Vì một số lý do mà giải pháp của Richard không hoạt động với tôi (insertAdjacentText không thành công với một ngoại lệ). Tuy nhiên, điều này dường như hoạt động:

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

Câu trả lời này giải thích cách đưa IHTMLScriptElementgiao diện vào dự án của bạn.


1
Thật tuyệt, tôi nghĩ việc sử dụng IHTMLScriptElement làm cho ý định mã rõ ràng hơn trong mọi trường hợp. Tôi tự hỏi tại sao bạn lại có một ngoại lệ, nhưng đôi khi tôi thấy tốt nhất với COM interop.
ZeroBugBounce 30/09/08

Điều gì về việc thêm một tham chiếu đến một tệp js cục bộ? Vui lòng xem stackoverflow.com/questions/4029602/…
IAmAN00B

Xin hãy giúp tôi với. Làm thế nào bạn làm điều này. Tôi muốn đưa JS vào trang của mình trong thời gian thực thông qua ứng dụng C ++. Làm thế nào tôi nên đi về nó.
Johnydep

Điều này cũng áp dụng cho việc tiêm tệp 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");

(được thử nghiệm trong .NET 4 / Ứng dụng Windows Forms)

Chỉnh sửa: Đã khắc phục sự cố trường hợp trong bộ chức năng.


12
Tôi đánh giá cao giải pháp này vì nó không dựa vào hội IHTMLSCriptElement (mặc dù hữu ích!).
Micah Smith

6
@jsight Đây phải là câu trả lời được chấp nhận. Nó giống như câu trả lời hiện tại, nhưng đơn giản hơn và không có sự IHTMLSCriptElementphụ thuộc.
BlueRaja - Danny Pflughoeft 12/1213

32

Đây là cách dễ nhất mà tôi tìm thấy sau khi làm việc này:

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

Hàm global JavaScript eval(str)làm gì là phân tích cú pháp và thực thi bất cứ thứ gì được viết trong str. Kiểm tra giới thiệu w3schools tại đây .


22

Ngoài ra, trong .NET 4, điều này thậm chí còn dễ dàng hơn nếu bạn sử dụng từ khóa động:

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

2
Tại sao mọi người cần năng động cho điều đó? Nếu bạn đang cố gắng lưu một số lần nhập, chúng tôi có suy luận kiểu kể từ C # 3.0 nên var sẽ được chấp nhận. Không cần phải bắt đầu gọi DLR.
alimbada

23
Về cơ bản, đây chính xác là điểm của từ khóa động: COM interop. Bạn thực sự không có Suy luận kiểu ở đây, bạn có tài liệu. Vì ví dụ như IHTMLElement2 không thể gán được từ IHtmlElement và trong thời gian chạy, bạn chỉ có một đối tượng proxy COM. Bạn chỉ cần biết giao diện nào để truyền vào cái gì. Từ khóa động giúp bạn cắt giảm rất nhiều điểm mấu chốt đó. Bạn biết phương thức tồn tại tại sao lại truyền nó vào một số giao diện? Nó không chính xác 'gọi DLR' mà chỉ tạo ra mã biết cách gọi phương thức trên các đối tượng COM (trong trường hợp này).
justin.m.chase

1
@ justin.m.chase bạn đã cứu mạng tôi.
Khizar Iqbal

17

Nếu tất cả những gì bạn thực sự muốn là chạy javascript, điều này sẽ dễ dàng nhất (VB .Net):

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

Tôi đoán rằng điều này sẽ không "tiêm" nó nhưng nó sẽ chạy chức năng của bạn, nếu đó là những gì bạn đang theo đuổi. (Đề phòng trường hợp bạn làm vấn đề quá phức tạp.) Và nếu bạn có thể tìm ra cách đưa vào javascript, hãy đặt nó vào phần thân của hàm "foo" và để javascript thực hiện việc tiêm cho bạn.


10

Trình bao bọc được quản lý cho tài liệu HTML không hoàn toàn triển khai chức năng bạn cần, vì vậy bạn cần phải nhúng vào API MSHTML để thực hiện những gì bạn muốn:

1) Thêm một tham chiếu đến MSHTML, sẽ được gọi là "Thư viện đối tượng HTML của Microsoft" trong tham chiếu COM .

2) Thêm 'using mshtml;' vào không gian tên của bạn.

3) Nhận tham chiếu đến IHTMLElement của phần tử tập lệnh của bạn:

IHTMLElement iScriptEl = (IHTMLElement)scriptEl.DomElement;

4) Gọi phương thức insertAdjacentText, với giá trị tham số đầu tiên là "afterBegin". Tất cả các giá trị có thể được liệt kê ở đây :

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

5) Bây giờ bạn sẽ có thể thấy mã trong thuộc tính scriptEl.InnerText.

Hth, Richard


1
Tuyệt vời ... điều này cùng với các mẹo do korchev cung cấp hoạt động hoàn hảo. Tôi ước tôi có thể đặt hai giải pháp được chấp nhận trên một giải pháp này. :)
jsight 30/09/08

8

Như một phần tiếp theo cho câu trả lời được chấp nhận , đây là một định nghĩa tối thiểu về IHTMLScriptElementgiao diện không yêu cầu bao gồm các thư viện loại bổ sung:

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

Vì vậy, một mã đầy đủ bên trong một lớp dẫn xuất điều khiển WebBrowser sẽ giống như sau:

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

Tôi tin rằng phương pháp đơn giản nhất để đưa Javascript vào Tài liệu HTML điều khiển WebBrowser từ c # là gọi phương thức "executeScript" với mã được đưa vào làm đối số.

Trong ví dụ này, mã javascript được đưa vào và thực thi ở phạm vi toàn cầu:

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

Nếu bạn muốn trì hoãn việc thực thi, hãy chèn các hàm và gọi chúng sau:

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

Điều này hợp lệ cho các điều khiển Windows Forms và WPF WebBrowser.

Giải pháp này không phải là trình duyệt chéo vì "executeScript" chỉ được định nghĩa trong IE và Chrome. Nhưng câu hỏi là về các điều khiển WebBrowser của Microsoft và IE là công cụ duy nhất được hỗ trợ.

Đối với một phương pháp trình duyệt chéo hợp lệ để chèn mã javascript, hãy tạo một đối tượng Hàm với Từ khóa mới. Ví dụ này tạo một hàm ẩn danh với mã được chèn vào và thực thi nó (javascript thực hiện các bao đóng và hàm có quyền truy cập vào không gian chung mà không bị ô nhiễm biến cục bộ).

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

Tất nhiên, bạn có thể trì hoãn việc thực thi:

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

Hy vọng nó giúp


7

đây là một giải pháp sử dụng 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
Vì đây là tài nguyên cộng đồng nên câu trả lời của anh ấy vẫn hữu ích cho những người khác (như bản thân tôi). +1 cho mshtml tương đương, đã lưu cho tôi một câu hỏi.
Kyeotic

1
Đối với bất kỳ ai tìm thấy điều này, hãy xóa 'lớp' khỏi dòng cuối cùng, nếu đọc, ((HTMLHeadElement)head).appendChild((IHTMLDOMNode)scriptObject);bạn sẽ gặp lỗi nếu không.
Kyeotic

1
Liệu câu trả lời này có thể được quảng bá bởi quản trị viên không? Những điều trên đây đều sai trong thực tế. Đây là một người đến muộn nhưng thực sự là câu trả lời chính xác nhất.
justin.m.chase

2

Tôi đã sử dụng cái này: D

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

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

Sau đó, bạn có thể thực thi và nhận kết quả với:

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

Tôi hy vọng sẽ hữu ích


2

Đây là một ví dụ VB.Net nếu bạn đang cố gắng truy xuất giá trị của một biến từ bên trong một trang được tải trong điều khiển WebBrowser.

Bước 1) Thêm tham chiếu COM trong dự án của bạn vào Thư viện đối tượng HTML của Microsoft

Bước 2) Tiếp theo, thêm mã VB.Net này vào Form1 của bạn để nhập thư viện mshtml:
Nhập mshtml

Bước 3) Thêm mã VB.Net này phía trên dòng "Public Class Form1" của bạn:
<System.Runtime.InteropServices.ComVosystemAttribute (True)>

Bước 4) Thêm điều khiển WebBrowser vào dự án của bạn

Bước 5) Thêm mã VB.Net này vào chức năng Form1_Load của bạn:
WebBrowser1.ObjectForScripting = Me

Bước 6) Thêm phụ VB.Net này sẽ đưa một hàm "CallbackGetVar" vào Javascript của trang web:

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

Bước 7) Thêm VB.Net con sau mà Javascript sẽ tìm kiếm khi được gọi:

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

Bước 8) Cuối cùng, để gọi lệnh gọi lại Javascript, hãy thêm mã VB.Net này khi một nút được nhấn hoặc bất cứ nơi nào bạn muốn:

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

Bước 9) Nếu làm bạn ngạc nhiên rằng điều này hoạt động, bạn có thể muốn đọc hàm "eval" của Javascript, được sử dụng trong Bước 6, đó là điều làm cho điều này có thể thực hiện được. Nó sẽ lấy một chuỗi và xác định xem một biến có tồn tại với tên đó hay không và nếu có, trả về giá trị của biến đó.


1

Bạn luôn có thể sử dụng thuộc tính "DocumentStream" hoặc "DocumentText". Để làm việc với các tài liệu HTML, tôi khuyên bạn nên dùng Gói HTML nhanh nhẹn .


Mẹo hay ... Tôi chắc chắn rằng lib sẽ có ích vào một lúc nào đó.
jsight 30/09/08

1

tôi sử dụng cái này:

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

0

Những gì bạn muốn làm là sử dụng Page.RegisterStartupScript (key, script):

Xem tại đây để biết thêm chi tiết: http://msdn.microsoft.com/en-us/library/aa478975.aspx

Về cơ bản, những gì bạn làm là xây dựng chuỗi javascript của mình, chuyển nó vào phương thức đó và cấp cho nó một id duy nhất (trong trường hợp bạn cố gắng đăng ký nó hai lần trên một trang.)

CHỈNH SỬA: Đây là những gì bạn gọi là kích hoạt hạnh phúc. Hãy hạ nó xuống. :)


4
ASP.Net không liên quan nhiều đến kịch bản điều khiển WebBrowser trong ứng dụng winforms.
jsight 30/09/08

Tôi có lẽ sẽ đọc thiếu theo cùng một cách và đưa ra cùng một câu trả lời không chính xác
Grank 30/09/08

0

Nếu bạn cần chèn toàn bộ tệp thì bạn có thể sử dụng cái này:

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

Hãy nhớ nhập khẩu System.IOđể sử dụng StreamReader. Tôi hi vọng cái này giúp được.


Tôi biết điều này đã được trả lời 3 ngày trước một năm, nhưng liệu bạn có thể sử dụng điều này để đưa một tệp vào một input type="file"phần không?
Chris Hobbs
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.