Interacting with the DOM

When hosted in a browser, Silverlight is a part of the page, the same as any other HTML object in it, so it's only fair that Silverlight will be able to interact with the different elements on the page. Meet the System.Window.Browser namespace. It will be your starting point for communicating with the HTML DOM. The namespace exposes different methods for accessing cookies and query strings, calling the JavaScript functions, and even manipulating the DOM elements.

Accessing cookies and query strings

We all know (and some of us love) HTML cookies, which are those little text nuggets that the browser saves on the user's computer and are mostly used for authentication, session tracking, and so on. Well, the good news is that you can access and save cookies using Silverlight as well.

Saving a cookie is a simple matter of calling the SetProperty method of the HtmlPage class's Document object with a string in the following format:

Key=Value;expires=ExpireDate

The following code snippet can be used to save a cookie on the user's computer:

public void SaveCookie(string key, string value, DateTime expireDate)
{
string newCookie = string.Format("{0}={1};expires={2}", key, value, expireDate.ToString("R"));
HtmlPage.Document.SetProperty("cookie", newCookie);
}

The newCookie object will hold a formatted string, as explained in the preceding code snippet. It is important to note that the DateTime object must be passed using the R parameter of its ToString method, which will output the date as follows:

Sun, 25 Jan 2012 22:45:07 GMT

Once we have the string for the cookie we wish to save, all that's left to do is to call the SetProperty method of the Document object. The SetProperty method requires two properties. First, is the property name we wish to set (in our case cookie) and second, is the value of that property (in our case the cookie string).

Retrieving a cookie can be done using the following code snippet:

public string GetCookie(string key)
{
string[] cookiesCollection = HtmlPage.Document.Cookies.Split(';'),
foreach (string cookie in cookiesCollection)
{
string[] keyValue = cookie.Split('='),
if (keyValue.Length == 2)
{
if (keyValue[0] == key)
return keyValue[1];
}
}
return null;
}

First, we get all the cookies the browser stores using the Cookies properties of the Document object. Once we have all the cookies, we will just iterate through them one by one using the foreach loop and once we find a cookie whose key is the same as the one we are looking for, we will return its value.

Getting the query string values is just as easy. By using the QueryString object of the Document object, we can pass in a key and get the value. For example, say my Silverlight application is hosted on a page whose URL is http://localhost:1080/Page/Silverlightapp.aspx?ID=5. Here, the query string I wish to read is ID, so in the Silverlight application we will use the following line of code:

string id = HtmlPage.Document.QueryString["ID"];

If you wish to first check whether the URL contains the key that you are after, simply use the ContainsKey method as follows:

string id;
if(HtmlPage.Document.QueryString.ContainsKey("ID"))
id = HtmlPage.Document.QueryString["ID"];

Working with cookies and a query string is a common scenario when working with Silverlight. Luckily, it's not an overly complicated process, and you would probably get used to it quickly.

Communication between JavaScript and Silverlight

When working with Silverlight as an in-browser application, there may come times when you wish to get additional data from the hosting context by using JavaScript. Silverlight allows us to do a two-way communication with JavaScript—a JavaScript method can call a Silverlight object's methods, and Silverlight can call JavaScript methods and get back data from them.

Calling a JavaScript function from Silverlight is done using the Invoke method of the HtmlPage class's Window object. Let's assume we have a JavaScript function in the host page of our Silverlight application called GetData, which accepts no arguments and returns a string value. The following line of code will be used to call it from Silverlight:

string dataFromJS = HtmlPage.Window.Invoke("GetData");

Another variation of communicating with JavaScript can be passing data to a JavaScript function from Silverlight. For example, let's assume we have the following JavaScript function:

function ShowName(name) {
alert("Hello, " + name);
}

The ShowName function must get a string argument from the calling party. The Invoke method allows us to specify an optional array of parameters to pass to the JavaScript function we are calling. In the ShowName function's case, the calling code will look as follows:

HtmlPage.Window.Invoke("ShowName","Johnny");

Calling a Silverlight method from JavaScript is quite a simple process as well. The first step is to declare either the entire class as scriptable using the ScriptableType attribute or declare specific methods as scriptable using the ScriptableMember attribute. For example, if I wish to expose all the public methods on my MainPage.xaml.cs file to JavaScript, it will use ScriptableType as follows:

