Have you ever wondered how to get more than one Silverlight element on your page? Have you ever wondered how to get two Silverlight controls to communicate? This post will address both of those questions.
For those of you not pondering those questions, here’s a common scenario: You want to have a common Silverlight navigation on your page, and you don’t want to redirect the user to another page for each click. Instead, we want a second Silverlight element on the page that changes as we click the nav.
It’s generally bad user experience to put everything in one, giant Silverlight container, because it will take FOREVER to load, forcing your users to sit and wait before they can do anything. By being more modular, we improve load times, and it’s actually pretty simple to do. Let’s get started:
1. Create your Silverlight project.
Make sure you create your accompanying Web project as well..
2. Make this XAML unique.
I’m just going to make the background of the Silverlight app orange. I’ve also added a “1” so that I’m sure which control it is. When we put 2 Silverlight controls on a page, we want to make sure we know which is which. There are also three buttons on this screen. When the user clicks those buttons, we’re going to change the background color of the other Silverlight control. We’ll get to the event handler code a little later. (You might also need to add the System.Windows.Browser namespace…it’s for talking to the DOM). Here’s the XAML I am using:
<UserControl x:Class="SilverlightWithTwoControls.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel x:Name="LayoutRoot" Background="Orange" HorizontalAlignment="Center" VerticalAlignment="Center" Width="400" Height="300">
<TextBlock Text="1" FontSize="100"></TextBlock>
<Button x:Name="Green" Content="Green" Width="100" Height="25" Margin="10" Click="Button_Click" />
<Button x:Name="Purple" Content="Purple" Width="100" Height="25" Margin="10" Click="Button_Click" />
<Button x:Name="Blue" Content="Blue" Width="100" Height="25" Margin="10" Click="Button_Click" />
</StackPanel>
</UserControl>
3. Create another Silverlight project.
Each Silverlight project will be independent of each other. Each Silverlight project creates ONE XAP file, and since we need two, this is the best solution.
4. Mark up our second XAML file.
This file is even simpler. We’re only modifying the background color and adding a 2 for identification. Here’s the code:
<UserControl x:Class="SecondControl.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Canvas x:Name="LayoutRoot" Background="#666666" HorizontalAlignment="Center" VerticalAlignment="Center" Width="400" Height="300">
<TextBlock Text="2" FontSize="100"></TextBlock>
</Canvas>
</UserControl>
5. Let’s add these to our .aspx page.
We’re just going to have 2 <asp:Silverlight> tags on our page in this example, pointing to the two individual .xap files. Here’s what the HTML looks like:
<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls" TagPrefix="asp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">
<head runat="server">
<title>Silverlight With Two Controls</title>
</head>
<body style="height:100%;margin:0;">
<form id="form1" runat="server" style="height:100%;">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<div style="position:absolute;top:10px;left:10px;">
<asp:Silverlight ID="Xaml1" runat="server" Source="/ClientBin/SilverlightWithTwoControls.xap" MinimumVersion="2.0.31005.0" Width="400" Height="300" />
</div>
<div style="position:absolute;top:320px;left:10px;">
<asp:Silverlight ID="Xaml2" runat="server" Source="/ClientBin/SecondControl.xap" MinimumVersion="2.0.31005.0" Width="400" Height="300" />
</div>
</form>
</body>
</html>
6. Writing the button event handler.
We need those buttons to actually do something. Let’s write that event handler code. Here’s what it looks like:
private void Button_Click(object sender, RoutedEventArgs e)
{
Button clicky = sender as Button;
HtmlPage.Window.Invoke("changeColor", clicky.Name);
}
7. Say it ain’t so…
I don’t know how many times I can tell you that Javascript rules the world, but here’s another example. We’re going to leverage the power of Javascript to talk between our Silverlight objects. Because it has the ability to leverage the Silverlight DOM, it’s actually a very useful and powerful tool. (And for all of you naysayers, if a user has Javascript turned off, it’s HIGHLY likely they’re not running rich UI plugins like Silverlight or Flash either.)
Anyways, there’s a pretty simple Javascript function we can write to get this action taken care of. In our previous step, we specified the name of the Javascript function, changeColors. We also pass the Name value of the Button, which just happens to be the name of the color we’re going to be changing the other control to. Forethought is cool. Here’s what my Javascript function looks like:
function changeColor(color) {
slObject = document.getElementById("Xaml2");
slObject.Content.Page.ChangeBackgroundColor(color);
}
What we’ve done here is call the method ChangeBackgroundColor inside the Xaml2 control. We’re passing the color we want to change it to.
8. Writing the final method in the 2nd control.
Now we just need to write that method in the code-behind of our second XAML file, and we should be done. Here’s my final code for the second control:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
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;
using System.Windows.Browser;
namespace SecondControl
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
[ScriptableMember]
public void ChangeBackgroundColor(string colorName)
{
if (colorName == "Blue")
{
LayoutRoot.Background = new SolidColorBrush(Colors.Blue);
}
else if (colorName == "Purple")
{
LayoutRoot.Background = new SolidColorBrush(Colors.Purple);
}
else if (colorName == "Green")
{
LayoutRoot.Background = new SolidColorBrush(Colors.Green);
}
}
}
}
You might have noticed that there’s something a little different in there. We have a decorator [ScriptableMember] in there. We had to make some changes to our application to make it exposed to Javascript. By default, it can’t just call inside our Silverlight app. We have to make that happen in code.
9. Editing our App.xaml file.
In the second Silverlight project, open your app.xaml file. In our Application_Startup method, you should have a line that looks like
this.RootVisual = new Page();
. We’re going to add one more line after that, which registers our control as a Scriptable object. Here’s the entire method, after my modifications:
private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new Page();
HtmlPage.RegisterScriptableObject("Page", this.RootVisual);
}
This line of code, in conjunction with the decorator we added in Step #8 will mean we’re done, and that our controls can now affect each other.
Sample Code
You can download the sample code for this example here. You should also be able to see these controls below this paragraph, but RSS readers like to ignore it. If it’s not showing up, you can also see Two Silverlight Controls together by clicking here.
function changeColor(color) {
slObject = document.getElementById(“Xaml2”);
slObject.Content.Page.ChangeBackgroundColor(color);
}
Leave a Reply