private void OnWork(JSValue[] arguments) { // Must be a function object. if (!arguments[0].IsFunctionObject) { return; } // You can cache this 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. JSFunction callbackArg = arguments[0]; // 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(); // Perform your heavy work. Task.Factory.StartNew( (Func <object, string>)PerformWork, callback).ContinueWith( /* Send a response when complete. */ SendResponse, /* Make sure the response is sent on the * initial thread. */ TaskScheduler.FromCurrentSynchronizationContext()); }
// 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()); }