Silverlight and JavaScript Interop Basics
I’ve been looking into Silverlight in my spare time a bit, to see what it has to offer, and the JavaScript “Interop” is actually pretty neat and simple to use. About three months ago I wrote a post titled “Working with HTML DOM in Silverlight using the Bridge Pattern”; so I think this time I’ll go over some of the basics involved with communicating back and forth between Silverlight and JavaScript. This article is written by referencing Silverlight 2 Beta 2, but should still hold relevent in the final release of Silverlight 2. ## Call a JavaScript Methods from within Silverlight
1) Using the Eval method
Silverlight does expose the JavaScript Eval method, so you can use it to call some JavaScript in the page
Here’s a couple examples of calling Eval from in Silverlight: <pre class="csharpcode">using System.Windows.Browser;
// set a global variable HtmlPage.Window.Eval(“myJSObject = 2;”);
// invoke a global method HtmlPage.Window.Eval(“myJSMethod();”);</pre>
One thing to keep in mind with using Eval, even from Silverlight, is you can potentially open yourself up to script injection vulnerabilities. Instead of using Eval, you should use Invoke, which is my next example.
2) Using the Invoke method
You can use the Invoke method to execute some global JavaScript method within your page.
Here’s a couple examples, one without arguments, the other passing in two arguments:
using System.Windows.Browser; // Call a global method without passing in arguments HtmlPage.Window.Invoke("myJSMethod"); // Call a global method, pass in two arguments // First argument is a string // Second argument is an integer HtmlPage.Window.Invoke("myJSMethod", "Chris", 42);
Returning Values From JavaScript Method Calls
Now that we’ve covered how to execute JavaScript methods from Silverlight, I’ll show how to captures values that are returned from those method call.
Both the Eval and Invoke methods return an Object. The Object returned is a reference to the JavaScript object that is returned from the method call. To get at the returned value the Object needs to be cast into the appropriate data type.
Here’s some examples of casting the ScriptObject to different data types to return different data types from JavaScript methods:
// Returning a Double double doubleValue = (double)HtmlPage.Window.Invoke("myJSMethod"); // Returning a String string stringValue = (string)HtmlPage.Window.Invoke("myJSMethod");
One thing to always rememer when casting the object returned to a specific data type, is to check for NULL before casting, just to make sure a value was returned.
Returning Objects From JavaScript Method Calls and Accessing Its Methods and Properties
You can also pass back Objects to Silverlight from your JavaScript methods calls. Instead of casting the object returned from the Eval or Invoke method call to a double, string or any other data type; you’ll need to cast it to a ScriptObject. ScriptObject is basically the data type used for a “general” JavaScript object.
// Execute the global JavaScript method and cast it to ScriptObject ScriptObject myScriptObject = (ScriptObject)HtmlPage.Window.Invoke("myJSMethod");
**1) Accessing the ScriptObjects Properties **
You can access the properties of the ScriptObject using the GetProperty method, then you must cast it to the appropriate data type.
// Get a Double Property value from our ScriptObject double doubleValue = (double)myScriptObject.GetProperty("DoubleValue"); // Get a String Property value from our ScriptObject double stringValue = (string)myScriptObject.GetProperty("StringValue");
2) Invoke one of the ScriptObjects Methods
The ScriptObject has an Invoke method that works just like the HtmlPage.Window.Invoke method shown above.
// Invoke a method that doesn't return a value myScriptObject.Invoke("myMethod"); // Invoke a method that returns a string value, and pass in some arguments string stringValue = myScriptObject.Invoke("myMethod", "Chris", 42);
Here’s the JavaScript code that defines an object that has the properties and method show above:
var myJSObject = function(){ this.DoubleValue = 42; this.StringValue = "Chris"; }; myJSObject.prototype.myMethod = function(arg1, arg2){ return "Chris"; };
Call Silverlight Methods From JavaScript
You can also call Silverlight methods from within JavaScript and return values from them.
1) Setup your Silverlight object as Scriptable
In order to interact with a Silverlight object from within JavaScript, it must be marked with the ScriptableType attribute, and any methods you want to expose need to be marked with the ScriptableMember attribute. Also, you must register the object as Scriptable in the page once the page loads, and give the object an alias that will be used to reference it within JavaScript.
Here’s a sample of a page that exposes a method to be called from JavaScript:
[ScriptableType] public partial class Page : UserControl { public Page() { InitializeComponent(); this.Loaded += new System.Windows.RoutedEventHandler(Page_Loaded); } void Page_Loaded(object sender, System.Windows.RoutedEventArgs e) { // Register this object in the page as Scriptable // so it can be access from within JavaScript HtmlPage.RegisterScriptableObject("myObject", this); } [ScriptableMember] public double GetDoubleValue() { // return a double return (double)42; } }
2) Write your JavaScript code
When writing your JavaScript code, you need to get a reference to the Silverlight Plugin in the page, so you can call methods on your Silverlight object.
Here’s a small example of doing this with a JavaScript method that calls the Silverlight method wired up to be fired on click of a button. In this example I’m using ASP.NET and the ASP.NET Silveright control.
<%@ Page Language="C#" AutoEventWireup="true" %> <%@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls" TagPrefix="asp" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;"> <head runat="server"> <title>Test Page For SilverlightJavaScriptInteropArticleCode</title> <script type="text/javascript"> function callGetDoubleValue() { // Get a reference to the Silverlight Plugin // Since we're using the ASP.NET Silverlight control // we can use $find with the controls ClientID to get // a reference to it var pluginObject = $find("<%=Xaml1.ClientID%>"); // Get a reference to the actual Silverlight // plugin element within the page var plugin = pluginObject.get_element(); // Call the GetDoubleValue method of our Silverlight object // notice we are referencing the object by the name of "myObject", that we setup // in Silverlight when we registered the object as Scriptable var dbl = plugin.Content.myObject.GetDoubleValue(); // Display the value to the user in an alert box alert(dbl); } </script> </head> <body style="height:100%;margin:0;"> <form id="form1" runat="server" style="height:100%;"> <input type="button" value="test" onclick="callGetDoubleValue();" /> <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager> <div style="height:100%;"> <asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/SilverlightJavaScriptInteropArticleCode.xap" MinimumVersion="2.0.30523" Width="100%" Height="100%" /> </div> </form> </body> </html>
Return Objects From Silverlight Method Calls To JavaScript
You can also return more complex object references to JavaScript from Silverlight method calls. One thing to remember, when returning objects from a Silverlight method call to JavaScript, is they need to be marked as Scriptble using the ScriptableType attribute, and the member (properties and methods) you want to expose must be marked with the ScriptableMember attribute.
Here’s an example method to be called by JavaScript that returns an object type that is marked as Scriptable:
[ScriptableMember] public myObject GetObjectValue() { myObject o = new myObject(); o.Name = "Chris"; return o; } [ScriptableType] public class myObject { [ScriptableMember] public string Name { get; set; } [ScriptableMember] public string GetName() { return this.Name; } }
Here’s the simple JavaScript (based on the other example above) to call the method and access the returned objects properties and methods:
// Call the method and get the returned object var obj = plugin.Content.myObject.GetObjectValue(); // Get the value of a property of the returned object var strName = obj.Name; // Get the returned value of a method of the returned object var strName = obj.GetName();
Conclusion
The JavaScript interop in Silverlight is fairly simple to use, however the ability to call Silverlight from JavaScript was a little tricky for me at first, mostly due to how few Silverlight articles are out there. I hope this helps you get your JavaScript code (new or existing) working along-side Silverlight in a friendly fashion.
Also, here’s a couple related posts I’ve written during the last couple months. The were written with Silverlight 2 Beta 1 as reference, but they still hold relevent with Beta 2.
Working with HTML DOM in Silverlight 2 Beta 1 using the Bridge Pattern
Show a MessageBox in Silverlight 2 Beta 1
Silverlight: Load JavaScript from Embedded Resource and Execute Within Page