wp新人打造专属windows phone博客园客户端

 

自从wp8面世,一直都想做wp8开发,苦于各种原因(主要是.net基础不好),一直没有学成。六月底换了新工作, 有幸进入一家wp应用的公司,也开始我正式学习wp开发之路。

 

拽点废话,类似于小说的背景,各位看官请勿吐槽。

 

首先,本人使用使用诺基亚将近一年了,每天有个习惯,就是稍微闲着点,就经常逛逛博客园,可以说我的零碎时间,让博客园占去了一大半。但应用商店里下载的各种博客园总觉得不是太好,也说不上来哪里不好。现在机会来了,在学习的过程中,一步步打造自己的专属博客园。

原理很简单,就是通过http请求,抓取博客园的页面,文章列表用ListBox显示,点击后,将地址传到另一个页面,进行详细内容的抓取,显示在WebBrowser中。中间用到了HtmlAgilityPack插件,这个插件也是刚刚接触,上次在我的博文《使用HttpWebRequest和HtmlAgilityPack抓取网页(拒绝乱码,拒绝正则表达式)》中提到过,后来被园友们一通吐槽,给我推荐了Jumony(地址),这个比HtmlAgilityPack牛逼多了,瞬间把HtmlAgilityPack抛弃了。苦逼的是,但我开始动手做的时候,发现Jumony竟然不能在wp8中使用,我又瞬间石化了,然后又把HtmlAgilityPack捡了起来。

下面上帮助类代码,及时Post请求,和Get请求,暂时只用到了Get请求, post请求是准备做用户中心的时候使用的。

 

 

 下面是判断手机的网络状态的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Utils
    {
        #region wp联网状态
        /// <summary>
        /// 获取设备当前的网络状态
        /// </summary>
        /// <returns></returns>
        public static string GetNetStates()
        {
            var info = Microsoft.Phone.Net.NetworkInformation.NetworkInterface.NetworkInterfaceType;
            switch (info)
            {
                case Microsoft.Phone.Net.NetworkInformation.NetworkInterfaceType.Ethernet: return "Ethernet";
                case Microsoft.Phone.Net.NetworkInformation.NetworkInterfaceType.MobileBroadbandCdma: return "CDMA";
                case Microsoft.Phone.Net.NetworkInformation.NetworkInterfaceType.MobileBroadbandGsm: return "GSM";
                case Microsoft.Phone.Net.NetworkInformation.NetworkInterfaceType.None: return "None";
                case Microsoft.Phone.Net.NetworkInformation.NetworkInterfaceType.Wireless80211: return "Wifi";
                default: return "None";
            }
        }
        #endregion
    }

 第一次做wp应用,有点小丑,先上图吧。

 

 

页面首页用Panorama布局,有四个栏目,分别是 首页,热门分类,知识库,(个人中心)暂时没做,后期加上。

首先说首页,主要是抓取博客园首页文章列表,然后分析页面后,加载到ListBox中。这里有个我所认为的难点:到页面滚动到底部的时候自动加载下一页。找了好多资料,最后还是找到了,先把主要代码贴出来

复制代码
 1 #region 获取ListBox的滚动条,实现下拉自动刷新
 2         private void RegisterScrollListBoxEvent()
 3         {
 4             List<ScrollBar> controlScrollBarList = UIHelper.GetVisualChildCollection<ScrollBar>(this.artList);
 5             if (controlScrollBarList == null)
 6                 return;
 7 
 8             foreach (ScrollBar queryBar in controlScrollBarList)
 9             {
10                 if (queryBar.Orientation == System.Windows.Controls.Orientation.Vertical)
11                     queryBar.ValueChanged += queryBar_ValueChanged;
12             }
13         }
14 
15         async void queryBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
16         {
17             if (probar.Visibility == Visibility.Visible)
18             {
19                 return;
20             }
21             ScrollBar scrollBar = (ScrollBar)sender;
22             object valueObj = scrollBar.GetValue(ScrollBar.ValueProperty);
23             object maxObj = scrollBar.GetValue(ScrollBar.MaximumProperty);
24             object minObj = scrollBar.GetValue(ScrollBar.MinimumProperty);
25 
26             if (valueObj != null && maxObj != null)
27             {
28                 double value = (double)valueObj;
29                 double max = (double)maxObj;
30                 double min = (double)minObj;
31 
32                 if (value >= Math.Floor(max))
33                 {
34                     probar.Visibility = System.Windows.Visibility.Visible;
35                     page += 1;
36                     await GetHomeArtcle(page);
37                 }
38 
39                 if (Math.Floor(value) <= min)
40                 {
41 
42                 }
43             }
44         }
45         #endregion
获取ListBox的滚动条,实现下拉自动刷新
复制代码

