1

I'm working on trying to write an c# program that will click a button on a webpage automatically. I know I could use a chrome driver, but I don't want this to turn into a browser and version specific application.

This is what I came up with so far, but I'm having some difficulty determining how to be able to trigger that button to be clicked once I have found the correct button.

    WebView webView = new WebView();
    var func = string.Format(@"document.getElementsByClassName('size-grid-button').innerText = '{0}';", size);            
    await webView.InvokeScriptAsync("eval", new string[] { func });

EDIT This is what I'm basing my project off currently, but I can't find a button based on innerText and then simulate button click.

1 Answers1

2

Here's a complete code example using NuGet package Microsoft.Web.WebView2 (v. 1.0.721-prerelease). See the Webview2 Release Notes for requirements.

Resources:

Note: This example will be using WinForms--Windows Forms App (.NET Framework). When using .NET Framework, versions >= 4.6.2 are supported (previously version 4.6.2 or greater was required. However, if one looks at the NuGet package folders, it appears that the required minimum version may now be 4.5. See the release notes for more information). See the documentation for other supported SDKs.

Visual Studio versions 2017 and 2019 are supported. If you don't have either, you may be able to Download Visual Studio Community -- which is free.

Download and install Microsoft Edge Dev (aka "Dev Channel"): Microsoft Edge Insider Channels -- see documentation for other options.

Open Visual Studio - (2017 or 2019)

Set Default package management format to PackageReference (this is optional, but recommended). See Migrate from packages.config to PackageReference for more information.

2019:

  • Click Continue without code
  • In Visual Studio (VS) menu, click Tools
  • Select Options
  • Expand NuGet Package Manager
  • Click General
  • Under Package Management, set Default package management format: to PackageReference

2017:

  • In Visual Studio (VS) menu, click Tools
  • Select Options
  • Expand NuGet Package Manager
  • Click General
  • Under Package Management, set Default package management format: to PackageReference

Create New Project

2019:

  • In VS menu, click File
  • Select New
  • Select Project
  • Optional: Use the following options to limit displayed selections: C# Windows Desktop
  • Click Windows Forms App (.NET Framework)
  • Click Next
  • Enter a name for you project (ex: WebView2Test), select desired location, and set Framework to a version >= 4.6.2
  • Click Create

2017:

  • In VS menu, click File
  • Select New
  • Select Project
  • Expand Visual C#
  • Click Windows Desktop
  • Click Windows Forms App (.NET Framework)
  • Enter a name for you project (ex: WebView2Test), select desired location, and set Framework to a version >= 4.6.2
  • Click OK

Add Microsoft.Web.WebView2 NuGet package to project (2019/2017)

  • In VS menu, click View
  • Select Solution Explorer
  • In Solution Explorer, right-click <project name>
  • Select Manage NuGet Packages...
  • Click Browse
  • Check Include prerelease
  • Search: Microsoft.Web.WebView2
  • Select Version 1.0.721-prerelease
  • Set any desired options by clicking the down-arrow next to the left of "Options" to show the available options (ie: Install and Update options and Uninstall options)
  • Click Install
  • If a window pops up, click OK

Optional: Add MenuStrip to Form (Form1)

  • In Solution Explorer, click Form1.cs to select it
  • In VS menu, click View
  • Select Toolbox
  • Expand All Windows Forms
  • Select MenuStrip
  • Click on Form (Form1) to add the control to the Form

Optional: Add StatusStrip to Form (Form1)

  • In Solution Explorer, click Form1.cs to select it
  • In VS menu, click View
  • Select Toolbox
  • Expand All Windows Forms
  • Select StatusStrip
  • Click on Form (Form1) to add the control to the Form

Add SplitContainer to Form (Form1)

  • In Solution Explorer, click Form1.cs to select it
  • In VS menu, click View
  • Select Toolbox
  • Expand All Windows Forms
  • Select SplitContainer
  • Click on Form (Form1) to add the control to the Form

Add button to left panel of SplitContainer (splitContainer1)

  • In Solution Explorer, click Form1.cs to select it
  • In VS menu, click View
  • Select Toolbox
  • Expand All Windows Forms
  • Select Button
  • Click on Form (Form1) to add the control to the Form. If necessary, move the button to the left panel (panel1) of the SplitContainer.

