Day #31: Geocoding and More Fun In Bing Maps for Silverlight

Can you believe it? We’re at the end of this (longer than it should have been) journey. Today is the last day of the 31 Days of Silverlight. We are going to be building a more advanced version of the application we started yesterday, Day #30, related to Bing Maps in Silverlight.

1. Geocoding an address

For those of you relatively new to mapping, there’s this wonderful concept called Geocoding which makes our lives as developers much, much simpler. The basic premise is that we can provide our application with an actual address, and have a geocoding service figure out the latitude/longitude coordinates of that address. This way, we don’t have to tell our users to figure it out for themselves. Can you imagine going to Bing Maps to look at your house, only to be told you need to know the lat/long of that location? Not exactly user friendly. So, let’s get to it.

2. Adding the Geocoding service to our application

Before we can geocode an address, we need to add a reference to Bing’s geocoding web service. So let’s start there. Click on your Silverlight project, and choose “Add service reference…” Use this address as your address, and click Go:

http://dev.virtualearth.net/webservices/v1/GeocodeService/GeocodeService.svc

You should end up with a window that looks like this:

3. Creating an asynchronous call to that service

Much like talking to any web service, we have a couple of things we need to do. The first is to create a new instance of the service. The second is to attach a Completed event handler to the service, so that we know when a response has occurred. Finally, we need to create our service request, and call the service asynchronously. In my example, I created a method called Geocode that takes the same two parameters as the web service: an address, and a waypointIndex. I’ll explain waypointIndex later, when we talk about routing and directions. So, here’s what my method looks like:

        private void Geocode(string address, int waypointIndex)
{
GeocodingService.GeocodeServiceClient geocodingService = new GeocodingService.GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
geocodingService.GeocodeCompleted += new EventHandler<SilverlightBingMapsGeocoding.GeocodingService.GeocodeCompletedEventArgs>(geocodingService_GeocodeCompleted);

GeocodingService.GeocodeRequest request = new GeocodingService.GeocodeRequest();
request.Credentials = new Credentials();
request.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)myMap.CredentialsProvider).ApplicationId;
request.Query = address;

geocodingService.GeocodeAsync(request, waypointIndex);
}

You can see that we also have to attach our API Credentials that we got in Day #30 to our request. Without a valid API key, we can’t make requests. Since I stored mine in the XAML, the reference you see in my code above is to that XAML location. For the Completed event handler, we need the event method for that as well. In mine, I am capturing the new Location object it returns, and adding that as a pushpin to my map, like we did yesterday. This solution only works when you’re certain the service will only be returning one value to you. Here’s the code:

        void geocodingService_GeocodeCompleted(object sender, SilverlightBingMapsGeocoding.GeocodingService.GeocodeCompletedEventArgs e)
{
Location center = e.Result.Results[0].Locations[0];
myMap.Center = center;
Pushpin pushpin = new Pushpin();
pushpin.Location = center;
myMap.Children.Add(pushpin);
}

After all of that is done, we just need to call our Geocode() method. In my example, I’m using the address of my office again. Here’s the method call:

Geocode("8800 Lyra Avenue, Columbus, OH  43240", 1);

4. Geocoding’s easy. How about turn-by-turn?

Directions are a little trickier, but not significantly. In fact, we wouldn’t need to change our Geocode method one bit. The major changes we make to our application include using another web service, the RouteService, and adding the Waypoints that it returns to your map.

There’s an excellent explanation of this on the MSDN reference for Bing Maps in Silverlight. You can read it here. http://msdn.microsoft.com/en-us/library/ee681887.aspx

I was originally planning on writing out an entire tutorial for this section as well, but after reading their explanation, I realized I’d only be taking away from an excellent article.

Summary

Getting an address to a latitude and longitude point is nothing to sneeze at. I don’t even want to think about what is required to happen inside those services. I’m happy to have this nice, thick layer of abstraction to manipulate. I think you’ll find as you go forward that the route plotting is really just as simple.

To download the source of this Silverlight Geocoding for Bing Maps application, click here.

This series on Silverlight has certainly been quite an adventure. I hope that you had an opportunity to learn a few things along the way. I certainly know that I did.

This coming February 2010, I am going to be starting another series, with a slightly less focused approach. They will all be related to software development and technology, but I’m going to branch out a bit. My first two posts will cover creating a theme in Windows 7, and the second will cover XNA development for the Zune. I also have plans to cover topics like ASP.NET MVC 2, among others. If there’s something you’d like to see me cover in this as-to-be-named series, please let me know, and I’ll do my best to accomodate you. For now, however, I’m signing off of this 31 Days of Silverlight, and look forward to the next adventure.

P.S. Tune in tomorrow for a game I created in Silverlight. The first 5 people to finish it will win a free O’Reilly ebook of their choice!

Day #30: Bing Maps In Silverlight

Today we continue our exploration through the 31 Days of Silverlight with something new. We now have the ability to add a Bing Maps control to our Silverlight application. There’s some downloading and installation necessary, so let’s start there.

1. Get the Bing Maps Silverlight Control SDK

It sounds as simple as it is. You can download and install the Bing Maps Silverlight Control SDK here. Once you’ve installed it, jump to the next step.

2. Get a Bing Maps API key

Next, you need to head over to http://www.bingmapsportal.com. Log in with your Live ID, and create a key. You’ll need this to build your application, so even though you’re thinking about skipping this step, don’t. Go get it.

3. Create a new Silverlight project

This is Day #30 of my Silverlight series, so I’m going to assume at this point that you know how to do this.

4. Add the Map .dll references

When you installed the SDK, it dropped two DLLs on your hard drive. If you left the default path during installation, you should be able to find them here: C:Program FilesBing Maps Silverlight ControlV1Libraries. We’re almost ready to add a map to our page.

5. Add the namespace declaration

The final “prep” step we need to take is to add the XML namespace to the top of our XAML file. We have done this in previous projects, so I’ll just show you what you need to add:

xmlns:bing="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"

6. Adding a map to your page

To take it very simply, we can add one line of XAML to get a map on our page. In fact, here’s what it looks like:

