WPF 客户端浏览器 添加Loading加载进度

简介: 原文:WPF 客户端浏览器 添加Loading加载进度在windows开发界面时,使用浏览器来请求和显示网页内容,是比较常见的。 但是在请求网页内容时,因网速或者前端功能复杂加载较慢,亦或者加载时遇到各种问题,如空白/黑屏/加载不完整/证书问题等。
原文: WPF 客户端浏览器 添加Loading加载进度

在windows开发界面时,使用浏览器来请求和显示网页内容,是比较常见的。

但是在请求网页内容时,因网速或者前端功能复杂加载较慢,亦或者加载时遇到各种问题,如空白/黑屏/加载不完整/证书问题等。

因此需要一个加载进度/加载失败的显示界面。

 加载进度显示

界面显示

1. 界面显示,加载进度样式可参考: 绕圈进度条

2. 添加Loading状态枚举。不加载/加载中/加载失败

1     public enum LoadingState
2     {
3         NotLoading,//正常的网页内容界面
4         Loading,   //加载进度显示
5         Error,     //加载失败界面
6     }

在控件内添加LoadingState附加属性,前端界面通过绑定此附加属性来确定是否显示,LoadingState的变更时,界面显示则直接变更。

进度显示处理

在封装相应浏览器后,针对三个事件DocumentCompleted、ProgressChanged、NavigateError作进度显示的处理。

结束加载进度

  1. DocumentCompleted文档加载完成后,结束加载进度。此事件只有Navigate调用后,才会触发
  2. ProgressChanged进度变更通知,Navigate、Refresh调用后都会触发。因为Navigate调用后,同一进度会重复触发ProgressChanged,ProgressChanged在Navigate调用时触发并没有任何意义,因此在DocumentCompleted之后再添加事件的订阅,ProgressChanged只开放给Refresh方法。
  3. 当前进度大于0时,立即结束Loading,减少延时。
 1     /// <summary>
 2     /// 文档加载完成
 3     /// </summary>
 4     /// <remark>Navigate方法触发,Refresh方法不会触发</remark>
 5     /// <remark>在首次加载时,添加DocumentCompleted订阅</remark>
 6     /// <param name="sender"></param>
 7     /// <param name="e"></param>
 8     private void Browser_OnDocumentCompleted(object sender, HtmlDocumentCompletedEventArgs e)
 9     {
10         //当前Loading状态不是Error的情况下,才结束加载
11         if (LoadingState == LoadingState.Loading)
12         {
13             LoadingState = LoadingState.NotLoading;
14         }
15 
16         //显示网页内容首次加载后,再订阅加载进度事件
17         _browser.ProgressChanged -= Browser_ProgressChanged;
18         _browser.ProgressChanged += Browser_ProgressChanged;
19         OnDocumentCompleted(e);
20     }
21 
22     /// <summary>
23     /// 加载进度事件
24     /// </summary>
25     /// <remark>Navigate会触发多次ProgressChanged事件,所以此事件订阅不应开放给Navigate</remark>
26     /// <remark>Refresh调用后,会触发一次</remark>
27     /// <param name="sender"></param>
28     /// <param name="e"></param>
29     private void Browser_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e)
30     {
31         //当前进度大于0,且当前Loading状态是Loading的情况下,才结束Loading动画
32         if (e.CurrentProgress > 0 && LoadingState == LoadingState.Loading)
33         {
34             LoadingState = LoadingState.NotLoading;
35         }
36     }

值得注意的是,如果按照如上设置,当IE8环境升级到IE11后,因WebBrowserProgressChangedEventArgs事件参数返回异常,不会结束Loading。

问题跟进记录:When IE updates from version 8 to version 11,this eventArgs value for event ProgressChanged is weird. 

原因:调用refresh方法。经调试发现ProgressedChanged的事件参数中,MaximumProgress一直等于0。
但是,正常情况下,同样的电脑环境,win7 IE8或者IE11下,refresh方法,返回的MaximumProgress不为0。

推荐分析:升级后,原有IE版本的注册项遗留,导致冲突。

解决方案:添加e.CurrentProgress == e.MaximumProgress的条件判断。

 1     private void Browser_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e)
 2     {
 3         //当以下俩种条件符合时,才结束Loading动画
 4         //1.当前Loading状态是Loading的情况下
 5         //2.当前进度大于0,或者当前进度等于进度上限阀值
 6         if (LoadingState == LoadingState.Loading && (e.CurrentProgress > 0 || e.CurrentProgress == e.MaximumProgress))
 7         {
 8             LoadingState = LoadingState.NotLoading;
 9         }
10     }

PS:微软小组成员推荐使用WebView,然而这个只为Win10的Microsoft Edge开发的控件,只能在win10上运行且只支持.NET4.6.2及以上,限制多多。

加载出错

 1     private void Browser_NavigateError(object sender, BrowserExtendedNavigateErrorEventArgs e)
 2     {
 3         e.Cancel = true;
 4         LoadingState = LoadingState.Error;
 5 
 6         //当前不是网络问题的异常,记录异常日志
 7         if (e.StatusCode != NavigationErrorHttpStatusCode.INET_E_RESOURCE_NOT_FOUND)
 8         {
 9             Console.WriteLine($"WebBrowser无法连接服务器:{e.Url},异常信息为:{e.StatusCode},异常Code为:{ (int)e.StatusCode }");
10         }
11     }

浏览器事件处理

针对如上三个事件,DocumentCompleted、ProgressChanged、NavigateError

winform版IE浏览器

