Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow easy access to DOM/HTML #77

Open
ukandrewc opened this issue Nov 21, 2019 · 11 comments
Open

Allow easy access to DOM/HTML #77

ukandrewc opened this issue Nov 21, 2019 · 11 comments
Labels
feature request feature request tracked We are tracking this work internally.

Comments

@ukandrewc
Copy link

ukandrewc commented Nov 21, 2019

I've just started writing one to compliment this implementation: https://github.com/michael-russin/webview2-control

But wondering if it's worth waiting if you have plans for one.
Thanks

AB#28556146

@david-risney
Copy link
Contributor

Hey I just saw your projects on nuget yesterday but haven't had a chance to look into them yet. Thanks for trying it out! Did you run into any interesting issues etc?

We are planning on producing a WPF & WinForms controls sometime by the first half of next year with a dev preview earlier than that.

@ukandrewc
Copy link
Author

Just to clarify, they aren't my projects ;-)
Sorry, but my question is: do you plan to have DOM classes that are accessible from .Net?
Thanks

@david-risney
Copy link
Contributor

Oh I see. If I understand what you're planning, no. Similar to the EdgeHtml WebView (and unlike the mshtml WebView/WebControl), we don't plan to expose the DOM via our API and instead it should be accessed via script.

@ukandrewc
Copy link
Author

Thanks David, for clarifying.
Ideally we'd like to see access similar to mshtml, but I'm sure we'll create our own, or cope with JS ;-)
Andrew

@ukandrewc
Copy link
Author

I'm really keen to see the Winforms control, as early as possible.
Our application is built on the mshtml control, which needed replacing a year ago ;-)
I need to create a .Net wrapper around the DOM, so would like to get started on that ASAP.
If there's anything that can be done to start work sooner, that would be great.
Thanks very much
Andrew

@kfke
Copy link

kfke commented May 21, 2021

Hi All,

Also, our win32 c++ application uses the mshtml (WebBrowser control) many times, and we want to replace them with the new webview2, but need a way to access DOM/HTML directly, is there any news about this?

Thanks

@Roadrunner67
Copy link

I have a scenario resembling that of @jbennink in issue #1058
It seems pretty obvious that this is a must and a showstopper for a lot of migrations from webview to webview2.
This issue has my upvote.

@jbennink
Copy link

Any news about DOM access in WebView2? It's been more than 1.5 years since this issue was opened and a lot of similar issues have been grouped together in this issue. but no new information.
Looking at the huge number of requests for this feature it should be obsious this has to be a part of the WebView2 control.

Please can we get an updated status on this!

@amaitland
Copy link

amaitland commented Mar 21, 2022

For those interested I've just released WebView2.DevTools.Dom to NuGet.org. The project has a public GitHub Page

