c# .net wpf webbrowser-control

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



.net webbrowser-control (9)

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 un ejemplo de cómo hacer esto sin usar la reflexión.

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

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

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


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


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


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:

<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>

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(); } /// <summary> /// Solution by Simon Mourier on /// http://.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 } }


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 here .


Pensé que sería relevante agregar aquí. Hay otra opción para acceder al control WebBorwser ActiveX Control de WPF WebBrowser y sus methods y events 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 here .



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("<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


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 dinámico elegante.

Debe suscribirse al evento LoadCompleted del elemento WebBrowser:

<WebBrowser x:Name="Browser" LoadCompleted="Browser_OnLoadCompleted" />

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