Search code examples
javascriptvb.netmutation-observers

Using a WebBrowser in .NET, can a mutation observer be used to watch for DIV changes?


I'm using vb.NET but I incorporated a C# example from here using addEventListener and DOMSubtreeModified to watch the entire DOM document:

    Dim script As HtmlElement = Me.Browser.Document.CreateElement("script")
    script.InnerHtml = "function listenToDOM() { document.addEventListener('DOMSubtreeModified', function(e) { window.external.DOMUpdate() }); }"
    Me.Browser.Document.GetElementsByTagName("body")(0).AppendChild(script)
    Me.Browser.Document.InvokeScript("listenToDOM")

...however, I'm trying to sort it out to more specific DIVs. I haven't succeeded on that front yet but the more I read the more it seems I should be using a MutationObserver which I know nothing about, and I especially don't know how to incorporate with a WebBrowser control.

Has anyone managed to do this?

Note: Yes this is WinForms WB and I did already set my BrowserEmulation to IE11 so that shouldn't be a problem.

Update: I attempted an implementation but it's not triggering:

    Dim scriptEl As HtmlElement = Me.Browser.Document.CreateElement("script")
    scriptEl.InnerHtml = "var targetNode = document.querySelector('.div-content');
        
        var Config = {
            attributes: true, 
            childList: true, 
            characterData: true,
            subtree: true
        };

        function (as Observer = new MutationObserver(function (MutationRecords, MutationObserver) { window.external.DivUpdated(); }); 
    
        Observer.observe(targetNode, Config);"

    Me.Browser.Document.GetElementsByTagName("body")(0).AppendChild(scriptEl)

Solution

  • Here's what I came up with. Granted I will develop it more regarding the specific changes that are being caught...

    Private Sub AddScript(Code As String)
    
        Dim script As HtmlElement = Me.Browser.Document.CreateElement("script")
        script.InnerHtml = Code
        Me.Browser.Document.GetElementsByTagName("body")(0).AppendChild(script)
    
    End Sub
    
    Public Sub CreateObserver(theQuery As String)
    
        Dim ScriptEl As String = "var observer = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
                window.external.DIVUpdated(mutation.type);
            });    
        });
    
        //everything
        var observerConfig = {
            attributes: true,
            subtree: true,
            childList: true, 
            characterData: true 
        };
    
        var targetNode = document.querySelector('" & theQuery & "');
        observer.observe(targetNode, observerConfig);"
    
        AddScript(ScriptEl)
    
    End Sub
    

    I have multiple scripts so I made a separate sub for adding each one. And because the DIV isn't loaded right away, I had to append it later (instead of in the DOC loaded event).

    So, from my form I run the CreateObserver('QueryForMyDIVClassOrOtherIdentifier') and the observer triggers my .NET function DIVUpdated() with a mutation.type. In my case I'm looking for characterData changes to the contained text.

    I still should add an observer.disconnect() but honestly it's not really important since in my case I'm looking to watch it for the life of the session. But I'm thinking if I return the observer object with the CreateObserver function, I could hold the variable with my .net as an Object and then use that when I do want to disconnect().