.NET混合开发解决方案9 WebView2控件的导航事件

WebView2控件应用详解系列博客

.NET桌面程序集成Web网页开发的十种解决方案

.NET混合开发解决方案1 WebView2简介

.NET混合开发解决方案2 WebView2与Edge浏览器的区别

.NET混合开发解决方案3 WebView2的进程模型

.NET混合开发解决方案4 WebView2的线程模型

.NET混合开发解决方案5 WebView2运行时与分发应用

.NET混合开发解决方案6 检测是否已安装合适的WebView2运行时

.NET混合开发解决方案7 WinForm程序中通过NuGet引用WebView2控件

.NET混合开发解决方案8 WinForm程序中集成WebView2控件方案2

 在我的博客《.NET混合开发解决方案7 WinForm程序中集成WebView2》中介绍了WinForm程序中集成WebView2组件的详细步骤以及注意事项。这只是最基本的应用,WebView2功能之所以强大,是因为它提供了很多开放的属性与事件供开发者调用以完成复杂的功能。具体可以参考我的博客《.NET混合开发解决方案2 WebView2与Edge浏览器的区别》。

  本文介绍WebView2应用程序的导航事件。当WebView2实例中显示的内容发生特定的异步操作时,导航事件会运行。例如,当WebView2用户导航到新网站时,本机内容(WinForm、WPF、Win32、WinUI)通过侦听 NavigationStarting 事件来侦听更改。导航操作完成后,NavigationCompleted 事件将运行。

导航事件的正常顺序为:

  1. NavigationStarting
  2. SourceChanged
  3. ContentLoading
  4. HistoryChanged
  5. BasicAuthenticationRequested
  6. DOMContentLoaded
  7. NavigationCompleted

以下事件描述每次导航操作期间 WebView2 的状态:

.NET混合开发解决方案9WebView2控件的导航事件

.NET混合开发解决方案9WebView2控件的导航事件

上图显示了在各自的事件参数上具有相同NavigationId属性的导航事件。

  • 使用导航ID(在NavigationId事件中提供)跟踪每个新文档的导航事件。每次成功导航到新文档时,WebView2的NavigationId事件都会发生更改。
  • 具有不同NavigationId事件实例的导航事件可能会重叠。例如,启动导航事件时,必须等待相关的NavigationStarting事件。如果随后启动另一个导航,您将看到以下序列:
  1. 第一次导航的 NavigationStarting 事件。第二次导航的 NavigationStarting 事件。第一次导航的 NavigationCompleted 事件。第二次导航的所有其他相应导航事件。
  • 在错误情况下,可能有或可能没有内容加载事件,这取决于导航是否继续导航到错误页面。
  • 如果发生HTTP重定向,则一行中有多个NavigationStarting事件,其中后面的事件参数设置了IsRedirect属性;但是,NavigationId事件保持不变。
  • 相同的文档导航事件(例如导航到同一文档中的片段)不会导致NavigationStarting事件,也不会增加NavigationId事件。
  • 要监视或取消WebView2实例中子框架内的导航事件,请使用FrameNavigationStarting和FrameNavigationCompleted事件。这些事件的行为类似于等效的非框架对应事件。

当在文本框中输入目标网址后,点击【导航】按钮,具体执行逻辑如下

.NET混合开发解决方案9WebView2控件的导航事件

发生错误时,会引发以下事件,这可能取决于对错误网页的导航:

  • SourceChanged
  • ContentLoading
  • HistoryChanged

如果发生HTTP重定向,则一行中有多个NavigationStarting事件。

示例演示

先看一个效果动画

.NET混合开发解决方案9WebView2控件的导航事件

public partial class Frm2Navigation : Form
{
    public Frm2Navigation()
    {
        InitializeComponent();

        InitializeAsync();

        webView2.CoreWebView2InitializationCompleted += WebView2_CoreWebView2InitializationCompleted;

        webView2.NavigationStarting += WebView2_NavigationStarting;
        webView2.NavigationCompleted += WebView2_NavigationCompleted;
    }

    async void InitializeAsync()
    {
        await webView2.EnsureCoreWebView2Async(null);
    }

