// This event is fired when a navigation or loading of a resource, has failed.
        // This event will also be fired for navigations blocked by the NavigationInterceptor
        // or an IResourceInterceptor, and the error code in this case will be: ABORTED.
        private void webControl_LoadingFrameFailed(object sender, LoadingFrameFailedEventArgs e)
        {
            if (!webControl.IsLive)
            {
                return;
            }

            if (e.IsMainFrame && (e.ErrorCode == NetError.ABORTED))
            {
                // This condition usually indicates a navigation blocked by the INavigationInterceptor
                // or an IResourceInterceptor. For this example, we add an additional check, to be sure.

                // Get the NavigationInterceptor service.
                INavigationInterceptor navigationInterceptor = webControl.GetService(typeof(INavigationInterceptor)) as INavigationInterceptor;

                // Check if this URL is actually blocked by the NavigationInterceptor service.
                if ((navigationInterceptor != null) && (navigationInterceptor.GetRule(e.Url.AbsoluteUri) == NavigationRule.Deny))
                {
                    // You can display your error message anyway you want, here.
                    Debug.Print(String.Format("Navigation to {0} was blocked.", e.Url));
                }
                else
                {
                    // You can display your error message anyway you want, here.
                    Debug.Print(String.Format("Navigation to {0} was aborted.", e.Url));
                }
            }
        }
        // This event is fired right when IsLive is set to true.
        private void webControl_NativeViewInitialized(object sender, WebViewEventArgs e)
        {
            if (!webControl.IsLive)
            {
                return;
            }

            // Acquire the NavigationInterceptor service. Navigation events (available through this interceptor)
            // are fired on the I/O thread.
            INavigationInterceptor navigationInterceptor = webControl.GetService(typeof(INavigationInterceptor)) as INavigationInterceptor;

            if (navigationInterceptor == null)
            {
                return;
            }

            // Add a handler for the BeginNavigation event. This will allow us
            // to explicitly cancel navigations.
            navigationInterceptor.BeginNavigation += OnBeginNavigation;
            // Declare a filtering rule. This accepts wildcards. In this example,
            // we deny navigations to any Google site. Note that this will not
            // prevent the initial loading of the WebControl; the value defined
            // to Source at design-time, will always be loaded. After the program
            // starts, try to navigate to any of the other Google services (Images, Mail etc.).
            navigationInterceptor.AddRule(@"http?://*.google.com/*", NavigationRule.Deny);
        }
            public JavascriptCallbackState(INavigationInterceptor navigationInterceptor, JSObject callback, object data, int timeout)
            {
                this.callback = callback;
                this.data     = data;

                cts = new CancellationTokenSource();
                cts.Token.Register(OnCanceled);

                this.navigationInterceptor             = navigationInterceptor;
                navigationInterceptor.BeginNavigation += OnNavigation;

                timer = new Timer(OnTimeout, null, timeout, Timeout.Infinite);
            }
            protected virtual void OnDispose(bool disposing)
            {
                lock ( SyncRoot )
                {
                    // To avoid race conditions, the first to
                    // be disposed must be the timer...
                    if (timer != null)
                    {
                        timer.Dispose();
                    }

                    timer = null;

                    // .. and then remove the event handler
                    // for the same reason.
                    if (disposing)
                    {
                        GC.SuppressFinalize(this);

                        if (navigationInterceptor != null)
                        {
                            navigationInterceptor.BeginNavigation -= OnNavigation;
                        }

                        navigationInterceptor = null;

                        if (cts != null)
                        {
                            cts.Dispose();
                        }

                        cts = null;

                        if (callback != null)
                        {
                            callback.Dispose();
                        }

                        callback = null;
                    }
                }
            }
        // Handler of the external.app.performHeavyWork method.
        private void OnWork(object sender, JavascriptMethodEventArgs e)
        {
            // Must have 2 arguments passed.
            if (e.Arguments.Length != 3)
            {
                return;
            }

            // Must be a function object.
            if (!e.Arguments[0].IsFunctionObject)
            {
                return;
            }

            // Must be a timeout value.
            if (!e.Arguments[1].IsNumber)
            {
                return;
            }

            // Must be the image id.
            if (!e.Arguments[2].IsNumber)
            {
                return;
            }

            // Get the NavigationInterceptor. This will allow us to cancel the operation
            // if the user navigates away.
            INavigationInterceptor navigationInterceptor = webControl.GetService(typeof(INavigationInterceptor)) as INavigationInterceptor;

            // Without this, do not proceed.
            if (navigationInterceptor == null)
            {
                return;
            }

            // You can cache the callback and call it only when your application
            // has performed all work necessary and has a result ready to send.
            // Note that this callback object is valid for as long as the current
            // page is loaded; a navigation will invalidate it. This is why we
            // need the NavigationInterceptor service acquired above.
            JSFunction callbackArg = e.Arguments[0];
            // Get the image id.
            int id = (int)e.Arguments[1];
            // Get the timeout specified.
            int timeout = (int)e.Arguments[2];

            // Make sure it's a function object.
            if (!callbackArg)
            {
                return;
            }

            // See it!
            Debug.Print(callbackArg.ToString());

            // You need to copy the object if you intend to cache it. The original
            // object argument passed to the handler is destroyed by default when
            // the handler returns. A copy will keep it alive. Note that the clone
            // of a JSFunction, will definitely be a JSFunction as well.
            JSFunction callback = (JSFunction)callbackArg.Clone();

            // Create a state object. This holds the callback and controls
            // cancellation. It is passed to both the background operation procedure
            // and the response procedure.
            JavascriptCallbackState state = new JavascriptCallbackState(navigationInterceptor, callback, id, timeout);

            // Perform your heavy work.
            Task.Factory.StartNew(
                /* The function that will perform the work. */
                (Func <Object, String>)PerformWork,
                /* Pass the state object. */
                state,

                /* The CancellationToken that will let us know if we
                 * should cancel passing back the result. */
                state.Token).ContinueWith(
                /* Send the result when complete. */
                SendResponse,

                /* Make sure the result is sent on the
                 * initial thread. */
                TaskScheduler.FromCurrentSynchronizationContext());
        }