Change button properties

  • In VS menu, click View
  • Select Properties Window
  • In Properties Window, use the drop-down to select the button (button1)
  • Change (Name) to the desired name (ex: btnClickJSButton)
  • Change text to desired text (ex: Click JS Button)

Add WebView2 control to SplitContainer (panel2)

  • In Solution Explorer, click Form1.cs to select it
  • In VS menu, click View
  • Select Toolbox
  • Expand WebView2 Windows Forms Control

Note: If "WebView2 Windows Forms Control" isn't in the Toolbox, right-click in an open space in the Toolbox, and select "Choose Items". Then click "Browse". Go to %UserProfile%.nuget\packages\microsoft.web.webview2\1.0.721-prerelease\lib\net45 (ex: C:\Users\<username>\.nuget\packages\microsoft.web.webview2\1.0.721-prerelease\lib\net45). Choose "Microsoft.Web.WebView2.WinForms.dll"

  • Select WebView2
  • Click on Form (Form1) to add the control to the Form. If necessary, move the WebView2 control to the right panel (panel2) of the SplitContainer.

Change WebView2 properties

  • In Properties Window, use the drop-down to select the WebView2 control instance (webView21)
  • Set Dock property to Fill

Add Load event handler to Form (Form1)

  • In Solution Explorer, click Form1.cs to select it
  • Double-click the top of the Form, which will add the event handler: Form1_Load

Add Button click event handler

  • In Solution Explorer, click Form1.cs to select it
  • On the Form (Form1), double-click the button (btnClickJSButton), to create the click event handler (btnClickJSButton_Click)

Create a folder for HTML code

  • In Solution Explorer, right-click <project name>
  • Select Add
  • Select New Folder. The folder will be selected. If not, right-click the folder and select "Rename". Set the name to "HTML".

Create index.html

  • In Solution Explorer, right-click <project name>
  • Right-click HTML folder
  • Select Add
  • Select New Item
  • Click HTML Page (Name: index.html)
  • Click Add

Change index.html property

  • In Solution Explorer, click index.html to select it
  • In Properties Window, set Build Action to Embedded Resource

Add code to: index.html

index.html

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>

    <script>
        function btnClickAction(name) {
            alert('button ' + name + ' was clicked');
        }
    </script>
</head>
<body>

    <button type="button" class="size-grid-button" id="size-grid-button1" onclick="btnClickAction('size-grid-button1')">Click Me 1</button>
    <button type="button" class="size-grid-button" id="size-grid-button2" onclick="btnClickAction('size-grid-button2')">Click Me 2</button>
    <button type="button" class="size-grid-button" id="size-grid-button3" onclick="btnClickAction('size-grid-button3')" value="Click Me 3">Click Me 3</button>

    <input type="button" class="size-grid-button" id="size-grid-button4" onclick="btnClickAction('size-grid-button4')" value="Click Me 4" />

</body>
</html>

Create a folder for JavaScript code

  • In Solution Explorer, right-click <project name>
  • Select Add
  • Select New Folder. The folder will be selected. If not, right-click the folder and select "Rename". Set the name to "JavaScript".

Create TestButtonClick.js

  • In Solution Explorer, right-click <project name>
  • Right-click JavaScript folder
  • Select Add
  • Select New Item
  • Click JavaScript File (Name: TestButtonClick.js)
  • Click Add

Change TestButtonClick.js property

  • In Solution Explorer, click TestButtonClick.js to select it
  • In Properties Window, set Build Action to Embedded Resource

Option 1 (desired HTML element is 'button')

Example:

<button type="button" class="size-grid-button" id="size-grid-button1" onclick="btnClickAction('size-grid-button1')">Click Me 1</button>

Add code to: TestButtonClick.js

TestButtonClick.js (Option 1)

function clickDesiredButtonByInnerText(btnInnerText) {

    //let buttons = document.getElementByTagName('button');
    let buttons = document.querySelectorAll('button');
    let i = 0;
    let result = null;

    if (buttons) {
        
        for (i = 0; i < buttons.length; i++) {
            //window.chrome.webview.postMessage("button[" + i + "].innerText: " + buttons[i].innerText);

            if (buttons[i].innerText === btnInnerText) {
                buttons[i].click();
                result = btnInnerText + ' clicked';
                break; //exit loop
            }
        }
    }

    //window.chrome.webview.postMessage("result:" + result);
    return result;
}

