我在这里找到了一个类似的问题:
但是那些解决方案都对我不起作用。我需要停止弹出窗口的出现,因为我正在使用WebBrowser在网站上自动化管理任务。
SuppressScriptErrors
在我的WebControl中似乎没有可用属性 :(
我在这里找到了一个类似的问题:
但是那些解决方案都对我不起作用。我需要停止弹出窗口的出现,因为我正在使用WebBrowser在网站上自动化管理任务。
SuppressScriptErrors
在我的WebControl中似乎没有可用属性 :(
这是一个能够将WPF的WebBrowser
设置为静默模式的C#例程。你不能在WebBrowser初始化时调用它,因为那时太早了,而是在导航发生后调用。以下是一个带有wbMain WebBrowser组件的WPF示例应用程序:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
wbMain.Navigated += new NavigatedEventHandler(wbMain_Navigated);
}
void wbMain_Navigated(object sender, NavigationEventArgs e)
{
SetSilent(wbMain, true); // make it silent
}
private void button1_Click(object sender, RoutedEventArgs e)
{
wbMain.Navigate(new Uri("... some url..."));
}
}
public static void SetSilent(WebBrowser browser, bool silent)
{
if (browser == null)
throw new ArgumentNullException("browser");
// get an IWebBrowser2 from the document
IOleServiceProvider sp = browser.Document as IOleServiceProvider;
if (sp != null)
{
Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");
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)]
private interface IOleServiceProvider
{
[PreserveSig]
int QueryService([In] ref Guid guidService, [In] ref Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
}
Silent
的属性。如果将Silent设置为true,它将阻止控件创建任何窗口。微软没有将所有属性移植到WPF(WinForms做得更好),因此您必须采用类似这样的黑客方式来在后期绑定中实际设置该属性。 - Asti提一下还有另一个方法可以获取到WPF WebBrowser的底层WebBorwser ActiveX Control及其平时无法访问的方法和事件。我几天前才发现这个方法。它非常简单,不需要在WB上进行初始导航:
dynamic activeX = this.WB.GetType().InvokeMember("ActiveXInstance",
BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, this.WB, new object[] { });
activeX.Silent = true;
当然,这种方法在未来版本的Framework中可能不再有效,但对于任何其他未记录的方法也是如此。到目前为止,它已经存在自.NET 3.0以来。 有了一个工作代码示例的更多细节在这里。
感谢Simon Mourier提供了解决这个问题的优雅方式。我进行了一些改进,并将Simon的解决方案封装成了附加属性。
在我的应用程序中,我使用了绑定到ViewModel的WebBrowser控件,WebBrowser可能会隐藏在非活动的TabItem上,因此在设置JavaScript错误静默之前,我必须检查它是否已经加载和导航。当然,这个设置只需要做一次,所以设置完成后,我释放了挂钩的事件。
XAML代码:
<TabControl xmlns:b="clr-namespace:MyApplication.Behaviors">
<TabItem Header="foo">...</TabItem>
<TabItem Header="Google map">
<WebBrowser b:BindableSource="{Binding Path=MapUrl}"
b:DisableJavascriptErrors="True" />
</TabItem>
</TabControl>
行为代码:
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
namespace MyApplication.Behaviors
{
public class WebBrowserBehavior
{
private static readonly Type OwnerType = typeof (WebBrowserBehavior);
#region BindableSource
public static readonly DependencyProperty BindableSourceProperty =
DependencyProperty.RegisterAttached(
"BindableSource",
typeof(string),
OwnerType,
new UIPropertyMetadata(OnBindableSourcePropertyChanged));
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static string GetBindableSource(DependencyObject obj)
{
return (string)obj.GetValue(BindableSourceProperty);
}
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static void SetBindableSource(DependencyObject obj, string value)
{
obj.SetValue(BindableSourceProperty, value);
}
public static void OnBindableSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var browser = d as WebBrowser;
if (browser == null) return;
browser.Source = (e.NewValue != null) ? new Uri(e.NewValue.ToString()) : null;
}
#endregion
#region DisableJavascriptErrors
#region SilentJavascriptErrorsContext (private DP)
private static readonly DependencyPropertyKey SilentJavascriptErrorsContextKey =
DependencyProperty.RegisterAttachedReadOnly(
"SilentJavascriptErrorsContext",
typeof (SilentJavascriptErrorsContext),
OwnerType,
new FrameworkPropertyMetadata(null));
private static void SetSilentJavascriptErrorsContext(DependencyObject depObj, SilentJavascriptErrorsContext value)
{
depObj.SetValue(SilentJavascriptErrorsContextKey, value);
}
private static SilentJavascriptErrorsContext GetSilentJavascriptErrorsContext(DependencyObject depObj)
{
return (SilentJavascriptErrorsContext) depObj.GetValue(SilentJavascriptErrorsContextKey.DependencyProperty);
}
#endregion
public static readonly DependencyProperty DisableJavascriptErrorsProperty =
DependencyProperty.RegisterAttached(
"DisableJavascriptErrors",
typeof (bool),
OwnerType,
new FrameworkPropertyMetadata(OnDisableJavascriptErrorsChangedCallback));
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static void SetDisableJavascriptErrors(DependencyObject depObj, bool value)
{
depObj.SetValue(DisableJavascriptErrorsProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static bool GetDisableJavascriptErrors(DependencyObject depObj)
{
return (bool)depObj.GetValue(DisableJavascriptErrorsProperty);
}
private static void OnDisableJavascriptErrorsChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var webBrowser = d as WebBrowser;
if (webBrowser == null) return;
if (Equals(e.OldValue, e.NewValue)) return;
var context = GetSilentJavascriptErrorsContext(webBrowser);
if (context != null) {
context.Dispose();
}
if (e.NewValue != null) {
context = new SilentJavascriptErrorsContext(webBrowser);
SetSilentJavascriptErrorsContext(webBrowser, context);
}
else {
SetSilentJavascriptErrorsContext(webBrowser, null);
}
}
private class SilentJavascriptErrorsContext : IDisposable
{
private bool? _silent;
private readonly WebBrowser _webBrowser;
public SilentJavascriptErrorsContext(WebBrowser webBrowser)
{
_silent = new bool?();
_webBrowser = webBrowser;
_webBrowser.Loaded += OnWebBrowserLoaded;
_webBrowser.Navigated += OnWebBrowserNavigated;
}
private void OnWebBrowserLoaded(object sender, RoutedEventArgs e)
{
if (!_silent.HasValue) return;
SetSilent();
}
private void OnWebBrowserNavigated(object sender, NavigationEventArgs e)
{
var webBrowser = (WebBrowser)sender;
if (!_silent.HasValue) {
_silent = GetDisableJavascriptErrors(webBrowser);
}
if (!webBrowser.IsLoaded) return;
SetSilent();
}
/// <summary>
/// Solution by Simon Mourier on StackOverflow
/// https://dev59.com/um025IYBdhLWcg3wOzPX#6198700
/// </summary>
private void SetSilent()
{
_webBrowser.Loaded -= OnWebBrowserLoaded;
_webBrowser.Navigated -= OnWebBrowserNavigated;
// get an IWebBrowser2 from the document
var sp = _webBrowser.Document as IOleServiceProvider;
if (sp != null)
{
var IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
var IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");
object webBrowser2;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out webBrowser2);
if (webBrowser2 != null)
{
webBrowser2.GetType().InvokeMember(
"Silent",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.PutDispProperty,
null,
webBrowser2,
new object[] { _silent });
}
}
}
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IOleServiceProvider
{
[PreserveSig]
int QueryService([In] ref Guid guidService, [In] ref Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
}
public void Dispose()
{
if (_webBrowser != null) {
_webBrowser.Loaded -= OnWebBrowserLoaded;
_webBrowser.Navigated -= OnWebBrowserNavigated;
}
}
}
#endregion
}
}
MapUrl
是指什么?我完全按照你这里的实现方式进行了操作,包括MapUrl
绑定,一切都运行良好。但是我没有任何MapUrl
变量/对象存在,所以我想知道这到底是如何工作的 :) - Keven M@SimonMourier的回答对我没用,但是这个有用:
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 });
}
请注意,我是从这里获取的。
我还发现了一种有趣的方法来禁用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);
}
如果必要的话,我会选择WinformHost
并将WebBrowser控件添加到其中并使用它。
在这里,您也可以轻松完成这些任务,因为我已经制作了整个应用程序来执行许多任务。
/// <summary>
/// Gets an interop web browser.
/// </summary>
/// <param name="browser"></param>
/// <returns></returns>
public static SHDocVw.WebBrowser GetInteropWebBrowser(this WebBrowser browser)
{
Guid serviceGuid = new Guid("0002DF05-0000-0000-C000-000000000046");
Guid iid = typeof(SHDocVw.IWebBrowser2).GUID;
Interop.IServiceProvider serviceProvider = (Interop.IServiceProvider)browser.Document;
SHDocVw.IWebBrowser2 browser2 = (SHDocVw.IWebBrowser2)serviceProvider.QueryService(ref serviceGuid, ref iid);
SHDocVw.WebBrowser wb = (SHDocVw.WebBrowser)browser2;
return wb;
}
/// <summary>
/// Disables script errors for the browser.
/// </summary>
/// <param name="browser"></param>
/// <param name="silent"></param>
public static void SetSilent(this WebBrowser browser, bool silent)
{
SHDocVw.WebBrowser browser2 = browser.GetInteropWebBrowser();
if (browser2 != null)
browser2.Silent = silent;
}
/// <summary>
/// Provides the COM interface for the IServiceProvider.
/// </summary>
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
/// <summary>
/// Queries the service.
/// </summary>
/// <param name="serviceGuid"></param>
/// <param name="riid"></param>
/// <returns></returns>
[return: MarshalAs(UnmanagedType.IUnknown)]
object QueryService(ref Guid serviceGuid, ref Guid riid);
}
然后在承载浏览器控件的视图的构造函数中,您需要:
Browser.Navigated += (s, e) =>
{
Browser.SetSilent(true);
};
我想补充一下,我尝试了上述所有解决方案来尝试停止长时间运行的脚本错误(虽然它们并不声称能够这样做,但这是我能找到的最接近的问题)。发帖是为了提醒其他人是否有相同的“此页面上的脚本正在使您的浏览器运行缓慢”的问题。
我唯一发现有效的方法是设置注册表键,必须在创建浏览器之前设置。
var keyName = "HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\styles";
if(Registry.GetValue(keyName, "MaxScriptStatements", null) == null)
{
Registry.SetValue(keyName, "MaxScriptStatements", unchecked((int)0xffffffff), RegistryValueKind.DWord);
}
wbSample.Navigating += (s, e) =>
{
var fiComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
if (fiComWebBrowser == null)
return;
object objComWebBrowser = fiComWebBrowser.GetValue(wbSample);
if (objComWebBrowser == null)
return;
objComWebBrowser.GetType().InvokeMember("Silent", System.Reflection.BindingFlags.SetProperty, null, objComWebBrowser, new object[] { true });
};
这段代码对我有效。将其添加到构造函数中。
非常简单,感谢您的解决方案。
Dim sb As New StringBuilder
sb.Append("<html>")
sb.Append("<head>")
sb.Append("</head")
sb.Append("<body>")
sb.Append("<iframe src ='" + url + "' height='" + webBrowser1.Height + "' width='" + webBrowser1.Width + "'></iframe>")
sb.Append("</body")
sb.Append("</html>")
WebBrowser1.DocumentText = sb.ToString