<bing:Map CredentialsProvider="put your api key here" />

And here’s what the control looks like (see this in a new window):

7. Customize away

There’s an absolutely crazy amount of stuff you can do to customize these maps. I’m going to show you a couple of the simple ones, saving some cooler stuff for the next post. Specifically, how to have it start on a specific location, and how to add points to a map.

8. Defining a starting position

The simple way to do this is just to add a latitude/longitude value directly to at map’s Center property. You can do this via the codebehind, or directly in your XAML. Like this:

themap.Center = new Location(40.1449, -82.9754);
themap.ZoomLevel = 15;

OR

<bing:Map Name="themap" Center="40.1449, -82.9754" ZoomLevel="15" CredentialsProvider="your api key"  />

You’ll notice that I also set the ZoomLevel in both examples, so that we were zoomed in near the location we centered on. That’s pretty simple, but it doesn’t show the user the location we were trying to call their attention to. Next, we’ll actually put a pushpin on the map.

9. Adding a pushpin to the map

There’s actually a Pushpin class, which is convenient, especially when we need to have collections of pushpins. I have named my map “themap” for this example. Also, you’ll notice that I have moved my latitude/longitude values into a seperate Location object. This way, I can reference that location multiple times, without having to continue to hardcode the coordinates.

What you will see in the following code is that after setting the center of my map (and its zoom level), I create a new Pushpin, set its location, and then add it as a Child to my map. Here’s the code:

            Location myOffice = new Location(40.1449, -82.9754);
themap.Center = myOffice;
themap.ZoomLevel = 15;
Pushpin myOfficePin = new Pushpin();
myOfficePin.Location = myOffice;
themap.Children.Add(myOfficePin);

And here’s how it looks on the map (see this in a new window):

To download this Bing Maps Silverlight solution, click here.

Summary

Tomorrow, on our final day of this series, we’ll be diving deeper into this mapping control, geocoding (turning an address into latitude/longitude), and directions from one point to another. See you then!

Day #29: Using Isolated Storage in Silverlight

Today is day #29 in my 31 Days of Silverlight series. We’re going to cover how to utilize the isolated storage available on the user’s machine today. We can use isolated storage when we are in out-of-browser mode, and I recently dedicated 3 entire posts (Days #23 – #25) to getting your application ready for out-of-browser. We will be starting with that codebase, and you can download my Silverlight Out of Browser application here.

1. Adding some using statements

First things first, we’re going to need some way to write files, and the way we do that is with the System.IO namespace family. We’re going to add two different using statements to our MainPage.xaml.cs file:

using System.IO;
using System.IO.IsolatedStorage;

These allow us to read and write files, as well as access the Isolated Storage on the user’s machine.

2. Adding to our XAML file

For this tutorial, I am going to be adding a textbox to our page that will contain the lyrics to the song “Big Bang Theory,” by the Barenaked Ladies. We’re making this box editable, however, so that a user can write in their own lyrics, or fix typos they may find. They will be saving these changes locally to their isolated storage. Here’s what our new XAML file looks like…the only real additions are a TextBox and a Button (for saving):

<UserControl x:Class="SilverlightOutOfBrowser.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<
Canvas x:Name="LayoutRoot">
<
Canvas.Background>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#FF2A2A2A" Offset="1"/>
<
GradientStop Color="#FF9D9D9D"/>
</
LinearGradientBrush>
</
Canvas.Background>
<
Image x:Name="networkimage" Height="48" Width="48" Canvas.Left="532" Canvas.Top="10" Source="network_unknown.png" Stretch="Fill" ToolTipService.ToolTip="Network Connectivity"/>
<
MediaElement x:Name="videobox" Height="384" Width="512" Source="/BigBangTheory.wmv" Stretch="Fill" Canvas.Left="12" Canvas.Top="10"/>
<
Image x:Name="outofbrowserimage" Height="48" Width="48" Canvas.Left="585" Canvas.Top="10" Source="outofbrowser_unknown.png" Stretch="Fill" ToolTipService.ToolTip="Install This Application"/>
<
TextBox x:Name="lyrics" Canvas.Top="400" Canvas.Left="12" Width="512" Height="80" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto"/>
<
Button x:Name="LyricSave" Click="LyricSave_Click" Width="100" Height="80" Content="Save Lyrics" Canvas.Top="400" Canvas.Left="530" />
</
Canvas>
</
UserControl>

3. Saving a file in isolated storage

Before we can retrieve our data from a file, we should probably write it, right? I am going to create a saveLyricsFile method that takes a string for the lyrics we want to save. All it really does is open a pathway to the isolated storage, creates a file (in our case, a .txt file), and then uses a StreamWriter to write the lyrics to the file. Here’s what my method looks like:

        string lyricsfile = "BigBangTheoryLyrics.txt";

private void saveLyricsFile(string lyricsToSave)
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream isfs = isf.OpenFile(lyricsfile, FileMode.Create, FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(isfs))
{
sw.WriteLine(string.Format("{0}", lyricsToSave));
sw.Close();
}
}
}
getLyrics();
}

You’ll notice that I also call a new method called getLyrics() at the end of this method. Once I’ve saved the file to the user’s machine, I want a different method to retrieve the contents of that file, and write them to the TextBox on my page. That way, each time that the page loads, the lyrics box will have the most up-to-date version of the user’s lyrics file.

4. Retrieving the info in the file

