写个Win8 Metro风格的RSS阅读器

今天尝试写一个Metro风格的RSS阅读器,数据源就用本博客的订阅地址吧,先上效果图:

写个Win8 Metro风格的RSS阅读器

点击其中的文章,再显示内容:

写个Win8 Metro风格的RSS阅读器

 

功能挺简单,先看工程结构:

写个Win8 Metro风格的RSS阅读器

MainPage是首页,一打开就显示博客标题和文章列表。

MainPage.xaml:

<Page 
    x:Class="Rss.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:Rss" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" x:Name="rootPage"> 
 
    <Grid Background="{StaticResource ApplicationPageBackgroundBrush}"> 
        <!--分面上下两行,上面显示博客标题,下面显示文章列表--> 
        <Grid.RowDefinitions> 
            <RowDefinition Height="120"></RowDefinition> 
            <RowDefinition Height="*"></RowDefinition> 
        </Grid.RowDefinitions> 
 
        <!--这个就是博客标题了--> 
        <TextBlock Name="pageTitle" Style="{StaticResource PageHeaderTextStyle}" Margin="30,20,0,0"></TextBlock> 
 
        <!--用GridView来承载文章列表,ItemsSource使用数据绑定方式,一会儿会把一个List<BlogArticle>赋值给它,所以绑定的是Value--> 
        <GridView Name="gvArticles" ItemsSource="{Binding Value}" Grid.Row="1" Padding="50" SelectionChanged="gvArticles_SelectionChanged"> 
            <!--定义模板,放一个图片和一行文本--> 
            <GridView.ItemTemplate> 
                <DataTemplate> 
                    <StackPanel Margin="5"> 
                        <Image Width="120" Height="120" Source="ms-appx:///Assets/Article.png"></Image> 
                        <!--文章标题又使用了数据绑定方式,绑定到BlogArticle.Title属性上--> 
                        <TextBlock Text="{Binding Title}" TextWrapping="Wrap" Width="120"></TextBlock> 
                    </StackPanel> 
                </DataTemplate> 
            </GridView.ItemTemplate> 
        </GridView> 
    </Grid> 
</Page>


MainPage.xaml.cs:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Net.Http; 
using System.Text; 
using Windows.Foundation; 
using Windows.Foundation.Collections; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Controls.Primitives; 
using Windows.UI.Xaml.Data; 
using Windows.UI.Xaml.Input; 
using Windows.UI.Xaml.Media; 
using Windows.UI.Xaml.Navigation; 
using Windows.Data.Xml.Dom; 
 
namespace Rss 
{ 
    public sealed partial class MainPage : Page 
    { 
        public MainPage() 
        { 
            this.InitializeComponent(); 
        } 
 
        //页面加载时会调用OnNavigateTo方法,把它变成async的,因为里面要用异步方法 
        protected async override void OnNavigatedTo(NavigationEventArgs e) 
        { 
            //拿HttpClient取rss的xml,WebClient这个类没有了。另外由于XmlDataProvider不能用了,所以只好自己解析并装载集合 
            var client = new HttpClient(); 
            string url = "http://boytnt.blog.51cto.com/rss.php?uid=966121"; 
 
            //注意51cto的rss是gbk编码的,所以不能直接client.GetStringAsync,会乱码,这里await关键字发威了~~ 
            StreamReader reader = new StreamReader(await client.GetStreamAsync(url), Encoding.GetEncoding("gbk")); 
            string rss = await reader.ReadToEndAsync(); 
            //XmlDocument也换到Windows.Data.Xml.Dom命名空间下了 
            XmlDocument xml = new XmlDocument(); 
            xml.LoadXml(rss); 
 
            //解析title 
            pageTitle.Text = xml.SelectSingleNode("/rss/channel/title").InnerText; 
 
            //解析item,然后装入List<BlogArticle>中,图省事只装载了title和link两个节点 
            var articles = new List<BlogArticle>(); 
            var nodes = xml.SelectNodes("/rss/channel/item"); 
            foreach (var node in nodes) 
            { 
                var article = new BlogArticle() 
                { 
                    Title = node.SelectSingleNode("title").InnerText, 
                    Link = node.SelectSingleNode("link").InnerText 
                }; 
                articles.Add(article); 
            } 
 
            //赋数据源 
            gvArticles.ItemsSource = articles; 
 
            //前面打开的StreamReader没关闭?是的,没有Close方法了  一_一# 
        } 
 
        private void gvArticles_SelectionChanged(object sender, SelectionChangedEventArgs e) 
        { 
            var articles = gvArticles.ItemsSource as List<BlogArticle>; 
            int index = gvArticles.SelectedIndex; 
 
            //跳转到ArticlePage去,并且把选中的文章作为参数传递过去 
            rootPage.Frame.Navigate(typeof(ArticlePage), articles[index]); 
        } 
    } 
}


ArticlePage是内容页,用于显示文章内容,能回退到MainPage。

ArticlePage.xaml:

<common:LayoutAwarePage 
    x:Name="pageRoot" 
    x:Class="Rss.ArticlePage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:Rss" 
    xmlns:common="using:Rss.Common" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d"> 
 
    <Grid Background="{StaticResource ApplicationPageBackgroundBrush}"> 
        <!--也分上下两行,上面显示回退按钮和标题,下面显示页面--> 
        <Grid.RowDefinitions> 
            <RowDefinition Height="120"/> 
            <RowDefinition Height="*"/> 
        </Grid.RowDefinitions> 
 
        <!--第一行放一个Grid,再分成两列,分别显示按钮和标题-->  
        <Grid> 
            <Grid.ColumnDefinitions> 
                <ColumnDefinition Width="Auto"/> 
                <ColumnDefinition Width="*"/> 
            </Grid.ColumnDefinitions> 
 
            <!--回退按钮使用了内置的样式--> 
            <Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/> 
            <TextBlock x:Name="pageTitle" Text="{Binding Group.Title}" Style="{StaticResource PageHeaderTextStyle}" Grid.Column="1"/> 
        </Grid> 
 
        <!--用WebView显示页面,现在没有WebBrowser了--> 
        <WebView Name="article" Grid.Row="1"></WebView> 
    </Grid> 
</common:LayoutAwarePage>


ArticlePage.xaml.cs:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using Windows.Foundation; 
using Windows.Foundation.Collections; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Controls.Primitives; 
using Windows.UI.Xaml.Data; 
using Windows.UI.Xaml.Input; 
using Windows.UI.Xaml.Media; 
using Windows.UI.Xaml.Navigation; 
 
namespace Rss 
{ 
    public sealed partial class ArticlePage : Rss.Common.LayoutAwarePage 
    { 
        public ArticlePage() 
        { 
            this.InitializeComponent(); 
        } 
 
        protected override void OnNavigatedTo(NavigationEventArgs e) 
        { 
            //e.Parameter中是传过来的参数 
            var param = e.Parameter as BlogArticle; 
            pageTitle.Text = param.Title; 
            article.Source = new Uri(param.Link); 
        } 
    } 
}



OK,Ctrl+F5运行吧。

PS:本文基于Win8 Consumer Preview + Visual Studio 11 Beta。

PPS:应小星同学强烈要求,补一下BlogArticle这个类,就是个数据实体,其实从前面赋值的代码里已经能推断出来了。 

using System; 
namespace Rss 
{ 
    public class BlogArticle 
    { 
        public string Title { get; set; } 
        public string Link { get; set; } 
    } 
}



PPPS:最近加了搜索功能,见文章http://boytnt.blog.51cto.com/966121/892682