65.9K
CodeProject 正在变化。 阅读更多。
Home

CodeProject Windows Phone应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (29投票s)

2012 年 2 月 1 日

CPOL

7分钟阅读

viewsIcon

67168

downloadIcon

5841

本文旨在构建一个简单的Windows Phone 7应用程序,用于访问CodeProject内容。

引言

本文试图构建一个(尽管很简陋的)应用程序,用于在Windows Phone 7手机上访问CodeProject。CodeProject提供的RSS Feed被用来更新应用程序中的内容。我厚颜无耻地利用了 Arik Poznanski 撰写的实用工具类(在文章“Reading RSS items on Windows Phone 7”中有提及),来读取RSS Feed。

提供的源代码需要VS2010、Windows Phone SDK 7.0才能编译,并需要Windows Phone模拟器进行模拟。我使用了MS Expression Blend来创建XAML文件。如果您想亲自动手,可以访问:http://www.microsoft.com/visualstudio/en-us/products/2010-editions/windows-phone-developer-tools

动机

CodeProject拥有超过800万用户,并且数量正在快速增长。许多人依靠这个网站来跟上软件开发日新月异的世界。对更多人来说,这是掌握新概念、新技术和框架的入门途径。最活跃的问答版块帮助许多人解决日常编码问题,而且很多情况下,提问者(当然,如果提问方式得当且内容合理)几乎在5分钟内就能得到答案。

得知如此美好的事物竟然没有移动应用程序(至少我没有遇到过),我感到有些遗憾。拥有这样一个应用程序的必要性本身就值得商榷。

目前CodeProject有一个移动网站,其中许多功能相比传统的桌面网站有所删减。但是,提供了一个链接可以访问完整网站。这是许多拥有不断更新内容的网站所采取的策略。但随着传统网站添加新功能,移动网站往往被忽视,迫使用户在手机上点击“完整网站”选项,从而违背了拥有独立移动网站的初衷。

此外,应用程序提供更好的浏览体验,方便在手机上浏览相同的内容,而不是在一个精简的网站上。至少我是这么认为的。这促使我尝试开发这款移动应用程序。

撇开这些不谈,拥有我们自己的移动应用程序难道不酷吗?

我选择在Windows Phone上开发应用程序,因为它拥有相当不错的开发工具,而且我更熟悉使用Visual Studio。如果反响良好,我也会尝试开发Android版本。

模拟器截图

在深入内部细节之前,让我们先在模拟器上可视化这个应用程序的样子(同样的内容也作为附件提供下载)。

图 1:应用程序界面

Apps.jpg

图 2:CodeProject主页(竖屏模式)

Home_Potrait.jpg

图 3:CodeProject主页(横屏模式)

Home_Landscape.jpg


图 4:获取最新的MFC/C++内容(竖屏模式)

Fetch_MFC_C___Potrait.jpg

图 5:获取最新的MFC/C++内容(横屏模式)

Fetch_MFC_C___Landscape.jpg

图 6:文章视图(竖屏模式)

Browser_Potrait.jpg

这些图片是不是很棒?希望到目前为止,你们都确信拥有这样一个应用程序确实很酷。

代码和页面的组织结构

现在,让我们看看页面是如何组织的和连接的。

MainPage.xaml 包含填充应用程序主屏幕的UI(如图2所示)。如果您解析这个xaml,可能会疑惑为什么每个按钮都被边框包裹。这个边框实际上是为了使按钮的角落变圆。由于无法直接为按钮设置圆角半径,我使用了边框并设置了其CornerRadius属性,以获得圆角按钮的视觉效果。

按钮的点击事件在代码中处理,根据不同的按钮,我们将从_RSSFeed数组中获取相应的RSS。

