zoukankan      html  css  js  c++  java
  • 解决WebBrowser多次触发LoadCompleted事件的问题

    一、起因

    最近有个WPF的项目,需要频繁的加载不同的网页并提取网页的数据,随后就使用了WebBrowser控件。WPF使用WebBrowser控件获取网页,一般步骤是:

    1、使用Navgiate方法或者WebBrowser的Source属性。

    2、监听LoadCompleted事件,当该事件触发时,可以获取DOM。

    由于我需要查看的网页比较多,需要依次向WebBrowser控件加载多个指定网址,随后获取各个DOM。一开始我是使用WithEvents来声明WebBrowser控件。但是随后发现会多次触发LoadCompleted事件。随着历史Navgiate方法的调用,该LoadCompleted事件会被越来越多的触发。

    举个例子来说明:窗体加载时,首次调用Navgiate方法,导航到URL1,此时只会触发一次LoadCompleted;如果第二次调用Navgiate方法,导航到URL2,此时LoadCompleted将被触发2次,依次是URL1和URL2;依次类推,当加载很多次后,该事件将多次触发。

    其实要避免这样的事情发生,可以通过手动绑定及解除LoadCompleted事件监听即可。我单独写了一个HtmlLoader类,来完成该操作,该类的详细代码如下:

    二、HtmlLoader类模块
     1 Imports mshtml
     2 Public Class HtmlLoader
     3     Private mWindow As Window
     4     Private wb As WebBrowser
     5     Private mURL As String
     6     Public Property URL() As String
     7         Get
     8             Return mURL
     9         End Get
    10         Set(ByVal value As String)
    11             mURL = value
    12         End Set
    13     End Property
    14 
    15     Private mLoadCompleted As Boolean
    16 
    17     Public Sub New(CurWindow As Window, webBrowser As WebBrowser)
    18         mWindow = CurWindow
    19         wb = webBrowser
    20     End Sub
    21 
    22     Public Sub New(CurWindow As Window, webBrowser As WebBrowser, URL As String)
    23         mWindow = CurWindow
    24         wb = webBrowser
    25         Me.Reload(URL)
    26     End Sub
    27 
    28     Public Sub Reload()
    29         mLoadCompleted = False
    30         If Me.URL Is Nothing OrElse Me.URL.Trim.Length = 0 Then Exit Sub
    31         mWindow.Dispatcher.Invoke(Sub()
    32                                       LogNote.WriteLine(wb.Name & "-StartLoad", Me.URL)
    33                                       AddHandler wb.LoadCompleted, AddressOf wb_LoadCompleted
    34                                       'wb.Source = New Uri(Me.URL)
    35                                       wb.Navigate(Me.URL)
    36                                   End Sub)
    37     End Sub
    38 
    39     Public Sub Reload(URL As String)
    40         Me.URL = URL
    41         Reload()
    42     End Sub
    43 
    44     Private Sub wb_LoadCompleted(sender As Object, e As NavigationEventArgs)
    45         mWindow.Dispatcher.Invoke(Sub()
    46                                       LogNote.WriteLine(wb.Name & "-LoadCompleted", Me.URL)
    47                                       RemoveHandler wb.LoadCompleted, AddressOf wb_LoadCompleted
    48                                   End Sub)
    49         mLoadCompleted = True
    50     End Sub
    51 
    52     Public Function GetDocument() As HTMLDocument
    53         Do Until mLoadCompleted
    54 
    55         Loop
    56         Return mWindow.Dispatcher.Invoke(Function() As HTMLDocument
    57                                              Return wb.Document
    58                                          End Function)
    59     End Function
    60 End Class
    三、说明

    这个类接受WebBrowser控件所在窗体、WebBrowser控件对象及定位的URL做为参数。由于涉及到UI更新问题,需要使用Window对象的Dispatcher来操作,所以需要传递Window。

    LogNote是我自己写的日志静态类,这里就不提供代码了,可以简单的将其注释掉就行了。

  • 相关阅读:
    检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件失败,原因是出现以下错误: 80070005 拒绝访问。 (异常来自 HRESULT:0x80070005 (E_ACCESSDENIED))。
    SAP middb主键加索引
    【深入理解JVM】类加载器与双亲委派模型 (转)
    一千行MySQL学习笔记 (转)
    Spring框架是怎么解决Bean之间的循环依赖的 (转)
    一步一步带你入门MySQL中的索引和锁 (转)
    如何决定使用 HashMap 还是 TreeMap? (转)
    JVM 线上故障排查基本操作 (转)
    分布式、集群、微服务的区别
    可能是把 Java 内存区域讲的最清楚的一篇文章
  • 原文地址:https://www.cnblogs.com/alexywt/p/7646040.html
Copyright © 2011-2022 走看看