Now that we have a file on the user’s machine, we need a way to get that information back, and use it. Using many of the same mechanisms from step #3, we are going to find our file in isolated storage, open it, and use a StreamReader to read the contents of the file into a string variable. Finally, we write that string to our TextBox. Here’s the method:

        string lyricstext = "Our whole universe was in a hot dense state,nThen nearly fourteen billion years ago expansion started. Wait...nThe Earth began to cool,nThe autotrophs began to drool,nNeanderthals developed tools,nWe built a wall (we built the pyramids),nMath, science, history, unraveling the mysteries,nThat all started with the big bang!nnSince the dawn of man is really not that long,nAs every galaxy was formed in less time than it takes to sing this song.nA fraction of a second and the elements were made.nThe bipeds stood up straight,nThe dinosaurs all met their fate,nThey tried to leap but they were latenAnd they all died (they froze their asses off)nThe oceans and pangeanSee ya, wouldn't wanna be yanSet in motion by the same big bang!nnIt all started with the big BANG!nnIt's expanding ever outward but one daynIt will cause the stars to go the other way,nCollapsing ever inward, we won't be here, it wont be hurtnOur best and brightest figure that it'll make an even bigger bang!nnAustralopithecus would really have been sick of usnDebating out while here they're catching deer (we're catching viruses)nReligion or astronomy, Encarta, DeuteronomynIt all started with the big bang!nnMusic and mythology, Einstein and astrologynIt all started with the big bang!nIt all started with the big BANG!";

private void getLyrics()
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
if (isf.FileExists(lyricsfile))
{
using (IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(lyricsfile, FileMode.Open, isf))
{
using (StreamReader sr = new StreamReader(isfs))
{
string lyricsdata = sr.ReadToEnd();
lyrics.Text = lyricsdata;
}
}
}
else
{
saveLyricsFile(lyricstext);
}
}
}

Notice that I set up an external string variable that is my original lyrics text. If the file doesn’t exist yet (a distinct possibility, since the user can delete it, or this may be their first time to the site), we need to populate it when we create it. So in my “else” statement, I call the saveLyricsFile method, passing those original lyrics in. Otherwise, if the file exists, we just read the contents of the file, and set those contents to the TextBox.Text value.

5. Calling the getLyrics() method when we load

We already have a Loaded event handler method, so let’s use that to call our getLyrics() method. This way, when the page loads, we’ll retrieve the contents of the file (and if the file doesn’t exist, we’ll create it.)

6. Making the button commit the “save”

The last step we need to take is to get our button to actually save the contents of the TextBox to the isolated storage file. The XAML I gave you earlier already had an event handler defined, so “navigate to event handler,” and add this line:

saveLyricsFile(lyrics.Text);

This will take the contents of our TextBox, and save it to the user’s local file. If you hit refresh in your browser, you should see that the new version of your text appears now. Because I embedded audio in my application, I am providing a link to see my Silverlight Isolated Storage application running. Normally I would just embed it here, but I don’t want to embarrass you at the office. 🙂

You can download my solution for Silverlight Isolated Storage here.

7. Summary

Isolated Storage in Silverlight works both in and outside the browser, but there are different storage requirements depending on how you use it. Out of browser applications have access to 25 MB of storage, while in-brower applications only have 1 MB. The reason for this makes sense, though. When we’re running out of browser, we could be running disconnected, which would require us to store all of the user’s changes locally until we reconnect to the network.

In short, using isolated storage is not very different from writing to the file system in WPF, but we don’t get to specify paths on the user’s machine. All of our data and files reside inside a sandboxed area, that has no access to other parts of the user’s machine. This keeps them safe from malicious attacks that could occur under other circumstances. Here’s a look at where these files are stored:

Windows Vista/7
Users\AppDataLocalLowMicrosoftSilverlightis

Windows XP
Documents and Settings\Local SettingsApplication DataMicrosoftSilverlightis

Mac OS X
/Users//Library/Application Support/Microsoft/Silverlight/is

Only a few more days left in the 31 Days of Silverlight, and then a fun little Silverlight game for you on January 1st. I hope you are enjoying this series!

Day #28: Silverlight Application Themes

Welcome to Day #28. We’ve nearly finished the 31 Days of Silverlight, but we have a few fun posts remaining. Today’s post is on creating Themes in Silverlight.

Theming is one of those pieces of functionality you see in consumer apps quite a bit. Basically changing the application to look and feel the way I want it. However, it’s definitely more than that. It’s the way you should write your styling information in Silverlight. For the most part, it’s advanced Styling, which we covered on Day #10: Styling A Silverlight Control. The difference is that we are creating external style files that we can then swap between inside the application.

1. Download the Silverlight 3 Toolkit

This article will cover the advanced features that Theming offers you, and assumes that you are somewhat familiar with styling. First, you need to download the Silverlight 3 Toolkit. If you haven’t done this already, head over to http://silverlight.codeplex.com and download it.

2. Add references to two assemblies

We need to add two references to our Silverlight project. They are System.Windows.Controls, and System.Windows.Controls.Theming (this one was added by the Toolkit). Go ahead and add them to your project.

3. Add an XML namespace reference to the Theming assembly

The next thing, as usual, is to add an XML namespace reference. To do this, I recommend relying on Intellisense for it, and just start typing the xmlns:theming=” before it recommends a list of assemblies. If you don’t want to type it, however, you can just use my snippet of code:

xmlns:theming="clr-namespace:System.Windows.Controls.Theming;assembly=System.Windows.Controls.Theming.Toolkit"

4. Add some controls to your page

Before we can start styling our application, we need some controls on our page. I’ve added a TextBlock, a Button, a TextBox, and a Slider to my StackPanel base control. Here’s what my full XAML looks like right now:

<UserControl x:Class="SilverlightTheming.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:theming="clr-namespace:System.Windows.Controls.Theming;assembly=System.Windows.Controls.Theming.Toolkit"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<
StackPanel x:Name="LayoutRoot" Width="200" HorizontalAlignment="Center" VerticalAlignment="Center">
<
TextBlock Text="This is our form." Margin="0,0,0,10"/>
<
Button Content="Save" Margin="0,0,0,10"/>
<
TextBox Text="Something to edit." Margin="0,0,0,10"/>
<
Slider/>
</
StackPanel>
</
UserControl>

5. Creating a ResourceDictionary

Our next step is going to be creating a ResourceDictionary file. If you choose “Add New Item…”, one of your choices is “Silverlight Resource Dictionary.” Even though it creates a XAML file (like nearly everything else in Silverlight), this will have a base tag of ResourceDictionary instead of UserControl. This is where we will define our theme. You’ll notice I named my file Green.xaml. This is so that I can remember that this is the green theme. Eventually, when you lather, rinse, and repeat, you’ll have Blue, Red, Black, White, Pink, etc. Effective naming is always useful. I never recommend going with names like “Professional,” “Glass,” and “Techno,” because it’s harder to remember what those look like just by reading the name.