Option 2 (desired HTML element is 'input')

Example:

<input type="button" class="size-grid-button" id="size-grid-button4" onclick="btnClickAction('size-grid-button4')" value="Click Me 4" />

Add code to: TestButtonClick.js

TestButtonClick.js (Option 2)

function clickDesiredInputButtonByTextValue(btnValue) {

    let i = 0;
    let result = null;

    buttons = document.querySelectorAll('input');

    if (buttons) {

        for (i = 0; i < buttons.length; i++) {
            //window.chrome.webview.postMessage("button[" + i + "].value: " + buttons[i].value + ' type: ' + buttons[i].type);

            if (buttons[i].type === 'button' && buttons[i].value === btnValue) {
                buttons[i].click();
                result = btnValue + ' clicked';
                break; //exit loop
            }
        }
    }

    //window.chrome.webview.postMessage("result:" + result);
    return result;
}

Option 3 (desired HTML element is ('button' OR 'input') AND element has an 'id' attribute that has a unique value)

Add code to: TestButtonClick.js

TestButtonClick.js (Option 3)

function clickDesiredButtonById(btnId) {
    let result = null;
    let desiredButton = document.getElementById(btnId);

    if (desiredButton) {
        desiredButton.click();
        result = 'button with id = ' + btnId + ' clicked';
    }

    //window.chrome.webview.postMessage("result:" + result);
    return result;
}

Create a new class (HelperLoadResource.cs)

  • In Solution Explorer, right-click <project name>
  • Select Add
  • Select Class... (Name: HelperLoadResource.cs)

Add using statements (HelperLoadResource.cs):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
using System.Diagnostics;

Add code to: HelperLoadResource.cs

Note: HelperLoadResource.ReadResource will read text from the embedded files (HTML and JavaScript) and put the text into a string variable.

HelperLoadResource.cs

public static class HelperLoadResource
{
    public static string ReadResource(string filename)
    {
        //use UTF8 encoding as the default encoding
        return ReadResource(filename, Encoding.UTF8);
    }

    public static string ReadResource(string filename, Encoding fileEncoding)
    {
        string fqResourceName = string.Empty;
        string result = string.Empty;

        //get executing assembly
        Assembly execAssembly = Assembly.GetExecutingAssembly();

        //get resource names
        string[] resourceNames = execAssembly.GetManifestResourceNames();

        if (resourceNames != null && resourceNames.Length > 0)
        {
            foreach (string rName in resourceNames)
            {
                if (rName.EndsWith(filename))
                {

                    //set value to 1st match
                    //if the same filename exists in different folders,
                    //the filename can be specified as <folder name>.<filename>
                    //or <namespace>.<folder name>.<filename>
                    fqResourceName = rName;

                    //exit loop
                    break;
                }
            }

            //if not found, throw exception
            if (String.IsNullOrEmpty(fqResourceName))
            {
                throw new Exception($"Resource '{filename}' not found.");
            }

            //get file text
            using (Stream s = execAssembly.GetManifestResourceStream(fqResourceName))
            {
                using (StreamReader reader = new StreamReader(s, fileEncoding))
                {
                    //get text
                    result = reader.ReadToEnd();
                }
            }
        }

        return result;
    }

}

Add code to: Form1.cs

  • In Solution Explorer, click <project name>
  • Right-click Form1.cs
  • Select View Code

Add using statements (Form1.cs):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using System.Diagnostics;

Add method InitializeCoreWebView2Async (Form1.cs)

InitializeCoreWebView2Async (Form1.cs)

private async Task InitializeCoreWebView2Async()
{
    //initialize CorewWebView2
    await webView21.EnsureCoreWebView2Async();
}

Add code to: Form1_Load (Form1.cs)

Note: Add the async keyword to Form_Load.

Form1_Load (Form1.cs)

