2

I am making a WPF application use WebView2.

There will be an installer that will installer the WPF application in a folder and will also download and write the website into a subfolder of the installation directory. Such as this:

Installation Directory
├───Website
│   ├───index.css
│   └───index.html
└───WPF Self Contained EXE

The WebView2 will load the website using this (I think): webView.CoreWebView2.Navigate(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Website");

This should load index.html and all the files it references such as index.css.

Now my main concern is that how do I call a JavaScript function from C#. So far after googling I have only found ways for WebView1. And I couldn't find anything about calling a C# method from JavaScript.

So three things:

  1. Is this webView.CoreWebView2.Navigate(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Website"); correct for loading a website from a local folder?
  2. How would I call a JavaScript function and pass an C# object to it from a C# method.
  3. How would I call a C# function from the JavaScript script?

Is this even possible?

Thanks.

admin
  • 55
  • 5
  • The following should help you get started: https://stackoverflow.com/questions/68578936/javascript-scripts-in-html-not-firing-from-winform-webbrowser-control/68592056#68592056, https://stackoverflow.com/questions/65452473/how-to-click-button-in-c-sharp-webview/65470588#65470588, and https://stackoverflow.com/questions/68350635/c-sharp-winform-application-webview2-webbrowser-submit-button-not-working/68353911#68353911 . However, rather than storing the files (.html and .css) as embedded resources (as shown in those posts), store them as files on disk-as you already planned to do. – Tu deschizi eu inchid Aug 02 '21 at 18:07
  • Thanks! This helps! I think that the storing the files on disk will make updating faster as they will probably be updated faster than the actual app... Thanks again! – admin Aug 02 '21 at 18:22
  • The following may be helpful for how to call a C# function from JavaScript: https://github.com/MicrosoftEdge/WebView2Feedback/issues/335 – Tu deschizi eu inchid Aug 02 '21 at 18:54

1 Answers1

5

Using file URI

I'm not sure if AppDomain.CurrentDomain.BaseDirectory will always get you the correct path. You can use something like the following:

string exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
string exeFolder = System.IO.Path.GetDirectoryName(exePath);
string websiteFolder = Path.Combine(exeFolder, "website");
string htmlPath = Path.Combine(websiteFolder, "index.html");

webView.CoreWebView2.Navigate(htmlPath);

You must include the path to the index.html itself and not just the folder containing the index.html.

Normally Navigate should take a URI, but if you provide a Windows file path instead it will convert it to a file URI for you and should work.

File URIs have some limitations when trying to incorporate http(s) URIs and other web platform features that require https.

Using a virtual HTTPS URI

If you hit issues using file URIs you can use CoreWebView2.SetVirtualHostNameToFolderMapping to map a Windows file path to a fake HTTPS hostname:

string exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
string exeFolder = System.IO.Path.GetDirectoryName(exePath);
string websiteFolder = Path.Combine(exeFolder, "website");

webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets.example", websiteFolder, CoreWebView2HostResourceAccessKind.DenyCors);
webView.CoreWebView2.Navigate("https://appassets.example/index.html");

This will make a fake hostname 'appassets.example' that will map to your Windows file path. And since its HTTPS URIs you don't hit the same issues as you do with file URIs.

Host objects in script

For your questions 2 & 3 you can use CoreWebView2.AddHostObjectToScript. The current implementation of AddHostObjectToScript requires your C# classes to be specially marked. You can see it in the AddHostObjectToScript documentation.

David Risney
  • 3,886
  • 15
  • 16
  • Hi. The local website works! Thanks! When I call a c# method inside a class that returns a List, I get null. This is my js code: `const transaction = chrome.webview.hostObjects.transaction; transaction.GetReceiptItems(10).then(TResult1 => {this.amount = TResult1.Count;});` – admin Aug 03 '21 at 07:40
  • This logs an error to the console: `Uncaught (in promise) TypeError: Cannot read property 'Count' of null` Note I am using react.js. – admin Aug 03 '21 at 07:41
  • Is the type of the result of GetReceiptItems also marked with the appropriate attributes `[ClassInterface(ClassInterfaceType.AutoDual)]` and `[ComVisible(true)]`? – David Risney Aug 03 '21 at 17:46
  • The JavaScript code on the MS website is incorrect. `const transaction = chrome.webview.hostObjects.transaction;` needs to have `await`. It should be `const transaction = await chrome.webview.hostObjects.transaction;` – Tu deschizi eu inchid Aug 03 '21 at 20:31
  • Ok. Thanks! Let me try the new code. The result is a List... Do you mean the class? – admin Aug 04 '21 at 10:33
  • Thanks! So far everything works! If I get stuck later on I will ask you! Thanks again! – admin Aug 04 '21 at 12:58