One important note before you move on from this point: By default, your new resource dictionary will have a “Build Action” of “Page” in its properties. You need this to be “Content” instead. If you don’t change this, you will get an error similar to: AG_E_PARSER_BAD_PROPERTY_VALUE. Just change it. It will make your life easier than mine just was.

Editing our new ResourceDictionary

This is where the work comes in. For theming an entire application, we really need to consider the styles for every possible control we might use. In my example, I know I’m only going to be using 4 controls: TextBlock, TextBox, Button, and Slider. But as your application grows, you can see how this would grow quickly as well. (If you don’t want the theme to apply to everything, your life gets easier. This effort only applies to those controls you actually want to change visually.) To make my life easier, I have pre-defined some colors and brushes that I will be using in my theme. This way, if I ever want to change them in the future, I don’t have to change them in 19 different places. Here’s the entirety of my Blue.xaml file…don’t be intimidated. It’s big, but no worse than any of the stylesheets you’ve ever created. 🙂

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<!--DEFINING A LIST OF COLORS FOR RE-USE-->
<Color x:Key="TextBrush">#FF000000</Color>

<
Color x:Key="NormalBrushGradient1">#FFBAE4FF</Color>
<
Color x:Key="NormalBrushGradient2">#FF398FDF</Color>
<
Color x:Key="NormalBrushGradient3">#FF006DD4</Color>
<
Color x:Key="NormalBrushGradient4">#FF0A3E69</Color>

<
Color x:Key="NormalBorderBrushGradient1">#FFBBBBBB</Color>
<
Color x:Key="NormalBorderBrushGradient2">#FF737373</Color>
<
Color x:Key="NormalBorderBrushGradient3">#FF646464</Color>
<
Color x:Key="NormalBorderBrushGradient4">#FF000000</Color>

<
Color x:Key="ShadeBrushGradient1">#FF62676A</Color>
<
Color x:Key="ShadeBrushGradient2">#FFD1D4D6</Color>
<
Color x:Key="ShadeBrushGradient3">#FFFFFFFF</Color>

<
Color x:Key="SliderBorderGradient1">#FF3F3F3F</Color>
<
Color x:Key="SliderBorderGradient2">#FFADADAD</Color>

<!--DEFINING A LIST OF BRUSHES FOR RE-USE-->
<LinearGradientBrush x:Key="NormalBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="{StaticResource NormalBrushGradient1}" Offset="0" />
<
GradientStop Color="{StaticResource NormalBrushGradient2}" Offset="0.41800001263618469" />
<
GradientStop Color="{StaticResource NormalBrushGradient3}" Offset="0.418" />
<
GradientStop Color="{StaticResource NormalBrushGradient4}" Offset="1" />
</
LinearGradientBrush>

<
LinearGradientBrush x:Key="NormalBorderBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="{StaticResource NormalBorderBrushGradient1}" />
<
GradientStop Color="{StaticResource NormalBorderBrushGradient2}" Offset="0.38" />
<
GradientStop Color="{StaticResource NormalBorderBrushGradient3}" Offset="0.384" />
<
GradientStop Color="{StaticResource NormalBorderBrushGradient4}" Offset="1" />
</
LinearGradientBrush>

<
LinearGradientBrush x:Key="ShadeBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="{StaticResource ShadeBrushGradient2}" Offset="0" />
<
GradientStop Color="{StaticResource ShadeBrushGradient3}" Offset="0.1" />
<
GradientStop Color="{StaticResource ShadeBrushGradient3}" Offset="1" />
</
LinearGradientBrush>

<!--Button-->
<Style TargetType="Button">
<
Setter Property="Background" Value="{StaticResource NormalBrush}"/>
<
Setter Property="Foreground" Value="#FF000000"/>
<
Setter Property="Padding" Value="3"/>
<
Setter Property="BorderThickness" Value="2"/>
<
Setter Property="BorderBrush" Value="{StaticResource NormalBorderBrush}" />
</
Style>

<!--TextBox-->
<Style TargetType="TextBox">
<
Setter Property="BorderThickness" Value="1"/>
<
Setter Property="Background" Value="{StaticResource NormalBrushGradient1}"/>
<
Setter Property="Foreground" Value="#FF000000"/>
<
Setter Property="Padding" Value="2"/>
<
Setter Property="BorderBrush" Value="{StaticResource NormalBorderBrush}" />
</
Style>

<!--Slider-->
<Style TargetType="Slider">
<
Setter Property="BorderThickness" Value="1"/>
<
Setter Property="Maximum" Value="10"/>
<
Setter Property="Minimum" Value="0"/>
<
Setter Property="Value" Value="0"/>
<
Setter Property="BorderBrush">
<
Setter.Value>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#FFA3AEB9" Offset="0"/>
<
GradientStop Color="#FF8399A9" Offset="0.375"/>
<
GradientStop Color="#FF718597" Offset="0.375"/>
<
GradientStop Color="#FF617584" Offset="1"/>
</
LinearGradientBrush>
</
Setter.Value>
</
Setter>
</
Style>

</
ResourceDictionary>

6. Using the ImplicitStyleManager

That last step was the hard part. Defining styles for your controls, picking colors, and getting all of that XAML created. The ImplicitStyleManager makes the rest of our life easy. We can use it two different ways, and I’ll show you each. The first is the simple way: in XAML. To our “LayoutRoot” element, we just need to apply two properties:

<StackPanel Name="LayoutRoot" theming:ImplicitStyleManager.ApplyMode="Auto" theming:ImplicitStyleManager.ResourceDictionaryUri="Blue.xaml" HorizontalAlignment="Center" VerticalAlignment="Center"> 

Obviously, you need to make sure that where I put “Blue.xaml,” that you put the location of your ResourceDictionary. After that, run your application. If you used my style information, you should have slightly different looking button and slider controls, and a textbox that has a blue background. Each and every textbox in my application will look like that, unless I explicitly override that styling.

