2013-10-14 81 views
2

我在我的项目中使用WebBrowser控件。Wpf WebBrowser刷新

而且我注意到,如果用户按右键 - >刷新

Navigating

LoadCompleted

不叫。

另一个奇怪的是,我按刷新后,点击浏览器中的另一个链接LoadCompleted不叫太。

这是我的导航页面中开始:

nrowser.Navigate(MYPAGE); 

任何想法可能是什么问题?

我可以用JavaScript修复吗?

回答

2

您可以处理刷新并区分导航。稍做练习,可以通过处理DOM document.onreadystatechangewindow.onunload事件以及底层的WebBrowser ActiveX控件的NavigateComplete2DownloadBegin事件来完成。

NavigateComplete2当页面正在刷新时,顶部WebBrowser对象没有被触发,但它在导航时会触发。对于任何下载,导航或刷新活动,可能会多次触发DownloadBegin。导航或刷新之前window.onunload被触发,导航或刷新时触发document.onreadystatechange。其余的是跟踪状态转换的问题。这是一个工作示例(它仍然可能包含错误)。

C#:

using Microsoft.Win32; 
using System; 
using System.Diagnostics; 
using System.Reflection; 
using System.Runtime.InteropServices; 
using System.Windows; 
using System.Windows.Controls; 

namespace WpfWebBrowser 
{ 
    public partial class MainWindow : Window 
    { 
     bool navigating = false; 
     bool loading = false; 
     bool loaded = false; 

     public MainWindow() 
     { 
      SetBrowserFeatureControl(); 
      InitializeComponent(); 

      this.Loaded += (s, e) => 
      { 
       var axWebBrowser = (SHDocVw.WebBrowser)GetActiveXInstance(this.webBrowser); 

       axWebBrowser.DownloadBegin += delegate 
       { 
        HandleDownloadActivity(); 
       }; 

       axWebBrowser.NavigateComplete2 += delegate(object pDisp, ref object URL) 
       { 
        // top frame? 
        if (Object.ReferenceEquals(axWebBrowser, pDisp)) 
        { 
         this.navigating = true; 
         HandleDownloadActivity(); 
        } 
       }; 

       this.webBrowser.Navigate("http://example.com"); 
      }; 
     } 

     // handler for document.readyState == "complete" 
     void DomDocumetCompleteHandler(dynamic domDocument) 
     { 
      dynamic domWindow = domDocument.parentWindow; 

      domWindow.attachEvent("onunload", new DomEventHandler(delegate 
      { 
       this.loaded = false; 
       this.loading = false; 
      })); 

      var navigated = this.navigating; 

      this.navigating = false; 
      this.loaded = true; 
      this.loading = false; 

      MessageBox.Show(navigated ? "Navigated" : "Refreshed"); 
     } 

     void HandleDownloadActivity() 
     { 
      dynamic domDocument = this.webBrowser.Document; 
      if (domDocument == null) 
       return; 

      if (loading || loaded) 
       return; 

      this.loading = true; 

      if (domDocument.readyState == "complete") 
      { 
       DomDocumetCompleteHandler(domDocument); 
      } 
      else 
      { 
       DomEventHandler handler = null; 
       handler = new DomEventHandler(delegate 
       { 
        if (domDocument.readyState == "complete") 
        { 
         domDocument.detachEvent("onreadystatechange", handler); 
         DomDocumetCompleteHandler(domDocument); 
        } 
       }); 
       domDocument.attachEvent("onreadystatechange", handler); 
      } 
     } 

     /// <summary> 
     /// Get the underlying WebBrowser ActiveX object; 
     /// this code depends on SHDocVw.dll COM interop assembly, 
     /// generate SHDocVw.dll: "tlbimp.exe ieframe.dll", 
     /// and add as a reference to the project 
     /// </summary> 
     static object GetActiveXInstance(WebBrowser wb) 
     { 
      return wb.GetType().InvokeMember("ActiveXInstance", 
       BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, 
       null, wb, new object[] { }) as SHDocVw.WebBrowser; 
     } 

     /// <summary> 
     /// EventHandler - adaptor to call C# back from JavaScript or DOM event handlers 
     /// </summary> 
     [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)] 
     public class DomEventHandler 
     { 
      [ComVisible(false)] 
      public delegate void Callback(ref object result, object[] args); 

      [ComVisible(false)] 
      private Callback _callback; 

      [DispId(0)] 
      public object Method(params object[] args) 
      { 
       var result = Type.Missing; // Type.Missing is "undefined" in JavaScript 
       _callback(ref result, args); 
       return result; 
      } 

      public DomEventHandler(Callback callback) 
      { 
       _callback = callback; 
      } 
     } 

     /// <summary> 
     /// WebBrowser version control 
     /// http://msdn.microsoft.com/en-us/library/ee330730(v=vs.85).aspx#browser_emulation 
     /// </summary> 
     void SetBrowserFeatureControl() 
     { 
      // http://msdn.microsoft.com/en-us/library/ee330720(v=vs.85).aspx 

      // FeatureControl settings are per-process 
      var fileName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName); 

      // make the control is not running inside Visual Studio Designer 
      if (String.Compare(fileName, "devenv.exe", true) == 0 || String.Compare(fileName, "XDesProc.exe", true) == 0) 
       return; 