只需在页面加载的时候注册下事件就OK了。

下面是抓取的方法代码

复制代码
 1         async Task GetHomeArtcle(int pageindex)
 2         {
 3             string url = "http://www.cnblogs.com/";
 4             if (pageindex > 1)
 5             {
 6                 url = string.Format("http://www.cnblogs.com/sitehome/p/{0}", pageindex);
 7             }
 8             await Task.Run(() =>
 9             {
10                 HttpHelper.HttpGetAsync(url, html =>
11                 {
12                     if (html == "no network")
13                     {
14                         Dispatcher.BeginInvoke(() =>
15                         {
16                             MessageBox.Show("sorry,貌似您没有联网哦");
17                         });
18                         return;
19                     }
20                     if (html == "network anomaly")
21                     {
22                         Dispatcher.BeginInvoke(() =>
23                         {
24                             MessageBox.Show("sorry,您的网络貌似有异常,请检查后再试吧!");
25                         });
26                         return;
27                     }
28                     HtmlDocument doc = new HtmlDocument();
29                     doc.LoadHtml(html);
30                     var artlist = doc.DocumentNode.SelectNodes("//div[@class='post_item']");
31                     List<art> art1 = new List<art>();
32                     foreach (var item in artlist)
33                     {
34                         HtmlDocument adoc = new HtmlDocument();
35                         adoc.LoadHtml(item.InnerHtml);
36                         var html_a = adoc.DocumentNode.SelectSingleNode("//a[@class='titlelnk']");
37                         var html_content = adoc.DocumentNode.SelectSingleNode("//p[@class='post_item_summary']");
38                         var comment = adoc.DocumentNode.SelectNodes("//a[@class='gray']");
39                         html_content.RemoveChild(html_content.FirstChild, true);
40                         var foot = adoc.DocumentNode.SelectSingleNode("//div[@class='post_item_foot']");
41                         foot.RemoveAll();
42                         art1.Add(new art
43                         {
44                             Title = html_a.InnerText,
45                             Content = html_content.InnerText,
46                             Comment = comment.First().InnerText.Replace("\r\n", ""),
47                             Read = comment.Last().InnerText,
48                             AddTime = foot.InnerText,
49                             Link = html_a.Attributes["href"].Value
50                         });
51                         //Response.Write(string.Format("标题为:{0},链接为:{1}<br>", html_a.InnerText, html_a.Attributes["href"].Value));
52                     }
53                     Dispatcher.BeginInvoke(() =>
54                     {
55                         for (int i = 0; i < artlist.Count; i++)
56                         {
57                             artsource.Add(art1[i]);
58                         }
59 
60                         probar.Visibility = System.Windows.Visibility.Collapsed;
61                     });
62                 });
63             });
64         }
异步抓取页面
复制代码

另外,定义了抓页面所需要的类

复制代码
 1     public class art
 2     {
 3         private string title;
 4         public string Title
 5         {
 6             get { return title; }
 7             set
 8             {
 9                 title = value;
10                 NotifyPropertyChanged("Title");
11             }
12         }
13         private string content;
14         public string Content
15         {
16             get { return content; }
17             set
18             {
19                 content = value;
20                 NotifyPropertyChanged("Content");
21             }
22         }
23         private string comment;
24         /// <summary>
25         /// 评论
26         /// </summary>
27         public string Comment
28         {
29             get { return comment; }
30             set
31             {
32                 comment = value;
33                 NotifyPropertyChanged("Comment");
34             }
35         }
36         private string read;
37         /// <summary>
38         /// 阅读
39         /// </summary>
40         public string Read
41         {
42             get { return read; }
43             set
44             {
45                 read = value;
46                 NotifyPropertyChanged("Read");
47             }
48         }
49 
50         /// <summary>
51         /// 发布时间
52         /// </summary>
53         public string AddTime { get; set; }
54         public string Link { get; set; }
55         public event PropertyChangedEventHandler PropertyChanged;
56         private void NotifyPropertyChanged(string info)
57         {
58             if (PropertyChanged != null)
59             {
60                 PropertyChanged(this, new PropertyChangedEventArgs(info));
61             }
62         }
63     }
64 
65     public class ArtCollection : ObservableCollection<art>
66     {
67         public ArtCollection()
68             : base()
69         {
70 
71         }
72     }
View Code
复制代码

