'WebView2 (2020/06) -> Where's the DOM?
I moved a sort of working Excel VBA app that automated IE as part of a web-scraping and order placing system I wrote for my wife who was spending hours tortured by the 90's style Usborne Children Books Consultant Portal to a C#/Windows Forms/WebView2 project.
Currently, it appears the basics are not there.
For example...
1- if(browser.navigationComplete == true){
That simple check isn't available.
How is one supposed to flow sequences of user actions without this?
2- htmlagilitypack like tools?
In VBA you can easily work with the DOM since there's types for pretty much everything. Where's that in WebView2?
Maybe I got it wrong, but it appears the webview2 is simply a browser with none of the automation tooling VBA has had for over twenty years. Please tell me I do not have to crawl back to my medieval Excel VBA dungeon. I have seen the light and it is good!
Any architectural or actual tested working code would be greatly appreciated :)
thank you kindly from Vancouver,
Antoine
Solution 1:[1]
1. browser.navigationComplete: You should be able to use the WebView2.NavigationCompleted event.
2. htmlagilitypack: While WebView2 doesn't provide direct DOM access, you could get the html as a string and use the htmlagilitypack LoadHtml function. There's also the htmlagilitypack from web functionality, but I'm not sure if that's just using a WebBrowser under the covers.
Solution 2:[2]
Here is an experimental DOM for Webview2: https://github.com/ukandrewc/Webview2.Winforms.DOM
Solution 3:[3]
For those interested I've just released WebView2.DevTools.Dom to NuGet.org. It's free for anyone to use.
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)
- Fully asynchronous
- Supports multiple frames
- Approximately 280
xUnittests - Supports returning of complex types from
JavaScript
More details and examples in the Readme
await webView.EnsureCoreWebView2Async();
// Create one instance per CoreWebView2
// Reuse devToolsContext if possible, dispose (via DisposeAsync) before creating new instance
// Make sure to call DisposeAsync when finished or await using as per this example
// Add using WebView2.DevTools.Dom; to access the CreateDevToolsContextAsync extension method
await using var devToolsContext = await webView2Browser.CoreWebView2.CreateDevToolsContextAsync();
// Get element by Id
// https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
var element = await devtoolsContext.QuerySelectorAsync("#myElementId");
// Get a custom attribute value
var customAttribute = await element.GetAttributeValueAsync<string>("data-customAttribute");
//Set innerText property for the element
await element.SetPropertyValueAsync("innerText", "Welcome!");
//Get innerText property for the element
var 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();
var divElements = await devtoolsContext.QuerySelectorAllAsync("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.SetAttributeValueAsync("data-customAttribute", "123");
await div.SetPropertyValueAsync("innerText", "Updated Div innerText");
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Nic Champagne Williamson |
| Solution 2 | AndrewC |
| Solution 3 | amaitland |