// string array to hold RSS feeds url
string[] _RSSFeed = { 
  "https://codeproject.org.cn/WebServices/ArticleRSS.aspx?cat=1", // All latest content
  "https://codeproject.org.cn/WebServices/ArticleRSS.aspx?cat=2", // MFC/C++ latest content
  "https://codeproject.org.cn/WebServices/ArticleRSS.aspx?cat=3", // C# latest content
  "https://codeproject.org.cn/WebServices/ArticleRSS.aspx?cat=6", // VB latest content
  "https://codeproject.org.cn/WebServices/ArticleRSS.aspx?cat=4", // ASP latest content
  "https://codeproject.org.cn/WebServices/ArticleRSS.aspx?cat=18", // Mobile latest content
  "https://codeproject.org.cn/webservices/LoungeRss.aspx" // Lounge latest content
 };

利用NavigationService.Navigate方法,我们将导航到ArticleView.xaml,并将获取到的RSS URL作为带有'RSSFeed'键的值传递给ArticleView.xaml。

NavigationService.Navigate(new Uri("/views/ArticleView.xaml?RSSFeed=" + 
                             _RSSFeed[(int)RSSCategory.AllArticlesRSS], UriKind.Relative));

在ArticleView的OnNavigatedTo事件中,该值会被取回。

protected override void OnNavigatedTo(NavigationEventArgs e)
{ 
    string strTemp;
    NavigationContext.QueryString.TryGetValue("RSSFeed", out strTemp);
    // ......
    // ......
}

这个RSS Feed URL通过RssService辅助类进行解析,数据存储在RssItem类中。然后,它被设置为列表框的数据源,从而获得如图4和图5所示的精美视图。

关于RSS Feed的详细信息以及解析方法,在文章《Reading RSS items on Windows Phone 7》中有更详细的解释。我不想通过重复所有这些信息来让读者感到厌烦。读者可以随时参考这篇很好的文章。

protected override void OnNavigatedTo(NavigationEventArgs e)
{ 
   // .....
   // .....

   // Fetch the RSS items using the helper and set this to the listbox controls
 WindowsPhone.Helpers.RssService.GetRssItems(
                             PhoneApplicationService.Current.State["RSSFeed"].ToString(),
                             (items) => { listbox.ItemsSource = items; },
                             (exception) => { MessageBox.Show(exception.Message); }, null );
}

如果在ArticleView.xaml中,这个列表框由一个超链接按钮和两个文本块组成,它们分别绑定到Title、PublishedDate和PlainSummary。

现在,当有人点击超链接按钮时,相应的页面会自动在浏览器中打开。但是,如果用户点击该网页上的另一个链接,然后想返回第一个页面,他们无法通过点击手机的硬件返回按钮来实现(这会将他们带回ArticleView.xaml页面,而不是第一个页面)。
这非常令人恼火,经过一番查找,我决定创建一个新的xaml页面,其中包含一个浏览器控件。在此页面中处理了前进和后退操作,以提供良好的用户体验。所有访问过的网页都存储在一个名为URLHistoryStack的列表中,以便在它们之间进行切换。

当用户首次通过点击ArticleView列表框的超链接按钮导航到Browser.xaml的webBrowserBrowser1时,相应的URL作为带有'SelectedArticle'键的值传递过来,在该页面的OnNavigatedTo事件中,URL被检索并设置为webBrowserBrowser1。

protected override void OnNavigatedTo(NavigationEventArgs e)
{ 
   string uri = "";
   if (NavigationContext.QueryString.TryGetValue("SelectedArticle", out uri))
   { 
      webBrowser1.Navigate(new Uri(uri, UriKind.Absolute)); // set the intial click url
   } 
}

当用户首次通过点击ArticleView列表框的超链接按钮导航到Browser.xaml的webBrowserBrowser1时,我们需要清除所有旧的历史记录并添加一个新的。

