Build: Sharing types and instances between Silverlight and JavaScript

 

The first thing that ASP.NET developers ask themselves is how to reuse the current existing JavaScript functionality with Silverlight applications. The good news is that the Silverlight team has delivered what they have promised regarding the interaction between these two worlds. This quick post will show you how to expose types and managed instances to be used with your scripted code.

Let’s start with types, the first thing that we need to do is register the type using the System.Windows.Browser.HtmlPage object, this exposes an interesting method called RegisterCreateableType(string scriptAlias, Type type). This method publishes a managed type into the JavaScript scope. In order to allow this operation you need to decorate the type with the attribute [ScriptableTypeAttribute]. Let’s see how this is done:

[ScriptableTypeAttribute]

public class HtmlObject

{

      public string Text {get;set;}

}

 

public partial class Page : UserControl

{

      public Page()

      {

            InitializeComponent();

            HtmlPage.RegisterCreateableType("HtmlObject", typeof(HtmlObject));

      }

}

It is important to understand that this model has some limitations, the most important one is that the constructor has to be public and it has to be parameter less. Now, we can change the script in our HTML page as follows:

<script type="text/javascript">

function OnClick()

    {

      var SLCtrl = document.getElementById('SilverlightControl');

    var ManagedType = SLCtrl.Content.services.createObject("HtmlObject");

    ManagedType.Text = "Hello from Javascript";

    alert(ManagedType.Text);

    }

</script>

Now, what if you want to share an existence instance so you can interact with both worlds in real time? Well, there is another very helpful method on the same namespace, it is called HtmlPage.RegisterScriptableObject(string scriptKey, object instance). This type needs to have the attribute [ScriptableMember()] on the methods and properties that we want to expose. Let’s see how we can do this:

public class SharedObject

{

      private Button source;

      public SharedObject(Button source)

      {

            this.source = source;

      }

     

      [ScriptableMember()]

      public bool IsEnabled

      {

            set { this.source.IsEnabled = value; }

      }

}

public partial class Page : UserControl

{

      public Page()

      {

            InitializeComponent();

            HtmlPage.RegisterScriptableObject("SharedObject", new SharedObject(cmdButton));

      }

}

This instance is now available to the Silverlight content object and can be accessed in a very easy manner. When the following method is executed it will change the “IsEnabled” property of our Silverlight button.

function OnClick()

{
SLCtrl.Content.SharedObject.IsEnabled = false;

}

We can also put everything together and have these shared objects passed back and forward from one context to the other, if we expand our SharedObject class with a new method that process the first object that we have created we will be able to properly cast it.

[ScriptableMember()]

public HtmlObject Process(HtmlObject info)

{

      info.Text += " (this has been processed)";

      return info;

}

<script type="text/javascript">

function OnClick()

    {

      var SLCtrl = document.getElementById('SilverlightControl');

    var ManagedType = SLCtrl.Content.services.createObject("HtmlObject");

    ManagedType.Text = "Hello from Javascript";

ManagedType = SLCtrl.Content.SharedObject.Process(ManagedType);

    alert(ManagedType.Text);

    }

</script>

 

 

As you can see “Process” is receiving a casted managed type. But what if you want to receive a non managed type? Well, there is another way of writing that method in a more generic way:

[ScriptableMember()]

public ScriptObject Process(ScriptObject info)

{

      string Text = info.GetProperty("Text").ToString();

      Text += " (this has been processed)";

      info.SetProperty("Text", Text);

      return info;

}

Think about the potential, not only sharing types and instances between your script and Silverlight but also when you need to share objects between different Silverlight applications