From Silverlight to Javascript and Back Again

The Scriptable Attributes

Where did he come from?

 

 

The Scriptable Attributes

We can call into Silverlight from Javascript using one technique, and a slightly different one for calling from Silverlight into Javascript. Both of them are based on marking classes and methods with .NET attributes.

Unfortunately we can't set attributes from IronPython, so we have to use a bit of C#. Fortunately we can create a stub-class, and then subclass from IronPython. The C# is simple enough that, even if you have never seen C# before, you should be able to understand it.

The Scriptable attributes lives in the System.Windows.Browser namespace. C# can be compiled using Visual Studio 2008 professional. You will also need Visual Studio tools for Silverlight installed. Fortunately you don't need these installed to compile assemblies for Silverlight - we'll see how in a few moments.

Scriptable C# Class

C# for a Scriptable class with a Scriptable method that takes and returns a string look like:

using System;
using System.Windows.Browser;

[ScriptableType]
public class ScriptableForString
{
    [ScriptableMember]
    public string method(string value)
    { return this._method(value); }

    public virtual string _method(string value)
    { return "override me"; }
}

This uses the ScriptableType and ScriptableMember attributes

We need a Scriptable class with a Scriptable method. This should call down to a virtual method that we can override in an IronPython subclass. If we want to pass and return arguments they need to be strongly typed, and can only be a primitive like a string or an integer. This isn't really a problem though because we can pass or return JSON as a string. There is a JSON serializer and deserializer available in Silverlight, and using it from Javascript is easy of course!

Using from IronPython

To use this from IronPython we need to import the class from the assembly we have compiled. To add a reference from the assembly, we have to use the full name:

import clr
clr.AddReference("Scriptable, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
from Scriptable import ScriptableForString

class SomeClass(ScriptableForString):
    def _method(self, string):
        ...
        return new_string

some_class = SomeClass()

Registering the Scriptable Object

Because our scriptable object needs to be visible from both IronPython and from Javascript we need to register it.

from System.Windows.Browser import HtmlPage

HtmlPage.RegisterScriptableObject(
    "someClass", someClass
)

Calling from Javascript

Once we have registered the scriptable object, it is then available on the control to be called from Javascript. (This is made easier by giving the Silverlight control an id in the object tag in the html.)

control = document.getElementById(
            'SilverlightPlugin'
          );
result = control.Content.someClass.method(
            value
         );

C# Scriptable Event

The techniques we have just looked at are fine for calling from Javascript into Silverlight. To go the other way (from Silvelright calling into Javascript) we need to create a scriptable event.

using System;
using System.Windows.Browser;

[ScriptableType]
public class ScriptableEvent
{
    [ScriptableMember]
    public event EventHandler Event;

    public virtual void OnEvent(ScriptableEventArgs e)
    {
        Event(this, e);
    }
}

This scriptable event needs to work with scriptable event args.

[ScriptableType]
public class ScriptableEventArgs : EventArgs
{
    private string _val;

    [ScriptableMember]
    public string val
    {
        get { return _val; }
        set { _val = value; }
    }
}

We need to register this on both the IronPython and the Javascript side. The Javascript needs to attach an event handler to the event we have exposed. This handler will receive the eventargs we pass in from the IronPython side and be able to access the scriptable members we gave it. THe Javascript side can modify those members to return values.

Using from IronPython

No need to subclass this time.

event = ScriptableEvent()

# This must also be registered
HtmlPage.RegisterScriptableObject(
    "event", event)

args = ScriptableEventArgs()
args.val = 'some string'
event.OnEvent(args)

The Javascript

In order to use this event, we have to assign a Javscript function to the event exposed on the control.

We can only assign one function to this event (no multicast). This function will receive two arguments (like normal .NET events), the sender and the event we pass in.

function some_function(sender, args) {
    value = args.val;
    ...
    args.val = new_value;
}

control = document.getElementById('SilverlightPlugin');
control.Content.event.Event = some_function;

When event.OnEvent(args) is called, the javascript function (some_function) is called and receives the arguments sender and our event args. The Javascript can modify the attributes on the event to return values. After the call returns, IronPython can look at the attributes on the event args to retrieve any return values.

Compiling C# with Notepad

Having to download Visual Studio 2008 (and that is one hefty download) just to compile a few lines of C# is a nuisance. Fortunately we can get round this by using the .NET 2 compiler to do it for us. (I think that the compiler, csc.exe, comes with the .NET 2 SDK - but it may even be included in a normal .NET 2 install.)

The following batch file tells csc to compile with references to the Sivlerlight DLLs instead of the standard framework ones. It compiles all the C# files in the directory (*.cs) into an assembly specified by the /out argument (/out:SilverlightApp.dll).

set sl=C:\Program Files\Microsoft Silverlight\2.0.30226.2
set csc=C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe

%csc% /out:Scriptable.dll
    /t:library /nostdlib+ /noconfig /r:"%sl%\mscorlib.dll"
    /r:"%sl%\System.dll" /r:"%sl%\System.Core.dll"
    /r:"%sl%\System.Net.dll" /r:"%sl%\System.Windows.Browser.dll"
    *.cs

pause

The lines that start %csc% need to be all on one line - I've split it into multiple lines here for readability. The paths I've included above are the paths that I found csc and the Silverlight assemblies on my machine (Windows Vista). You may need to modify them for yours. I haven't tried this with Mono on the Mac, but I would be interested to hear from anyone who gets it working (or otherwise).

From compiling C# for use with IronPython, the next logical step is embedding the IronPython interpreter in a C# Silverlight application:

For buying techie books, science fiction, computer hardware or the latest gadgets: visit The Voidspace Amazon Store. If you're looking for a new techie job, try the Voidspace Tech Job Board. This is part of the Hidden Network of technology and programming jobs.

Hosted by Webfaction

Return to Top

Page rendered with rest2web the Site Builder

Last edited Sun Jun 1 23:37:08 2008.


Counter...


Voidspace: Cyberpunk, Technology, Fiction and More
Search this Site:
 
Web Site

IronPython in ActionIronPython in Action

Blogads

Follow me on:

Twitter

Pownce

Jaiku

Del.icio.us

Shared Feeds

Tech Jobs

Hidden Network

Tech Jobs Board

Hosting for an agile web