[ScriptableType]
public partial class MainPage : UserControl
{
...
}

To expose specific methods and not the entire class to JavaScript, we will use the ScriptableMember attribute as follows:

[ScriptableMember]
public void ExposedMethod()
{
...
}

Once we declare what we wish to expose, we need to create a so-called bridge to JavaScript so that it will be able to access the scriptable member. The bridge itself is nothing more than an alias that can be used in the JavaScript function to gain access to the Silverlight content. Creating the bridge is a simple matter of calling the RegisterScriptableObject method of the HtmlPage class. Let's assume we have declared the entire MainPage.xaml.cs class as ScriptableType and we wish to create an alias for it. The following code snippet will get the job done:

public MainPage()
{
InitializeComponent();
HtmlPage.RegisterScriptableObject("myScriptableClass", this);
}

Our Silverlight code is now ready for some JavaScript communication!

The Silverlight plug-in exposes an object called content which exposes to the world (or in this case JavaScript) the content of the plug-in. When we register an object using the RegisterScriptableObject method, the alias we chose for it will be appended to that content property. The last steps of accessing the Silverlight method using JavaScript is retrieving the plugin instance (using document.getElementById for example) and then refering the scriptable method using the content property. Assuming that our Silverlight object has the ID of MySilverlightControl and our Silverlight control has a method called ExposedMethod, which is scriptable and was registerd using the RegisterScriptableObject with the alias of myScriptableClass, we will be able to access it from JavaScript using the following code snippet:

function GetDataFromSilverlight() {
var slCtrl = document.getElementById("MySilverlightControl");
slCtrl.content.myScriptableClass.ExposedMethod();
}

Manipulating the HTML DOM

Silverlight's interaction with its host doesn't end at JavaScript. Silverlight is also powerful enough to manipulate the HTML Document Object Model (DOM) as well.

The main entry point for working with the HTML DOM in Silverlight is the Document object of the HtmlPage class. Once you have a reference to the Document object, you can get any HTML element using the GetElementById method and set any property that you wish on it. Let's assume our host ASPX page has a div tag with id of messageText:

<div id="messageText">
</div>

We wish to have a button on the hosted Silverlight application which, when clicked, will change the content of messageText div (using the InnerHTML property) to a predefined value. Examine the following code snippet:

private void btnHtmlMessage(object sender, RoutedEventArgs e)
{
HtmlDocument hDoc = HtmlPage.Document;
HtmlElement divElement = hDoc.GetElementById("messageText");
divElement.SetProperty("innerHTML", "Hello from Silverlight!!!");
}

The preceding code snippet will first get an instance of the Document object of the HTML DOM using the HtmlPage class's Document object. Once we have the HtmlDocument object declared, we will find the element we wish to alter using the GetElementById method (an other alternative would be using the GetElementsByTagName method, which gets all the elements of a specific tag, such as div or span) and set its property using the SetProperty method.

The SetProperty method isn't limited to just the innerHTML property. Any valid HTML property (for example, Background or Width) can be used within SetProperty.

Silverlight to Silverlight communication

Silverlight 3 introduced the concept of local messaging. Local messaging allows us to communicate multiple Silverlight controls hosted on the same page, across browser tabs or even across browsers! The following screenshot shows how a message from a Silverlight application running in one instance of Internet Explorer is shown in a Silverlight application running in a completely different instance of Internet Explorer:

Silverlight to Silverlight communication

The System.Windows.Messaging namespace contains two objects that allow us to create the communication. The LocalMessageSender class represents the sending end of the local messaging channel and the LocalMessageReceiver class represents the receiving end of that same channel. A basic configuration of local messaging is given ahead.

On the sender application, we will have the following object initialized:

LocalMessageSender messageSender = new LocalMessageSender("localChannel");

The argument passed to the constructor represents a name for the channel communication. In order for the receiver to be able to receive communication from the sender, it must specify the same channel communication name. By default, the name supplied will be scoped to the domain level, but by specifying a second parameter of the ReceiverNameScope type, you can scope it to global level as well.

