Calling Silverlight Methods using JavaScript

Posted by: Malcolm Sheridan , on 4/15/2009, in Category Silverlight 2, 3, 4 and 5
Views: 40928
Abstract: The following article demonstrates how to use JavaScript to call Silverlight methods.
Calling Silverlight Methods using JavaScript
 
I recently did an article on Calling JavaScript functions from Silverlight 2. This article will reverse that and use JavaScript to call Silverlight methods.
I’m going to create a fictional business application that uses JavaScript to call a Silverlight application to search for Australian post codes. The benefit of calling Silverlight code from JavaScript is that the calls are made asynchronously, so there is no page refresh for the end user.
To begin with open Visual Studio 2008 and choose File > New > Project > Silverlight > Silverlight Application. Navigate to the Silverlight application and open the Page.xaml file. Copy the following xaml into the file:
<UserControl x:Class="SilverlightApplication1.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="0" Height="0">
    <Grid x:Name="LayoutRoot" Background="White">
       
    </Grid>
</UserControl>
In the code above, notice that the width and height of the UserControl is set to zero and the Grid is empty. This is because the user will not see any Silverlight control’s, it will all be plain HTML and JavaScript. The trick to making your Silverlight code accessible from JavaScript is via the HtmlPage.RegisterScriptableObject method. This method registers managed objects for scriptable access by JavaScript code.   Copy the following code into the Page constructor:
C#
public Page()
{
InitializeComponent();           
      HtmlPage.RegisterScriptableObject("SilverlightPostCode", this);
}
VB.NET
Public Sub New()
       InitializeComponent()
       HtmlPage.RegisterScriptableObject("SilverlightPostCode", Me)
End Sub
The first parameter, SilverlightPostCode, will be referenced in JavaScript to access the Page class. The second parameter is used to declare which object you want accessible, and this or Me means the current object.
The work in the Silverlight project is done for now. Switch back to the web application and add a new class. Name it AddressInfo and add the following code:
C#
public class AddressInfo
{
public string Suburb { get; set; }
      public string State { get; set; }
      public string Postcode { get; set; }
}
VB.NET
Public Class AddressInfo
      Private privateSuburb As String
      Public Property Suburb() As String
            Get
                  Return privateSuburb
            End Get
            Set(ByVal value As String)
                  privateSuburb = value
            End Set
      End Property
       Private privateState As String
       Public Property State() As String
             Get
                   Return privateState
             End Get
             Set(ByVal value As String)
                   privateState = value
             End Set
       End Property
       Private privatePostcode As String
       Public Property Postcode() As String
             Get
                   Return privatePostcode
             End Get
             Set(ByVal value As String)
                   privatePostcode = value
             End Set
       End Property
End Class
This class will hold the data that relates to the post code search. The next step is to add a web reference to the following URL:
AddWebReference
This is a free service for querying Australian post codes. Now that we have our source of data, create a Silverlight-enabled WCF Service to retrieve the data. Call it PostCodeService:
AddNewItem
Add the following code to the WCF service:
C#
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class PostCodeService
{
    [OperationContract]
    public List<AddressInfo> DoWork(string code)
    {
       List<AddressInfo> addresses = new List<AddressInfo>();
       PostcodeService postCode = new PostcodeService();
       DataSet ds = postCode.GetPostcodeAndSuburbForAustralia(string.Empty, string.Empty, code);
 
       if (ds.Tables[0] != null)
      {
          foreach (DataRow item in ds.Tables[0].Rows)
          {
              addresses.Add(new AddressInfo()
              {
                  Suburb = item[0] as string,
                  Postcode = item[1] as string,
                  State = item[2] as string                       
              });
          }
       }
       return addresses;
   }       
}
VB.NET
 
<ServiceContract(Namespace := ""), AspNetCompatibilityRequirements(RequirementsMode := AspNetCompatibilityRequirementsMode.Allowed)> _
Public Class PostCodeService
      <OperationContract> _
      Public Function DoWork(ByVal code As String) As List(Of AddressInfo)
        Dim addresses As New List(Of AddressInfo)()
         Dim postCode As New PostcodeService()
         Dim ds As DataSet = postCode.GetPostcodeAndSuburbForAustralia(String.Empty, String.Empty, code)
 
         If ds.Tables(0) IsNot Nothing Then
             For Each item As DataRow In ds.Tables(0).Rows
                   addresses.Add(New AddressInfo() With {.Suburb = TryCast(item(0), String), .Postcode = TryCast(item(1), String), .State = TryCast(item(2), String)})
             Next item
         End If
         Return addresses
      End Function