    private void WebView2_CoreWebView2InitializationCompleted(object? sender, CoreWebView2InitializationCompletedEventArgs e)
    {
        if (e.IsSuccess == false)
        {
            MessageBox.Show("WebView2_CoreWebView2InitializationCompleted 事件,发生异常。"
                          + Environment.NewLine + e.InitializationException.Message,
                            "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        webView2.SourceChanged += WebView2_SourceChanged;
        webView2.ContentLoading += WebView2_ContentLoading;
        webView2.CoreWebView2.HistoryChanged += CoreWebView2_HistoryChanged;
        webView2.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoaded;

        webView2.CoreWebView2.BasicAuthenticationRequested += CoreWebView2_BasicAuthenticationRequested;
        webView2.CoreWebView2.ProcessFailed += CoreWebView2_ProcessFailed;
    }

    private void WebView2_NavigationStarting(object? sender, CoreWebView2NavigationStartingEventArgs e)
    {
        string uri = e.Uri;
        if (!uri.StartsWith("https://"))
        {
            //webView2.CoreWebView2.ExecuteScriptAsync(#34;alert('{uri} 不安全, 请尝试https链接。')");

            DialogResult dr = MessageBox.Show(#34;{uri} 不安全, 请尝试https链接。\r\n\r\n 确定要访问吗?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
            if (dr == DialogResult.Cancel)
            {
                e.Cancel = true;
            }
        }
    }

    private void WebView2_SourceChanged(object? sender, CoreWebView2SourceChangedEventArgs e)
    {
        //if(e.IsNewDocument)
        //{
        // webView2.CoreWebView2.ExecuteScriptAsync("alert('WebView2_SourceChanged事件。= e.IsNewDocument = true')");
        //}

        MessageBox.Show("WebView2_SourceChanged 事件。"
                      + Environment.NewLine + "e.IsNewDocument = " + e.IsNewDocument,
                        "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }

    private void WebView2_ContentLoading(object? sender, CoreWebView2ContentLoadingEventArgs e)
    {
        //webView2.CoreWebView2.ExecuteScriptAsync("alert('WebView2_SourceChanged事件。= e.IsNewDocument = true')");

        MessageBox.Show("WebView2_ContentLoading 事件。"
                      + Environment.NewLine + "e.IsErrorPage = " + e.IsErrorPage,
                        "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }

    private void CoreWebView2_HistoryChanged(object? sender, object e)
    {
        MessageBox.Show("CoreWebView2_HistoryChanged 事件。",
                        "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }

    private void CoreWebView2_DOMContentLoaded(object? sender, CoreWebView2DOMContentLoadedEventArgs e)
    {
        MessageBox.Show("CoreWebView2_DOMContentLoaded 事件。"
                      + Environment.NewLine + "e.NavigationId = " + e.NavigationId,
                        "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }

    private void WebView2_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e)
    {
        MessageBox.Show("WebView2_NavigationCompleted 事件。"
                      + Environment.NewLine + "e.NavigationId = " + e.NavigationId
                      + Environment.NewLine + "e.IsSuccess = " + e.IsSuccess
                      + Environment.NewLine + "e.WebErrorStatus = " + e.WebErrorStatus,
                      "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }


    private void CoreWebView2_ProcessFailed(object? sender, CoreWebView2ProcessFailedEventArgs e)
    {
        MessageBox.Show("CoreWebView2_ProcessFailed 事件。"
                      + Environment.NewLine + "e.ExitCode = " + e.ExitCode
                      + Environment.NewLine + "e.FrameInfosForFailedProcess = " + e.FrameInfosForFailedProcess
                      + Environment.NewLine + "e.ProcessDescription = " + e.ProcessDescription
                      + Environment.NewLine + "e.ProcessFailedKind = " + e.ProcessFailedKind
                      + Environment.NewLine + "e.Reason = " + e.Reason,
                      "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }


    private void CoreWebView2_BasicAuthenticationRequested(object? sender, CoreWebView2BasicAuthenticationRequestedEventArgs e)
    {
        MessageBox.Show("CoreWebView2_BasicAuthenticationRequested 事件。"
                      + Environment.NewLine + "e.Uri = " + e.Uri
                      + Environment.NewLine + "e.Cancel = " + e.Cancel
                      + Environment.NewLine + "e.Challenge = " + e.Challenge
                      + Environment.NewLine + "e.Response = " + e.Response,
                        "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

    }


    // 访问url
    private void btnGo_Click(object sender, EventArgs e)
    {
        string rawUrl = txtUrl.Text;
        if (string.IsNullOrWhiteSpace(rawUrl))
        {
            MessageBox.Show("请输入网址。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

            txtUrl.Focus();

            return;
        }

        Uri uri;

        if (Uri.IsWellFormedUriString(rawUrl, UriKind.Absolute))
        {
            uri = new Uri(rawUrl);
        }
        else if (rawUrl.Contains(" ") == false && rawUrl.Contains(".") == false)
        {
            // 无效的URI包含一个点且没有空格,请尝试在前面添加http://标记
            uri = new Uri("http://" + rawUrl);
        }
        else if (rawUrl.StartsWith("http://") == false)
        {
            uri = new Uri("http://" + rawUrl);
        }
        else
        {
            // 其他情况将其视为网络搜索
            uri = new Uri("https://bing.com/search?q=" + string.Join("+", Uri.EscapeDataString(rawUrl).Split(new string[] { "%20" }, StringSplitOptions.RemoveEmptyEntries)));
        }

        //webView2.CoreWebView2.Navigate(url.Trim());
        webView2.Source = uri;
    }
}

注意事项

CoreWebview2的相关事件必须在它的 CoreWebView2InitializationCompleted 事件(CoreWebView2对象初始化完成后事件)里面注册

  • webView2.CoreWebView2.HistoryChanged
  • webView2.CoreWebView2.DOMContentLoaded
  • webView2.CoreWebView2.BasicAuthenticationRequested
  • webView2.CoreWebView2.ProcessFailed

如上第31、32、34、35行。

欢迎关注、转发、交流。每天分享优质IT内容。

#俄方公布乌军投降新画面#

#杨洁篪:美若执意打台湾牌必将行动#

#阳性不得参加春考?天津修改规定#

#上海疫情中的血透病房#

#央行货币政策司原司长孙国峰被查#