private async void Form1_Load(object sender, EventArgs e)
{
    //show MS Edge version -- also ensures that an exception will be raised if proper MS Edge version isn't installed
    Debug.WriteLine(CoreWebView2Environment.GetAvailableBrowserVersionString());

    //initialized CorewWebView2
    await InitializeCoreWebView2Async();

    //get HTML
    string html = HelperLoadResource.ReadResource("index.html");
    
    //display HTML in WebView2
    webView21.NavigateToString(html);
    
}

Subscribe to WebView2 CoreWebView2InitializationCompleted event

  • In Properties Window, use the drop-down to select the WebView2 instance (webView21)
  • Click the orange lightning bolt to see available events
  • Double-click CoreWebView2InitializationCompleted to add the event handler to the Form (Form1.cs)

Add the following code to CoreWebView2InitializationCompleted

CoreWebView2InitializationCompleted (Form1.cs)

private void webView21_CoreWebView2InitializationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e) 
{

    //subscribe to CoreWebView2 events (add event handlers)
    webView21.CoreWebView2.WebMessageReceived += CoreWebView2_WebMessageReceived;         
}

CoreWebView2_WebMessageReceived (Form1.cs)

private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
{
    Debug.WriteLine("Info: MSG (JSON): " + e.WebMessageAsJson);
    Debug.WriteLine("Info: MSG (String): " + e.TryGetWebMessageAsString());
}

If using Option 1 above (desired HTML element is 'button'), add method ClickWebView2ButtonByInnerText

ClickWebView2ButtonByInnerText (Form1.cs)

private async Task ClickWebView2ButtonByInnerText(string btnInnerText)
{
    if (webView21 != null && webView21.CoreWebView2 != null)
    {
        string jsCode = HelperLoadResource.ReadResource("TestButtonClick.js");
        jsCode += System.Environment.NewLine;
        jsCode += "clickDesiredButtonByInnerText('" + btnInnerText + "');";

        var result = await webView21.CoreWebView2.ExecuteScriptAsync(jsCode);

        Debug.WriteLine("result: " + result);
    }
}

Add the following code to the Button click event handler btnClickButton_Click (Option 1)

Note: Add the async keyword.

private async void btnClickButton_Click(object sender, EventArgs e)
{
    await ClickWebView2ButtonByInnerText("Click Me 3");
}

If using Option 2 above (desired HTML element is 'input'), add method ClickWebView2InputButton

ClickWebView2InputButton (Form1.cs)

private async Task ClickWebView2InputButton(string btnValue)
{
    if (webView21 != null && webView21.CoreWebView2 != null)
    {
        string jsCode = HelperLoadResource.ReadResource("TestButtonClick.js");
        jsCode += System.Environment.NewLine;
        jsCode += "clickDesiredInputButtonByTextValue('" + btnValue + "');";

        var result = await webView21.CoreWebView2.ExecuteScriptAsync(jsCode);

        Debug.WriteLine("result: " + result);
    }
}

Add the following code to the Button click event handler btnClickButton_Click (Option 2)

Note: Add the async keyword.

private async void btnClickButton_Click(object sender, EventArgs e)
{
    await ClickWebView2InputButton("Click Me 4");
}

If using Option 3 above (desired HTML element is ('button' OR 'input') AND element has an 'id' attribute that has a unique value), add method ClickWebView2ButtonById

ClickWebView2ButtonById (Form1.cs)

private async Task ClickWebView2ButtonById(string btnId)
{
    if (webView21 != null && webView21.CoreWebView2 != null)
    {
        string jsCode = HelperLoadResource.ReadResource("TestButtonClick.js");
        jsCode += System.Environment.NewLine;
        jsCode += "clickDesiredButtonById('" + btnId + "');";

        var result = await webView21.CoreWebView2.ExecuteScriptAsync(jsCode);

        Debug.WriteLine("result: " + result);
    }
}

Add the following code to the Button click event handler btnClickButton_Click (Option 3)

Note: Add the async keyword.

private async void btnClickButton_Click(object sender, EventArgs e)
{
     await ClickWebView2ButtonById("size-grid-button2");
     await ClickWebView2ButtonById("size-grid-button4");
}

Run the program. Click the button on the form to test.

Additional Resources

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24