一步一步学Silverlight 2系列(18):综合实例之RSS阅读器

概述

Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, Ironpython,对JSON、Web Service、WCF以及Sockets的支持等一系列新的特性。《一步一步学Silverlight 2系列》文章将从Silverlight 2基础知识、数据与通信、自定义控件、动画、图形图像等几个方面带您快速进入Silverlight 2开发

本文将综合前面十七篇讲过的界面布局、样式、控件模板、数据绑定、网络通信等几个方面,来开发一个综合实例——简易RSS阅读器。

界面布局

我们最终完成的RSS阅读器界面如下:

TerryLee_Silverlight2_0082

定义一个三行两列的Grid,分别放置顶部信息、分割线和下面的内容区:

<Grid.RowDefinitions>
    <RowDefinition Height="50"></RowDefinition>
    <RowDefinition Height="20"></RowDefinition>
    <RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
    <ColumnDefinition Width="240"></ColumnDefinition>
    <ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>

设计顶部输入区域,对Grid第一行做合并,并且放置一个StackPanel:

<StackPanel x:Name="Header" Orientation="Horizontal"
             Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
    <Image Source="Rss.png" Width="32" Height="32" Margin="10 0 10 0"></Image>
    <Border Style="{StaticResource titleBorder}">
        <TextBlock Text="基于Silverlight的RSS阅读器" Foreground="#FFFFFF"
                   VerticalAlignment="Center" Margin="12 0 0 0"></TextBlock>
    </Border>
    <WatermarkedTextBox x:Name="feedAddress" Width="300" Height="35"
                        FontSize="16" Margin="10 0 10 0">
        <WatermarkedTextBox.Watermark>
            <TextBlock Text="请输入有效的RSS地址" VerticalAlignment="Center"
                       Foreground="#FBA430" FontSize="16"></TextBlock>
        </WatermarkedTextBox.Watermark>
    </WatermarkedTextBox>
    <Button x:Name="displayButton" Style="{StaticResource button}"
            Content="显 示" Click="displayButton_Click"></Button>
    <Button x:Name="fullScreenButton" Style="{StaticResource button}"
            Content="全 屏" Click="fullScreenButton_Click"></Button>
</StackPanel>

鉴于两个按钮的风格一致,在App.xaml中定义一个button样式:

<Style x:Key="button" TargetType="Button">
    <Setter Property="Width" Value="100"></Setter>
    <Setter Property="Height" Value="35"></Setter>
    <Setter Property="Background" Value="#FBA430"></Setter>
    <Setter Property="Foreground" Value="#FBA430"></Setter>
    <Setter Property="FontSize" Value="16"></Setter>
</Style>
<Style x:Key="titleBorder" TargetType="Border">
    <Setter Property="CornerRadius" Value="10"></Setter>
    <Setter Property="Width" Value="220"></Setter>
    <Setter Property="Height" Value="40"></Setter>
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0,0">
                <GradientStop Color="#FBA430" Offset="0.0" />
                <GradientStop Color="#FEF4E7" Offset="0.5" />
                <GradientStop Color="#FBA430" Offset="1.0" />
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
</Style>
定义分割线,用Rectangle来表示:
<StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Center">
    <Rectangle Style="{StaticResource rectangle}"/>
</StackPanel>

为了显示出渐变的样式,我们定义样式如下:

<Style x:Key="rectangle" TargetType="Rectangle">
    <Setter Property="Width" Value="780"></Setter>
    <Setter Property="Height" Value="5"></Setter>
    <Setter Property="RadiusX" Value="3"></Setter>
    <Setter Property="RadiusY" Value="3"></Setter>
    <Setter Property="Fill">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0,0">
                <GradientStop Color="#FEF4E7" Offset="0.0" />
                <GradientStop Color="#FBA430" Offset="1.0" />
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
</Style>
定义左边的列表区,用ListBox来显示,并且定义ItemTemplate:
<ListBox x:Name="PostsList" Grid.Column="0" Grid.Row="2"
         Margin="10 5 5 10" SelectionChanged="PostsList_SelectionChanged">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Title.Text}" 
                           TextWrapping="Wrap" Width="200"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

最后定义右边的详细信息区域,在StackPanel中垂直放置三个Border:

