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