Published: 11 Sep 2009
By: Manfred Pohler
Download Sample Code

This article shows how to use the new Silverlight Local Communication API to connect Silverlight Islands in an ASPX Website.

Contents [hide]

The Idea behind

Silverlight (SL) becomes more and more common, so it’s a good idea to think about the use in web applications.I'm not talking about pure SL pages - what I mean are "SL Islands". More or less some kind of user controls sitting in the middle of normal HTML content. And such "SL Islands" - will exist on multiple places on a page. The content can sometimes be the same - but with a different view.

What this is NOT

It is not complete well designed web application with full error handling and a perfect implementation following the "best practices". Missing features:

  • Data Access via Services. We use static data instead; assume one part calls a service and hands over the data to the other part. This avoids further service calls (less wire transfer)
  • Good error handling (Very important - but boring)
  • Good looking styles - I guess you heard about Microsoft Expression Blend

What it is

A solution that highlights some interesting features of the new (Silverlight 3) LocalCommunication features. Special features of this sample:

  • Inline Silverlight use - We will build a control that's displayed as "flow element" in the HTML content
  • Communication using complex data - We will use XML and some kind of custom Serialization
  • Checking for the reaction of the receiver (We will check if the receiver got the data.)
  • Using Silverlight control parameters - We will build 2 controls, but change the behavior of one control via parameters

Parts of the sample

The masterpage

The page has 3 frames and looks like a lot of websites look today.

The top frame holds some kind of navigation. In this case static and simple. It will give us the choice to select one of three products - and a "home link" to go to the start page.

The content (or left) frame holds the content - which will be different for each product.

The right pane will hold some graphical information about the product. And we will be able to choose what's displayed via a SL control in the content.

The right frame

This frame is "static" - it will always be the same and it is defined in the masterpage. Here's the code for it:

This code is simply a copy of the "ASPX Test page" which the Silverlight application template generates. On top of the master page (in the head section) I further added the link to Silverlight.js and the script from the "ASPX Test page" it looks like this:

So till now I only used some simple HTML div to build 3 frames and further I copied 2 parts of an auto generated page to the master page.

The content pages

They will have some "lorem ipsum" text and a SL control which allows us to choose one of three options. Here's a sample of one page:

