Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle WPF WebBrowser control navigation exception

Tags:

c#

.net

wpf

Let's say that WPF WebBrowser control shows some navigation errors and the page is not showing.

So there is an exception of WPF WebBrowser control.

I found some similar questions here but it is not what I need.

In fact, I need some method and object that has an exception to get it somehow.

How do we can handle it?

Thank you!

P.S. There is some approach for WinForm WebBrowser Control... Can we do something similar to WPF WebBrowser control?

public Form13()
{
     InitializeComponent();

     this.webBrowser1.Navigate("http://blablablabla.bla");

      SHDocVw.WebBrowser axBrowser = (SHDocVw.WebBrowser)this.webBrowser1.ActiveXInstance;
      axBrowser.NavigateError +=
           new SHDocVw.DWebBrowserEvents2_NavigateErrorEventHandler(axBrowser_NavigateError);
}

void axBrowser_NavigateError(object pDisp, ref object URL,
       ref object Frame, ref object StatusCode, ref bool Cancel)
{
     if (StatusCode.ToString() == "404")
     {
         MessageBox.Show("Page no found");
     }
}

P.S. #2 To host WinForm WebBrowser control under WPF App is not an answer I think.

like image 778
Friend Avatar asked Sep 06 '12 12:09

Friend


4 Answers

I'd been struggling with this issue for some time. I discovered a cleaner way to handle this than the accepted answer. Checking for res://ieframe.dll didn't always work for me. Sometimes the document url is null when a navigation error happened.

Add the following References to you project:

  1. Microsoft.mshtml
  2. Microsoft.VisualStudio.OLE.Interop
  3. SHDocVw (Under COM it's called "Microsoft Internet Controls")

Create the following helper class:

using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Windows.Controls;
using System.Windows.Navigation;

/// <summary>
/// Adds event handlers to a webbrowser control
/// </summary>
internal class WebBrowserHelper
{
    [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:FieldNamesMustNotContainUnderscore", Justification = "consistent naming")]
    private static readonly Guid SID_SWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");

    internal WebBrowserHelper(WebBrowser browser)
    {
        // Add event handlers
        browser.Navigated += this.OnNavigated;

        // Navigate to about:blank to setup the browser event handlers in first call to OnNavigated
        browser.Source = null;
    }

    internal delegate void NavigateErrorEvent(string url, int statusCode);

    internal event NavigateErrorEvent NavigateError;

    private void OnNavigated(object sender, NavigationEventArgs e)
    {
        // Grab the browser and document instance
        var browser = sender as WebBrowser;
        var doc = browser?.Document;

        // Check if this is a nav to about:blank
        var aboutBlank = new Uri("about:blank");
        if (aboutBlank.IsBaseOf(e.Uri))
        {
            Guid serviceGuid = SID_SWebBrowserApp;
            Guid iid = typeof(SHDocVw.IWebBrowser2).GUID;

            IntPtr obj = IntPtr.Zero;
            var serviceProvider = doc as Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
            if (serviceProvider?.QueryService(ref serviceGuid, ref iid, out obj) == 0)
            {
                // Set up event handlers
                var webBrowser2 = Marshal.GetObjectForIUnknown(obj) as SHDocVw.IWebBrowser2;
                var webBrowserEvents2 = webBrowser2 as SHDocVw.DWebBrowserEvents2_Event;
                if (webBrowserEvents2 != null)
                {
                    // Add event handler for navigation error
                    webBrowserEvents2.NavigateError -= this.OnNavigateError;
                    webBrowserEvents2.NavigateError += this.OnNavigateError;
                }
            }
        }
    }

    /// <summary>
    /// Invoked when navigation fails
    /// </summary>
    [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "consistent naming")]
    [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "consistent naming")]
    private void OnNavigateError(object pDisp, ref object URL, ref object Frame, ref object StatusCode, ref bool Cancel)
    {
        this.NavigateError.Invoke(URL as string, (int)StatusCode);
    }
}

Then in your window class:

// Init the UI
this.InitializeComponent();
this.WebBrowserHelper = new WebBrowserHelper(this.MyBrowserPane);

// Handle nav error
this.WebBrowserHelper.NavigateError += this.OnNavigateError;
like image 170
cppguy Avatar answered Oct 30 '22 18:10

cppguy


It's an old question but since I have just suffered through this, I thought I may as well share. First, I implemented Markus' solution but wanted something a bit better as our Firewall remaps 403 message pages.

I found an answer here (amongst other places) that suggests using NavigationService as it has a NavigationFailed event.

In your XAML, add:

<Frame x:Name="frame"/>

In your code-behind's constructor, add:

frame.Navigated += new System.Windows.Navigation.NavigatedEventHandler(frame_Navigated);
frame.NavigationFailed += frame_NavigationFailed;
frame.LoadCompleted += frame_LoadCompleted;

frame.NavigationService.Navigate(new Uri("http://theage.com.au"));

The handlers can now deal with either a failed navigation or a successful one:

void frame_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
{
  e.Handled = true;
  // TODO: Goto an error page.
}

private void frame_Navigated(object sender,  System.Windows.Navigation.NavigationEventArgs e)
{
  System.Diagnostics.Trace.WriteLine(e.WebResponse.Headers);
}

BTW: This is on the .Net 4.5 framework

like image 26
dave Avatar answered Oct 30 '22 17:10

dave


I'm struggling with a similar problem. When the computer loses internet connection we want to handle that in a nice way.

In the lack of a better solution, I hooked up the Navigated event of the WebBrowser and look at the URL for the document. If it is res://ieframe.dll I'm pretty confident that some error has occurred.

Maybe it is possible to look at the document and see if a server returned 404.

private void Navigated(object sender, NavigationEventArgs navigationEventArgs)
{
    var browser = sender as WebBrowser;
    if(browser != null)
    {
        var doc = AssociatedObject.Document as HTMLDocument;
        if (doc != null)
        {
            if (doc.url.StartsWith("res://ieframe.dll"))
            {
                // Do stuff to handle error navigation
            }
        }
    }
}
like image 37
Markus Avatar answered Oct 30 '22 16:10

Markus


It is also possible to use dynamic approach here.

wb.Navigated += delegate(object sender, NavigationEventArgs args)
        {
            dynamic doc = ((WebBrowser)sender).Document;
            var url = doc.url as string;
            if (url != null && url.StartsWith("res://ieframe.dll"))
            {
                // Do stuff to handle error navigation
            }
        };
like image 45
Maxim Avatar answered Oct 30 '22 16:10

Maxim