1     /// <summary>
2     ///<see cref="T:System.Windows.Forms.WebBrowser" /> 控件完成加载文档时发生。
3     /// </summary>
4     [SRCategory("CatBehavior")]
5     [SRDescription("WebBrowserDocumentCompletedDescr")]
6     public event WebBrowserDocumentCompletedEventHandler DocumentCompleted;
1     /// <summary>
2     ///<see cref="T:System.Windows.Forms.WebBrowser" /> 控件已更新有关要导航到的文档的下载进度的信息时发生。
3     /// </summary>
4     [SRCategory("CatAction")]
5     [SRDescription("WebBrowserProgressChangedDescr")]
6     public event WebBrowserProgressChangedEventHandler ProgressChanged;

NavigateError加载失败事件,需要重写CreateSink、DetachSink。在对应的cookie中添加额外事件的处理:(在此不详述,这个封装模块本人也不太了解~囧)

1     public void NavigateError(object pDisp, ref object url, ref object frame, ref object statusCode, ref bool cancel)
2     {
3         _browser?.NavigateError?.Invoke(this, new BrowserExtendedNavigateErrorEventArgs((string)url, (string)frame, (int)statusCode, cancel));
4     }

Cef浏览器

 1     private void Register()
 2     {
 3         _cefBrowser.LoadingStateChanged += CefBrowserOnLoadingStateChanged;
 4         _cefBrowser.LoadError += CefBrowserOnLoadError;
 5     }
 6     private void CefBrowserOnLoadError(object sender, LoadErrorEventArgs args)
 7     {
 8         // Don't display an error for downloaded files where the user aborted the download.
 9         if (args.ErrorCode == CefErrorCode.Aborted)
10         {
11             return;
12         }
13         _isLoadError = true;
14         DispatcherUtil.Invoke(() =>
15         {
16             NavigateError?.Invoke(this, new BrowserExtendedNavigateErrorEventArgs(args.FailedUrl, args.Frame.Name, (int)args.ErrorCode, false));
17         });
18     }
19 
20     private void CefBrowserOnLoadingStateChanged(object sender, LoadingStateChangedEventArgs args)
21     {
22         //isLoading为false,代表LoadingCompleted
23         //_isLoadError为false,代表未加载出错
24         if (!args.IsLoading && !_isLoadError)
25         {
26             DispatcherUtil.Invoke(() =>
27             {
28                 DocumentCompleted?.Invoke(this, new HtmlDocumentCompletedEventArgs(null));
29             });
30         }
31     }

 

目录
相关文章
|
5月前
|
JavaScript 前端开发 开发者
如何检测浏览器是否支持最新的 image lazy loading 特性
如何检测浏览器是否支持最新的 image lazy loading 特性
|
2天前
|
安全 Oracle Java
edge浏览器加载java插件
edge浏览器加载java插件
16 1
|
2月前
|
网络协议 前端开发 JavaScript
浏览器加载网页的幕后之旅:从URL到页面展示详解
【8月更文挑战第31天】当在浏览器地址栏输入URL并回车后,一系列复杂过程随即启动,包括DNS解析、TCP连接建立、HTTP请求发送、服务器请求处理及响应返回,最后是浏览器页面渲染。这一流程涉及网络通信、服务器处理和客户端渲染等多个环节。通过示例代码,本文详细解释了每个步骤,帮助读者深入理解Web应用程序的工作机制,从而在开发过程中作出更优决策。
33 5
|
2月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
62 0
|
2月前
|
API C# 开发框架
WPF与Web服务集成大揭秘:手把手教你调用RESTful API,客户端与服务器端优劣对比全解析!
【8月更文挑战第31天】在现代软件开发中,WPF 和 Web 服务各具特色。WPF 以其出色的界面展示能力受到欢迎,而 Web 服务则凭借跨平台和易维护性在互联网应用中占有一席之地。本文探讨了 WPF 如何通过 HttpClient 类调用 RESTful API,并展示了基于 ASP.NET Core 的 Web 服务如何实现同样的功能。通过对比分析,揭示了两者各自的优缺点:WPF 客户端直接处理数据,减轻服务器负担,但需处理网络异常;Web 服务则能利用服务器端功能如缓存和权限验证,但可能增加服务器负载。希望本文能帮助开发者根据具体需求选择合适的技术方案。
66 0
|
2月前
|
存储 API 网络架构
【Azure 存储服务】MP4视频放在Azure的Blob里面,用生成URL在浏览器中打开之后,视频可以正常播放却无法拖拽视频的进度
【Azure 存储服务】MP4视频放在Azure的Blob里面,用生成URL在浏览器中打开之后,视频可以正常播放却无法拖拽视频的进度
|
4月前
|
JavaScript 前端开发
WebView2 控件(基于 Microsoft Edge (Chromium) 的嵌入式浏览器控件),获取网页加载后的标题
在使用 WebView2 控件(基于 Microsoft Edge (Chromium) 的嵌入式浏览器控件)时,要获取网页加载后的标题,可以监听 WebView2 的 NavigationCompleted 事件。这个事件被触发时,表示导航已完成,此时执行JavaScript代码可以安全地获取网页的标题。
WebView2 控件(基于 Microsoft Edge (Chromium) 的嵌入式浏览器控件),获取网页加载后的标题
|
11月前
|
C# 开发者
一款WPF开发的网易云音乐客户端 - DMSkin-CloudMusic
一款WPF开发的网易云音乐客户端 - DMSkin-CloudMusic
194 36
|
网络协议 前端开发 JavaScript
一个浏览器从加载URL到页面展示出来,经过了哪些步骤?
一个浏览器从加载URL到页面展示出来,经过了哪些步骤?
|
Web App开发 内存技术
selenium--加载浏览器配置
selenium--加载浏览器配置