Win8的RSS阅读器
学习Win8开发也有一段时间,最初是看传智播客老杨的Win8视频教程,才对Win8有了一定开发基础,然后参考着微软官方的API及源码学习。在这里与大家分享我做的一个小小Demo供大家参考。
本Demo只是现实了Rss的基本阅读功能,当然还可以扩展很多的功能,让它变得更完美些。在这里先与大家分享这基本的现实功能,我也一会继续优化。。。
在项目中我觉得最核心的知识点:
1、使用Win8提供的类库下载并解析Xml文件。
2、格式化文本展示新闻内容。
先上效果图 ,有图有真相。然后再分享实现过程,在结尾处会提供参考源代码。
下面,我们一起实现步骤:
1、创建Win8商店应用程序(不要说不会啊~~ )。
2、随便找个RSS订阅的地方,了解了解结构,大家从贴图上也看出来了,我这里用的就是博客园的最新新闻,提供个地址:http://feed.cnblogs.com/news/rss
3、有了第2步的基础之后,我们来创建一个类:FeedItem.cs ,属性字段看着办就行~~,开发Win8程序的实体类要记得实现一个这个接口(INotifyPropertyChanged),至于是为什么,直接不解释,不会的去看视频。贴上源代码:
/// <summary> /// 新闻实体类 /// </summary> public class FeedItem : INotifyPropertyChanged { private int _id; public int Id { get { return _id; } set { _id = value; OnPropertyChanged("Id"); } } private string _title; public string Title { get { return _title; } set { _title = value; OnPropertyChanged("Title"); } } private string _content; public string Content { get { return _content; } set { _content = value; OnPropertyChanged("Content"); } } private DateTime _pubDate; public DateTime PubDate { get { return _pubDate; } set { _pubDate = value; OnPropertyChanged("PubDate"); } } private string _link; public string Link { get { return _link; } set { _link = value; OnPropertyChanged("Link"); } } protected void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; }
4、添加一个新的空白页:Index.xmal 这个页面是重点,用到了GridView来展示集合中的内容。
XMAL代码:
<Grid Background="Gray"> <Grid.RowDefinitions> <RowDefinition Height="auto"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <StackPanel Margin="20"> <TextBlock Text="博客园 - 最新新闻" Style="{StaticResource HeaderTextStyle}"></TextBlock> <GridView Grid.Row="1" Margin="0 30 0 0" x:Name="ItemGridView" ItemTemplate="{StaticResource StoreFrontTileTemplate}" ItemContainerStyle="{StaticResource StoreFrontTileStyle}" ItemsPanel="{StaticResource StoreFrontGridItemsPanelTemplate}" VerticalAlignment="Top" BorderThickness="1" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" SelectionMode="Single" SelectionChanged="ItemGridView_SelectionChanged_1" /> <ProgressBar Name="pro1" Grid.Row="1" Background="White" IsIndeterminate="True" /> </StackPanel> </Grid>
后台代码:
/// <summary> /// 可用于自身或导航至 Frame 内部的空白页。 /// </summary> public sealed partial class Index : Page { //新闻集合 ObservableCollection<FeedItem> feedData = null; public Index() { InitializeComponent(); } /// <summary> /// 在此页将要在 Frame 中显示时进行调用。 /// </summary> /// <param name="e">描述如何访问此页的事件数据。Parameter /// 属性通常用于配置页。</param> protected override void OnNavigatedTo(NavigationEventArgs e) { //加载 InitItem(); this.ItemGridView.ItemsSource = feedData; } /// <summary> /// 加载XML /// </summary> public async void InitItem() { if (feedData != null) { return; } SyndicationClient client = new SyndicationClient(); Uri feedUri = new Uri("http://feed.cnblogs.com/news/rss"); feedData = new ObservableCollection<FeedItem>(); try { SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri); pro1.Visibility = Windows.UI.Xaml.Visibility.Collapsed; foreach (SyndicationItem item in feed.Items) { FeedItem feedItem = new FeedItem(); string id = item.Id.ToString(); Regex reg = new Regex(@".(\d+)."); Match m = reg.Match(id); string s = m.Groups[1].ToString(); feedItem.Id = Convert.ToInt32(s); feedItem.Link = item.Id.ToString(); feedItem.Title = item.Title.Text; feedItem.PubDate = item.PublishedDate.DateTime; if (feed.SourceFormat == SyndicationFormat.Atom10) { feedItem.Content = item.Content.Text; } else if (feed.SourceFormat == SyndicationFormat.Rss20) { feedItem.Content = item.Summary.Text; } feedData.Add(feedItem); } } catch (Exception) { } } private void ItemGridView_SelectionChanged_1(object sender, SelectionChangedEventArgs e) { FeedItem feedItem = e.AddedItems[0] as FeedItem; //页面跳转 Frame.Navigate(typeof(Details), feedItem); } }
哈哈,完成这四步就可以展示列表信息了。当然要注意的几点:
(1)、xmal中的GridView几个模版样式我是写在app.xmal中,你必须要在app.xmal中写上模版样式,要不然肯定会报错滴。因为我也不知道要用啥颜色效果,所以整个的页面风格我全部设置为灰色了。自己改改喜欢的样式呗。
app.xmal中的代码:
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!-- 用于定义平台外观的共同方面的样式 Visual Studio 项目和项模板所必需的 --> <ResourceDictionary Source="Common/StandardStyles.xaml"/> </ResourceDictionary.MergedDictionaries> <Style x:Key="ItemTitleStyle" TargetType="TextBlock"> <Setter Property="FontFamily" Value="Segoe UI Light"/> <Setter Property="FontSize" Value="34"/> </Style> <Style x:Key="ItemSubtitleStyle" TargetType="TextBlock"> <Setter Property="FontFamily" Value="Segoe UI Light"/> <Setter Property="FontSize" Value="24"/> </Style> <DataTemplate x:Key="StoreFrontTileTemplate"> <Grid HorizontalAlignment="Left" Background="DarkGray" > <StackPanel Orientation="Horizontal" Margin="5,5,0,0" > <StackPanel Margin="0,0,0,0" Orientation="Vertical"> <TextBlock TextWrapping="Wrap" Foreground="{StaticResource ApplicationForegroundThemeBrush}" Style="{StaticResource ItemTitleStyle}" Width="400" Height="200" VerticalAlignment="Center" Text="{Binding Title}" HorizontalAlignment="Left" FontFamily="Segoe UI" /> <TextBlock TextWrapping="Wrap" Foreground="{StaticResource ApplicationForegroundThemeBrush}" Style="{StaticResource ItemSubtitleStyle}" Width="400" Height="100" VerticalAlignment="Center" Text="{Binding PubDate}" HorizontalAlignment="Left"/> </StackPanel> </StackPanel> </Grid> </DataTemplate> <Style x:Key="StoreFrontTileStyle" TargetType="GridViewItem"> <Setter Property="FontFamily" Value="Segoe UI" /> <Setter Property="Height" Value="300" /> <Setter Property="Width" Value="400" /> <Setter Property="Padding" Value="0" /> <Setter Property="Margin" Value="0,0,8,8" /> <Setter Property="HorizontalContentAlignment" Value="Left" /> <Setter Property="VerticalContentAlignment" Value="Top" /> <Setter Property="BorderThickness" Value="0"/> <Setter Property="TabNavigation" Value="Local" /> </Style> <Style x:Key="StoreFrontLVTileStyle" TargetType="ListViewItem"> <Setter Property="FontFamily" Value="Segoe UI" /> <Setter Property="Height" Value="80" /> <Setter Property="Width" Value="292" /> <Setter Property="Padding" Value="0" /> <Setter Property="Margin" Value="0,0,8,8" /> <Setter Property="HorizontalContentAlignment" Value="Left" /> <Setter Property="VerticalContentAlignment" Value="Top" /> <Setter Property="BorderThickness" Value="0"/> <Setter Property="TabNavigation" Value="Local" /> </Style> <ItemsPanelTemplate x:Key="StoreFrontGridItemsPanelTemplate"> <WrapGrid MaximumRowsOrColumns="2" VerticalChildrenAlignment="Center" HorizontalChildrenAlignment="Left"/> </ItemsPanelTemplate> </ResourceDictionary> </Application.Resources>
(2)、得使用ObservableCollection集合类型,比List之类的要更先进此。
(3)、InitItem方法 加载并解析xml方法。要记得引用几个命名空间。
(4)、ItemGridView_SelectionChanged_1这个当点击之后要执行的事件,因为我们还没有创建详情页,但是你又想看看效果,可以先这里面的代码注释一下,跑跑看,如果能跑起来,那就说明离成功不远了。先休息一会儿,坐久了可不好,顺便喝个水。
当然如果跑起来有错误,不要着急,看错误在哪,有问题解决就行。。。
过了N久之后。。。。
5、好,我们接着来创建一个新的页面:Details.xaml
先直接贴上代码:
<Grid Background="Gray"> <Grid Margin="20"> <Grid.RowDefinitions> <RowDefinition Height="auto"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Button Grid.Row="0" Grid.Column="0" Content="返回" Style="{StaticResource BackButtonStyle}" Click="Button_Click_1" HorizontalAlignment="Left" Margin="44,35,0,0" VerticalAlignment="Top"/> <TextBlock Name="txtTitle" HorizontalAlignment="Center" VerticalAlignment="Bottom" Style="{StaticResource HeaderTextStyle}" Grid.Row="0" Grid.Column="1"></TextBlock> <ScrollViewer Grid.Row="1" Grid.ColumnSpan="2" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden"> <StackPanel Name="stPanel" Orientation="Horizontal"></StackPanel> </ScrollViewer> </Grid> </Grid>
后台代码:
/// <summary> /// 可用于自身或导航至 Frame 内部的空白页。 /// </summary> public sealed partial class Details : Page { public Details() { this.InitializeComponent(); } /// <summary> /// 在此页将要在 Frame 中显示时进行调用。 /// </summary> /// <param name="e">描述如何访问此页的事件数据。Parameter /// 属性通常用于配置页。</param> protected override void OnNavigatedTo(NavigationEventArgs e) { if (e.NavigationMode == NavigationMode.New) { FeedItem f = e.Parameter as FeedItem; txtTitle.Text = f.Title; //对新闻内容字符串处理 string content = HtmlUtilities.ConvertToText(f.Content + " --" + f.PubDate).Replace("本文链接", ""); ShowTxt(content); } } private void Button_Click_1(object sender, RoutedEventArgs e) { //返回 Frame.GoBack(); } const double CT_WIDTH = 400d; //文本块的宽度 const double CT_HEIGHT = 600d; //文本块的高度 const double CT_MARGIN = 20d; //文本块的边距 /// <summary> /// 显示新闻 /// </summary> /// <param name="msg"></param> private void ShowTxt(string msg) { stPanel.Children.Clear(); // 去掉特殊的换行符 msg = msg.Replace(" ", "").Replace("\n", "").Replace("\r", "\n").Replace("\t", ""); msg = Regex.Replace(msg, @"\r\n{1,}", "\r\n"); msg = Regex.Replace(msg, @"\n{1,}", "\n"); msg = Regex.Replace(msg, @"^\n{1,}", ""); // 为了支持文本分块,使用RichTextBlock RichTextBlock tbContent = new RichTextBlock(); tbContent.Width = CT_WIDTH; tbContent.Height = CT_HEIGHT; tbContent.TextWrapping = TextWrapping.Wrap; tbContent.Margin = new Thickness(CT_MARGIN); Paragraph ph = new Paragraph(); ph.TextIndent = 33; Run txtRun = new Run(); txtRun.Text = msg; ph.Inlines.Add(txtRun); tbContent.Blocks.Add(ph); tbContent.FontSize = 24; stPanel.Children.Add(tbContent); // 更新一下状态,方便获取是否有溢出的文本 tbContent.UpdateLayout(); bool isflow = tbContent.HasOverflowContent; // 因为除了第一个文本块是RichTextBlock, // 后面的都是RichTextBlockOverflow一个一个接起来的 // 所以我们需要两个变量 RichTextBlockOverflow oldFlow = null, newFlow = null; if (isflow) { oldFlow = new RichTextBlockOverflow(); oldFlow.Width = CT_WIDTH; oldFlow.Height = CT_HEIGHT; oldFlow.Margin = new Thickness(CT_MARGIN); tbContent.OverflowContentTarget = oldFlow; stPanel.Children.Add(oldFlow); oldFlow.UpdateLayout(); // 继续判断是否还有溢出 isflow = oldFlow.HasOverflowContent; } while (isflow) { newFlow = new RichTextBlockOverflow(); newFlow.Height = CT_HEIGHT; newFlow.Width = CT_WIDTH; newFlow.Margin = new Thickness(CT_MARGIN); oldFlow.OverflowContentTarget = newFlow; stPanel.Children.Add(newFlow); newFlow.UpdateLayout(); // 继续判断是否还有溢出的文本 isflow = newFlow.HasOverflowContent; // 当第一个变量填充了文本后, // 把第一个变量的引用指向当前RichTextBlockOverflow // 确保OverflowContentTarget属性可以前后相接 oldFlow = newFlow; } } }
关于这个展示文本的方法:ShowTxt(),算个重点, 用RichTextBlock控件来展示新闻内容。当然这里面的代码不了解的,先贴上去看看效果,哈哈,我也不太了解,只是写了很多次,把这个格式背下来了,反正以后要用到类似的地方,直接把这个代码贴上去就可以。
F5 跑起来~~~~
先按照步骤一步步做下来,如果还是有错呢,可以下载源代码,对比一下。
终于给写完了,如果你看到了这里,真是谢谢啊!
此项目参考"传智播客.net培训Windows 8开发视频教程" 、 Microsoft官方提供API帮助。