RSS 2.0 Feed

Tuesday, April 29, 2008

【原文地址】Silverlight FlickR Example
【原文发表日期】25 April 08 11:23

在这个示例中,我将示范在Silverlight客户端通过一个非常简单的调用去访问FlickR的REST API。最终我们将得到一个应用程序,它看上去是这样的:

FlickR example

第一部分,定义部分Silverlight用户界面

第二部分,展示对本机的“打开文件”对话框的支持

第三部分,调用FlickR的服务并找到图片

第四部分,使用隔离存储(IsolatedStorage)在多次运行中保持某些本地设置的值

第五部分,为用户界面添加皮肤

 

同时欢迎你们获取完整的例子示例文件

 

第一部分,定义部分Silverlight用户界面

开始部分的创建,你可以回头看看我的这篇帖子End to End Silverlight Application post。在Blend里添加一个TextBox和一个Button到窗口中,并如下图所示摆放。

Window

 

确认你在属性窗口中为它们取了有意义的名称,以便稍后我们以编程的方式访问它们。我给它们起的名字是searchTermTextBox和button。

 

把一张图片拖入窗口中,我们就有了操作的对象了。(你可以使用SilverlightFlickRDemoFiles压缩包中的cow.jpg)

cow.jpg

确认你也为这张图片命名了……我起的名字是searchResultsImage

 

第二部分,本机的“打开文件”对话框

为了测试一下我们的排版,让我们添加一项功能,弹出“打开文件”的对话框并让它操作客户端的图片。这一点如今你已经可以通过Ajax\HTML轻易地实现。

在page.xaml中,添加一个Click事件处理器

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

在page.xaml.cs文件中,实现这个按钮的click事件,调用“打开文件”的对话框。

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

这段代码会打开系统的“打开文件”对话框,允许用户选择某个磁盘上的文件。开发者只具有保存这个文件的权限(仅指保存到应用程序中,而非文件的实际路径)。注意我们是如何操作这张客户端图片的。

open file dialogue

 

现在你可以上传一个文件到服务器,或者使用Isolated Storage将它存到本地。不过这已经有些超出了这个示例的范围了,我们要做的仅仅是在flickr中查找一张图片……

第三部分,调用FlickR的服务并找到图片

重头戏现在开始了。我们需要将查询关键字发送到FlickR REST API,并显示查询结果的图片。当用户点击图片时,我们能够显示出结果中的下一张图片。

首先我们需要调用FlickR REST API。为此你需要一个键值(key),你可以免费从FlickR获得……

接着我们要在Silverlight客户端调用这个REST API,让我们定义一个helper方法来完成它。

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

接下来我们要解析查询结果,你可以查看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解析的工作。所幸有LinqToXml的支持,在Silverlight中实现这一点非常简单,只需添加一个对System.Xml.linq.dll程序集的引用。

System.Xml.Linq

现在让我们实现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);
}

运行应用,如果你看到的是这样的信息,请回头检查一下你的API键值。

如果看到这个,说明一切顺利,已经准备好进入下一步了。

现在,我们需要解析这个Xml结果集,并取出图片的URL。我们将使用Linq的强大功能处理所有这些丑陋的Xml解析工作。所有要做的就是定义一个.NET类,将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++;

}

现在当你点击图片时,它就会在结果集中循环显示所有图片。

第四部分,使用隔离存储(IsolatedStorage)在多次运行中保持部分本地设置的值

现在,让我们尝试在多次运行时保持部分状态的值。

首先,让我们在“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那个风格粗犷的皮肤。

只需从Corrina的示例中剪切、粘贴<ApplicationResources>这一部分到你的App.Xaml中

并添加样式

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

就大功告成了!

 

 

同时欢迎你们获取完整的例子示例文件

posted @ | Feedback (0) | Filed Under [ Silverlight ]

【原文地址】Updated ASP.NET Dynamic Data Bits Posted
【原文发表日期】23 April 08 10:17

我们刚刚发布了ASP.NET 动态数据(Dynamic Data)的一些更新与示例……我鼓励大家去尝试它并告诉我们你的想法……

在这个版本中有一些很酷的新东西:

  1. 与Visual Studio的集成更加整洁了
  2. 现在支持更“漂亮的”URL了
    http://products/details/1 而不是 http://products/details.aspx?id=123
  3. 完整的文档
  4. 对第三方的控件提供商和O/R映射器提供额外的支持(更多的细节即将展示)

Scott Hunter最近发布了一篇HanselMinutes的播客(podcast),你应该查看一下……

ScottGu最近发布了一篇帖子,述及了动态数据中的关键点……

尝试一下这些东西,我们将乐于倾听你的反馈!

http://code.msdn.microsoft.com/dynamicdata

posted @ | Feedback (0) | Filed Under [ ASP.NET ]