<StackPanel x:Name="Detail" Grid.Column="1" Grid.Row="2">
    <Border CornerRadius="10" Background="#CDFCAE" Margin="10 5 10 10"
            Width="540" Height="40">
        <TextBlock Text="{Binding Title.Text}"  TextWrapping="Wrap"
                   VerticalAlignment="Center" Foreground="Red"/>
    </Border>
    <Border CornerRadius="10" Background="#CDFCAE" Margin="10 5 10 10"
            Width="540" Height="300">
        <TextBlock Text="{Binding Summary.Text}"  TextWrapping="Wrap"/>
    </Border>
    <Border CornerRadius="10" Background="#CDFCAE" Margin="10 5 10 10"
            Width="540" Height="40">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="评论日期:"  TextWrapping="Wrap"
                       Foreground="Red" VerticalAlignment="Center"/>
            <TextBlock Text="{Binding PublishDate}"  TextWrapping="Wrap"
                       Foreground="Red" VerticalAlignment="Center"/>
        </StackPanel>
    </Border>
</StackPanel>

界面布局到此大功告成。

实现功能

下面实现数据的获取,采用WebRequest来实现,也可以使用其他方式。

/// <summary>
/// 显示列表
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void displayButton_Click(object sender, RoutedEventArgs e)
{
    Uri uri = new Uri(feedAddress.Text);
    WebRequest request = (WebRequest)WebRequest.Create(uri);
    request.BeginGetResponse(new AsyncCallback(responseReady), request);
}

void responseReady(IAsyncResult asyncResult)
{
    WebRequest request = (WebRequest)asyncResult.AsyncState;
    WebResponse response = (WebResponse)request.EndGetResponse(asyncResult);

    XmlReader reader = XmlReader.Create(response.GetResponseStream());
    SyndicationFeed feed = SyndicationFeed.Load(reader);

    PostsList.ItemsSource = feed.Items;
}

显示详细信息:

/// <summary>
/// 查看详细信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PostsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    SyndicationItem item = PostsList.SelectedItem as SyndicationItem;

    Detail.DataContext = item;
}

实现全屏按钮的代码:

/// <summary>
/// 全屏显示
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void fullScreenButton_Click(object sender, RoutedEventArgs e)
{
    Content contentObject = Application.Current.Host.Content;
    contentObject.IsFullScreen = !contentObject.IsFullScreen;
}

运行效果

运行后界面如下:

TerryLee_Silverlight2_0080 

输入豆瓣的最新影评Feed:

TerryLee_Silverlight2_0081

选择其中一项后,将显示出详细信息:

 TerryLee_Silverlight2_0082

结束语

本文对前面十七篇内容做了一个小结,并开发出了一个简易RSS阅读器,你可以从这里下载本文示例代码。

下一篇:一步一步学Silverlight 2系列(19):如何在Silverlight中与HTML DOM交互(上)

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
Tag标签: Silverlight
posted @ 2008-03-10 21:40 TerryLee 阅读(7491) 评论(88)  编辑 收藏 网摘 所属分类: [03]  银光点亮世界

  回复  引用    
#1楼 2008-03-10 21:46 | jejwe [未注册用户]
讲如何使用javascript操作silverlight

btw : sl的显示字体太难看了。
  回复  引用  查看    
#2楼 [楼主]2008-03-10 21:49 | TerryLee      
@jejwe
不明白为什么还要用javascript呢。。。

btw:sl是什么意思?:)
  回复  引用  查看    
#3楼 2008-03-10 22:01 | Q.Lee.lulu      
@TerryLee
兄弟速度够快的,我都看不过来了..
sl就是silverlight哈...
  回复  引用  查看    
#4楼 2008-03-10 22:01 | 菜菜灰      
我靠,又更新了,TerryLee 太强了,佩服佩服
  回复  引用  查看    
#5楼 [楼主]2008-03-10 22:08 | TerryLee      
@Q.Lee.lulu
呵呵,看来是我写头晕了,居然没想到sl就是Silverlight,我以为1楼的说我Blog上的某种字体太难看了:-)
  回复  引用  查看    
#6楼 [楼主]2008-03-10 22:08 | TerryLee      
@菜菜灰
呵呵,谢谢,欢迎多讨论:)
  回复  引用  查看    
#7楼 2008-03-10 22:37 | ArthurHend      
继续关注学习中!
  回复  引用  查看    
#8楼 [楼主]2008-03-10 22:43 | TerryLee      
@ArthurHend
谢谢:)
  回复  引用  查看    
#9楼 2008-03-10 22:59 | 王德水      
持续关注,学习
  回复  引用    
#10楼 2008-03-10 23:06 | jejwe [未注册用户]
--引用--------------------------------------------------
TerryLee: @jejwe
不明白为什么还要用javascript呢。。。

