Wpf 网页浏览器刷新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19362003/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Wpf WebBrowser Refresh
提问by MTA
I am using WebBrowsercontrol in my project.
我WebBrowser在我的项目中使用控件。
And i noticed that if the user press right click -> Refresh the
我注意到,如果用户按右键单击 -> 刷新
Navigating
Navigating
LoadCompleted
LoadCompleted
not called.
不叫。
And another strange thing is that after i press the refresh and click another link in the webbrowser the LoadCompletednot called too.
另一个奇怪的事情是,在我按下刷新并单击网络浏览器中的另一个链接后,LoadCompleted也未调用。
This is how i navigate the page in the start :
这是我在开始时导航页面的方式:
nrowser.Navigate(MYPAGE);
Any idea what can be the problem?
知道可能是什么问题吗?
Can i fix it with JavaScript?
我可以用它修复它JavaScript吗?
回答by noseratio
You can handle a refresh and differentiate it from navigation. With a little exercise, it can be done by handling DOM document.onreadystatechangeand window.onunloadevents, as well as the underlying WebBrowser ActiveX control's NavigateComplete2and DownloadBeginevents.
您可以处理刷新并将其与导航区分开来。只需稍加练习,就可以通过处理 DOMdocument.onreadystatechange和window.onunload事件以及底层的 WebBrowser ActiveX 控件NavigateComplete2和DownloadBegin事件来完成。
NavigateComplete2doesn't get fired for the top WebBrowserobject when the page is being refreshed, but it does when navigating. DownloadBeginalways gets fired, for any download, navigation or refresh activity, possibly multiple times. window.onunloadgets fired before navigation or refresh, and document.onreadystatechangegets fired during navigation or refresh. The rest is the matter of tracking the state transitions. Here is a working example (which still may contain bugs).
NavigateComplete2WebBrowser刷新页面时不会为顶部对象触发,但在导航时会触发。 DownloadBegin对于任何下载、导航或刷新活动,可能多次被触发。window.onunload在导航或刷新之前document.onreadystatechange被触发,在导航或刷新期间被触发。剩下的就是跟踪状态转换的问题。这是一个工作示例(仍然可能包含错误)。
C#:
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:
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>
回答by sikemullivan
Thanks Noseratio, it works great. I wrapped what you did into an object that you can just pass the web browser into and handle the events.
谢谢 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;
}
}
}

