How can I trigger JavaScript to execute after a Silverlight applet loads? - javascript

I am working on a project where I have a lot of interaction between JavaScript and managed code. In fact, I need the JS application to interface with the Silverlight application in the page right from the beginning. So I need the Silverlight application to load before the JS code gets executed.
But while doing so, most of the times I get the error that the object was not found as the Silverlight application has not yet been loaded. So I need the Silverlight to load before the JS executes.
Is there a way I can put a stop on the JS application until the Silverlight loads and then start executing?

First, you need to add an event handler to the Loaded event of your app, from that event handler you can call the javascript function like this:
using System.Windows.Browser;
namespace SilverlightApplication3
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
HtmlPage.Window.CreateInstance("SomeFunction", new string[] { "parameter1", "parameter2" });
}
}
}
Note that you need the System.Windows.Browser namespace to use HtmlPage

Related

Trigger an event in javascript inside WebView from Windows Runtime Component

I am looking for a way to trigger a custom event in javascript from C# code written in a Windows Runtime Component with the AllowForWeb Attribute.
I know that the other way around works (triggering an event from javascript to C#) like this
public delegate void NotifyAppHandler( string str );
[AllowForWeb]
public sealed class WebViewInjectionObject
{
public event NotifyAppHandler OnNotifyApp;
public void NotifyApp( string str )
{
OnNotifyApp?.Invoke( str );
}
}
You can then subscribe to the event in C# and trigger it from javascript like this
nativeObject.notifyApp(JSON.stringify(callInfo));
Where nativeObject has been injected into the WebView with AddWebAllowedObject
Now I am looking for a solution to do the opposite.
I want to create an event in javascript and trigger it from C# using again the injected object from the Windows Runtime Component.
You can assume that I have control over the javascript code that will run in the WebView and can make changes there if required.
Note: The need to do this quite unorthodox thing arises from the fact that I cannot use/don't want to use InvokeScriptAsync due to this issue

Closing a webpage running in a WPF WebBrowser

First a bit of background
I'm working on a Web application, that will be running within a WebBrowser, within a WPF application.
This is a temporary necessity while we're gradually moving functionality to the web app. As long as that's not finished, the WPF client is still needed. Ultimately the WPF client will phase out completely.
Now to the issue at hand
When the user closes the client (webpage), the webbrowser should catch that event and also close the window it is a child to.
I found this link describing what I would need: WebBrowser and javascript window.close()
Alas, I don't think the answer described there would still work, as it's not possible to even do a window.close(), because I'm not the one opening the window I'm running on. Browsers have (rightfully) tightened their security since then.
The question
Is there a way to trigger a Window close from the client, that bubbles up to the WPF?
Thanks.
I have used a WebBrowser control to call methods in a WPF application from the JavaScript before using WebBrowser.InvokeScript and WebBrowser.ObjectForScripting
See this MSDN article How to: Implement Two-Way Communication Between DHTML Code and Client Application Code
Also see this CodeProject article which looks like it might solve your problem
Call a C# Method From JavaScript Hosted in a WebBrowser
[ComVisible(true)]
public class ScriptManager
{
// Variable to store the form of type Form1.
private Window _window;
// Constructor.
public ScriptManager(Window window)
{
// Save the form so it can be referenced later.
_window = window;
}
// This method can be called from JavaScript.
public void MethodToCallFromScript()
{
// Call a method on the form.
_window.Close();
}
}
from code behind of Window:
webBrowser1.ObjectForScripting = new ScriptManager(this);
That worked, thanks!
I did the following:
[ComVisible(true)]
public class ScriptManager
{
protected Window Window { get; set; }
public ScriptManager(Window window)
{
this.Window = window;
}
public void CloseWindow()
{
this.Window.Close();
}
}
And in my Window (Loaded Event):
// Build browser
this.Browser = new WebBrowser();
this.Browser.Navigate(this.GetUri());
this.Browser.ObjectForScripting = new ScriptManager(this);
The client Javascript then does:
$scope.Close = function() {
window.external.CloseWindow();
}

Pass and return the values from javascript and android and use as a phone gap plugin

I want to create a plugin for phone which pass and returns the value between javascript and android.
Can anybody suggest any ideas on how to do this?
Actually, this is not very difficult. Here, I will show you how to call native code from javascript within the page and vice-versa:
Calling native code from within web view:
When creating the web view add javascript interface (basically java class whose methods will be exposed to be called via javascript in the web view.
JavaScriptInterface jsInterface = new JavaScriptInterface(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInterface, "JSInterface");
The definition of the javascript interface class itself (this is exemplary class I took from another answer of mine and opens video in native intent)
public class JavaScriptInterface {
private Activity activity;
public JavaScriptInterface(Activity activiy) {
this.activity = activiy;
}
public void startVideo(String videoAddress){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(videoAddress), "video/3gpp"); // The Mime type can actually be determined from the file
activity.startActivity(intent);
}
}
Now if you want to call this code form the HTML of the page you provide the following method:
<script>
function playVideo(video){
window.JSInterface.startVideo(video);
}
</script>
Easy isn't it?
Calling javascript code from native code:
This is also simple suppose in the code of the HTML loaded in WebView you have javascript function defined:
<script>
function function(){
//... do something
}
</script>
Then you call this function through the WebView in the native code like that:
webView.loadUrl("javascript:function()");
Here's a tutorial for creating a PhoneGap Plugin. Also the instructions for the ChildBrowser plugin are especially good.

Registering a javascript method in GWT java code so that it can be invoked based on an event in GWT

I tried looking for a similar post but couldn't find any, hence posting this query for your help. Essentially, I have a custom UI created on the GWT side. Now, I want to send events occuring at the GWT side over to the javascript/jsp page. For this I was wondering if there's a way for the jsp/javascript to register a method in the GWT code, and whenever, any event happens at the GWT side, the GWT java code can simply invoke this javascript method (which is like a function pointer/object), and the information would be notified at the jsp page. Though I can directly call javascript methods from within the GWT code, however, that means that the GWT code also need to know the javascript method name, and this results in a tight coupling. Instead the javascript could simply pass in a handle to the function to the GWT code, which would simply invoke this handle to pass in necessary events on the jsp/javascript code. Any ideas would be very helpful.
You can use a Dictionary to pass the function name to your application.
In the JSP host page:
<script type="text/javascript">
function myFunction() {
// Do stuff...
}
var MyDictionary = {
myCallback = "myFunction"
};
</script>
And in your application:
public void onEvent(EventType event) {
Dictionary d = Dictionary.getDictionary("MyDictionary");
invokeNativeCallback(d.get("myCallback"));
}
private native void invokeNativeCallback(String callbackName) /*-{
if (typeof $wnd[callbackName] === "function") {
$wnd[callbackName]();
}
}-*/;

Javascript/Silverlight proxy double load delay

I am creating a Silverlight application which will be heavily javascripted against.
To enable JS interaction, I have created the following SL class:
[ScriptableType]
public class JavaScriptProxy
{
private string _version;
// provided for testing SL-JS integration
[ScriptableMember]
public void SmokeTest() { HtmlPage.Window.Alert("Hello world!"); }
}
And loaded it on the constructor of the main SL application:
public App()
{
this.Startup += this.onStartup;
this.Exit += this.Application_Exit;
this.UnhandledException += this.Application_UnhandledException;
InitializeComponent();
// register javascript bridge proxy
// (must register in constructor so proxy is available immediatly)
HtmlPage.RegisterScriptableObject("JsProxy", new JavaScriptProxy());
}
However, as this is a Javascript-heavy app, it must be loadable via javascript itself.
I.e. something alongs:
// called on body.onLoad
function init() {
var proxy;
var el = document.getElementById("target_canvas");
Silverlight.createObject(..., el, "agApp" ..., {
onLoad: function() {
proxy = agApp.Content.JsProxy;
// ***this line is ok***
proxy.SmokeTest();
}
});
// ***this line fails (of course)***
proxy.SmokeTest();
}
However, this raise the error because agApp.Content.JsProxy is not available fully until the Silverlight onLoad event is fired, thus the JsProxy field is unavailable.
How can I enable access to the JsProxy class immediately as I create the Silverlight instance? Some thing alongs while(_mutex); is probably a bad idea.
I had to this because there will be another layer of abstraction building on the creation of Silverlight app instances, so that function must synchronously load all SL contents in one go.
This is due to Silverlight and JavaScript are operating on seperate threads. Even though you've requested the browser to load the said Silverlight control, it doesn't wait around for Silverlight to finish loading before it proceeds to the next line.
You can only access the JS Proxy after Silverlight has instantiated it so you can either wait for the OnLoad event to fire (but this will only fire after the entire Silverlight.xap is fully loaded) that or after you RegisterScriptableObject fire a JavaScript method called onYourJSProxyNameLoaded() which will put you back inline with the workflow you desire.
HTH.
-
Scott Barnes / Rich Platforms Product Manager / Microsoft.

Categories