btw:sl是什么意思?:)
--------------------------------------------------------
因为Silverlight 1.0中有javascript的操作,所以我想2.0应该也有,但没看到有相关文档

另外现在的Silverlight 显示中文字体不好看。 呵呵
  回复  引用  查看    
#11楼 2008-03-10 23:07 | Cat Chen      
你的文章发表速度真实高啊!介绍一下经验吧~
  回复  引用  查看    
#12楼 [楼主]2008-03-10 23:12 | TerryLee      
@王德水
:)
  回复  引用  查看    
#13楼 [楼主]2008-03-10 23:14 | TerryLee      
@jejwe
在Silverlight 2.0中有使用.NET语言(C#、VB.NET)进行DOM和JavaScript的操作等内容,后面会写到:)
  回复  引用  查看    
#15楼 [楼主]2008-03-10 23:16 | TerryLee      
@Cat Chen
呵呵,多谢支持,主要是最近有点时间,再加上看了一下觉的Silverlight 2确实功能很强大,就忍不住多写一些^_^
  回复  引用  查看    
#16楼 [楼主]2008-03-10 23:17 | TerryLee      
@Silverlight Search Engine
这玩意儿挺好玩:)
  回复  引用    
#17楼 2008-03-10 23:18 | jejwe [未注册用户]
--引用--------------------------------------------------
TerryLee: @jejwe
在Silverlight 2.0中有使用.NET语言(C#、VB.NET)进行DOM和JavaScript的操作等内容,后面会写到:)
--------------------------------------------------------
谢谢。
现在明白了SL字体的默认中文字体是有问题。看来还是要用样式美化一下。开始就以为SL对中文支持不好呢
  回复  引用  查看    
#18楼 [楼主]2008-03-10 23:20 | TerryLee      
@jejwe
:)
  回复  引用    
#19楼 2008-03-10 23:21 | jejwe [未注册用户]
另外我觉得现在的Silverlight 右键菜单支持太少了,老想着粘贴复制了。哈哈
  回复  引用  查看    
#20楼 [楼主]2008-03-10 23:24 | TerryLee      
@jejwe
是的,现在支持的右键菜单太少
  回复  引用    
#21楼 2008-03-10 23:28 | jejwe [未注册用户]
--引用--------------------------------------------------
TerryLee: @jejwe
在Silverlight 2.0中有使用.NET语言(C#、VB.NET)进行DOM和JavaScript的操作等内容,后面会写到:)
--------------------------------------------------------
刚才正好到
http://www.dzone.com/links/queue/tag/.net.html (这个网站蛮不错的,可以作为TerryLee 每周推荐的信息来源)
看到一篇
http://www.jondavis.net/blog/post/2008/03/Silverlight---Weve-Got-WindowEval!!-Yay!!.aspx
  回复  引用  查看    
#22楼 [楼主]2008-03-10 23:39 | TerryLee      
@jejwe
嗯,好的,太感谢了,以后每周推荐的文章又多了一个来源,呵呵

我明天有时间就写这方面的内容:)
  回复  引用    
#23楼 2008-03-10 23:57 | 过客007 [未注册用户]
继续学习.

不过看了半天,好象是silverlight是不能够直接与数据源相交互的,只能通过某种通讯的方式取得数据.不知这种想法对不对,是不是这种限制是由于安全上的原因造成的呢?

沙箱??
  回复  引用  查看    
#24楼 2008-03-11 00:05 | 阿布      
silverlight是客户端技术,就像FLASH,当然不能直接与数据源打交道
  回复  引用    
#25楼 2008-03-11 00:23 | qeilf [未注册用户]
有个问题请教一下,执行到下面的时候出错了,不知道什么原因,
XmlReader reader = XmlReader.Create(response.GetResponseStream());
错误是:An exception of type 'System.ArgumentNullException' occurred in System.Xml.dll but was not handled in user code
似乎没有返回响应流.


  回复  引用  查看    
#26楼 2008-03-11 00:47 | nfa2dfa      
@qeilf
恐怕是不能访问到rss。地址错误?没联网?
  回复  引用    
#27楼 2008-03-11 01:03 | qeilf [未注册用户]
能给个rss地址吗?
  回复  引用  查看    
#28楼 2008-03-11 07:02 | 生鱼片      
silverlight真的是很强啊
  回复  引用  查看    
#29楼 [楼主]2008-03-11 08:37 | TerryLee      
@过客007
阿布已经回答过了:)
  回复  引用  查看    