But Jeff, can I call this from code?

Why yes, you can! The other way to invote the ImplicitStyleManager is to just create a reference to it in code. Keep in mind that to do this, you’ll need a using statement for the System.Windows.Controls.Theming assembly, but otherwise, here’s the code:

            Uri theme = new Uri("Blue.xaml", UriKind.Relative);
ImplicitStyleManager.SetResourceDictionaryUri(LayoutRoot, theme);
ImplicitStyleManager.SetApplyMode(LayoutRoot, ImplicitStylesApplyMode.Auto);
ImplicitStyleManager.Apply(LayoutRoot);

If you’re planning on giving your user the ability to change their theme on the fly, I’d recommend going the code route. You can add that code to an event handler, and just choose the appropriate Dictionary as the user selected it. So, that’s it! Pretty simple, huh?

Summary

I highly recommend Theming your application, regardless of whether you plan to allow your user to choose a theme or not. By externalizing all of your styling information, you create a familiar feel to traditional web development with CSS. In addition, you could technically create a seperate dictionary for Buttons, TextBlocks, etc. You’d then pull of those together in yet another master dictionary, keeping the code seperated and clean. Go forth and theme!

To download my application sample for Silverlight Theming, click here.

Day #27: Templating Controls In Silverlight

Ah, we’ve made it to Day #27 of the 31 Days of Silverlight. Today, we’re going to be decontructing one of the most common XAML elements: the Button. The reason we’re doing this is to demonstrate how templates work, and how even complex controls are really just compositions of much simpler ones.

1. Add a button to your XAML page

Button, button, who’s got the button? Just add a simple button to your page. If you need help, you can use this XAML:

<Button Content="Click Me!" Width="200" Height="200" />

2. Open your solution in Expression Blend 3

If you haven’t already installed Expression Blend 3, you can get a 60 day trial here.

Open MainPage.xaml, and you should see your button in the middle of the design surface. If you right click on the button, you should see a menu option: Edit Template. From there we’re going to choose “Create Empty…”

3. Creating a style resource

When you choose that menu item, you are presented with the “Create ControlTemplate Resource” dialog box. Here, you can name your new Template, as well as define its scope. For my example, I am choosing Application level scope, so that I can use this across all of my pages. What you will see is that you have added a big style-type definition to your App.xaml file. (For more info on styling, you can check out Day #10: Styling Silverlight Controls.)

4. Looking at our template

If you look at the “Objects and Timeline” panel in Expression Blend, you’ll see very little in the way of structure. The only thing that is provided is a Grid. If you open your “States” window, you’ll find that a button has several different states. This is where we will be spending most of our time.

5. Adding an image to our template

I called this Template an ImageButton, because I am going to create a button that has a consistent image in the background. So, to add an image, just double-click on the Image control in your toolbox.

I recommend stretching it to the size of your template…that way, your button will be proportional when you create other sizes in your application. Also, you need to add an image to your project that you’re going to use. For my example, I’m using a picture of my face. Think of it as a public service for you to hit me in the face over and over. 🙂

6. We also need a ContentPresenter

We need to add a ContentPresenter control, but that’s what it is. This will show the “Content” property of our buttons. I’m putting this control on my forehead. Here’s what it looks like:

If you go back to Visual Studio and run this project, you should now have a button on your page that instead looks like your image, but still displays your button Content. Give it a try. Mine says “Click Me!” like the initial XAML I gave you.

7. Playing with States

If you open the States window in Expression Blend 3, you’ll see that we already have a bunch of States defined for a button. We’re going to be modifying some of these, so that our ImageButton actually does something. You may have noticed that while our Content showed up appropriately, the button didn’t have that “click” feel we’re used to. This will fix that. Here’s a shot of the States window:

What we are going to do is add some behaviors to the “Pressed” state so that the button reacts when it’s clicked.

8. Adding the Pressed state

In the States window, click on the “Pressed” item. You’ll notice that immediately the design pane is outlined in red. This is because we’ve started recording our actions. The changes you make at this point will be the changes that happen when you “Press” the button. In my example, I am going to have my Image control change its opacity. At this point, we’re just creating a simple animation. Look back to Day #11 in this series to see more about animation. I am going to create an animation that changes the opacity from 100% to 33% in just 0.1 seconds. Here’s what the entire contents of my App.xaml file looks like now:

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="SilverlightTemplating.App"
mc:Ignorable="d"
>
<
Application.Resources>

<
ControlTemplate x:Key="ImageButton" TargetType="Button">
<
Grid Height="200" Width="200">
<
VisualStateManager.VisualStateGroups>
<
VisualStateGroup x:Name="CommonStates">
<
VisualState x:Name="Pressed">
<
Storyboard>
<
DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Opacity)">
<
EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
<
EasingDoubleKeyFrame KeyTime="00:00:00.1000000" Value="0.33"/>
</
DoubleAnimationUsingKeyFrames>
</
Storyboard>
</
VisualState>
</
VisualStateGroup>
</
VisualStateManager.VisualStateGroups>
<
Image x:Name="image" Source="jeffblankenburgheadshot.jpg" Width="200" Height="200"/>
<
ContentPresenter Height="24" VerticalAlignment="Top" Margin="53,60,53,0"/>
</
Grid>
</
ControlTemplate>
</
Application.Resources>
</
Application>

You may notice, when you run this project, that when you click on the button, it goes transparent, but when you release the mouse, it doesn’t “un-transparentize.” We need to tell it to do that as well. This is a completely open slate we’re working with, and nothing is assumed in a template. This is a plus, however, because although we are working in blank template, if we like 90% of a certain control, we can use that as our starting point. Let’s add the “MouseOver” state now.

9. Adding the “MouseOver” state

Since we want the button to return to its original state when we lift the mouse button, we also create a MouseOver state. This is the state that the control will revert to when we lift the mouse button. I actually copied and pasted the XAML from my Pressed state into this new MouseOver state, and changed the opacity values. Here’s my new XAML:

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
x:Class="SilverlightTemplating.App"
>
<
Application.Resources>

