August 18th, 2009, Paul , Tags: Silverlight month, TastyLibrary
What you’ll need
Okay okay, it hasn’t exactly been all within the same month, but with exams and illness, I haven’t had time to dive into it! Unlike last time, I’m not going through every single step, just the interesting snippets. Because of that, there isn’t a starter kit, just the final project.
Click to view the demo!
Silverlight 3 bringing in more awesome
You may notice that I am now using Silverlight 3. Silverlight 3 is even closer to WPF than before and it solves some of the "hackery" in TastyLibrary. In the first post, I used LINQ to rebind the ItemSource every time you click a new category. Thanks to the filtering capabilities introduced in Silverlight 3, we can "do it right" by filtering the CollectionViewSource.
private void lstCategories_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
cvsItems.Filter += new FilterEventHandler(cvsItems_Filter);
}
void cvsItems_Filter(object sender, FilterEventArgs e)
{
if (lstCategories.SelectedIndex >= 0)
{
if (((Item)(e.Item)).Category == ((Category)lstCategories.SelectedItem))
e.Accepted = true;
else
e.Accepted = false;
}
else
e.Accepted = true;
}
Functionally, it appears to be the same… until you start adding more data. When you’re setting the ItemSource to a LINQ query, it doesn’t automatically update when new items are added into the base collection but when you are filtering every item has to pass through the filtering method even the new items that are added.
Apart from filtering, Silverlight 3 now has hardware accelerated effects, such as drop shadows or whatever you can build with pixel shaders! While it sounds gimmicky, drop shadows can help to create a much more refined UI. I’ve chosen to add this to various Grid’s in XAML:
<Grid.Effect>
<DropShadowEffect BlurRadius="16" Direction="238" ShadowDepth="0"/>
</Grid.Effect>
(Don’t worry, there are plenty of other new features in Silverlight 3, but those are all I’m using)
Adding more data
In the last episode, we created a very basic clone of Delicious Library. Our version let you view a "bookshelf" of a set of albums, DVDs or games, the only problem was it was a fixed set of data. That makes it not particularly useful, because you’d have to manually edit the XML files whenever you wanted to add or remove an item. For a data source, I’d recommend and I have used Amazon simply because they are one of the (if not the largest) online stores and they provide a nice API.
If we were creating a desktop application, we could quiet easily use the SOAP interface and auto-generate the classes from the WSDL. However, Silverlight has security restrictions on the way it can interact with websites. If you are interacting with a web service on the same domain there are no restrictions, but interacting with services on other domains requires the domain to implement a cross domain policy file (and it must permit your application). Flash has similar restrictions on it. A common work around to this ‘problem’ is to use a proxy on your own server which does all the interaction with the service, but it’s messy, particularly when in this case, the Amazon Advertising (formerly ECS) REST/XML API has a cross domain policy file that works properly with Silverlight.
The SignedRequestHelper is provided from Amazon’s C# example of connecting to their API, while the Amazon namespace is a small helper library I’ve made to make it easier to choose various parameters/methods when interacting with Amazon’s API.
private void Search(string Keyword, string SearchIndex)
{
SignedRequestHelper helper = new SignedRequestHelper(amazonAccessKey, amazonSecretKey, Amazon.Destinations.US);
IDictionary<string, string> requestParams = new Dictionary<string, String>();
requestParams["Service"] = "AWSECommerceService";
requestParams["Version"] = "2009-03-31";
requestParams["Operation"] = Amazon.Operation.ItemSearch;
requestParams["Keywords"] = HttpUtility.UrlEncode(Keyword);
requestParams["SearchIndex"] = SearchIndex;
requestParams["ResponseGroup"] = Amazon.ResponseGroup.Medium;
string requestUrl = helper.Sign(requestParams);
WebClient req = new WebClient();
req.DownloadStringCompleted += new DownloadStringCompletedEventHandler (req_DownloadStringCompleted);
req.DownloadStringAsync(new Uri(requestUrl));
}
Searching for items is easy! Wait, hang on, where is the response? Silverlight requires network interactions to be asynchronous so that the calling thread (ie, the UI) doesn’t hang which would result in the entire browser locking up! (unless it separates tabs/plugins into threads like Google Chrome)
The response…
private void req_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
XNamespace ns = NAMESPACE;
XDocument results = XDocument.Parse(e.Result);
var resultItems = from i in results.Descendants(ns + "Item")
select i;
foreach (var item in resultItems)
{
try
{
var img = (from i in item.Element(ns + "ImageSets").Elements(ns + "ImageSet")
where i.Attribute("Category").Value == "primary"
select i).First().Element(ns + "MediumImage").Element(ns + "URL").Value;
Item temp = new Item()
{
Name = item.Element(ns + "ItemAttributes").Element(ns + "Title").Value,
Image = img
};
if (cbCategory.SelectedItem == cbiGames)
temp.Category = catList["Games"];
else if (cbCategory.SelectedItem == cbiDVDs)
temp.Category = catList["DVDs"];
else if (cbCategory.SelectedItem == cbiMusic)
temp.Category = catList["Music"];
lstSearchItems.Items.Add(temp);
}
catch (Exception ex)
{
}
}
}
To parse the response I’ve used Linq-to-XML, created my new Item, and then inserted into the listbox containing all the search items.
This post shows off some basic Silverlight 3 features as well as interaction with web services uses Silverlight. Next post – interacting with persisting data!
No Comments »
May 17th, 2009, Paul , Tags: Silverlight, Silverlight month
I’ve prattled on about what Silverlight is and what is coming in Silverlight’s future, but how do you go about making your own Silverlight applications/websites?
Silverlight 1.0 was XAML + JavaScript, while Silverlight 2/3 is .NET + XAML (+ JavaScript if you want it). If you already know a .NET language, you can use that to create Silverlight goodness.
Silverlight tools
Before we get going with Silverlight goodness, you’ll need to download some basic tools.
Expression Blend
Expression Blend is a WPF application – meaning it was created using XAML too! Like most (all?) of Microsoft’s developer tools, it’s available free to students through Dreamspark.
You’ll need Expression Blend 2 Service Pack 1 (17.8meg) if you want to use this with Silverlight 2
Visual Studio 2008
Expression Blend 2 isn’t able to play with the C#/.NET code behind, although this changes in Expression Blend 3 which introduces Intellisense for both XAML and C#.
Grab your free copy at Dreamspark
Silverlight 2 Tools for VS2008
Weighing in at 72.7meg, the Silverlight 2 tools for VS2008 includes the Silverlight 2 runtime & SDK, enables Silverlight specific Intellisense & code generation in VS2008, and provides Silverlight templates for VS2008.
Deep Zoom Composer
Deep Zoom Composer (5mb) is entirely optional, but it is fun to play around with if you think Deep Zoom is cool. Or, you know, you want to use it in your Silverlight app. And it’s free.
Silverlight 2 Toolkit
Silverlight doesn’t come with every single control, so instead of releasing a completely new version everytime Microsoft adds a new control, developers can download the Silverlight 2 Toolkit, and then it gets automatically downloaded when users visit your application.
Grab it from Codeplex (we need WrapPanel from it!)
Silverlight 101: TastyLibrary – DeliciousLibrary clone
Although it won’t be anywhere near feature comparable, I wanted to do something a little bit more exciting than just "Hello World", so this tutorial – TastyLibrary – will replicate the basic UI of Delicious-Monster’s DeliciousLibrary for OSX. DeliciousLibrary is a catalogue for your books, movies, music, software, etc.
I’ve created a starter kit which contains sample XML files, a few JPEGs, and two classes LibraryItems and Categories which are just wrappers around the XML files. If you want to see how it all works, but can’t be bothered making it yourself, you can download the completed solution too! Or if you just want to see the demo in action… do that clicky thing.

