2
votes

In my WPF application I need to show an html string, and I know that I need to call EnsureCoreWebView2Async method before calling NavigateToString because otherwise the CoreWebView will be null and I would have an exception. The problem is that awaiting EnsureCoreWebView2Async never ends.

I created a little application in order to reproduce the problem (and excluding issues related to my big project) and the problem is the same.

  • If I set the WebView2's Source property passing an Url, then it works!
  • If I call NavigateToString without calling EnsureCoreWebView2Async, I get an exception (as expected).
  • If I call EnsureCoreWebView2Async before calling NavigateToString or before setting the Source property (it should not be a problem, because calling it many times should not have any effect according to the documentation) then it hangs forever. No exceptions are raised by the call, and no messages in the console. Very frustrating.

Here are the code for the sample application (I main window with 2 buttons, one that opens the url and one that load the html string - the first one works):

<Window x:Class="WebViewApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WebViewApp" xmlns:wpf="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<StackPanel>
    <Button Width="200" Height="40" Click="OpenUrl_Click">Open url</Button>
    <Button Width="200" Height="40" Click="OpenHtml_Click">Open html</Button>
</StackPanel></Window>

MainWindow behind code:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private async void OpenUrl_Click(object sender, RoutedEventArgs e)
    {
        var browserWindow = new WebWindow();
        //await browserWindow.Initialize();  // this also never completes
        browserWindow.OpenUrl("http://www.microsoft.com");
        browserWindow.Show();
    }

    private async void OpenHtml_Click(object sender, RoutedEventArgs e)
    {
        var browserWindow = new WebWindow();
        await browserWindow.Initialize();
        browserWindow.LoadHtml(@"<html><head><title>Test title</title></head><body><p>Test</p></body></html>");
        browserWindow.Show();
    }
}

Here is the browserView xaml (add the WebView2 nuget package):

<Window x:Class="WebViewApp.WebWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WebViewApp" xmlns:wpf="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
    mc:Ignorable="d"
    Title="WebWindow" Height="450" Width="800">
<Grid>
    <wpf:WebView2 Name="WpfBrowser" />
</Grid></Window>

and the code behind:

public partial class WebWindow : Window
{
    public WebWindow()
    {
        InitializeComponent();
    }

    public async Task Initialize()
    {
        try
        {
            await WpfBrowser.EnsureCoreWebView2Async();  // never completes
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.Message);
        }
    }

    public void LoadHtml(string html)
    {
        WpfBrowser.NavigateToString(html);
    }

    public void OpenUrl(string url)
    {
        WpfBrowser.Source = new Uri(url);
    }
}

I also tried to change the Target platform, but nothing changed.

1
Does it hang on EnsureCoreWebView2Async or throw an exception? Are you using the latest WebView2 control? - Poul Bak
Yes, it hangs on EnsureCoreWebView2Aync and never enters the catch exception. I am using the last prerelease version suggested by nuget (version="1.0.824-prerelease") - Daniele Armanasco

1 Answers

2
votes

You should defer to initialize the webview until OnContentRendered is called. I changed your code and it worked as a charm. See the changes below.

    public partial class WebWindow : Window
    {
        private string _url;
        private string _html;

        public WebWindow()
        {
            InitializeComponent();
        }

        protected override async void OnContentRendered(EventArgs e)
        {
            base.OnContentRendered(e);
            try
            {
                var webView2Environment = await CoreWebView2Environment.CreateAsync();
                await WpfBrowser.EnsureCoreWebView2Async(webView2Environment);

                if(!string.IsNullOrEmpty(_url))
                    WpfBrowser.Source = new Uri(_url);
                else if(!string.IsNullOrEmpty(_html))
                    WpfBrowser.NavigateToString(_html);
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
            }
        }

        public void ShowFromUrl(string url)
        {
            _url = url;
            Show();
        }

        public void ShowFromHtml(string html)
        {
            _html = html;
            Show();
        }
    }
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void OpenUrl_Click(object sender, RoutedEventArgs e)
        {
            var browserWindow = new WebWindow();
            browserWindow.ShowFromUrl("http://www.microsoft.com");
        }

        private async void OpenHtml_Click(object sender, RoutedEventArgs e)
        {
            var browserWindow = new WebWindow();
            browserWindow.ShowFromHtml(@"<html><head><title>Test title</title></head><body><p>Testsdfsdfsdfsdfdsfdsfklsdkflkdlf<br>dsfdsfdsfdsfsdfdsfds</p></body></html>");
        }
    }

You can also check out the code from my git repo that does something similar. KioskBrowser (GitHub)