这些就是首页栏目的主要代码了,下面会把源码贴出来,所以就不一一贴在这里了。

绑定后列表后,就要绑定Tap事件了,个人觉得这个事件可以理解为web开发中的单击事件。代码如下:

复制代码
 1    private void Border_Tap(object sender, System.Windows.Input.GestureEventArgs e)
 2         {
 3             try
 4             {
 5                 string link = ((Border)sender).Tag.ToString();//获取页面链接
 6                 NavigationService.Navigate(new Uri(string.Format("/show.xaml?linkurl={0}", link), UriKind.Relative));
 7             }
 8             catch (Exception)
 9             {
10 
11             }
12         }
Tap事件
复制代码

 

其次说热门分类

热门分类没有做抓取,只是手工将博客园中的一级分类写出来,把单击事件里传递对应的地址,到列表页面。

列表页面是采用的Pivot布局,将分类依次排列,当从热门分类中跳转过来时,根据参数进行判断,加载对应的分类列表

复制代码
 1         protected override void OnNavigatedTo(NavigationEventArgs e)
 2         {
 3             base.OnNavigatedTo(e);
 4             if (e.NavigationMode == NavigationMode.New)
 5             {
 6                 IDictionary<string, string> queryString = this.NavigationContext.QueryString;
 7                 var selectedItem = pivot.Items.First(item =>
 8                 {
 9                     PivotItem temp = (PivotItem)item;
10                     return temp.Tag.ToString() == queryString["type"];
11                 });//查找对应的PivotItem
12                 pivot.SelectedItem = selectedItem;//设置为当前Item
13                // await GetHomeArtcle(pagedb, queryString["type"]);
14             }
15         }
选择对应的Item
复制代码

当Pivot进行切换的时候,触发SelectionChanged事件,在事件中,首先判断当前的Item是否已经加载数据,如果尚未加载,就加载,如果已经加载了, 就不做操作了。

复制代码
 1   private async void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
 2         {
 3             PivotItem item = (PivotItem)pivot.SelectedItem;
 4             ListBox tempList = (ListBox)item.Content;
 5             if (tempList.Items.Count==0)
 6             {
 7                 probar.Visibility = System.Windows.Visibility.Visible;
 8                 await GetHomeArtcle(1, item.Tag.ToString());
 9                // tempList.Tag = (page + 1).ToString();
10             }
11             
12         }
SelectionChanged事件
复制代码

 

忽然觉得代码太多了,先写到这吧。 下班回家啦。

 

博客园的编辑器怎么没找到上传附件的呢???

 

把源码上传到了云盘里, 下面是地址http://yunpan.cn/Qh4xxMwEHmutb  提取码 d3b4(已失效,360云盘分享只能被下载5次, 我无力吐槽了啊)

 

百度网盘分享链接:链接: http://pan.baidu.com/s/1bnjayNP 密码: ijch

 

微云分享链接 链接:http://url.cn/Pqa3vH (密码:7Gim)

已经上传到应用商店了,需要吐槽的点这里:http://www.windowsphone.com/zh-cn/store/app/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E5%AE%A2%E6%88%B7%E7%AB%AF/4ceda3f2-bef6-4231-a6bb-b8d9a0cc7b87

 

未打完,也要收工。一是东西太多了, 本来打算分几次写的,后来觉得太麻烦了。二是,本人表达能力有限,看不明白的直接看源码吧,源码有注释哦。

posted @   billsking  阅读(4026)  评论(25编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示