I'd like to answer on one of very frequent question I've been asked by great many developers, which playing with Silverlight v1.1 Alpha.
So, how one can execute managed code from JavaScript, and how JavaScript can get notification (event) from Silverlight (and possibly lunch some JavaScript functionality)?
Well, it's pretty simple. First, lets create Silverlight project (I'm using Visual Studio 2008 with Silverlight tools for Visual Studio 2008 installed).
Well... After creating the projects, let's do some coding... First of all, let's add some HTML button to out TestPage...
<input id="Button2" type="button" value="Test JavaScript to Silverlight Interoperability" onclick="JavaScriptToSilverlightInteroperability();"/>
In button "onclick" event I define call to some JavaScript function in my example I've called it "JavaScriptToSilverlightInteroperability".
Lets write such a function definition in JavaScript part of TestPage:
function JavaScriptToSilverlightInteroperability(sender, args)
{
}
Well... So far, so good. Now let's do some basic XAML editing... I'll add some TextBlock to my default Page.xaml and will change background... Here what I've got:
<Canvas x:Name="parentCanvas"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="Page_Loaded"
x:Class="Silverlight_JS_Interoperability.Page;assembly=ClientBin/Silverlight_JS_Interoperability.dll"
Width="640"
Height="480"
Background="LightSalmon"
>
<!--Some text block to enable some basic output-->
<TextBlock x:Name="txtMyText" Canvas.Left="10" Canvas.Top="10" Width="300" Height="25"/>
</Canvas>
Now it is a time to write some real code (C#)... I'll gonna add some class, which will be accessed from JavaScript, implement couple of functions and property, define some Event and fire it. Most important here, is that every part of managed code, which need to be accessed from JavaScript need to be decorated with [Scriptable] attribute:
Now this is my very simple class:
//Class which will be acessed by Javascript
[Scriptable]
public class ManagedClass
{
public ManagedClass()
{
//Registering class as "Scriptable" object to enable it being called from Javascript - will be used in Event firing from Silverlight to Javascript
WebApplication.Current.RegisterScriptableObject("ManagedClassInstance", this);
}
//Event definition
[Scriptable]
public event EventHandler CallbackToBrowser_SomeEvent;
//Some functions & Properties
[Scriptable]
public void VoidFunction(string Param1, string Param2)
{
//Some functionality here... For example updating textblock on XAML
Page.txtBlock.Text = Param1 + " " + Param2;
}
[Scriptable]
public int IntFunction(int Param)
{
//Firing event to Javascript
CallbackToBrowser_SomeEvent(this, new MyEventAtgs() { SomeValue = "This is test message from Silverlight event!" });
//Some functionality here....
return Param;
}
[Scriptable]
public int SomeProperty { set; get; }
}
Event arguments definition:
//Event arguments class - pretty simple here
public class MyEventAtgs : EventArgs
{
[Scriptable]
public string SomeValue {get; set;}
}
And finally, the main Page class:
public partial class Page : Canvas
{
//Class being called by Javascript - instanciation
ManagedClass managedClassExample = new ManagedClass();
static internal TextBlock txtBlock;
public void Page_Loaded(object o, EventArgs e)
{
// Required to initialize variables
InitializeComponent();
//Registering class as "Scriptable" object to enable it being called from Javascript
WebApplication.Current.RegisterScriptableObject("Silverlight_Test_Class", managedClassExample);
//simple access to XAML control to eneble class make some changes in Silverlight textblock
txtBlock = txtMyText;
}
}
Almost done... Pay attention, that instance of class, which I'm gonna access from JavaScript was initialized in page load event handler, and it was registered as "Scriptable object", which actually gives it access from JavaScript.
Now all I need to do, is actually access it from JavaScript and make JavaScript to "listen" to my CallbackToBrowser_SomeEvent event. Here is "JavaScriptToSilverlightInteroperability" function body:
function JavaScriptToSilverlightInteroperability(sender, args)
{
//Receives Silverlight control from document
var silverlightControl = document.getElementById("SilverlightControl").Content;
if (silverlightControl)
{
//Silverlight void function call example
silverlightControl.Silverlight_Test_Class.VoidFunction("Executed from", "HTML button click!");
//Silverlight property set example
silverlightControl.Silverlight_Test_Class.SomeProperty = 123;
//Silverlight function call with returned value example
var IntFunction = silverlightControl.Silverlight_Test_Class.IntFunction(12345);
alert("Got IntFunction return = " + IntFunction);
//Silverlight property get examples
alert("SomeProperty = " + silverlightControl.Silverlight_Test_Class.SomeProperty);
}
}
And here is plumbing needed to "connect" managed events to BLOCKED SCRIPT
1. In function "CreateSilverlight" add event handler, which give me an opportunity to do some work:
//contains calls to silverlight.js, example below loads Page.xaml
function createSilverlight()
{
Silverlight.createObjectEx({
source: "Page.xaml",
parentElement: document.getElementById("SilverlightControlHost"),
id: "SilverlightControl",
properties: {
width: "100%",
height: "100%",
version: "1.1",
enableHtmlAccess: "true"
},
events: {
onLoad: onLoaded //Execute function on Silverlight control load
}
});
2. Now, lets write this "onLoaded" function and write actual JavaScript event handler:
//Silverlight control OnLoaded event handler
function onLoaded(sender, args)
{
sender.Content.ManagedClassInstance.CallbackToBrowser_SomeEvent = OnAlertCallback;
}
//Function to handle Silverlight events
function OnAlertCallback(sender, args)
{
alert(args.SomeValue);
}
That's it... We done...
Let's lunch this project and click on HTML button:
Everything worked as planned - we got out managed code executed, updated XAML element from code, raised managed event and captured it in JavaScript.
And last, but not least, we able to debug out managed code while executing the project!!!
Hope this helps :)
Here is sources.
Enjoy,
Alex