<
ControlTemplate x:Key="ImageButton" TargetType="Button">
<
Grid Height="200" Width="200">
<
VisualStateManager.CustomVisualStateManager>
<
ic:ExtendedVisualStateManager/>
</
VisualStateManager.CustomVisualStateManager>
<
VisualStateManager.VisualStateGroups>
<
VisualStateGroup x:Name="CommonStates">
<
VisualState x:Name="MouseOver">
<
Storyboard>
<
DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Opacity)">
<
EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
</
DoubleAnimationUsingKeyFrames>
</
Storyboard>
</
VisualState>
<
VisualState x:Name="Pressed">
<
Storyboard>
<
DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Opacity)">
<
EasingDoubleKeyFrame KeyTime="00:00:00" Value="0.33"/>
</
DoubleAnimationUsingKeyFrames>
</
Storyboard>
</
VisualState>
</
VisualStateGroup>
</
VisualStateManager.VisualStateGroups>
<
Image x:Name="image" Source="jeffblankenburgheadshot.jpg" Width="200" Height="200"/>
<
ContentPresenter Height="24" VerticalAlignment="Top" Margin="53,60,53,0"/>
</
Grid>
</
ControlTemplate>
</
Application.Resources>
</
Application>

Summary

In short, this is a robust piece of functionality in Silverlight. Not only can we completely overhaul any of the controls, but we can also use them as templates for future, robust controls that we may imagine tomorrow. If there’s ANYTHING you don’t like about the default controls in Silverlight, you have the power to change them. That is incredibly liberating. Here’s what my new pseudo-button looks like:

Also, if you would like to download the source code for this Silverlight templating example, you can get it here.

Day #26: Silverlight Data Grid

Welcome to day #26 in my series called the 31 Days of Silverlight. Today, we’re going to be talking about how to use a DataGrid control in your Silverlight applications. Let’s get right to it.

1. Add a new reference to your Silverlight project

In order to use the Silverlight DataGrid control, we first need to add a new reference to our project. Go find System.Windows.Controls.Data, and add a reference to that assembly to your project. Make sure you’re only including this reference if you’re using a DataGrid. It’s sizeable, and you really don’t want the burden of this DLL unless you fully intend to use it.

2. Add the XML namespace to your XAML.

In order to use that reference, we need to add the XML namespace for that assembly to our page. This will allow us to add an actual DataGrid to our page. Here’s what my entire XAML page looks like before we begin:

<UserControl x:Class="SilverlightDataGrid.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<
Canvas x:Name="LayoutRoot">

</
Canvas>
</
UserControl>

3. Add a DataGrid to your page

Adding the DataGrid is the simple part of this tutorial. We’ll spend most of our time today manipulating its data. To add the grid to the page, however, use this little snippet of code inside your <Canvas>:

<data:DataGrid x:Name="citygrid" AutoGenerateColumns="True" />

Now, before you get too excited and start running your project, remember that we haven’t added any data to this DataGrid yet. We should probably do that first.

4. Adding data to the DataGrid from code

In order to have some data with some substance, I have set up a new Class file that defines a simple “Location.” Here’s how it looks:

public class Location
{
//Fields
private string _city;
private int _population;
private double _latitude;
private double _longitude;
private double _elevation;

//Properties
public string City
{
get { return _city; }
set { _city = value; }
}

public int Population
{
get { return _population; }
set { _population = value; }
}

public double Latitude
{
get { return _latitude; }
set { _latitude = value; }
}

public double Longitude
{
get { return _longitude; }
set { _longitude = value; }
}

public double Elevation
{
get { return _elevation; }
set { _elevation = value; }
}
}

Next, I’m going to create a List of Locations, and use that as my data source. For my locations, I have the population, elevation, and latitude/longitude or the 16 largest cities in the United States (according to the 2000 US Census). Here’s my data:

List<Location> locations = new List<Location>{
new Location {City="New York, NY", Population=8363710, Latitude=40.714269, Longitude=-74.005973, Elevation=10},
new Location {City="Los Angeles, CA", Population=3833995, Latitude=34.052234, Longitude=-118.243685, Elevation=71},
new Location {City="Chicago, IL", Population=2853114, Latitude=41.850033, Longitude=-87.650052, Elevation=182},
new Location {City="Houston, TX", Population=2242193, Latitude=29.763284, Longitude=-95.363271, Elevation=13},
new Location {City="Phoenix, AZ", Population=1567924, Latitude=33.448377, Longitude=-112.074037, Elevation=340},
new Location {City="Philadelphia, PA", Population=1540351, Latitude=39.952335, Longitude=-75.163789, Elevation=12},
new Location {City="San Antonio, TX", Population=1351305, Latitude=29.424122, Longitude=-98.493628, Elevation=198},
new Location {City="Dallas, TX", Population=1279910, Latitude=32.783330, Longitude=-96.800000, Elevation=131},
new Location {City="San Diego, CA", Population=1279329, Latitude=32.715329, Longitude=-117.157255, Elevation=22},
new Location {City="San Jose, CA", Population=948279, Latitude=37.339386, Longitude=-121.894955, Elevation=26},
new Location {City="Detroit, MI", Population=912062, Latitude=42.331427, Longitude=-83.045754, Elevation=183},
new Location {City="San Francisco, CA", Population=808976, Latitude=37.774929, Longitude=-122.419415, Elevation=16},
new Location {City="Jacksonville, FL", Population=807815, Latitude=30.332184, Longitude=-81.655651, Elevation=5},
new Location {City="Indianapolis, IN", Population=798382, Latitude=39.768377, Longitude=-86.158042, Elevation=218},
new Location {City="Austin, TX", Population=757688, Latitude=30.267153, Longitude=-97.743061, Elevation=149},
new Location {City="Columbus, OH", Population=754885, Latitude=39.961176, Longitude=-82.998794, Elevation=275}
};

Once we have some data to work with, we just need to set the ItemsSource property of our grid. I named my grid “citygrid,” so our statement will look like this:

