You can also call PageMethods from a Silverlight application by using the ScriptManager
control.
In order to begin utilizing PageMethods in your ASP.Net enabled webpage via Silverlight,
you need to do 3 things:
1. Set the ScriptManager's "EnablePageMethods" property to "true".
2. Write Public Static WebMethods in the Code Behind file of the web page that will
return the information required.
3. Write Script that calls the PageMethods and reacts to the return results (information
or errors).
When the EnablePageMethods attribute is present, the ScriptManager automatically
does number 3 above, injecting all the clientscript needed to call the PageMethods
at the server:
<script type="text/javascript">
//<![CDATA[
var PageMethods = function() {
PageMethods.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
PageMethods.prototype = {
_get_path:function() {
var p = this.get_path();
if (p) return p;
else return PageMethods._staticInstance.get_path();},
Hello:function(name,succeededCallback, failedCallback, userContext) {
/// <param name="name" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'Hello',false,{name:name},succeededCallback,failedCallback,userContext); },
Add:function(x,y,succeededCallback, failedCallback, userContext) {
/// <param name="x" type="Number">System.Int32</param>
/// <param name="y" type="Number">System.Int32</param>
/// <param name="succeededCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'Add',false,{x:x,y:y},succeededCallback,failedCallback,userContext); },
TestDict:function(dict,succeededCallback, failedCallback, userContext) {
/// <param name="dict" type="Object">System.Collections.Generic.Dictionary`2[[System.String,
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String,
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]</param>
/// <param name="succeededCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'TestDict',false,{dict:dict},succeededCallback,failedCallback,userContext); }}
PageMethods.registerClass('PageMethods',Sys.Net.WebServiceProxy);
PageMethods._staticInstance = new PageMethods();
PageMethods.set_path = function(value) {
PageMethods._staticInstance.set_path(value); }
PageMethods.get_path = function() {
/// <value type="String" mayBeNull="true">The service url.</value>
return PageMethods._staticInstance.get_path();}
PageMethods.set_timeout = function(value) {
PageMethods._staticInstance.set_timeout(value); }
PageMethods.get_timeout = function() {
/// <value type="Number">The service timeout.</value>
return PageMethods._staticInstance.get_timeout(); }
PageMethods.set_defaultUserContext = function(value) {
PageMethods._staticInstance.set_defaultUserContext(value); }
PageMethods.get_defaultUserContext = function() {
/// <value mayBeNull="true">The service default user context.</value>
return PageMethods._staticInstance.get_defaultUserContext(); }
PageMethods.set_defaultSucceededCallback = function(value) {
PageMethods._staticInstance.set_defaultSucceededCallback(value); }
PageMethods.get_defaultSucceededCallback = function() {
/// <value type="Function" mayBeNull="true">The service
default succeeded callback.</value>
return PageMethods._staticInstance.get_defaultSucceededCallback(); }
PageMethods.set_defaultFailedCallback = function(value) {
PageMethods._staticInstance.set_defaultFailedCallback(value); }
PageMethods.get_defaultFailedCallback = function() {
/// <value type="Function" mayBeNull="true">The service
default failed callback.</value>
return PageMethods._staticInstance.get_defaultFailedCallback(); }
PageMethods.set_enableJsonp = function(value) { PageMethods._staticInstance.set_enableJsonp(value);
}
PageMethods.get_enableJsonp = function() {
/// <value type="Boolean">Specifies whether the service supports
JSONP for cross domain calling.</value>
return PageMethods._staticInstance.get_enableJsonp(); }
PageMethods.set_jsonpCallbackParameter = function(value) { PageMethods._staticInstance.set_jsonpCallbackParameter(value);
}
PageMethods.get_jsonpCallbackParameter = function() {
/// <value type="String">Specifies the parameter name that contains
the callback function name for a JSONP request.</value>
return PageMethods._staticInstance.get_jsonpCallbackParameter(); }
PageMethods.set_path("Default.aspx");
PageMethods.Hello= function(name,onSuccess,onFailed,userContext) {
/// <param name="name" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
PageMethods._staticInstance.Hello(name,onSuccess,onFailed,userContext); }
PageMethods.Add= function(x,y,onSuccess,onFailed,userContext) {
/// <param name="x" type="Number">System.Int32</param>
/// <param name="y" type="Number">System.Int32</param>
/// <param name="succeededCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
PageMethods._staticInstance.Add(x,y,onSuccess,onFailed,userContext); }
PageMethods.TestDict= function(dict,onSuccess,onFailed,userContext) {
/// <param name="dict" type="Object">System.Collections.Generic.Dictionary`2[[System.String,
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String,
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]</param>
/// <param name="succeededCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true"
mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
PageMethods._staticInstance.TestDict(dict,onSuccess,onFailed,userContext); }
//]]>
</script>
In this simple Silverlight Test app, I have the following XAML Markup:
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<Button HorizontalAlignment="Left" Width="100" Height="20" Content="Hello + Time" Click="Hello_Click" />
<Button HorizontalAlignment="Left" Width="100" Height="20" Content="Add" Click="Add_Click" />
<Button HorizontalAlignment="Left" Width="100" Height="20" Content="Dictionary" Click="Dictionary_Click" />
<TextBox HorizontalAlignment="Left" Name="txt" Height="60" Width="200" />
</StackPanel>
</Grid>

And the codebehind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightPageMethods
{
public static class PageMethodExtensions
{
public static object ToJSDictionary<T>(this Dictionary<string, T> dict)
{
var jsdict = HtmlPage.Window.CreateInstance("Object");
foreach (string key in dict.Keys)
jsdict.SetProperty(key, dict[key].ToString());
return jsdict;
}
}
public partial class MainPage : UserControl
{
delegate void PageMethodDelegate(object result, object context);
public MainPage()
{
InitializeComponent();
}
public ScriptObject PageMethods
{
get
{
return (ScriptObject)HtmlPage.Window.GetProperty("PageMethods");
}
}
private void Hello_Click(object sender, RoutedEventArgs e)
{
// Invoke the Hello PageMethod, passing in "There" as the second parameter
PageMethods.Invoke("Hello", "There", new PageMethodDelegate(Success), new PageMethodDelegate(Fail), "Context");
}
private void Add_Click(object sender, RoutedEventArgs e)
{
// Invoke the Add method, passing in 10 and 20 as the two parameters
PageMethods.Invoke("Add", 10, 20, new PageMethodDelegate(Success), new PageMethodDelegate(Fail), "Context");
}
private void Dictionary_Click(object sender, RoutedEventArgs e)
{
//Create a dictionary we want to send
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("test", "1");
dict.Add("test2", "2");
//Call PageMethod, providing delegate callbacks
PageMethods.Invoke("TestDict", dict.ToJSDictionary<string>(), new PageMethodDelegate(Success2), new PageMethodDelegate(Fail), "Context");
}
public void Success(object result, object context)
{
this.txt.Text = result.ToString();
}
public void Success2(object result, object context)
{
txt.Text = "";
ScriptObject so = result as ScriptObject;
txt.Text += so.GetProperty("test").ToString() +"\r\n";
txt.Text += so.GetProperty("test2").ToString() +"\r\n";
txt.Text += so.GetProperty("FromServer").ToString();
}
public void Fail(object result, object context)
{
txt.Text = "FAIL";
}
}
}
Note that we have an extension method on the Dictionary class which will convert
a dictionary to its Javascript object equivalent using the Silverlight HtmlPage.Window.CreateInstance("Object")
method.
The PageMethods script object is easily obtained in Silverlight with:
(ScriptObject)HtmlPage.Window.GetProperty("PageMethods");
This returns a Silverlight ScriptObject on which we can call the Invoke, or GetProperty
methods.
The rest is simply providing callbacks that match the signature of the Invoke Method
- the PageMethod name, a success callback, a failure callback, and something
for the context. Invoke is very flexible as it accepts a params Object[] args
second parameter (the first being the method name).
The actual PageMethods in the ASP.NET page are easy:
[WebMethod]
public static string Hello(string name)
{
return "Hello: " + name + " at " + DateTime.Now.ToShortTimeString();
}
[WebMethod]
public static int Add(int x, int y)
{
return x + y;
}
[WebMethod]
public static Dictionary<string, string> TestDict(Dictionary<string, string> dict)
{
if (dict.Count > 0)
dict.Add("FromServer", "Howdy From Server!");
return dict;
}
You can download the sample Visual Studio 2010 Silverlight 4.0 Solution here.