Unlike some of the other packages currently available it's Chrome DevTools Protocol based framework for JavaScript execution, DOM access/manipulation and automation. Requires .Net 4.6.2 or .Net Core 3.1 or greater

  • Direct connection to browser via Microsoft.Web.WebView2.DevToolsProtocolExtension (doesn't open a remote debugging port).
  • QuerySelector and QuerySelectorAll support
  • Can be used for automation, supports emulating keyboard and mouse events (like puppeteer)
  • Emulate Keyboard/Mouse
  • Fully asynchronous
  • Supports multiple frames
  • Approximately 280 xUnit tests
  • Supports returning of complex types from JavaScript

More details and examples in the Readme

 await webView.EnsureCoreWebView2Async();
 
 // WebView2DevToolsContext implements IAsyncDisposable and can be Disposed
// via await using or await devToolsContext.DisposeAsync();
// https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#using-async-disposable
await using var devToolsContext = await coreWebView2.CreateDevToolsContextAsync();

// Get element by Id
// https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
var element = await devToolsContext.QuerySelectorAsync("#myElementId");

//Strongly typed element types
//Only a subset of element types have been added so far, use HtmlElement as a generic type for all others
var htmlDivElement = await devToolsContext.QuerySelectorAsync<HtmlDivElement>("#myDivElementId");
var htmlSpanElement = await devToolsContext.QuerySelectorAsync<HtmlSpanElement>("#mySpanElementId");
var htmlSelectElement = await devToolsContext.QuerySelectorAsync<HtmlSelectElement>("#mySelectElementId");
var htmlInputElement = await devToolsContext.QuerySelectorAsync<HtmlInputElement>("#myInputElementId");
var htmlFormElement = await devToolsContext.QuerySelectorAsync<HtmlFormElement>("#myFormElementId");
var htmlAnchorElement = await devToolsContext.QuerySelectorAsync<HtmlAnchorElement>("#myAnchorElementId");
var htmlImageElement = await devToolsContext.QuerySelectorAsync<HtmlImageElement>("#myImageElementId");
var htmlTextAreaElement = await devToolsContext.QuerySelectorAsync<HtmlImageElement>("#myTextAreaElementId");
var htmlButtonElement = await devToolsContext.QuerySelectorAsync<HtmlButtonElement>("#myButtonElementId");
var htmlParagraphElement = await devToolsContext.QuerySelectorAsync<HtmlParagraphElement>("#myParagraphElementId");
var htmlTableElement = await devToolsContext.QuerySelectorAsync<HtmlTableElement>("#myTableElementId");

// Get a custom attribute value
var customAttribute = await element.GetAttributeAsync<string>("data-customAttribute");

//Set innerText property for the element
await element.SetPropertyValueAsync("innerText", "Welcome!");

await element.SetInnerTextAsync("Welcome 2!");

//Get innerText property for the element
var innerText = await element.GetInnerTextAsync();
//Can also be acessed via calling GetPropertyValueAsync
//Can use this method to get any property that isn't currently mapped
innerText = await element.GetPropertyValueAsync<string>("innerText");

//Get all child elements
var childElements = await element.QuerySelectorAllAsync("div");

//Change CSS style background colour
_ = await element.EvaluateFunctionAsync("e => e.style.backgroundColor = 'yellow'");

//Type text in an input field
await element.TypeAsync("Welcome to my Website!");

//Scroll Element into View (if needed)
//Can optional specify a Rect to be scrolled into view, relative to the node's border box,
//in CSS pixels. When omitted, center of the node will be used
await element.ScrollIntoViewIfNeededAsync();

//Click The element
await element.ClickAsync();

//Event Handler
//Expose a function to javascript, functions persist across navigations
//So only need to do this once
await devToolsContext.ExposeFunctionAsync("jsAlertButtonClick", () =>
{
	_ = devToolsContext.EvaluateExpressionAsync("window.alert('Hello! You invoked window.alert()');");
});

var jsAlertButton = await devToolsContext.QuerySelectorAsync("#jsAlertButton");

//Write up the click event listner to call our exposed function
_ = jsAlertButton.AddEventListenerAsync("click", "jsAlertButtonClick");

        //Get a collection of HtmlElements
        var divElements = await devToolsContext.QuerySelectorAllAsync<HtmlDivElement>("div");

        foreach (var div in divElements)
        {
            // Get a reference to the CSSStyleDeclaration
            var style = await div.GetStyleAsync();

            //Set the border to 1px solid red
            await style.SetPropertyAsync("border", "1px solid red", important: true);

            await div.SetAttributeAsync("data-customAttribute", "123");
            await div.SetInnerTextAsync("Updated Div innerText");
        }

        //Using standard array
        var tableRows = await htmlTableElement.GetRowsAsync().ToArrayAsync();

        foreach(var row in tableRows)
        {
            var cells = await row.GetCellsAsync().ToArrayAsync();
            foreach(var cell in cells)
            {
                var newDiv = await devToolsContext.CreateHtmlElementAsync<HtmlDivElement>("div");
                await newDiv.SetInnerTextAsync("New Div Added!");
                await cell.AppendChildAsync(newDiv);
            }
        }

        //Get a reference to the HtmlCollection and use async enumerable
        //Requires Net Core 3.1 or higher
        var tableRowsHtmlCollection = await htmlTableElement.GetRowsAsync();

        await foreach (var row in tableRowsHtmlCollection)
        {
            var cells = await row.GetCellsAsync();
            await foreach (var cell in cells)
            {
                var newDiv = await devToolsContext.CreateHtmlElementAsync<HtmlDivElement>("div");
                await newDiv.SetInnerTextAsync("New Div Added!");
                await cell.AppendChildAsync(newDiv);
            }
        }

@amaitland
Copy link

For those interested I've just released WebView2.DevTools.Dom to NuGet.org

Unlike some of the other packages currently available it's Chrome DevTools Protocol based framework for JavaScript execution, DOM access/manipulation and automation. Requires .Net 4.6.2 or .Net Core 3.1 or greater

Just as a follow up I'm working on a guide Porting from the IE WebBrowser control, I'm looking for ~3 people to provide real world samples that they'd be interested in porting over. I'll provide a port of those examples that can be used as a reference for everyone.

I'll also be offering paid consultancy services for those that need/require more than just a guide.

@weitzhandler
Copy link

Are there any plans to adopt this functionality and make it part of the WV2?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request feature request tracked We are tracking this work internally.
Projects
None yet
Development

No branches or pull requests

8 participants