我有一个 WPF 应用程序,使用 WPF WebBrowser 控件在平板电视上展示有趣的网页(类似于新闻源)。
问题是,我偶尔会收到 HTML 脚本错误提示,弹出令人讨厌的 IE 错误消息,询问是否要“停止运行此页上的脚本”。有没有方法可以抑制此错误检查?
注意:我已经在 IE 设置中禁用了脚本调试。
这是我刚刚用反射创建的解决方案。解决了问题 :) 我将它在Navigated事件中运行,因为在那之前似乎ActiveX对象不可用。
它所做的是在基础ActiveX对象上设置.Silent属性。这与.ScriptErrorsSuppressed属性相同,后者是Windows窗体的等效属性。
public void HideScriptErrors(WebBrowser wb, bool Hide) {
FieldInfo fiComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);
if (fiComWebBrowser == null) return;
object objComWebBrowser = fiComWebBrowser.GetValue(wb);
if (objComWebBrowser == null) return;
objComWebBrowser.GetType().InvokeMember("Silent", BindingFlags.SetProperty, null, objComWebBrowser, new object[] { Hide });
}
一个更好的版本,可以在任何时候运行,而不是在 ".Navigated" 事件之后:
public void HideScriptErrors(WebBrowser wb, bool hide) {
var fiComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);
if (fiComWebBrowser == null) return;
var objComWebBrowser = fiComWebBrowser.GetValue(wb);
if (objComWebBrowser == null) {
wb.Loaded += (o, s) => HideScriptErrors(wb, hide); //In case we are to early
return;
}
objComWebBrowser.GetType().InvokeMember("Silent", BindingFlags.SetProperty, null, objComWebBrowser, new object[] { hide });
}
如果第二个示例存在任何问题,请尝试将 wb.Loaded 与 wb.Navigated 交换。
刚从另一个问题中发现,这个方法非常优雅且有效。
dynamic activeX = this.webBrowser1.GetType().InvokeMember("ActiveXInstance",
BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, this.webBrowser1, new object[] { });
activeX.Silent = true;
WebBrowser_OnNavigating
事件下,它可以正常工作!+1 - Mike Keskinov这里的问题是WPF中的WebBrowser
没有像2.0控件那样实现此属性。
您最好在WPF应用程序中使用WindowsFormsHost
,并使用2.0的WebBrowser
属性:SuppressScriptErrors
。即使这样,您也需要将应用程序设置为完全信任才能执行此操作。
虽然不算理想,但目前几乎是唯一的选择。
我找到了一个有趣的方法来禁用JavaScript错误。但是你需要使用至少.Net Framework 4.0,因为使用了优雅的动态类型。
你需要订阅WebBrowser元素的LoadCompleted事件:
<WebBrowser x:Name="Browser"
LoadCompleted="Browser_OnLoadCompleted" />
此后,您需要编写一个事件处理程序,其代码如下:
void Browser_OnLoadCompleted(object sender, NavigationEventArgs e)
{
var browser = sender as WebBrowser;
if (browser == null || browser.Document == null)
return;
dynamic document = browser.Document;
if (document.readyState != "complete")
return;
dynamic script = document.createElement("script");
script.type = @"text/javascript";
script.text = @"window.onerror = function(msg,url,line){return true;}";
document.head.appendChild(script);
}
window.Browser.LoadCompleted.Add(fun _ ->
window.Browser.Source <- new System.Uri("javascript:window.onerror=function(msg,url,line){return true;};void(0);"))
这个代码示例是用F#编写的,但它的功能非常明显。
public MainWindow
{
InitializeComponent();
WebBrowserControlView.Navigate(new Uri("https://www.hotmail.com"));
//The below checks for script errors.
ViewerWebBrowserControlView.Navigated += ViewerWebBrowserControlView_Navigated;
}
void ViewerWebBrowserControlView_Navigated(object sender, NavigationEventArgs e)
{
BrowserHandler.SetSilent(ViewerWebBrowserControlView, true); // make it silent
}
public static class BrowserHandler
{
private const string IWebBrowserAppGUID = "0002DF05-0000-0000-C000-000000000046";
private const string IWebBrowser2GUID = "D30C1661-CDAF-11d0-8A3E-00C04FC9E26E";
public static void SetSilent(System.Windows.Controls.WebBrowser browser, bool silent)
{
if (browser == null)
MessageBox.Show("No Internet Connection");
// get an IWebBrowser2 from the document
IOleServiceProvider sp = browser.Document as IOleServiceProvider;
if (sp != null)
{
Guid IID_IWebBrowserApp = new Guid(IWebBrowserAppGUID);
Guid IID_IWebBrowser2 = new Guid(IWebBrowser2GUID);
object webBrowser;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out webBrowser);
if (webBrowser != null)
{
webBrowser.GetType().InvokeMember("Silent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.PutDispProperty, null, webBrowser, new object[] { silent });
}
}
}
}
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleServiceProvider
{
[PreserveSig]
int QueryService([In] ref Guid guidService, [In] ref Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
}
如果您正在使用Winforms Web浏览器与winforms主机,您需要设置一个名为“SuppressScriptErrors”的属性,并将其设置为true。
<WindowsFormsHost Name="WinformsHost" Grid.Row="1">
<winForms:WebBrowser x:Name="WebBrowserControlView" ScriptErrorsSuppressed="True" AllowWebBrowserDrop="False"></winForms:WebBrowser>
</WindowsFormsHost>
你可以使用这个技巧
vb.net
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Const WM_CLOSE As Short = &H10s
并调用最后一个库:
dim hwnd
dim vreturnvalue
hwnd = FindWindow(vbNullString,"script error")
if hwnd<>0 then vreturnvalue = SendMessage(hwnd, WM_CLOSE, &O0s, &O0s)
if (objComWebBrowser == null)
似乎不起作用。相反,我检查WebBrowser
实例的IsLoaded
属性:public void HideScriptErrors(WebBrowser webBrowser)
{
if (!webBrowser.IsLoaded)
{
webBrowser.Loaded += WebBrowser_Loaded; // in case we are too early
return;
}
var objComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(webBrowser);
if (objComWebBrowser == null)
{
return;
}
objComWebBrowser.GetType().InvokeMember("Silent", BindingFlags.SetProperty, null, objComWebBrowser, new object[] { true });
}
private void WebBrowser_Loaded(object sender, RoutedEventArgs e)
{
var webBrowser = sender as WebBrowser;
webBrowser.Loaded -= WebBrowser_Loaded;
HideScriptErrors(webBrowser);
}
在第一次之后,有必要移除Loaded
事件处理程序,因为当通过切换到不同的选项卡使其不可见时,控件可能会多次卸载和加载。此外,当WebBrowser
在第一次导航时尚未可见时,例如它位于应用程序启动时不可见的不同选项卡上时,if (!wb.Loaded))
回退仍然很重要。