Silverlight FlickR Example
May 29th, 2008 by kerrysoft and tagged J2EE, real estate software, web applicationIn this example I will exhibit a very bare call to the FlickR REST APIs from a Silverlight client. At the end we will terminate up with an app that appears like this:
Part 1. Specify some Silverlight UI
Part 2. Shew the local exposed file dialog support
Part 3. Call in the FlickR Service to rule a picture
Part 4. Employ IsolatedStorage to uphold some local settings across runs
Part 5. Scraping the UI
You are welcome to besides catch the finished sample , and demo files
Part 1. Limit some Silverlight UI
You can plump backwards and view the post on my End to Finish Silverlight Application post for the making commenced. In Blend sum up a TextBox, and Button to the window and layout as proven.
Be certain to pass on them some meaningful name in the properties window so we can refer to them pragmatically later. Mine are called off searchTermTextBox, and button.
Dredge an example image on to the window so we can have something to work with. (You can apply cow.jpg from the SilverlightFlickRDemoFiles zip)
Get surely you identify this one as intimately… I applyed searchResultsImage
Part 2. Local Open File Dialog
Barely to try out out our layout, tot up support for poping up unresolved the undecided file dialog and work with the image client side. This is something that you can’t promptly do in Ajax\HTML today.
In page.xaml Add together a Click event handler
<Button x:Name="button" Width="100" Height="50" Content="Go" Click="button_Click"
In page.xaml.cs follow out the button click to call up unresolved file dialog.
secret void button_Click(object sender, RoutedEventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "JPEG Files (*.jpg;*.jpeg)|*.jpg;*.jpeg | All Files (*.*)|*.*"; ofd.FilterIndex = 1; if (ofd.ShowDialog() == DialogResult.OK) { Stream stream = ofd.SelectedFile.OpenRead(); BitmapImage bi = new BitmapImage(); bi.SetSource(stream); searchResultsImage.Source = bi; stream.Near(); } }
This code will unfold the system undetermined file dialog permiting the user to take a file on disk. And so the developer is left merely make unnecessary access to the file (that is scarcely the bits, not hte path to the file). Acknowledge how we are capable to work with the image client slide.
At this point you could upload the file to a server or hive away it topically in Sequestrated Storage. But this is a little off from where we were attaching to looking for flickr for an image..
Part 3. Ring the FlickR Service to see a picture
Today we tangle with the meat of it. We call for to legislate our search term into FlickRs REST API and planted the image to be the results. As the user clicks on the image, we can render the next one in the results planted.
First we demand to telephone FlickRs REST API. To do this you call for a key, which you can get for spare from FlickR…
Next we need to in reality phone the REST API from the Silverlight client. To do that, let’s define a helper method
void LoadPhotos(string topic) { string apiKey = "<<get your own >>"; string secret = "<<get your own >>"; string url = String.Format("http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key={1}&text={0}", topic, apiKey, secret); WebClient flickRService = new WebClient(); flickRService.DownloadStringCompleted += new DownloadStringCompletedEventHandler(flickRService_DownloadStringCompleted); flickRService.DownloadStringAsync(new Uri(url)); searchTermTextBox.Text = "Calling FlickR...";
}
Next we need to parse the results. You can see the format of the results by looking at http://flickr.com/services/api/explore/. Basically, the results look like this:
<?xml version="1.0" encoding="utf-8" ?> <rsp stat="ok"> <photos page="1" pages="32769" perpage="100" total="3276843"> <photo id="2436622217" owner="22956152@N04" secret="6c8293bb5c" server="2070" farm="3" title="IMG_3492_resize" ispublic="1" isfriend="0" isfamily="0" /> <photo id="2437437876" owner="41848473@N00" secret="97a7e1a066" server="2303" farm="3" title="Eric & Dog" ispublic="1" isfriend="0" isfamily="0" /> </photos> </rsp>
So, we need to do a little Xml parsing. Luckily this is very easy to do in Silverlight with LinqToXml support. Just add a reference to the System.Xml.linq.dll assembly.
Now let’s implement flickRService_DownloadStringCompleted. The first thing we need to do is a little error checking… This will help a lot making sure everything is right calling FlickR.
XDocument xmlPhotos = XDocument.Parse(e.Result); if (e.Error != null || xmlPhotos.Element("rsp").Attribute("stat").Value == "fail"){ string results = e.Result; searchTermTextBox.Text= "Error! (" + results + ")"; return; } else { searchTermTextBox.Text = "It worked!"; }
Now we just need to wire up the call to LoadPhotos.
private void button_Click(object sender, RoutedEventArgs e) { LoadPhotos(searchTermTextBox.Text); }
Run it. If you see this, go back and check your API key.
When you see this, you are golden and ready for the next step!
Now, we need to parse the Xml results and pull out the URLs to the image. We are going to use the magic of Linq to handle all the ugly Xml parsing. All we need to do is to define a.NET class we want the XML elements mapped into.
public class FlickRPhoto { public string Id { get; set; } public string Owner { get; set; } public string Secret { get; set; } public string Server { get; set; } public string Farm { get; set; } public string Title { get; set; } }
And, leet’s just add another property that class which follows the FlickR URL conventions for form up a Url to the image
public string ImageUrl { get { return string.Format("http://farm{0}.static.flickr.com/{1}/{2}_{3}.jpg", Farm,Server,Id,Secret); } }
Now, we need the Linq code that maps the Xml elements into this class.
Photos = from photo in xmlPhotos.Element("rsp").Element("photos").Descendants().ToList() select new FlickRPhoto { Id = (string)photo.Attribute("id"), Owner = (string)photo.Attribute("owner"), Secret = (string)photo.Attribute("secret"), Server = (string)photo.Attribute("server"), Farm = (string)photo.Attribute("farm"), Title = (string)photo.Attribute("title"), };
Let’s define Photos as a field on this class, so we can access it later.
IEnumerable<FlickRPhoto> Photos;
Now we just need to display the image. To do that, we but seize the first record from the result set and expose it!
FlickRPhoto p = Photos.First(); this.searchResultsImage.SetValue(Image.SourceProperty, p.ImageUrl); searchTermTextBox.Text = p.Title;
Today that is nerveless, but I desire to understand the other photos.. A agile a marked-up way to do this is to alter the photo when the photo is snaped. To do this sign up for the event handler
<Image MouseLeftButtonDown="searchResultsImage_MouseLeftButtonDown" x:Name="searchResultsImage"
And follow out it. I do a slight error disciplining up front, and utilise a newfangled class field telephoned ImageNumber to hold up with hither I am.
secret void searchResultsImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (Photos == null) give; if (ImageNumber >= Photos.Count()) ImageNumber = 0; FlickRPhoto p = Photos.Skip(ImageNumber).First(); this.searchResultsImage.SetValue(Image.SourceProperty, p.ImageUrl); ImageNumber++; }
At present as you click on the picture, it bicycles you through the result planted
Part 4: Use IsolatedStorage to preserve some local settings across runs
At present, let’s see about preserving some of this state across runs.
First, let’s save off the results of the textbox when the "Go" button is pressed.
private void button_Click(object sender, RoutedEventArgs e) { LoadPhotos(searchTermTextBox.Text); ApplicationSettings.Default["searchTerm"] = txtBox.Text; ApplicationSettings.Default.Save(); }
and the same idea when the image changes
private void searchResultsImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (Photos == null) return; if (ImageNumber >= Photos.Count()) ImageNumber = 0; FlickRPhoto p = Photos.Skip(ImageNumber).First(); this.searchResultsImage.SetValue(Image.SourceProperty, p.ImageUrl); searchTermTextBox.Text = p.Title; ApplicationSettings.Default["imageNumber"] = ImageNumber; ApplicationSettings.Default.Save(); ImageNumber++; }
Then when the application starts up we can pull the latest set and initialize with it.
public Page() { InitializeComponent(); if (ApplicationSettings.Default.Contains("searchTerm")){ this.txtBox.Text = (string)ApplicationSettings.Default["searchTerm"]; button_Click(null, null); } if (ApplicationSettings.Default.Contains("imageNumber")){ ImageNumber = (int)ApplicationSettings.Default["imageNumber"]; } }
When you run it the first time, it has not saved state so it uses the default. But run it again and notice it picks up where you left off!
Part 5: Skin it
Now, let’s give it a nice skin. Again, I will use Corrina’s Rough Skin.
Just cut and paste the <ApplicationResources> section from Corrina’s example into your App.Xaml
Then add the styles
<Button Style="{StaticResource buttonStyle}"
<TextBox Style="{StaticResource textBoxStyle}"
Done!
You are welcome to also get the completed sample , and demo files
Relating Posts:
Scott Guthrie presents at NDDNUG
Updated ASP.NET Dynamic Data Bits Posted
Win friends and influence your team
A quick update on me.
Be my Support Group
Debugging a MissingMethodException, MissingFieldException, TypeLoadException
Posted in Technology | Comments Off