none
Silverlight 2 (beta1)数据操作(7)——调用FlickR REST APIs来查询图片 RRS feed

  • 常规讨论

  • 这篇文章介绍Silverlight客户端如何调用FlickR REST APIs来查询图片


    原文:Silverlight FlickR Example (Brad Abrams)
    地址:http://blogs.msdn.com/brada/archive/2008/04/25/silverlight-flickr-example.aspx

    在这个例子中我将展示从Silverlight客户端调用FlickR REST APIs。最后实现如下图所示:

    整体效果图

    目录

    • 确定Silverlight用户界面
    • 本地打开文件对话框
    • 调用FlickR服务来查找图片
    • 使用IsolatedStorag来维持跳转设置
    • 定义皮肤
    • 下载 完整例子 demo文件

    第一部分:确定Silverlight用户界面

    你可以回顾我的End to End Silverlight Application 这篇帖子了解如何开始。首先在Blend中添加一个TextBox和Button控件,如下图所示:

    添加一个TextBox和Button控件

    务必在属性窗口为这些控件设置有意义的名称以便以后可以方便使用,我把这两个控件分别命名为searchTermTextBox和button。

    拖一个示例图片到窗口中,接下来我们需要用到这个图片(你可以在SilverlightFlickRDemoFiles zip中使用cow.jpg这个图片)

    拖一个示例图片到窗口中

    还有一点务必设置它的名称,我命名为searchResultsImage

    第二部分:本地打开文件对话框

    为了测试布局,我们添加一个打开文件对话框来处理客户端的图片。

    在page.xaml中为Button按钮添加一个单击事件

    <Button x:Name="button" Width="100" Height="50" 
            Content="Go"
            Click="button_Click"

    在page.xaml.cs中编写按钮事件来调用打开文件对话框。

        private 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.Close();
            }
        }

    这段代码作用是打开系统本地文件对话框允许用者在本地磁盘选择文件。然后开发者只保存文件路径。注意我们怎样在客户端处理图片呢?

    image

    image

    使用打开文件对话框,你可以上传文件到服务器或者存储文件到本地。但是这里我们是从flickr上查询图片。

    第三部分:调用FlickR服务来查找图片

    现在我们进入程序的主要部分了,我们根据查询条件通过调用FlickRs REST API来获取图片结果集。并且当用户在图片上单击,可以自动跳至下一张图片。

    首先,调用FlickRs REST API,你需要申请一个Key,从这里可以获取。

    接下来,定义一个LoadPhotos()方法在Silverlight客户端调用REST API。

    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...";
    }

    调用REST API完成之后,我们需要分析XML格式,你可以参考 http://flickr.com/services/api/explore/这个页面,其格式基本上像下面样子:

    <?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>

    所以,我们需要用到XML,Silverlight 2对LinqToXml很好的支持,我们很容易利用LinqToXml来获取节点,使用LinqToXml之前,你需要在Silverlight工程中添加System.Xml.linq.dll程序集。

    image

    现在,让我们实现flickRService_DownloadStringCompleted方法。首先判断是否在调用过程中发生了错误,确定一下是否正确的调用了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!";
    }

    现在在单击事件中使用LoadPhotos方法。

    private void button_Click(object sender, RoutedEventArgs e)
    {
        LoadPhotos(searchTermTextBox.Text);
    }

    运行程序,如果你看到如下图所示的话,key验证失败,请检验你的API key

    image

    当你看到的是这样,你上面做的全部都正确了,可以接着往下做!

    image

    我们分析一下XML结果集,需要截取图片的URL地址,我们使用LINQ,首先呢,定义一个FlickRPhoto类来封装一下XML节点的映射。

    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; }
    }

    还要添加一个属性值在遵循FlickR URL协议下格式化输出图片URL。

    public string ImageUrl
    {
        get
        {
            return string.Format("http://farm{0}.static.flickr.com
                /{1}/{2}_{3}.jpg", Farm,Server,Id,Secret);
        }
    }

    现在,我们需要使用LINQ编码实现类成员与XML节点的映射。

    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"),
             };

    在这个类中定义一个Photos字段,将来会用到。

    IEnumerable<FlickRPhoto> Photos;

    接下来显示图片,获取返回的结果集第一个记录并且显示。

    FlickRPhoto p = Photos.First();
    this.searchResultsImage.SetValue(Image.SourceProperty, p.ImageUrl);
    searchTermTextBox.Text = p.Title;

    现在非常酷了,但是我想要显示别的图片,当单击图片的时候显示另一张图片。这样做的话先定义一个事件驱动。

    <Image MouseLeftButtonDown="searchResultsImage_MouseLeftButtonDown" 
                 x:Name="searchResultsImage" 

    接下来实现这个事件,先预先检验图片是否为空,在使用当前ImageNumber字段数值获取下一张图片。

    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);
    
        ImageNumber++;
    }

    现在你在图片上点击,它循环的显示图片了。

    image

    第四部分:使用IsolatedStorag来维持跳转设置

    现在,我们考虑一下跳转时候的一些状态。

    首先,当“Go”按钮按下的时候,保存textbox所有的信息。

    private void button_Click(object sender, RoutedEventArgs e)
    {
        LoadPhotos(searchTermTextBox.Text);
        ApplicationSettings.Default["searchTerm"] = txtBox.Text;
        ApplicationSettings.Default.Save();
    
    }

    当改变图片的时候,同样也这样处理。

    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++;
    
    }

    其次,当程序开始运行的时候,我们获取最近的设置并且用它初始化这个程序

    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"];
        }
    }

    当你第一次运行时,它不需要保存状态,使用默认设置。但是,再一次运行的时候,它获取你之前设置的状态。

    第五部分:定义皮肤

    现在,我们为它设置一款漂亮的皮肤,我使用的是Corrina's Rough皮肤样式。

    这步很简单,仅仅需要从Corrina的样例App.Xaml中的 <ApplicationResources>节点部分复制粘贴到你的App.Xaml文件中去。然后在页面中添加如下的样式:

    <Button Style="{StaticResource buttonStyle}"
    <TextBox Style="{StaticResource textBoxStyle}" 

    OK,完成了这个程序了: 

    image

    下载完整文件 demo文件

    2009年5月31日 3:07