#30楼 [楼主]2008-03-11 08:40 | TerryLee      
@qeilf
可能是访问的rss地址有问题,你试试这个地址
http://www.douban.com/feed/review/movie
  回复  引用  查看    
#31楼 [楼主]2008-03-11 08:40 | TerryLee      
@生鱼片
Silverlight 2功能确实很强大:)
  回复  引用  查看    
#32楼 2008-03-11 09:15 | 巫云      
sl是不编译的吧?会不会有安全问题,性能呢?
  回复  引用  查看    
#33楼 2008-03-11 09:19 | 小庄      
有个想法:如果用silverlight做一个OA系统,可不可以只需要一个web页面,然后根据浏览器端的需求不同动态下载需要的silverlight代码来自动构建功能界面?
  回复  引用  查看    
#34楼 2008-03-11 09:35 | 骑着夕阳看着猪      
没有问题,顶一下!
  回复  引用  查看    
#35楼 2008-03-11 09:57 | 菜菜灰      
用你的测试代码测试你的博客rss地址http://www.cnblogs.com/Terrylee/rss,点击显示时没有响应,点过去就是一片白屏。
  回复  引用  查看    
#36楼 2008-03-11 10:13 | SZW      
Need for Speed
  回复  引用  查看    
#37楼 2008-03-11 10:29 | 菜菜灰      
这一课中的{Binding Title.Text}、{Binding PublishDate}和{Binding Summary.Text} 的属性是从哪里得到的
  回复  引用  查看    
#38楼 2008-03-11 10:59 | 阿布      
--引用--------------------------------------------------
小庄: 有个想法:如果用silverlight做一个OA系统,可不可以只需要一个web页面,然后根据浏览器端的需求不同动态下载需要的silverlight代码来自动构建功能界面?
--------------------------------------------------------
asp.NET有一个silverlight控件,当然是可以的
  回复  引用  查看    
#39楼 2008-03-11 11:00 | 阿布      
--引用--------------------------------------------------
菜菜灰: 用你的测试代码测试你的博客rss地址<a href="http://www.cnblogs.com/Terrylee/rss" target="_new">http://www.cnblogs.com/Terrylee/rss</a>,点击显示时没有响应,点过去就是一片白屏。
--------------------------------------------------------
博客园的RSS有问题,这上例子好像只对DOUBAN的RSS起作用,所以找个豆瓣的RSS地址就OK了
http://www.douban.com/feed/review/movie
  回复  引用  查看    
#40楼 2008-03-11 11:01 | 阿布      
--引用--------------------------------------------------
菜菜灰: 这一课中的{Binding Title.Text}、{Binding PublishDate}和{Binding Summary.Text} 的属性是从哪里得到的
--------------------------------------------------------
SyndicationItem item = PostsList.SelectedItem as SyndicationItem;

Detail.DataContext = item;

这里给Detail的DataContext 赋值了
即绑定的是SyndicationItem 的相关属性
  回复  引用  查看    
#41楼 2008-03-11 11:46 | 菜菜灰      
谢谢 阿布,原来System.ServiceModel.Syndication是3.5新增加的一类。
  回复  引用  查看    
#42楼 [楼主]2008-03-11 11:47 | TerryLee      
@巫云
编译之后打包成了.xap文件
  回复  引用  查看    
#43楼 [楼主]2008-03-11 11:48 | TerryLee      
@SZW
:)
  回复  引用  查看    
#44楼 [楼主]2008-03-11 11:48 | TerryLee      
@小庄
这个想法不错,Silverlight基于插件形式,并且具有很好的与HTML的交互
  回复  引用  查看    
#45楼 [楼主]2008-03-11 11:48 | TerryLee      
@骑着夕阳看着猪
:)
  回复  引用  查看    
#46楼 [楼主]2008-03-11 11:50 | TerryLee      
@菜菜灰
有些RSS有问题,可以自定义一个SyndicationItem,然后根据获取到的XML,使用LINQ to XML,这里为了简单,就直接使用了内置的SyndicationItem
  回复  引用    
#47楼 2008-03-11 16:08 | GoneSky [未注册用户]
写的很好啊!
我是一个刚开始参加工作的实习生(08年6月毕业,从天津毕业喔).
想请教一个问题,我在设计一个下拉式菜单的时候,是把它作为一个用户控件的,当把它放到主页面的时候,它一旦显示动画(下拉动画)的时候,总会把它下面的其他元素往下挤.也就是它会扩大它所要占用的空间.这给整体布局造成了麻烦,不知道该如何解决?
  回复  引用    
