Paulo Barretto
Paulo Barretto

Reputation: 175

Is there an event fired when WebBrowser content is redrawn?

I'm using a WebBrowser control, and at a certain point I update the style of an element with, for instance: WebBrowser1.Document.GetElementById("elementId").Style = "color: red";

The WebBrowser control is automatically redrawn to reflect the changed style, but the DocumentCompleted event does not fire. Is there an event that fires in this case?

Upvotes: 0

Views: 717

Answers (1)

Lukas Körfer
Lukas Körfer

Reputation: 14503

By default, the WinForms WebBrowser control does not provide such an event. But the control is really mighty, so with some tricks you can implement your desired behaviour: You already discovered, that you can access the DOM tree via the Document property, but you can also communicate with scripts running in the WebBrowser via both the ObjectForScripting property and the method Document.InvokeScript. Since 'Vanilla' Javascript can listen to DOM tree changes, you can create a script, which registers for such changes and route them to the application that hosts your WebBrowser control.

The small class below is just an example how this could work, of course you can alter the Javascript listener to receive more specialized events.

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
[ComVisibleAttribute(true)]
public class DOMListener
{
    public event Action DOMChanged;

    private WebBrowser Browser;

    public DOMListener(WebBrowser webbrowser)
    {
        this.Browser = webbrowser;
        this.Browser.ObjectForScripting = this;
        this.Browser.DocumentCompleted += OnDOMLoaded;
    }

    private void OnDOMLoaded(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        HtmlElement script = this.Browser.Document.CreateElement("script");
        script.InnerHtml = "function listenToDOM() { document.addEventListener('DOMSubtreeModified', function(e) { window.external.DOMUpdate() }); }";
        this.Browser.Document.GetElementsByTagName("body")[0].AppendChild(script);
        this.Browser.Document.InvokeScript("listenToDOM");
    }

    public void DOMUpdate()
    {
        if (this.DOMChanged != null) this.DOMChanged.Invoke();
    }
}

Just create an instance of this class with your WebBrowser as argument and you will be able to receive DOM tree changes via the DOMChanged event:

private DOMListener Listener;

public Form1()
{
    this.InitializeComponent();
    this.Listener = new DOMListener(this.WebBrowser);
    this.Listener.DOMChanged += this.OnDOMChanged;
    this.WebBrowser.Navigate("www.google.de");
}

void OnDOMChanged()
{
    Console.WriteLine(DateTime.Now.ToLongTimeString() + ": DOM changed");
}

Upvotes: 2

Related Questions