WPF WebBrowser control - как подавить ошибки скрипта?
Я нашел аналогичный вопрос здесь:
как подавить ошибки скрипта при использовании элемента управления WPF WebBrowser?
но не из этих решений работают для меня. Мне нужно, чтобы остановить всплывающие окна от появления, как я использую WebBrowser для автоматизации задач администрирования на сайте.
SuppressScriptErrors не представляется доступным атрибутом на моем WebControl : (
9 ответов:
вот процедура C#, которая способна помещать WPF
WebBrowserв беззвучный режим. Вы не можете вызвать его при инициализации WebBrowser, так как это слишком рано, но вместо этого после навигации произошло. Вот пример на WPF приложения с компонентом WebBrowser элемент wbMain: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); }
подумал, что было бы уместно добавить здесь. Есть еще один вариант добраться до WPF WebBrowser лежит в основе WebBorwser Управления ActiveX и его недоступных методы и событий. Я обнаружил это несколько дней назад. Это очень просто и не требует начальной навигации по WB:
dynamic activeX = this.WB.GetType().InvokeMember("ActiveXInstance", BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, null, this.WB, new object[] { }); activeX.Silent = true;конечно, есть шанс, что этот метод может не работать в будущих версиях платформы, но так можно сказать о любой другой недокументированный метод. До сих пор он был там с .NET 3.0. Подробнее с рабочим примером кода здесь.
спасибо Симону Мурье за элегантный способ решить эту проблему. Я сделал небольшое улучшение и инкапсулировал решение Саймона в прикрепленное свойство.
в моем приложении я использую элемент управления WebBrowser databounded в модель представления, в данной статье может быть скрыта на tabitem в не активен, так что я должен проверить, что это был загружается и переход перед установкой ошибок javascript молчит. И, конечно же, эта настройка должна быть выполнена только один раз, поэтому после установки I отпустите подключенные события.
код 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 /// http://stackoverflow.com/a/6198700/741414 /// </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 } }
ответ @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 }); }обратите внимание, что я получил его от!--4-->здесь.
Я вот тоже нашел интересный способ, чтобы отключить сообщения об ошибках JavaScript. Но вам нужно использовать хотя бы .Net Framework 4.0 из-за использования элегантного динамического типа.
вам необходимо подписаться на событие LoadCompleted элемента WebBrowser:
<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); }
вы можете посмотреть на мое решение: отключение ошибок JavaScript в элементе управления WebBrowser в Silverlight - это для Silverlight, но также должно работать для WPF.
Ну если бы это было необходимо я бы пошел за
WinformHostи добавил к нему элемент управления WebBrowser и использовал его.вы можете легко сделать эти задачи здесь в
WinformHostтакже потому, что я сделал целые приложения, которые делают кучу вещей
вот пример, как это сделать без использования отражения.
/// <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); };
действительно очень просто, спасибо за решение.
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
Comments