Yes, I made it :) Welcome to this last post in my Silverlight Advent Calendar! From December 1st until today, December 24th, I have created each day, a Silverlight article. When I first thought about it, I feared there would be at least one day I would not be able to create my post. Well, this didn’t happen, and this means that after 24 articles, we have finally arrived at Christmas Eve. I really hope you enjoyed these posts and I’ll sure be doing something similar in the future!
On a “real” advent calendar, on December 24th, the final day of the calendar, you get a special surprise: a bigger image, a bigger gift or a larger chunk of chocolate than on other days. Well, I thought this needed to be the case in my advent calendar as well, so I decided to end my series with a special post. It gives a preview of something that can in much more detail be found in my upcoming book AND it brings some more Christmas spirit on this day: a Flickr Christmas image browser. All free as my gift to you!
Below is the interface of the application.
We’re in luck when working with Flickr: it exposes a cross-domain file so we can access their API services from a client Silverlight application, even without running with elevated permissions! Therefore, we do not need to create a service layer that sits in between our application and Flickr’s services.
When clicking on the Get Pictures button, we load thumbnails into a templated StackPanel. When clicking on any of these thumbnails, the large image is loaded. To store the information needed for a thumbnail, I created a class called SmallFlickrImage.
public class SmallFlickrImage
{
public string ImageId { get; set; }
public string FarmId { get; set; }
public string ServerId { get; set; }
public string Secret { get; set; }
public string ImageUrl
get
return string.Format(
"http://farm{0}.static.flickr.com/{1}/{2}_{3}_m.jpg",
FarmId,
ServerId,
ImageId,
Secret
);
}
In the click event, we perform a service call to Flickr. To call Flickr’s API, you’ll need an API key which can be obtained for free at http://www.flickr.com/services/api/. Once obtained, you need to embed this key in each request your application will perform with Flickr. Also on this site, you’ll find a complete overview of all available methods. Here, I’m using the flickr.photos.search method, which accepts a search string and returns me an XML response, containing all the information I need to display images in my client side application.
Working with Flickr is a typical example of a REST service. When working with these services from Silverlight, we actually need to do 3 steps:
The URL is constructed as follows (as directed by Flickr):
string searchUrl =
"http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key={0}
&text=christmas tree snow";
To send a request to this URL, we can use either the WebClient, or the HttpWebRequest. WebClient is sufficient (there are cases where this is not the case, I spent many pages to this topic in my book ;) ). Working in Silverlight with WebClient is identical to working with this class in the full .NET framework. One thing though: just like any interaction with a service, the service call is to be done asynchronously. The code below sends a request to Flickr:
private void GetPicturesButton_Click(object sender, RoutedEventArgs e)
WebClient client = new WebClient();
client.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri(string.Format(searchUrl, api_key)));
In the callback, which is invoked automatically when the service returns, using some very simple LINQ-To-XML, we can parse the results. The returned XML is always of the same format and can be seen as the contract between Flickr and my application. Because we cannot set the Source property of an Image control directly, we need to go around using a BitmapImage.
protected void client_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
XDocument xml = XDocument.Parse(e.Result);
var photos = from results in xml.Descendants("photo")
select new SmallFlickrImage
ImageId = results.Attribute("id").Value.ToString(),
FarmId = results.Attribute("farm").Value.ToString(),
ServerId = results.Attribute("server").Value.ToString(),
Secret = results.Attribute("secret").Value.ToString()
};
foreach (var photo in photos)
Image image = new Image();
BitmapImage bitmapImage = new BitmapImage(new Uri(photo.ImageUrl, UriKind.Absolute));
image.Source = bitmapImage;
image.Width = 160;
image.Height = 160;
image.Stretch = Stretch.Uniform;
image.Tag = photo;
image.Margin = new Thickness(3);
image.HorizontalAlignment = HorizontalAlignment.Center;
image.MouseLeftButtonDown += new MouseButtonEventHandler(img_MouseLeftButtonDown);
PicListBox.Items.Add(image);
At this point, the ListBox is filled. This ListBox is templated; the code for this can be seen in the sample code download.
When clicking (we attached a MouseLeftButtonDown event on each dynamically added image) on an image, we’ll load the "full” image into an Image control. This requires some code, mostly concerning which type of URL is used by Flickr for the image.
void img_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
Image img = sender as Image;
SmallFlickrImage smallFlickrImage = img.Tag as SmallFlickrImage;
if (smallFlickrImage != null)
WebClient detailClient = new WebClient();
detailClient.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(detailClient_DownloadStringCompleted);
detailClient.DownloadStringAsync(
new Uri(string.Format(detailUrl, api_key, smallFlickrImage.ImageId)));
void detailClient_DownloadStringCompleted(object sender,
XDocument xmlDocument = XDocument.Parse(e.Result);
XElement photoElement;
Uri detailImageUrl;
if (xmlDocument.Descendants("photo").Count<XElement>() > 0)
photoElement = xmlDocument.Descendants("photo").First<XElement>();
string serverId = photoElement.Attribute("server").Value;
string farmId = photoElement.Attribute("farm").Value;
string imageId = photoElement.Attribute("id").Value;
string secret;
if (photoElement.Attribute("originalsecret") != null)
secret = photoElement.Attribute("originalsecret").Value;
detailImageUrl = new Uri(string.Format
("http://farm{0}.static.flickr.com/{1}/{2}_{3}_o.jpg",
farmId,
serverId,
imageId,
secret)
else
secret = photoElement.Attribute("secret").Value;
("http://farm{0}.static.flickr.com/{1}/{2}_{3}.jpg",
BitmapImage bitmapImage = new BitmapImage(detailImageUrl);
DetailImage.Source = bitmapImage;
With that, the sample is working!
The complete code sample can be downloaded here: SLChristmasFlickr.zip (31.34 KB)
MERRY CHRISTMAS!
Ads by The Lounge
All content is property of www.snowball.be. Nothing on this site can be copied or published elsewhere, unless otherwise stated.
This site is made by Gill Cleeren.
Questions? Opinions? E-mail