Как подавить ошибки сценария при использовании элемента управления WPF WebBrowser?

У меня есть приложение WPF, которое использует элемент управления WPF WebBrowser для отображения интересных веб-страниц для наших разработчиков на плоском экране (например, в ленте новостей).

Проблема в том, что я иногда получаю ошибку сценария HTML, которая выскакивает неприятное сообщение об ошибке IE с вопросом, не хочу ли я «остановить выполнение сценариев на этой странице». Есть ли способ подавить эту проверку ошибок?

ПРИМЕЧАНИЕ. Я уже отключил отладку скриптов в настройках IE.


person willem    schedule 19.08.2009    source источник
comment
Еще одно двухстрочное решение находится здесь: stackoverflow.com/a/18289217/1768303   -  person noseratio    schedule 07.11.2013


Ответы (9)


Проблема здесь в том, что WPF WebBrowser не реализовал это свойство, как в элементе управления 2.0.

Лучше всего использовать WindowsFormsHost в приложении WPF и использовать свойство WebBrowser 2.0: SuppressScriptErrors. Даже в этом случае для этого вам понадобится приложение, которое будет полностью доверять.

Не то, что можно было бы назвать идеальным, но в настоящее время это практически единственный вариант.

person Kyle Rosendo    schedule 26.08.2009
comment
Теперь у меня есть еще один аргумент против этих винформеров. Слишком много not-possible - person C4d; 14.06.2016

Вот решение, которое я только что сделал с отражением. Решает проблему :) Я запускаю его в событии Navigated, так как до тех пор кажется, что объект activeX недоступен.

Он устанавливает свойство .Silent для базового объекта ActiveX. Это то же самое, что и свойство .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.

person Wolf5    schedule 06.07.2010
comment
+1 Спасибо за это - мне действительно не нравились накладные расходы на использование WindowsFormsHost для получения этой функциональности, и ваш код, похоже, достойно справляется со своей работой. - person Sheridan; 05.09.2011
comment
Как добавить это к объекту веб-браузера? - person MonsterMMORPG; 16.03.2012
comment
var wb = новый WebBrowser (); wb.Navigated + = (a, b) = ›{HideScriptErrors (wb, true); }; Нужно запустить это только один раз, но вы уловили идею. Вы не можете установить свойство, пока не будет запущено событие Navigated. - person Wolf5; 12.04.2012
comment
Инновационный! Спасибо! - person Rich; 26.10.2015
comment
молодец! как ты мог это разобрать :) - person Boppity Bop; 26.10.2020

Только что найдено в другом вопросе, это элегантно и отлично работает.

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

activeX.Silent = true;
person Carol    schedule 29.01.2016
comment
Я поместил это в событие WebBrowser_OnNavigating, и он работает! +1 - person Mike Keskinov; 17.08.2017

Я также нашел интересный способ отключить ошибки 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);
    }
person Ashot Muradian    schedule 11.02.2015
comment
В моем случае код, который мне пришлось исправить, создает полную разметку как MemoeryStream и передает ее браузеру с помощью NavigateToStream. Решением было просто добавить функцию window.onerror, которая молча обрабатывает ошибку. Спасибо @Ashot Muradian - person pasx; 13.04.2016
comment
В 99% случаев трюка с ActiveX было достаточно, и он работал, но у меня был один случай и только один случай, когда это был единственный вариант скрытия ошибок JS. СПАСИБО! - person Edi; 24.10.2019

Я хотел добавить это в качестве комментария к ответу @Alkampfer, но у меня недостаточно репутации. Это работает для меня (Windows 8.1, NET 4.5):

 window.Browser.LoadCompleted.Add(fun _ -> 
    window.Browser.Source <- new System.Uri("javascript:window.onerror=function(msg,url,line){return true;};void(0);"))

Этот пример кода написан на F #, но довольно ясно, что он делает.

person alexb    schedule 13.02.2015

У меня была эта проблема в прошлом, и я, наконец, решил ее с помощью инъекции сценария Javascript, который подавляет обработку ошибок. Надеюсь, это тоже поможет тебе.

Отключить Ошибки Javascript в WEbBrowsercontrol

person Alkampfer    schedule 31.08.2010
comment
На самом деле у меня он работает с 8.1 и 4.5 в производственной программе, но код, вероятно, изменился по сравнению с этим примером. Если вам интересно, я могу попробовать проверить новый код и сделать обновленный пост. - person Alkampfer; 23.08.2014

Проверьте приведенный ниже код для подавления ошибок скрипта для управления браузером WPF ..

    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 с хостом winforms .. у вас есть свойство "SuppressScriptErrors", для которого установлено значение true

    <WindowsFormsHost Name="WinformsHost" Grid.Row="1">
    <winForms:WebBrowser x:Name="WebBrowserControlView" ScriptErrorsSuppressed="True" AllowWebBrowserDrop="False"></winForms:WebBrowser>
</WindowsFormsHost>
person Darey    schedule 06.11.2013
comment
При копировании существующего кода следует обращаться к исходному сообщению. - person noseratio; 07.11.2013

ты можешь использовать этот трюк

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)
person Mwaffak Jamal Zakariya    schedule 28.04.2012

Ответ Wolf5 хорош, но 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 после первого раза, так как элемент управления может быть выгружен и загружен снова несколько раз, если он станет невидимым путем переключения на другую вкладку. Также резервный вариант if (!wb.Loaded)) по-прежнему важен, когда WebBrowser еще не отображается при первой навигации, например если он находится на другой вкладке, которая не отображается при запуске приложения.

person Kim Homann    schedule 13.04.2021