我们紧接着上篇,开始我们的Metro风格应用开发。
-----------------------------------我是华丽的分割线-----------------------------------------
9.将数据获取到应用
a)既然我们创建的应用可以从 Internet 下载数据,我们便可以编写代码以将博客信息提要置于其中了。
我的博客以 RSS 展示了文章的完整文本。我们希望在阅读器应用中显示的博客数据为
每篇最新博客文章的标题、作者、日期和内容。首先,我们需要下载每篇文章的数据。
幸运的是,Windows 运行时包含一组类,这些类可以为我们执行处理信息提要数据的许多工作。
我们可以在 Windows.Web.Syndication命名空间中可以找到这些类。可以直接使用这些类显示 UI 中的数据。
但在我的博客阅读器中,我将创建属于自己的数据类。
b)向项目添加新的类文件
选择“项目”>“添加类”。“新增项目”对话框即会打开。
输入类文件的名称FeedData。
单击“添加”。
c)代码如下:
/// <summary>
/// FeedData 类容纳有关 RSS 或 Atom 信息提要的信息
/// </summary>
public class FeedData
{
public string Title { get; set; }
public string Description { get; set; }
public DateTime PubDate { get; set; }
private List<FeedItem> items = new List<FeedItem>();
public List<FeedItem> Items
{
get
{
return items;
}
}
}
其中FeedData类中包含了FeedItem 类,FeedItem 类容纳有关信息提要所包含的单个博客文章的信息,
FeedItem 类代码如下:
/// <summary>
/// FeedItem 类容纳有关信息提要所包含的单个博客文章的信息
/// </summary>
public class FeedItem
{
public string Title { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public DateTime PubDate { get; set; }
public Uri Link { get; set; }
}
有了以上两个基础数据类,我们就可以准备Rss的数据源,新建一个类:FeedDataSource,代码如下:
/// <summary>
/// FeedDataSource 类包含信息提要的机会以及从网络检索信息提要的方法
/// </summary>
public class FeedDataSource
{
private ObservableCollection<FeedData> feeds = new ObservableCollection<FeedData>();
public ObservableCollection<FeedData> Feeds
{
get
{
return feeds;
}
}
public async Task GetFeedsAsync()
{
Task<FeedData> feed = GetFeedAsync("http://feed.cnblogs.com/blog/u/118198/rss");
//如果在 C# 和 Visual Basic 中使用await关键字,
//则以异步方式检索信息提要的代码将与以同步方式检索信息提要时所使用的代码相似
//你只能在被定义为async的方法中使用await关键字
Feeds.Add(await feed);
}
private async Task<FeedData> GetFeedAsync(string feedUrl)
{
SyndicationClient client = new SyndicationClient();
Uri feedUri = new Uri(feedUrl);
try
{
//此处的await关键字会告诉编译器在后台自动为我们执行多种处理。
//编译器会将该方法中位于此调用之后的其余部分作为此调用返回后将要执行的回调。
//它会紧接着将控制返回给调用会话(通常是 UI 会话),以使应用保持响应。
//此时,会将表示此方法的最终输出的 Task(一个FeedData 对象)返回给调用者。
//当 RetrieveFeedAsync 返回包含我们所需数据的 SyndicationFeed 时,
//将执行我们的方法中其余的代码。重要的是,系统在我们从中进行原始调用的相同会话上下文
//(UI 会话)中执行这些代码,因此当我们需要在此代码中更新 UI 时不必担心使用调度程序。
//检索到 SyndicationFeed 后,我们将需要的部分复制到 FeedData 和 FeedItem 数据类中。
SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);
// This code is executed after RetrieveFeedAsync returns the SyndicationFeed.
// Process it and copy the data we want into our FeedData and FeedItem classes.
FeedData feedData = new FeedData();
feedData.Title = feed.Title.Text;
if (feed.Subtitle.Text!=null)
{
feedData.Description = feed.Subtitle.Text;
}
feedData.PubDate = feed.Items[0].PublishedDate.DateTime;
foreach (var item in feed.Items)
{
FeedItem feedItem = new FeedItem();
feedItem.Title = item.Title.Text;
feedItem.PubDate = item.PublishedDate.DateTime;
feedItem.Author = item.Authors[0].Name.ToString();
if (feed.SourceFormat==SyndicationFormat.Atom10)
{
feedItem.Content = item.Content.Text;
}
else if (feed.SourceFormat == SyndicationFormat.Rss20)
{
feedItem.Content = item.Content.Text;
feedItem.Link = item.Links[0].Uri;
}
feedData.Items.Add(feedItem);
}
//当我们执行到 return 语句时,我们并未真正返回 FeedData 对象。
//请记住,当方法紧随 await 语句返回给调用程序时,会返回一个表示该方法的最终输出结果的 Task。
//现在,我们就已经最终获得想要的结果了。
//return feedData; 将作为方法结果的 FeedData 对象提供给正在等待该对象的 Task。
//GetFeedsAsync 方法中的 Feeds.Add(await feed) 在等待 Task。
//当 Task 获得正在等待的 FeedData 结果后,代码执行将继续,
//FeedData 将被添加到 FeedDataSource.Feeds 集合中。
return feedData;
}
catch (Exception)
{
return null;
}
}
}
FeedDataSource类应用了.Net4的新类Task,C#5.0新增关键字async,await,具体用法请参考msdn.
10.检索信息提要数据
在准备好用于容纳我们的数据的数据类后,我们回过头来下载这些博客信息提要。
Windows.Web.Syndication.SyndicationClient 类可检索完全解析的 RSS 或 Atom 信息提要,
因此,我们不用担心解析 XML 的问题,而可以继续构建应用中更加有趣的部分。
SyndicationClient类只提供一种检索信息提要的方法,并且是异步的。
异步编程模型在 Windows 运行时中常常用于帮助应用保持响应。
幸运的是,程序已经为我们处理好了在使用异步方法时可能会遇到的许多复杂问题。
11.使用应用中的数据
为了使用我们的应用中的数据,我们在 App.xaml.cs/vb 中创建了数据源的一个静态实例。
我们将实例命名为 DataSource。
代码如下:
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
sealed partial class App : Application
{
public static FeedDataSource DataSource;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
DataSource = new FeedDataSource();
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
// Do not repeat app initialization when already running, just ensure that
// the window is active
if (args.PreviousExecutionState == ApplicationExecutionState.Running)
{
Window.Current.Activate();
return;
}
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Create a Frame to act navigation context and navigate to the first page
var rootFrame = new Frame();
if (!rootFrame.Navigate(typeof(MainPage)))
{
throw new Exception("Failed to create initial page");
}
// Place the frame in the current Window and ensure that it is active
Window.Current.Content = rootFrame;
Window.Current.Activate();
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
}
页面模板已经在它的代码隐藏文件中包含一个 OnNavigatedTo 方法的替代。
我们将代码置于此方法中,以获得应用的 FeedDataSource 实例并获得源。
首先,我们将 async 关键字添加到方法声明,因为我们在方法中使用 await 关键字。
导航到页面时,我们检查以查看 FeedDataSource 是否已包含源。如果未包含,
我们调用 FeedDataSource.GetFeedsAsync 方法。然后,将页面的 DataContext 设置为第一个源。
以下是 MainPage.xaml.cs/vb 的相关代码:
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
FeedDataSource feedDataSource = App.DataSource;
if (feedDataSource.Feeds.Count==0)
{
await feedDataSource.GetFeedsAsync();
}
DataContext = (feedDataSource.Feeds).First();
}
未完待续,敬请期待....