#48楼 2008-03-11 16:14 | xuzhibin [未注册用户]
你好,我在下载运行你的例子时,一开始还没问题,但是后来就出现中文乱码了,连我自己写的都是这样(之前不会),我想请问一下是什么问题呢?用的是Silverlight 2 Beta 1版本
  回复  引用  查看    
#49楼 2008-03-11 16:43 | 菜菜灰      
To : GoneSky

我没有尝试过,不过我想用户控件的父目录应该使用Canvas来布局,这样就可以实现你想要的效果
  回复  引用  查看    
#50楼 [楼主]2008-03-11 18:20 | TerryLee      
@GoneSky
把你的布局思路大概说一下吧?:)
  回复  引用  查看    
#51楼 [楼主]2008-03-11 18:21 | TerryLee      
@xuzhibin
是在编辑XAML的时候出现乱码吧?运行正常吗?

//我这儿编辑的时候有时也会出现乱码,但运行正常
  回复  引用    
#52楼 2008-03-12 09:11 | xuzhibin [未注册用户]
汗,我的是编辑的时候正常,运行的时候出现类似于"口"字的乱码
  回复  引用  查看    
#53楼 [楼主]2008-03-12 09:15 | TerryLee      
@xuzhibin
呵呵,我这儿跟你正好相反:)
  回复  引用    
#54楼 2008-03-13 15:45 | JeffreyChen [未注册用户]
速度太快了,这两天跟着你学了一把,呵呵
  回复  引用  查看    
#55楼 [楼主]2008-03-13 17:24 | TerryLee      
@JeffreyChen
呵呵,只要对大家有用就好:)
  回复  引用    
#56楼 2008-03-24 10:18 | ondogdog [未注册用户]
这个例子不能在IE6下运行,Firefox就可以
  回复  引用  查看    
#57楼 [楼主]2008-03-24 21:25 | TerryLee      
@ondogdog
我这里只有IE8和Firefox,IE6没有测试,应该也没有问题吧,只要安装了插件
  回复  引用  查看    
#58楼 2008-03-26 00:13 | 笑煞天      
Terry兄,有些RSS地址是没问题的,但有些就不行,获取到的Stream是null,比如Google Picasa的rss,不知Terry兄有否解决方法。
  回复  引用  查看    
#59楼 2008-04-21 13:06 | rocklau      
--引用--------------------------------------------------
笑煞天: Terry兄,有些RSS地址是没问题的,但有些就不行,获取到的Stream是null,比如Google Picasa的rss,不知Terry兄有否解决方法。
--------------------------------------------------------
我也出现这个问题。
  回复  引用    
#60楼 2008-06-02 14:41 | wbixd [未注册用户]
你好 我下载你的例子 直接运行就出现了错误

是不是http://www.douban.com/feed/review/movie这个地址现在出现问题了 但是直接打开http://www.douban.com/feed/review/movie是没问题的
  回复  引用  查看    
#61楼 2008-07-14 14:00 | kklldog      
WatermarkedTextBox 这个是自定义的吧 是哪个教程里面实现的呀 我跳过了几个
  回复  引用  查看    
#62楼 2008-07-14 14:19 | kklldog      
汗2.O里移除了 我把他换成TextBox了 调试成功 但是http://www.douban.com/feed/review/movie解析不出来
  回复  引用  查看    
#63楼 [楼主]2008-07-14 17:37 | TerryLee      
@kklldog
1.在2.0 RTM的时候,将会给TextBox提供Watermarked属性

2.解析RSS我在Beta 2下测试过,没有问题,你试试其它的Rss Feed看看。
  回复  引用    
#64楼 2008-08-01 13:37 | hp100277 [未注册用户]
在 beta 2 的版本中会我遇到跨线程的问题,解决的办法
Dispatcher.BeginInvoke(delegate
{
PostsList.ItemsSource = feed.Items;
});

  回复  引用  查看    
#65楼 [楼主]2008-08-01 17:51 | TerryLee      
@hp100277
嗯,木野狐写了一篇文章,也可以参考一下
  回复  引用  查看    
#66楼 2008-08-12 14:18 | Jerin      
在绑定Summary的时候,内容中可能会有一些HTML标记(我用cnblogs的RSS测试了),请问你是怎么处理的?
  回复  引用  查看    
#67楼 [楼主]2008-08-13 21:40 | TerryLee