I’ll be using a combination of Expression Blend and VS2008, but for now, just fire up Blend, select New Project, Silverlight 2 Application.
DeliciousLibrary is divided into two main regions – the navigation and presentation of library items. By default in Blend, Silverlight 2 applications are created with only a Grid object (named LayoutRoot) in the page. This works out great, because we can easily divide the grid into two columns to better align the two regions in TastyLibrary.
To create columns in a Grid, select the Grid, then move your mouse around the blue area to the top and left of the WYSIWYG area in Blend. As you’re hovering it will create a vertical (or horizontal if you’re trying to create a row!) orange line – once you click it creates the column and changes to a blue line. Don’t worry if don’t place it exactly where you want, you can always move the column around.
Add in two ListBoxes – one to each column – by going to Asset Library (the ">>" button in the toolbar on the left), and typing in Listbox. Double click and resize OR draw the two ListBoxes onto the page.
Select each of the ListBoxes to give them a name by going to the top-right of the screen and replacing the default ‘[ListBox]‘. I’ve used lstItems and lstCategories.
Data
Now to actually start implementing some of the code behind so things start appearing on the screen. For this, I’d recommend switching over to Visual Studio 2008.
For this tutorial, we’ll just use a static list of items, but in the next tutorial we’ll be fetching them in more advanced ways.
Add the two XML files and all the images in the starter kit to the project (right click on the project, Add –> Existing Item), and make sure you set Copy To Output Directory to Copy If Newer, otherwise the files won’t be in the right directory when TastyLibrary is compiled.
Also add Categories.cs and LibraryItems.cs. They were generated by a tool called XSD which takes a XML file and generates a class for handling that type of data.
Your project should look something like this:
Double click on Page.xaml.cs to open it up.
To the top of the page add:
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Linq;
These are the namespaces which contain the objects and structures that we need.
Just under the class declaration, add:
private List<CategoriesCategory> catList = new List<CategoriesCategory>();
private List<LibraryItemsLibraryItem> itemList = new List<LibraryItemsLibraryItem>();
private void LoadXMLFile()
{
XmlReader xreader = XmlReader.Create("Items.xml");
XmlSerializer serialiser = new XmlSerializer(typeof(LibraryItems));
LibraryItems libraryItems = serialiser.Deserialize(xreader) as LibraryItems;
foreach (LibraryItemsLibraryItem li in libraryItems.Items)
{
itemList.Add(li);
}
xreader = XmlReader.Create("Categories.xml");
serialiser = new XmlSerializer(typeof(Categories));
Categories Categories = serialiser.Deserialize(xreader) as Categories;
foreach (CategoriesCategory ci in Categories.Items)
{
catList.Add(ci);
}
}
This method loads both the categories and the items into the Lists at the start of this code block. All we need to do is call it, then bind the Lists to our ListBoxes. We could bind directly to the ListBoxes, but then we lose the (easy) filtering ability.
public Page()
{
InitializeComponent();
LoadXMLFile();
lstItems.ItemsSource = itemList;
lstCategories.ItemsSource = catList;
}
This will load our items straight into our ListBox. Go to Debug –> Start Debugging, which will fire the page up in your browser of choice. You’ll notice it looks very… boring. For a start, we want images, not the type! We can fix that by creating a DataTemplate.
Go back to Page.xaml, and before “<Grid x:Name="LayoutRoot" Background="White">” paste in this code:
<UserControl.Resources>
<DataTemplate x:Name="dtItems">
<Image Source="{Binding Path=Image}" Width="150" Height="150" />
</DataTemplate>
<DataTemplate x:Name="dtCategories">
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</UserControl.Resources>
And change the lstItem’s ListBox to:
<ListBox Margin="8,8,8,8" Grid.Column="1" x:Name="lstItems"
ItemTemplate="{StaticResource dtItems}" />
This way the ListBox will use the data template named ‘dtItems’ for its items. Do the same for lstCategories (obviously changing it to dtCategories instead!)
The next problem is that there is only one LibraryItem per row, when ideally, we want as many as will fit on a row. The easiest way to do this is with a WrapPanel…which is in the Silverlight 2 Toolkit (which you hopefully downloaded at the very start of this post!)
Once you have installed that, you will need to add a reference to your project for System.Windows.Controls.Toolkit. Right click on your project, Add References, select Browser, then navigate to "C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Toolkit\March 2009\Libraries" and select System.Windows.Controls.Toolkit.DLL.