End Class
 
In the code above, the return type is a generic List<AddressInfo> collection. I always try to use strongly typed objects whenever I code, and the data returned from the web service is a DataSet, so if there is data found relating to the post code, I am using a foreachloop to enumerate through each record and adding it to an AddressInfo object. This collection is what will be consumed by the Silverlight application and displayed to the end user.
 
Next let’s add the HTML to the page so that we can see our UI. Open the SilverlightApplication1TestPage.aspx and add the following code:
 
<h1>Search Australian Postcodes</h1>
    <input type="button" onclick="loadPicturesSilverlight();" value="Search" />
    <input type="text" name="txtPostCode" maxlength="4" />
    <div id="sampleDiv">
    </div>
    <div>
        <asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/SilverlightApplication1.xap"
            MinimumVersion="2.0.31005.0" Width="100%" />
    </div>
 
The button in the code above will execute a JavaScript function called loadPicturesSilverlight. We will create that last. The text box will allow the user to type in a post code. A div named sampleDiv will hold the results from the search. Very simple stuff indeed!
 
The web application is done for now. Switch back to the Silverlight application and add a new Service Reference to the WCF service we just created:
 
AddServiceReference
 
Open the Page.xaml.cs or Page.xaml.vb file and add the following code:
 
C#
 
[ScriptableMember(ScriptAlias = "SearchPostCode")]
public void InternalNameOnly(string postCode)
{
PostCodeServiceReference.PostCodeServiceClient client = new PostCodeServiceReference.PostCodeServiceClient();
      client.DoWorkCompleted += new EventHandler<SilverlightApplication1.PostCodeServiceReference.DoWorkCompletedEventArgs>(client_DoWorkCompleted);
      client.DoWorkAsync(postCode);           
}
 
VB.NET
 
<ScriptableMember(ScriptAlias := "SearchPostCode")> _
Public Sub InternalNameOnly(ByVal postCode As String)
Dim client As New PostCodeServiceReference.PostCodeServiceClient()
       AddHandler client.DoWorkCompleted, AddressOf client_DoWorkCompleted
       client.DoWorkAsync(postCode)
End Sub
 
The code in the method above does a normal asynchronous call to the WCF service. The code above is what we will execute when the user clicks the HTML button in the web application. The magic behind this is decorating the method with the ScriptableMember attribute.   The ScriptableMember attribute indicates that this method is accessible by JavaScript callers. The ScriptAlias property is optional and it means that this method will be referred to in JavaScript as SearchPostCode, NOT InternalNameOnly. This is the way to hide method names from JavaScript. Next add the following code for the EventHandler:
 
C#
 
void client_DoWorkCompleted(object sender, SilverlightApplication1.PostCodeServiceReference.DoWorkCompletedEventArgs e)
{
    HtmlElement parent = HtmlPage.Document.GetElementById("sampleDiv");
    parent.SetAttribute("innerHTML", string.Empty);
    ObservableCollection<PostCodeServiceReference.AddressInfo> addresses = e.Result;
 
    if (addresses.Count > 0)
    {
        HtmlElement ul = HtmlPage.Document.CreateElement("ul");
        foreach (PostCodeServiceReference.AddressInfo item in addresses)
        {
            HtmlElement li = HtmlPage.Document.CreateElement("li");
            li.SetAttribute("innerHTML", string.Format("{0} ({1})", item.Suburb, item.State));
            ul.AppendChild(li);
        }
        parent.AppendChild(ul);
    }
    else
    {
        HtmlElement p = HtmlPage.Document.CreateElement("p");
        p.SetAttribute("innerHTML", "No records found");
        parent.AppendChild(p);
    }
}     
VB.NET
 
Private Sub client_DoWorkCompleted(ByVal sender As Object, ByVal e As SilverlightApplication1.PostCodeServiceReference.DoWorkCompletedEventArgs)
      Dim parent As HtmlElement = HtmlPage.Document.GetElementById("sampleDiv")
      parent.SetAttribute("innerHTML", String.Empty)
      Dim addresses As ObservableCollection(Of PostCodeServiceReference.AddressInfo) = e.Result
 
      If addresses.Count > 0 Then
            Dim ul As HtmlElement = HtmlPage.Document.CreateElement("ul")
            For Each item As PostCodeServiceReference.AddressInfo In addresses
                  Dim li As HtmlElement = HtmlPage.Document.CreateElement("li")
                  li.SetAttribute("innerHTML", String.Format("{0} ({1})", item.Suburb, item.State))
                  ul.AppendChild(li)
            Next item
            parent.AppendChild(ul)
      Else
            Dim p As HtmlElement = HtmlPage.Document.CreateElement("p")
            p.SetAttribute("innerHTML", "No records found")
            parent.AppendChild(p)
      End If
