Windows Phone 7上的CPVanity移植与RSS阅读器

在Windows Phone 7平台上,移植CPVanity应用并添加CodeProject文章和论坛的RSS阅读器功能,是一种快速而有效的开发方式。本文将详细介绍这一过程,包括必要的前提条件、代码实现以及一些关键的技术点。

为了将CPVanity应用移植到Windows Phone 7平台,首先从桌面版本复制了三个文件:Article.cs、User.cs和CPSite.cs。这些文件是移植过程中的基础。

前提条件

在开始之前,需要确保已经具备以下条件:

代码实现

在移植过程中,需要对CPSite类进行一些修改。桌面版本中,CPSite类在后台线程上执行任务,然后在该线程上同步下载HttpWebRequest。由于Windows Phone7的所有网络通信都是异步的,因此需要将后台线程移动到该类中。

以下是修改后的代码示例:

#if WINDOWS_PHONE public void GetArticlePage(Action callback) { Debug.Assert(callback != null); downloadPage("script/Articles/MemberArticles.aspx?amid=" + memberID, callback); } #else public string GetArticlePage() { page = downloadPage("script/Articles/MemberArticles.aspx?amid=" + memberID); return page; } #endif

在ViewModel中,根据用户ID的变化,执行以下操作:

private CPSite _site; ... if (_site != null) _site.GetArticlePage(GotUserPage); ... private void GotUserPage(string result) { if (_site != null) { string name = _site.GetName(); string adornedName = _site.GetAdornedName(); if (adornedName.Length == 0) adornedName = name; UserName = adornedName; var articles = _site.GetArticles(); ArticleCount = plural(articles.Count, "article#s available"); if (articles.Count > 1) AverageRating = "Average rating: " + _site.GetAverageRating() + "/ 5"; foreach (var a in articles.OrderByDescending(a => a.Updated)) Articles.Add(new ArticleViewModel(a)); } }

其余部分则是使用Silverlight数据绑定来填充UI。

RSS阅读器

获取和显示RSS源使用WebClient,同时还需要一些基本的XML序列化。以下是代码示例:

public void Load() { WebClient client = new WebClient(); client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted); client.DownloadStringAsync(Uri); } void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { var serializer = new XmlSerializer(typeof(RssChannel)); try { using (var text = new StringReader(e.Result)) using (var reader = XmlReader.Create(text)) { reader.ReadToDescendant("channel"); Channel = (RssChannel)serializer.Deserialize(reader); } } catch (Exception ex) { Debug.WriteLine(ex); } finally { ((WebClient)sender).DownloadStringCompleted -= new DownloadStringCompletedEventHandler(client_DownloadStringCompleted); } }

其中RssChannel和RssItem的定义如下:

[XmlRoot("channel")] public class RssChannel { public RssChannel() { } [XmlElement("title")] public string Title { get; set; } [XmlElement("item")] public List Items { get; set; } } [XmlRoot("item")] public class RssItem { public RssItem() { } [XmlElement("title")] public string Title { get; set; } [XmlElement("description")] public string Description { get; set; } [XmlElement("link")] public string Link { get; set; } [XmlElement("author")] public string Author { get; set; } [XmlElement("pubDate")] public string Date { get; set; } [XmlElement("GUID")] public string GUID { get; set; } }

视图到视图模型的绑定

虽然MVVMViewModelLocator在视图和视图模型之间存在1:1映射时工作得很好,但在需要重用页面来渲染不同的视图模型时,它的效果就不那么理想了。ViewModelLocator在XAML中静态设置,创建了1:1的绑定。

为了解决ViewModelLocator中的1:1映射问题,使用Attribute来标记ViewModel:

[AttributeUsage(AttributeTargets.Class)] public sealed class PageAttribute : Attribute { public readonly Uri Page; public PageAttribute(string address) { Page = new Uri(address, UriKind.Relative); } } [Page("/ArticlesPage.xaml?vm=ArticlesStatic")] public class ArticlesViewModel : ContainerViewModel { } [Page("/ArticlesPage.xaml?vm=ForumsStatic")] public class ForumsViewModel : ContainerViewModel { }

然后在处理导航事件的代码中:

private void Select(object o) { var vm = o as CPViewModel; if (vm != null) { Debug.Assert(vm.GetType().HasAttribute()); var page = vm.GetType().GetAttribute(); Navigate(page.Page); } }

页面代码后端需要做一些工作,因为所需的ViewModel是在URI的查询字符串中指定的:

protected override void OnNavigatedTo(NavigationEventArgs e) { if (NavigationContext.QueryString.ContainsKey("vm")) { Dispatcher.BeginInvoke(() => DataContext = ViewModelLocator.FindViewModel(NavigationContext.QueryString["vm"])); } base.OnNavigatedTo(e); } public class ViewModelLocator { public static object FindViewModel(string key) { var prop = typeof(ViewModelLocator).GetProperty(key, BindingFlags.Public | BindingFlags.Static); Debug.Assert(prop != null); return prop.GetValue(null, null); } }

XML

<controls:Pivot Title="{Binding Name}" ItemsSource="{Binding Items}" ItemTemplate="{StaticResource DynamicContentTemplate}" />
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485