Chris Pietschmann

husband, father, hacker, entrepreneur, futurist, innovator, autodidact

NAVIGATION - SEARCH

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:

using System.Windows.Browser; 

// set a global variable
HtmlPage.Window.Eval("myJSObject = 2;"); 

// invoke a global method
HtmlPage.Window.Eval("myJSMethod();");

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%;">

        <!-- The button that calls the js method above -->
        <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

blog comments powered by Disqus