After you’ve done that, go back to Page.Xaml, and to the opening UserControl tag, add:
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
This allows us to access the toolkits controls by prefixing tags with ‘controls’.
To use the WrapPanel with our listbox, replace lstItems with this:
<ListBox
x:Name="lstItems"
Margin="8,8,8,8"
Grid.Column="1"
ItemTemplate="{StaticResource dtItems}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<controls:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
Finally, all we need to do is filter our the library items by the type item type (music, book, dvd). We can achieve what we want by using LINQ. Add a handler to SelectionChanged on lstCategories:
<ListBox
x:Name="lstCategories"
Margin="8,8,8,8"
ItemTemplate="{StaticResource dtCategories}"
SelectionChanged="lstCategories_SelectionChanged"
/>
and to the code behind add:
private void lstCategories_SelectionChanged(object senderSelectionChangedEventArgs e)
{
var filteredItemSource = from i in itemList
where i.Category == ((CategoriesCategory)lstCategories.SelectedItem).Name
select i;
lstItems.ItemsSource = filteredItemSource;
lstItems.UpdateLayout();
}
If you’ve not used LINQ before, this may look a little bit like an SQL query… LINQ stands for Language-INtergrated-Query, so it isn’t far off!
The statement basically selects all the LibraryItems in itemList that have the same Category value as the Category selected in lstCategories. This means if you select ‘games’, only the ‘games’ appear.
I hope you’ve enjoyed this "Hello World" replacement to Silverlight 2!
9 Comments »