Like for the right frame the "Silverlight object code" is copied from an APSX test page generated by the Silverlight Application Template. (I'll talk about this later).

Parts of the sample

The Data

As I told in the introduction we will use static data. The data is simple - but complex enough to demonstrate XML serialization. It looks like this:

As you see we have a class with three members. They represent the sales data from the last 3 years.

This could be units, K-Euros or tons or...

Important for us - we have three values which we can display graphically. For each product we will generate 3 records of this data. One for Asia, one for Europe and one for the USA.

The "data generation" looks like this:

The display

As I said before, we will build 3 controls. One is the "controller" which tells the other ("consumer") what to display. The controller itself will get some information via a parameter passed through the object tag. Let's see how those controls look finally:

Figure 1: First look of the two controls

First look of the two controls

Notice the frame configuration of this page. Left we have some content and in the right pane we show bar graphs about the sales history.

The graphic shows the data for USA at the moment. And on the left side we can make a choice between Europe, USA and Asia.

Creating the project

First of all sorry - I use a German VS 2008 - but I'm sure you'll find the things

In VS create a new project - choose "Silverlight Application" and give it the name DataSelector.Check the following dialog:

Figure 2: Confirmation Dialog

Confirmation Dialog

Host the Silverlight Application in a new website must be checked - if you have installed RIA Services don't check this option.

Now in your Project explorer right click on the Workspace and choose "Add new project":

Figure 3: Add new project dialog

Add new project dialog

Choose Silverlight Application and call it DataDisplay. Check the following screen:

Figure 4: Confirmation Screen

Confirmation Screen

There is no need for a Testpage (we have one for the first project) so you can uncheck "Testseite hinzufügen" (Add Test page).

Next let's add the class for the data. On your DataSelector project choose Add new Item - Class.Name the class SalesHistory. And in the code enter:

Notice that I changed the Namespace from DataSelector to DataSelectorAndDisplay.

Next in the Project DataDisplay choose "Add existing item". Navigate to the DataSelector project directory and select the SalesHistory.cs file.

Figure 5: Use Link file in this dialog

Use Link file in this dialog

Take a look at the "Add button" - it has two options - one is Add (Hinzufügen) and the second is "Add as link" - use the second. So if you change the class the changes will appear in both projects since they refer to the same file.

The last things we have to do on both Silverlight projects - right click References - choose add and add a reference to System.XML.Serialization.

Figure 6: Add reference dialog

Add reference dialog

We are almost done with the pre work. What's left is to add a masterpage to the web project and then three product pages.

  • Delete Default.aspx
  • Add new Item - MasterPage (Site1.master)
  • Add new Item - Web Content Page - Default.aspx
  • Add new Item - Web Content Page - Prod1.aspx
  • Add new Item - Web Content Page - Prod2.aspx
  • Add new Item - Web Content Page - Prod3.aspx

Next we will integrate the Scripts from the DataSelectorTestPage.aspx (head section) to our master page - also in the head section. Then we create the divs for the frames - and in the right frame we add the DataDisplay Silverlight control. We also copy the code (object range) from DataSelectorTestPage.aspx and change width, height and the xap link (we need DataDisplay instead of DataSelector).

The final master page looks like this:

In Default.aspx enter something - there is no data.

In the Prod1-3 .aspx pages enter some content and include the object tag from DataSelectorTestPage.aspx.

They will look like this:

Notice that there is no need for the Silverlight scripts in the content pages - we get them via the master page.So, that was our "infrastructure". The pages should run without a problem - and display nothing from Silverlight (also no errors).

Silverlight Infrastructure (Display)

First we will give the two Silverlight graphic applications some basic functionality.

For this sample I use the telerik RadControls for Silverlight 3 You can use your own kind of data display if you want. All you have to do is to adapt the code of this section. Only keep the function name BuildChart and the control name rcInfo (because we will hide / show it).

The XAML part is very simple:

That's why I like the telerik controls. They are very easy to use. If you want to use the product code and don't own these controls you can download them for free (trial version) from here: http://www.telerik.com/account/free-trials.aspx

These trial versions are fully functional - they sometimes display a message in their content.

Code behind looks like this - (at the moment):

Important is our function BuildChart which takes a string with the region as well as one SalesHistory item. This item then is added to three bars on the chart. Then we directly change the size on the Y axis to have the biggest bar filling the chart.

The CreateChartTitle function builds a StackPanel for the text and the region.

The UserControl_Loaded method hides the grid and shows the "Sorry no data" TextBlock. Of course this could be done in XAML - but we will later add more code to this handler so it doesn't matter.There is one thing left to have this thing running - we need some references to the Telerik controls.Simply choose References - Add - Browse and browse you telerik RadControls for Silverlight installation directory.

Then select the following DLLs:

Figure 7: Add reference dialog

Add reference dialog

So this control is done so far - let's go on with the DataSelector.

Silverlight Infrastructure (DataSelector)

This control will do two things - it will allow the use to choose between three regions and it will provide data. This could be done by consuming a service or via resources. In our case we use a static method which builds data for one of the three records.

The function looks like this:

The member m_lSD is a list we'll use later. So the function (if called with the correct parameter) creates a list and adds three SalesHistory entries.

Let's check the XAML:

We have an "inner grid" (grdDataButtons) which enables us to hide the buttons - and as with the DataDisplay we have some kind of "no data" display.

The handlers for the Checked and the Loaded events look like this:

Every Checked handler ensures that the other controls are not checked and it resets the border of each ToggleButton to black. Not the best idea - if the control is styled with a different border color this would cause a "bad look" - but it's good enough for the sample. Moreover, I can re-use brushes.

Now our infrastructure is almost ready - and we can come to the interesting things.

I'll do this step by step - the first step will be to pass parameters.

Silverlight Parameters

In this section I'll show how to pass parameters to a Silverlight application.

Parameters are passed as name-value pairs separated by a comma. So to pass the parameters to the control we will change our three content pages (Prod1-3.aspx).

There, we add a line to the Silverlight object:

Notice the line <param name="InitParams" ... tag.

Add this line to every page - with a different value of course. So we pass ONE, TWO and THREE on the pages. Also notice the name - Product. We will access the parameter via this name.

And we do this in App.xaml.cs (DataSelector):

We check if InitParams has a value - and if it contains the key Product.

Our name-value pairs are passed as a dictionary - with the name as key. When we find it, we add this value to our Resources. Notice if we do not get a parameter I create my own with the value NONE - this prevents me from checking later again if a parameter is there. I can assume there is one.

Now it's time to enhance our UserControl_Loaded event handler:

We call a helper function CheckProductData and pass our Parameter (Product) to it.

If it is NONE - we hide the buttons - and show the "No data...." textblock.

If we got one - we check if it has a correct value.

If NOT, we display the wrong parameter; else we call LoadProductData - which we have seen before. This function chooses one of the three products and creates SalesHistory entries for each region. It stores it in a private list m_lSD.

Notice that we check the btnEurope. This makes things going since it calls the Checked handler of this control.

Silverlight Communication (Basics)

Finally we reached the point where we can (almost) start our communication. But before we can do this we have to do some "data encapsulation".

LocalCommunication allows us to transfer strings between different Silverlight applications. The amount of data is (documentation in MSDN) limited to 40K size.If you have to transfer more data you have to split it into several messages.

Silverlight doesn't care about the content of your strings - it's your choice how you encode / decode your data.In our case I decided to do two things.

First I want to transfer the SalesHistory object via XML (as it would be done for a web service).

Then I want to do a bit of "custom encoding" - so I'll pass the region as extra part of the string.

The string will look like this: Region:<xmldata....>

To get the XML data I use the Silverlight XML.Serializer. The function is simple.

We add the following code to MainPage of the DataSelector:

To undo the things on the other side add the following code to MainPage of DataDisplay:

Now since the data is ready to be transferred, we will start with the sender:

We create a LocalMessagSender - and pass the name of the Receiver as Parameter. This name is NOT the name of the control - it is the name of the Receiver (see receiver code) and it must be unique.

In every Checked handler we added code to send a string and a number. Ignore the number for the moment - I'll talk about it later.

Finally, notice that we build our data by adding the region in front of the XML string.

The receiver is simple, too:

Take a look at the MainPage constructor. Here we define our LocalMessageReceiver - and the name passed in the constructor is the one we have to use with the sender.

The handler is very simple - it checks if the data has the correct format and calls the BuildChart function.With this code (under perfect circumstances) everything works.

But there are some possible problems which I will show in the next part.

Silverlight Communication (Extended)

As I told in the previous part, there can be problems in the communication. And I'm not talking about errors.

The first problem is the load sequence. If the sender is loaded before the receiver and it sends, no one receives.In our case - we initially select Europe - and send the data. We think the display shows the data - but if it isn't loaded when we send, nothing will be displayed.

The idea to fix this is the following. We try it several times and check if the receiver got the data.And if the retries do not help we remove the checked state from Europe to ensure that the user has a visual feedback for the fact that no detail data is displayed.

Then we also give positive feedback to show the user that the data is displayed. I do this simply by setting the border of the checked button to green.

The question is - how can we detect if data has been transferred? And how can we get some kind of response from the receiver?

There is already support to provide a response. And there is also support for having some status information, which is useful for retries.

The “protocol”

I will define a little protocol which tells the sender that (and for what region) a message has been (correctly) received. First let's take a look at the MessageReceivedEventArgs:

Figure 8: Intellisense

Intellisense

You can see there is a member called Response - this is also a string and we can use it to give some information back to the sender. We will simply return the region in this string when we got data to display. This means adding ONE line of code to the existing handler.

The new line is line 12, where I assign the region to the response.

Notice also line 8 which (if you keep tbNoData visible) can be used to display the data in a string.

You can use this line if you don't want to use the Telerik controls for data display.

For the sender this means that if the receiver is acting correct (following the protocol) and if it found data we can display this to the user. We do it simply by adding a green border to the matching ToggleButton. Until now we had an empty SendCompleted handler. This handler is called when sending is done.

In general this function is call when

  • Complete Send / Receive is finished
  • An Error occurred
  • No Receiver did respond (also treated as error)
  • The call was canceled.

Our updated handler looks like this:

First we check for an error (we could also display something to the user). We say "No one did receive - uncheck the button, so the user sees that nothing is displayed".

If we have no error we check if the response is one of the valid reasons. If so, we set the border of the corresponding ToggleButton to green.

This works also in the situation when the DataDisplay is loaded later then the DataSelector. So the user has to check one of the ToggleButtons to display some data.

In our situation (depends on how the page is constructed) this will allays happen. So setting Europe as default is more or less useless. But there is a solution for this.

You may recall that we sent our data in this form:

m_lS.SendAsync("USA:" + SerializeData(m_lSD[1]), 0);

This third parameter (called UserState type object) is described as "A unique state object which acts as work ID for transfer".

In simple words - this object is passed to the SendCompleted handler where we can use it. In this case I use it as some kind of retry counter.

Yes I could use a class member. The problem is that if I send multiple things (remember it works asynchronously) I would need some extra logic to determine for which sent message the SendCompleted handler was called.

Using the UserState parameter makes the things a lot easier.

I changed the SendCompleted handler to this:

In Line 3 I read the UserState and in the following line I check if it has reached the limit. If not, I wait a bit to give the other control the time to download / init. Then I try it again with an incremented Retry counter as UserState.

Notice that I simply use e.Message as data because (nice feature) in SendCompleted we also have access to the data we sent!

That's it - my sample is finished. All the code is contained in this article. I'll post the complete project to the Telerik Code Library where you can download it if you want. Telerik screens new entries - so it may take one or two days before you can download it.

As long as I can keep it online you can run the demo from here.

Something left?

Yes - I didn't talk about sending data to controls from other domains. This is also possible - but it's beyond the scope of this article.

I hope you enjoyed my sample

Links

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Manfred Pohler

Sorry, no bio is available

This author has published 2 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


WPF Tutorial
With all the new technology that Microsoft is releasing, it's hard to keep up. WPF is one such techn...
Silverlight "WPF/E" first steps: Getting started with simple analog clock
This article is an introductory article on how to build a WPF/E simple web application that represen...
Introduction to XAML Part 1
You are coding in .NET and have basic knowledge of XML. You heard about that Windows Presentation F...
RIA Services With Silverlight 3 - Part 1
What RIA services actually are and how to use them with Silverlight.
Silverlight 3 and the Data Form Control—part I
Dino will briefly go through some patterns that help organizing the presentation layer and then focu...

You might also be interested in the following related blog posts


Silverlight 3 and WCF Faults read more
WPF Bindings and CurrentCulture Formatting read more
Silverlight MVP read more
WPF Localization Guidance Paper Posted on CodePlex read more
Enhancing the Localization Support of RadControls for Silverlight and WPF read more
Detecting Design Mode in Silverlight read more
Telerik Announces Support for Microsoft Silverlight 3 read more
Why Embedded Silverlight Makes Sense read more
The June Microsoft Silverlight links read more
Silverlight and localizing string data read more
Top
 
 
 

Please login to rate or to leave a comment.

Product Spotlight