citygrid.ItemsSource = locations;

If you run your project at this point, you should have a working grid, with all of the data populating it.

5. Using “some” of the data

Much like we did in Day #15, we’re going to use LINQ to select the cities we want. In this case, perhaps we only want cities with more than 1,000,000 citizens. Here’s how you can modify your ItemsSource statement to select just a portion of the entire set of data:

            citygrid.ItemsSource = from location in locations
where location.Population > 1000000
orderby location.City, location.Population
select location;

6. Checking out the built in functionality

If you haven’t run your project yet, give it a try. You should see a grid on your page, with either some or all of your data, depending on what you did in step #5. The grid has some built in functionality that makes our lives a little easier, and required ZERO code.

The first thing is that the columns auto-sort. So you can click on a column heading, and it will sort your cities, populations, etc. from top to bottom, and reversed.

Second, the cells are editable. So you can change the values we have stored in code without writing anything additionally. If you want to turn that off, just add the IsReadOnly=”True” property to your grid.

Third, the grid also has native validation. So, for example, if you try to edit one of the longitude cells, and enter a string for a value, it will prompt you that the value you entered is invalid. A nice bit of functionality for free, huh? Here’s my working Silverlight DataGrid in action (see it in a new window):

You can download my Silverlight DataGrid application here.

7. Summary

In short, it’s incredibly refreshing to have a DataGrid control for Silverlight. There’s thousands of business applications for this, and if you dig a little deeper, you’ll discover just how customizable this control really is. It doesn’t have to look like a grid at all, to be honest. Dan Wahlin has a good tutorial on customizing a grid to look like a timesheet application.

Day #25: Silverlight Outside The Browser (Part 3 of 3)

If you’re wondering, I am certainly not writing these on the day they publish. These were written many, many days prior, and are only being published over the holidays. I’m spending my time celebrating with my family, exchanging gifts, and catching up on some sleep. Have a happy holiday season everyone.

Detecting A Network Connection

Today is the final part of a three part series on “Out of Browser”, which is a part of a larger series, the 31 Days of Silverlight.

We continued yesterday with a simple Silverlight project that had Out of Browser enabled, and was capable of installation and detected its state. You can download that out of browser application here. We’ll be adding to that project today.

Our next step is to determine whether a user has a network connection while running our application.

1. Checking the network connection

We have to add an additional namespace in order to work with our network connection, so let’s start there. Add this using statement to the top of your MainPage.xaml.cs file:

using System.Net.NetworkInformation;

Once we’ve added that, we can use the NetworkInterface API. Since we know we’re going to need to extract this code into its own method, let’s just do that out of the gate. I am creating a function that has an if statement checking another boolean value, this time to determine if there is a network connection. If there is, my network status image is green, and if not, the image is red. Here’s the entire method:

        private void CheckNetworkStatus()
{
if (NetworkInterface.GetIsNetworkAvailable())
{
networkimage.Source = new BitmapImage(new Uri("network_on.png", UriKind.Relative));
}
else
{
networkimage.Source = new BitmapImage(new Uri("network_off.png", UriKind.Relative));
}
}

2. Setting up an event handler for changes

Because our network status can change while we’re running the application, we need to make sure that we’ve subscribed to the NetworkAddressChanged event. This way, our application will always be aware of the current network status. Here’s my event handler code:

NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);

Hooking everything up

Now, we’ve got an CheckNetworkStatus() method, but it’s not being called yet. I’m actually going to call it from two places: once when our apoplication loads, and the other in the event handler method. Here’s what our final code looks like:

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.Media.Imaging;
using System.Windows.Shapes;
using System.Net.NetworkInformation;

namespace SilverlightOutOfBrowser
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
outofbrowserimage.MouseLeftButtonUp += new MouseButtonEventHandler(installBigBangTheory);
}

void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
{
CheckNetworkStatus();
}

void installBigBangTheory(object sender, MouseButtonEventArgs e)
{
if (Application.Current.InstallState == InstallState.NotInstalled)
{
Application.Current.Install();
}
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
checkOOB();
CheckNetworkStatus();
}

private void CheckNetworkStatus()
{
if (NetworkInterface.GetIsNetworkAvailable())
{
networkimage.Source = new BitmapImage(new Uri("network_on.png", UriKind.Relative));
}
else
{
networkimage.Source = new BitmapImage(new Uri("network_off.png", UriKind.Relative));
}
}

private void checkOOB()
{
if (Application.Current.IsRunningOutOfBrowser)
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_on.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Big Bang Theory is installed on your machine.");
}
else
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_off.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Install Big Bang Theory");
}
}
}
}

Summary

For many applications, network status may seem like something you don’t need. But if you’re talking to web services, data, etc., you absolutely need to know that those things are not available. In general, I’d recommend setting up a local data cache, and synchronizing that in the background, so that you can pass the data back and forth with the confidence that you won’t lose it if the user loses their connection. But that’s an article for another time.

Launch this completed Silverlight Out of Browser application.

You can download the final source code for this Out of Browser Silverlight project here.

Day #24: Silverlight Outside The Browser (Part 2 of 3)

Detecting Whether A User Is In Or Out Of Browser

Today is the second part of a three part series on “Out of Browser”, which is a part of a larger series, the 31 Days of Silverlight.

We started yesterday with a simple Silverlight project that had Out of Browser enabled. You can download that out of browser application here. We’ll be adding to that project today.

In our next step, we’re going to need to know when the application is running in an out of browser state vs. a traditional in-browser state. With some simple event handlers, we can make this happen. We can also change our application to accommodate these changes.

1. Setting up a Loaded event handler

The first thing we need to do is tell our application to call an initial method when it loads. To do this, I added a simple event handler in my MainPage() method.

        public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}

This also creates the event handler method for us, and I’m going to add a simple if/then/else statement to determine our browser state.

2. Detecting the browser state

In our new event handler method, I’ve created an if statement that just checks the boolean value of Application.Current.IsRunningOutOfBrowser. In each case, I change the image to either red or green, and adjust the tooltip to read the appropraite text for the state. Here’s what the method looks like:

        void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (Application.Current.IsRunningOutOfBrowser)
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_on.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Uninstall Big Bang Theory");
}
else
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_off.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Install Big Bang Theory");
}
}