private void webBrowser1_Navigated(object sender,
                                   System.Windows.Navigation.NavigationEventArgs e)
{ 
   if (this.webBrowser1.Source != null && !this.IsNavigationButtonClicked)
   { 
     if (PositionIndex == 0)
     { 
        // This is the first page, so clear the old history if any and add this a fresh
        string firstURL = this.URLHistoryStack[0];
        this.URLHistoryStack.Clear();
        this.URLHistoryStack.Add(firstURL);
      }
     // Add this url to the history and increment the index
     this.URLHistoryStack.Add(this.webBrowser1.Source.ToString());
     PositionIndex++;
  }
  this.IsNavigationButtonClicked = false;
}

为了实现我所描述的网页之间的导航,添加了两个新按钮,并通过处理它们的点击事件来更新历史记录堆栈。

// Handling back button click
private void Button_Click_Backward(object sender, RoutedEventArgs e)
{ 
   if (PositionIndex <= 0)
   { 
     // He came to the first page and may be wants to go back to ArticleView
     NavigationService.Navigate(new Uri("/views/ArticleView.xaml", UriKind.Relative));
   } 
   else
   { 
     // Add this url to the history and decrement the index
     this.IsNavigationButtonClicked = true;
     this.webBrowser1.Navigate(new Uri(this.URLHistoryStack[PositionIndex - 1].
                                                                     ToString()));
     PositionIndex--;
   }
} 

// Handling forward button click
private void Button_Click_Forward(object sender, RoutedEventArgs e)
{ 
   if (this.URLHistoryStack.Count > PositionIndex + 1)
   { 
     // Add this url to the history and increment the index
     this.IsNavigationButtonClicked = true;
     this.webBrowser1.Navigate(new Uri(this.URLHistoryStack[PositionIndex + 1]
                                                                  .ToString()));
     PositionIndex++;
   }
}

此页面还提供另一组按钮,用于返回ArticleView或主页。当用户返回ArticleView页面时,我们将无法获得用于填充该页面的原始RSS Feed。因此,为了处理这个问题,RSS Feed被存储为应用程序状态数据。

 PhoneApplicationService.Current.State["RSSFeed"] = strTemp;

// Note how the RSS data is stored as application data with RSSFeed as key.   
 

结语和值得关注的点

由于我刚刚涉足Windows Phone开发领域,我没有开发专业移动应用程序的经验或专长。我知道这个应用程序很简陋,但它能让读者熟悉一些概念,如在Windows Phone中访问RSS Feed、使用应用程序状态数据、创建图像按钮、制作圆角按钮等。

我想在这个应用程序中做更多的事情,例如:

1. 让用户自定义/选择他们想要监控的RSS Feed。

2. 提供登录其账户的选项(目前我不知道如何在应用中实现这一点)。

3. 使控件在横屏模式下正确对齐,并改善其外观和感觉。

4. 允许用户收藏条目并在它们更新时弹出通知(以正确的方式,否则我们可能会过度消耗手机资源,用户可能不会欣赏)。

等等。我认为要完成一些事情(如提供登录支持),我们需要CP网站的数据/帮助 - 希望 Chris Maunder(CP网站管理员)和 Sean(CP网站内容经理)有兴趣提供它们。

我希望有兴趣的业余爱好者能够进行适当的修改,以获得更好的用户体验。

感谢您阅读本文,希望您能欣赏我的这份小小的努力。

外部参考

1. https://codeproject.org.cn/Articles/153472/Reading-RSS-items-on-Windows-Phone-7
2. http://silvergeek.net/2011/01/14/imagebutton-control-for-win-phone-7/
3. http://microsoftfeed.com/2011/how-to-convert-an-image-into-a-button-control-in-windows-
phone-7/

4. http://msdn.microsoft.com/en-us/library/ff817008%28v=vs.92%29.aspx
5. http://www.kunal-chowdhury.com/2011/06/windows-phone-7-mango-tutorial-11.html

致谢

感谢Sifayideen在创建XAML文件方面的帮助。

历史

2012年2月1日:添加本文
2012年2月20日:添加xap文件以供下载

© . All rights reserved.