In order to receive communication from the preceding sender, the receiving application will have the following object initialized:

LocalMessageReceiver messageReceiver = new LocalMessageReceiver("localChannel");

Each object exposes an event to serve its purpose. The LocalMessageSender class exposes the SendCompleted event, which fires as soon as the sender finishes sending the message. The LocalMessageReceiver class exposes the MessageReceived event, which fires as soon as the receiver receives a message from a sender.

In order to receive a message, the receiver has run the Listen method. Once the Listen method is run, the receiver configuration cannot be changed.

Sending a message is a simple matter of calling the SendAsync method of the LocalMessageSender object and passing it a string message.

Creating a local communication demo application

To better demonstrate the use of Silverlight to Silverlight communication, open the Chapter6-SL2SL project in Visual Studio 2010. The project consists of two Silverlight projects and a web project. Each Silverlight project represents one end of the solution. The first project will act as the sender, meaning we will send text messages from it to the other project, which will act as the receiver.

Both Silverlight projects have a simple UI that consist of a Grid control, and a few TextBox and TextBlock controls. The sender application's TextBox is named tbMessage and the receiver's TextBlock is named tbMsgReceived.

To get started, open the MainPage.xaml.cs file of the Chapter6-SL2SL sender project. The first thing we need to do is to define the private variable to hold an instance of LocalMessageSender. LocalMessageSender is a class, which represents the sending end of the local messaging channel between the Silverlight applications.

Add the following line of code just above the MainPage constructor:

private LocalMessageSender _sender;

Next, we need to initiate the new variable using the LocalMessageSender constructor. The constructor of LocalMessageSender requires one argument—the name of the receiver that will receive messages from it. Inside the MainPage_Loaded method, add the following line of code:

_sender = new LocalMessageSender("msgReceiver");

We now have a sender object ready for use! The last task we have for this application is to actually send the message when the Send button is clicked. Sending a message is a simple matter of using the SendAsync method of the LocalMessageSender method, with the message we wish to send as the argument. Because this is an asynchronous method, we can also handle the SendCompleted event, which fires as soon as the message is sent. For this simple demo application though, we won't use it. Add the following line of code inside the btnSend_Click method:

_sender.SendAsync(tbMessage.Text);

Now that we are done with the sending end of our application, it's time to handle the receiving end. To get started, open the MainPage.xaml.cs file of the Chapter6-SL2SL receiver project. In order to handle incoming messages, we first need to create an instance of the LocalMessageReceiver class and attach a handler to its MessageReceived event. Add the following code snippet to the MainPage_Loaded method:

LocalMessageReceiver rec = new LocalMessageReceiver("msgReceiver");
rec.MessageReceived += new EventHandler <MessageReceivedEventArgs>(rec_MessageReceived);

The preceding code snippet creates a new instance of the LocalMessageReceiver class, passing the same receiver name to the constructor as we did in the LocalMessageSender class. In addition to the preceding code snippet, register a handler to the MessageReceived event, which fires as soon as a message is sent to the specific receiver (named msgReceiver).

In order for LocalMessageReceiver to be in a state that it awaits incoming messages, we have to use the Listen method of the class. Add the following line of code in the MainPage_Loaded method:

rec.Listen();

The last thing we need to deal with for this application is what happens when the receiver receives a message. For that we need to handle the rec_MessageReceived method. Add the following code snippet to the MainPage.xaml.cs file:

void rec_MessageReceived(object sender, MessageReceivedEventArgs e)
{
tbMsgReceived.Text = e.Message;
}

Build and run the application. A browser will be opened with the Chapter6-SL2SLTestPage.aspx page open. Copy the URL and open a second browser. Paste the URL to the address bar and change the page from Chapter6-SL2SLTestPage.aspx to SL2SL-ReceiverTestPage.aspx. Try to enter a message in the sender application and click on Send. If all goes well, you will see the same message in the receiver application!

A screenshot of the application can be seen at the beginning of this topic.

If you wish to learn more about local communication, please refer to the MSDN documentation located at http://msdn.microsoft.com/en-us/library/dd833063(v=vs.95).aspx.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.138.104