Control WPF WebBrowser: cómo suprimir los errores de script

Encontré una pregunta similar aquí:

¿Cómo suprimo los errores de script cuando uso el control WPF WebBrowser?

Pero ninguna de esas soluciones funciona para mí. Necesito evitar que aparezcan las ventanas emergentes, ya que estoy usando WebBrowser para automatizar las tareas administrativas en un sitio web.

SuppressScriptErrors no parece ser un atributo disponible en mi WebControl 🙁

Aquí hay una rutina C # que es capaz de poner WebBrowser de WPF en modo silencioso. No puede invocarlo en la inicialización de WebBrowser ya que es demasiado pronto, pero en su lugar después de la navegación. Aquí hay una aplicación de ejemplo de WPF con un componente wbMain WebBrowser:

 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); } 

Pensé que sería relevante agregar aquí. Hay otra opción para acceder al control WebBorwser ActiveX Control de WPF WebBrowser y sus métodos y eventos inaccesibles. Acabo de descubrirlo hace unos días. Es muy simple y no requiere navegación inicial en WB:

 dynamic activeX = this.WB.GetType().InvokeMember("ActiveXInstance", BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, null, this.WB, new object[] { }); activeX.Silent = true; 

Por supuesto, existe la posibilidad de que este método no funcione en la versión futura del Framework, pero también es cierto sobre cualquier otro método no documentado. Hasta ahora, ha estado allí desde .NET 3.0. Más detalles con una muestra de código de trabajo aquí .

Gracias a Simon Mourier por la manera elegante de resolver este problema. Hice una pequeña mejora y encapsulé la solución de Simon en la propiedad adjunta.

En mi aplicación uso el control de WebBrowser databounded to viewmodel, el webbrowser puede estar oculto en TabItem inactivo, así que tengo que verificar que se haya cargado y navegado antes de configurar silencios de JavaScript. Y por supuesto, esta configuración debe hacerse solo una vez, así que después de configurar, libero eventos enganchados.

Código XAML:

  ...     

Código de comportamiento:

 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(); } ///  /// Solution by Simon Mourier on StackOverflow /// http://stackoverflow.com/a/6198700/741414 ///  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 } } 

La respuesta de @SimonMourier no funcionó para mí, pero esto hizo:

 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 }); } 

Tenga en cuenta que lo tengo desde aquí .

También encontré una forma interesante de deshabilitar los errores de JavaScript. Pero debe usar al menos .Net Framework 4.0 debido a que utiliza un tipo dynamic elegante.

Debe suscribirse al evento LoadCompleted del elemento WebBrowser:

  

Después de eso, debe escribir un controlador de eventos que se ve a continuación:

  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); } 

Puede ver mi solución: Deshabilitar los errores de JavaScript en el control WebBrowser en Silverlight : es para Silverlight pero también debería funcionar para WPF.

Bueno, si fuera necesario, habría WinformHost por WinformHost añadido WebBrowser Control y lo WinformHost utilizado.

Puede hacer fácilmente esas tareas aquí en WinformHost también porque he hecho aplicaciones completas que hacen un conjunto de cosas

Aquí hay un ejemplo de cómo hacer esto sin usar la reflexión.

  ///  /// Gets an interop web browser. ///  ///  ///  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; } ///  /// Disables script errors for the browser. ///  ///  ///  public static void SetSilent(this WebBrowser browser, bool silent) { SHDocVw.WebBrowser browser2 = browser.GetInteropWebBrowser(); if (browser2 != null) browser2.Silent = silent; } ///  /// Provides the COM interface for the IServiceProvider. ///  [ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IServiceProvider { ///  /// Queries the service. ///  ///  ///  ///  [return: MarshalAs(UnmanagedType.IUnknown)] object QueryService(ref Guid serviceGuid, ref Guid riid); } 

Luego, en el constructor de la vista que aloja el control del navegador, tiene:

  Browser.Navigated += (s, e) => { Browser.SetSilent(true); }; 

Realmente muy simple, gracias por tu solución.

http://social.msdn.microsoft.com/Forums/en-US/6996b0c5-b44d-4040-9dbe-6206b1d9185e/webbrowser-script-error-when-using-google-maps?forum=wpf&prof=required


 Dim sb As New StringBuilder sb.Append("") sb.Append("") sb.Append("") sb.Append("") sb.Append("") WebBrowser1.DocumentText = sb.ToString