      // Webpages containing standards-based !DOCTYPE directives are displayed in IE9/IE10 Standards mode. 
      SetBrowserFeatureControlKey("FEATURE_BROWSER_EMULATION", fileName, 9000); 
     } 

     void SetBrowserFeatureControlKey(string feature, string appName, uint value) 
     { 
      using (var key = Registry.CurrentUser.CreateSubKey(
       String.Concat(@"Software\Microsoft\Internet Explorer\Main\FeatureControl\", feature), 
       RegistryKeyPermissionCheck.ReadWriteSubTree)) 
      { 
       key.SetValue(appName, (UInt32)value, RegistryValueKind.DWord); 
      } 
     } 

    } 
} 

XAML:

<Window x:Class="WpfWebBrowser.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Width="800" Height="600"> 
     <WebBrowser Name="webBrowser"/> 
</Window> 
0

感谢Noseratio,它的伟大工程。我将你所做的事情封装到一个对象中,你可以通过Web浏览器来处理事件。

public class WebBrowserHook 
{ 
    private bool _isNavigating = false; 
    private bool _isLoading = false; 
    private bool _isLoaded = false; 
    private WebBrowser _webBrowser = null; 

    public WebBrowserHook(WebBrowser webBrowser) 
    { 
     _webBrowser = webBrowser; 

     _webBrowser.Loaded += (s, e) => 
     { 
      try 
      { 
       var axWebBrowser = (SHDocVw.WebBrowser)GetActiveXInstance(this._webBrowser); 

       axWebBrowser.DownloadBegin += delegate 
       { 
        HandleDownloadActivity(); 
       }; 

       axWebBrowser.NavigateComplete2 += delegate(object pDisp, ref object URL) 
       { 
        // top frame? 
        if (Object.ReferenceEquals(axWebBrowser, pDisp)) 
        { 
         this._isNavigating = true; 
         HandleDownloadActivity(); 
        } 
       }; 
      } 
      catch (Exception ex) 
      { 
       AppLog.LogException(ex); 
      } 

     }; 

    } 

    public event EventHandler Navigated; 
    public event EventHandler Refreshed; 

    public WebBrowser Browser 
    { 
     get{return _webBrowser;} 
    } 

    // handler for document.readyState == "complete" 
    private void DomDocumentCompleteHandler(mshtml.HTMLDocument domDocument) 
    { 
     try 
     { 
      mshtml.HTMLWindow2 domWindow = (mshtml.HTMLWindow2)domDocument.parentWindow; 

      domWindow.attachEvent("onunload", new DomEventHandler(delegate 
      { 
       this._isLoaded = false; 
       this._isLoading = false; 
      })); 

      var navigated = this._isNavigating; 

      this._isNavigating = false; 
      this._isLoaded = true; 
      this._isLoading = false; 

      if (navigated) 
      { 
       if (Navigated != null) 
        Navigated(this, new EventArgs()); 
      } 
      else 
      { 
       if (Refreshed != null) 
        Refreshed(this, new EventArgs()); 
      } 
     } 
     catch (Exception ex) 
     { 
      AppLog.LogException(ex); 
     } 
    } 

    private void HandleDownloadActivity() 
    { 
     try 
     { 
      mshtml.HTMLDocument domDocument = (mshtml.HTMLDocument)this._webBrowser.Document; 
      if (domDocument == null) 
       return; 

      if (_isLoading || _isLoaded) 
       return; 

      this._isLoading = true; 

      if (domDocument.readyState == "complete") 
      { 
       DomDocumentCompleteHandler(domDocument); 
      } 
      else 
      { 
       DomEventHandler handler = null; 
       handler = new DomEventHandler(delegate 
       { 
        if (domDocument.readyState == "complete") 
        { 
         domDocument.detachEvent("onreadystatechange", handler); 
         DomDocumentCompleteHandler(domDocument); 
        } 
       }); 
       domDocument.attachEvent("onreadystatechange", handler); 
      } 
     } 
     catch (Exception ex) 
     { 
      AppLog.LogException(ex); 
     } 
    } 

    /// <summary> 
    /// Get the underlying WebBrowser ActiveX object; 
    /// this code depends on SHDocVw.dll COM interop assembly, 
    /// generate SHDocVw.dll: "tlbimp.exe ieframe.dll", 
    /// and add as a reference to the project 
    /// </summary> 
    private static object GetActiveXInstance(WebBrowser wb) 
    { 
     return wb.GetType().InvokeMember("ActiveXInstance", 
      BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, 
      null, wb, new object[] { }) as SHDocVw.WebBrowser; 
    } 

    /// <summary> 
    /// EventHandler - adaptor to call C# back from JavaScript or DOM event handlers 
    /// </summary> 
    [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)] 
    public class DomEventHandler 
    { 
     [ComVisible(false)] 
     public delegate void Callback(ref object result, object[] args); 

     [ComVisible(false)] 
     private Callback _callback; 

     [DispId(0)] 
     public object Method(params object[] args) 
     { 
      var result = Type.Missing; // Type.Missing is "undefined" in JavaScript 
      _callback(ref result, args); 
      return result; 
     } 

     public DomEventHandler(Callback callback) 
     { 
      _callback = callback; 
     } 
    } 
}