End Sub
 
 
The above code will run once the WCF service has finished executing. If results are found, the code will dynamically create one HTML unordered list (UL) and enumerate through each AddressInfo item in the collection and create a list item (LI). Once it is finished it will add the HTML to the sampleDiv. However, if no data is found it will dynamically create a paragraph and display No records foundto the user.
 
The last step is to switch back to the web application and add a new JavaScript file to the project. Add the following code to the file:
 
function loadPicturesSilverlight() {
// Get the silverlight server control
    var slPlugin = document.getElementById("Xaml1");    
    var content = slPlugin.Content;
 
    var postCode = document.getElementById("txtPostCode").value;
    if (postCode.match(/^\d{4}$/))
    {
// Use the SilverlightPostCode that was exposed by the HtmlPage.RegisterScriptableObject method
      // Call SearchPostCode as this is the ScriptAlias for the method.
        content.SilverlightPostCode.SearchPostCode(postCode);
    }
    else {
        alert("Enter a 4 digit postcode");
    }
 
In the code above, the important variable is content because it gets a reference to the Silverlight Content. From there it parses the text from the text box to ensure the input from the user is four (4) numbers, as Australian post codes must meet that requirement. Once the data is correct, the code can now call Silverlight methods directly via the following line:
 
content.SilverlightPostCode.SearchPostCode(postCode);
 

If you remember earlier in the article, we setup the SilverlightPostCode code in the HtmlPage.RegisterScriptableObject method in the Page.xaml file. That is the code that enables managed objects to be accessible by JavaScript callers. If you run the code and search for an Australian post code, for example 3000, the code will be initiated from JavaScript but Silverlight will create the resulting HTML. Pretty cool if you ask me!

The source code of this article can be downloaded from here

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @malcolmsheridan


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by SLK on Wednesday, July 22, 2009 12:51 AM
Hi,

Thank you for the article. "The benefit of calling Silverlight code from JavaScript is that the calls are made asynchronously, so there is no page refresh for the end user." . I am sure you know that SilverLight only supports Asynchronous calls should you use Javascript or code behind. I appreciate your work, but if you can rephrase your lines, it will help the newbies and not misguide them about the technology.
Comment posted by Malcolm Sheridan on Monday, August 3, 2009 7:30 PM
@SLK
Yes all Silverlight calls are made asynchronously as I said in the article.
Comment posted by subrat on Wednesday, February 3, 2010 7:27 AM
How can we call a silverlight function from an aspx page using jquery?
Comment posted by Malcolm Sheridan on Friday, March 12, 2010 10:19 PM
@subrat
jQuery is JavaScript, so it's pretty much the same.
Comment posted by Experts Comment on Saturday, October 23, 2010 2:48 AM
Nice article, below link provide good explanation of same.
http://www.a2zmenu.com/Silverlight/Calling-Silverlight-Method-from-JavaScript.aspx
Comment posted by Mshini on Monday, January 31, 2011 6:38 AM
Nice article Malcolm. One question, how do i clear all the textboxes using JavaScript/JQuery in a silverlight page? I have been looking for solutions all over. thanks in advance.
Comment posted by Suffian Ahmed on Thursday, March 24, 2011 7:19 AM
Hi,

Nice Code, Thanks a lot.

Visit http://www.webnoesys.com
Comment posted by Suffian Ahmed on Thursday, March 24, 2011 7:24 AM
Hi,
Nice article. JQuery is same as java script, so both are same.
visit webnoesys.
need a sesson on how to use the componentart controls with the silverlight.

Thanks in advance.
visit www.webnoesys.com
Comment posted by Richa on Friday, May 18, 2012 12:56 AM
Hi,

Thanks for this useful code.
But it is not working with Mozilla Firefox(version 12.0).
Here it is not showing the innerHtml of controls on screen.
Comment posted by Richa on Friday, May 18, 2012 1:28 AM
Hi,

Thanks for this useful code.
But it is not working with Mozilla Firefox(version 12.0).
Here it is not showing the innerHtml of controls on screen.