Because I might want to call this functionality at other times than when the application loads, I’m going to refactor this code a little. If you haven’t used this functionality of Visual Studio 2008 before, I highly recommend it.

3. Refactoring our code

Highlight the code you want to move to its own method, and right click on it. Like this:

It will prompt you to give this code a new method name. I called my method CheckOOB, since that’s what it will do.

So here’s what my entire code-behind file looks like now:

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.Media.Imaging;

namespace SilverlightOutOfBrowser
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
checkOOB();
}

private void checkOOB()
{
if (Application.Current.IsRunningOutOfBrowser)
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_on.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Uninstall Big Bang Theory");
}
else
{
outofbrowserimage.Source = new BitmapImage(new Uri("outofbrowser_off.png", UriKind.Relative));
ToolTipService.SetToolTip(outofbrowserimage, "Install Big Bang Theory");
}
}
}
}

The next thing I want to do it make it so that the image I am using to show status is also a button for the user to click. I don’t want them to have to discover the right-click menu to install, instead, I want to make it an obvious choice. Let’s do that next.

4. Creating an Install button

We will need an event handler on the image, so let’s start there:

outofbrowserimage.MouseLeftButtonUp += new MouseButtonEventHandler(outofbrowserimage_MouseLeftButtonUp);

In the subsequent method, we can simply call the Application.Current.Install() method. We need to wrap this statement in a check to make sure that the application has not already been installed. Where this becomes the biggest issue is when the user has installed your application, but is back at the website version of your app. If they click the Install button again, your application will throw an error, because it’s already been installed. Here’s the code:

void installBigBangTheory(object sender, MouseButtonEventArgs e)
{
if (Application.Current.InstallState == InstallState.NotInstalled)
{
Application.Current.Install();
}
}

An important thing to note about this Install() function is that it MUST be called by a user-instantiated action. This means that you can’t just call it when the application loads, or in the background. It has to have a code pathway that resulted from a user action.

Also, regarding uninstalling…there’s no way to do it via code. To uninstall, your user will have to right-click on the application, or go to their control panel to uninstall it. I’m hoping that we can provide a more user-friendly solution to this in future versions of Silverlight, but for SL3, this is the way it is.

Summary

This is actually a pretty simple process. Check a boolean value, and act accordingly. But, as we learned from the Spiderman movies, “with great power comes great responsibility.” Make sure that you’re providing clear instructions for your users regarding how to install and uninstall your application. Installing, as a word, is frightening to many users and most every systems administrator.

To see this application running, and to install it, click here.

If you’d like to download this code for this project, you can get my Out of Browser Detection solution here.

Day #23: Silverlight Outside The Browser (Part 1 of 3)

Enabling Out Of Browser in Your Silverlight App

For the next three days in the 31 Days of Silverlight, we’re going to cover some of the intricacies of getting a Silverlight application to run outside the user’s browser. This is a relatively simple change to your app, but it also introduces new challenges, like the need to detect which mode the user is in, and whether they have network connectivity or not. The next two articles will cover these topics specifically.

Today, we’re going to show you how to get out-of-browser working. So let’s get started.

To make this a little easier, I have created a sample project for you to start with. Inside, you’ll find a simple application that has a video player, and two images. The first image indicates whether there is network connectivity, and the other is to allow the user to “Install” the application to their machine.

But before we deal with any of that, we need to get our application “enabled” for the out of browser experience. By default, Silverlight 3 applications are not enabled.

1. Go to your Silverlight project properties

Opening the properties of your Silverlight project will give you the choice to “Enable running the application out of the browser, in addition to some new configuration choices. We’ll get to those in a second. Here’s what the screens look like:

2. Customize Your Settings

Once you’ve enabled Out of Browser for your Silverlight application, you get a new button to customize the settings for your installation. It includes things like titles, descriptions, and icons of different sizes for the shortcuts on your user’s machines. Here’s my completed Settings screen:

In case you’re curious, these settings are saved in a new XML file in your project. Look for OutOfBrowserSettings.xml in your Silverlight project’s Properties folder. Here’s what my settings file looks like:

<OutOfBrowserSettings ShortName="Big Bang Theory" EnableGPUAcceleration="False" ShowInstallMenuItem="True">
<
OutOfBrowserSettings.Blurb>This application will play the theme song for the CBS television show Big Bang Theory in a video found on YouTube. You can also find the video here: http://www.youtube.com/watch?v=lhTSfOZUNLo</OutOfBrowserSettings.Blurb>
<
OutOfBrowserSettings.WindowSettings>
<
WindowSettings Title="Big Bang Theory" Height="480" Width="640" />
</
OutOfBrowserSettings.WindowSettings>
<
OutOfBrowserSettings.Icons>
<
Icon Size="16,16">globe_16.png</Icon>
<
Icon Size="32,32">globe_32.png</Icon>
<
Icon Size="48,48">globe_48.png</Icon>
<
Icon Size="128,128">globe_128.png</Icon>
</
OutOfBrowserSettings.Icons>
</
OutOfBrowserSettings>

3. Installing the Application

I’ve chosen not to embed my application below (you can launch it here), because it has audio, and I don’t want to have that playing while you’re reading this post. If you right click on the application, you should have a second choice: Installing the application. If you choose this, it will save your application down to the local sandbox on your machine, and also gives you some choices for where to install it. When you’re done, it will also launch the local version for you as well. At that point, you can close your browser, and the application still works.

Here is a screenshot of the installation dialog (with my custom icon):

And here is a screenshot of the application running in the out-of-browser window.

Summary

You can see that this is a pretty simple process to enable Out of Browser functionality for your Silverlight application. In the next two days, we’re going to work on adding to this application, detecting whether the user has installed it or not, and then whether or not they have a network connection. Yes, Virginia, your Silverlight application can now run in a disconnected mode. See you tomorrow!

If you’d like to download this starter application, you can get my Out of Browser solution here.