简体   繁体   中英

How to retrieve the WebBrowser control from the HTMLDocument it contains, in WPF?

My WPF application is creating multiple WebBrowser controls. I know how to manipulate the HtmlDocument within each and also how to handle mouse events on them. However, from within a mouse event which has a IHTMLEventObj2 object as parameter, how can I retrieve the hosting WebBrowse? I can get to the document through the srcElement.document but how do I 'navigate up' to the WebBrowser that is hosting this document? I thought of using a 'Tag' property, but HTMLDocument does not have one. As a last resort, I probably could use a hash table based on the HtmlDocument object, but this is a bit complicated for such a simple thing ...

Where/how do you get your mouse event and srcElement.document ? It seems like javascript.

If true, then I'm pretty sure you can't access the web control from JavaScript, because the web control is not exposed within the DOM tree. You could try to use window.external (or similar) and to expose methods through it, and then have the methods operate on the webbrowser, but that'd be a little convoluted, but I'm sure this way it is possible.

If not true and if you have some mouseevent handler in C#, then simply link the handler with the webbrowser before the event is invoked. Instead of:

// inside your Window/etc:

private int otherData;
private void MyHandler(...args) {
    if(otherData > 5)
        browser.Navigate("foobar.html");
}

WebBrowser wb = ...;
wb.themouseevent += myhandler; // equivalent to wb.themouseevent += this.myhandler;

use closures or custom objects to expose a handler from an object that will "know" the browser beforewards:

// inside or outside your Window/etc:
class MyHandlersWithSomeData
{
    public WebBrowser browser;
    public string someContextuaData;
    public int otherData;
    ....

    public void MyHandler(...args) {
        if(otherData > 5)
            browser.Navigate("foobar.html");
    }
}

// inside your Window/etc:
WebBrowser wb = ...;
var smartHandler = new MyHandlersWithSomeData{ browser = wb, otherData = 10 };
wb.themouseevent += smartHandler.MyHandler; // note that handler is not from "this" anymore

edit: As you asked, a "simpler" approach would be to use lambdas and closures:

// inside your Window/etc:

private int otherData;
private void JustAMethodNotAHandler(WebBrowser browser, object sender, EventArgs args) {
    if(otherData > 5)
        browser.Navigate("foobar.html");
}

WebBrowser wb = ...;
wb.themouseevent += (sender, args) => JustAMethodNotAHandler(wb, sender, args);

However there is no magic. Under the hood, it does it almost exactly as the example above with an extra class, so called "closure". This class will store the reference to WebBrowser wb local variable and only thanks to that, when JustAMethodNotAHandler is later called, the wb is still available and passable to that method.

However, since we are now using lambdas ( (blah)=>blah syntax) to quickly create the delegate, you must notice two very important things:

  • JustAMethodNotAHandler is not the handler , it is just a method. The anonymous function created by the lambda will be the actual handler
  • since the anonymous function is, well, anonymous, you will have a hard time if you ever want to unregister it later. Attempts like:

    wb.themouseevent -= (sender, args) => JustAMethodNotAHandler(wb, sender, args);

will not work since each time that line is executed, a new handler is created, totally not equal to the one created with +=

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM