wp新人打造專屬windows phone博客園客戶端

 

自從wp8面世,一直都想作wp8開發,苦於各類緣由(主要是.net基礎很差),一直沒有學成。六月底換了新工做, 有幸進入一家wp應用的公司,也開始我正式學習wp開發之路。javascript

 

拽點廢話,相似於小說的背景,各位看官請勿吐槽。html

 

首先,本人使用使用諾基亞將近一年了,天天有個習慣,就是稍微閒着點,就常常逛逛博客園,能夠說個人零碎時間,讓博客園佔去了一大半。但應用商店裏下載的各類博客園總以爲不是太好,也說不上來哪裏很差。如今機會來了,在學習的過程當中,一步步打造本身的專屬博客園。java

原理很簡單,就是經過http請求,抓取博客園的頁面,文章列表用ListBox顯示,點擊後,將地址傳到另外一個頁面,進行詳細內容的抓取,顯示在WebBrowser中。中間用到了HtmlAgilityPack插件,這個插件也是剛剛接觸,上次在個人博文《使用HttpWebRequest和HtmlAgilityPack抓取網頁(拒絕亂碼,拒絕正則表達式)》中提到過,後來被園友們一通吐槽,給我推薦了Jumony(地址),這個比HtmlAgilityPack牛逼多了,瞬間把HtmlAgilityPack拋棄了。苦逼的是,但我開始動手作的時候,發現Jumony居然不能在wp8中使用,我又瞬間石化了,而後又把HtmlAgilityPack撿了起來。git

下面上幫助類代碼,及時Post請求,和Get請求,暫時只用到了Get請求, post請求是準備作用戶中心的時候使用的。github

 

 

public class HttpHelper
    {
        public static CookieContainer cc = new CookieContainer();
        /// <summary>
        /// 發起異步post的請求,可用於模擬登錄。
        /// </summary>
        /// <param name="url">post的地址</param>
        /// <param name="poststr">參數字符串</param>
        /// <param name="action">回調函數</param>
        public static void HttpPostAsync(string url, string poststr, Action<string> action)
        {
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
            req.Method = "POST";
            req.CookieContainer = cc;
            req.Accept = "application/json, text/javascript, */*; q=0.01";
            req.ContentType = "application/x-www-form-urlencoded";
            req.AllowAutoRedirect = false;
            req.BeginGetRequestStream(new AsyncCallback(asy =>
            {
                HttpWebRequest req1 = (HttpWebRequest)asy.AsyncState;
                using (Stream stream1 = req1.EndGetRequestStream(asy))
                {
                    byte[] postData = Encoding.UTF8.GetBytes(poststr);
                    stream1.Write(postData, 0, postData.Length);
                }
                //開始異步接收數據
                req1.BeginGetResponse(new AsyncCallback(res =>
                {
                    HttpWebRequest req2 = (HttpWebRequest)res.AsyncState;
                    //結束返回的請求數據
                    HttpWebResponse response = (HttpWebResponse)req2.EndGetResponse(res);
                    using (Stream stream2 = response.GetResponseStream())
                    {
                        StreamReader reader = new StreamReader(stream2);
                        string resStr = reader.ReadToEnd();
                        action(resStr);
                    }
                }), req1);
            }), req);
        }

        public static void HttpGetAsync(string url,Action<string> action)
        {
            if (Utils.GetNetStates()=="None")
            {
                action("no network");//無網絡
                return;
            }
            HttpWebRequest req1 = (HttpWebRequest)HttpWebRequest.Create(url);
            req1.CookieContainer = cc;
            //開始異步接收數據
            req1.BeginGetResponse(new AsyncCallback(res =>
            {
                try
                {
                    HttpWebRequest req2 = (HttpWebRequest)res.AsyncState;
                    //結束返回的請求數據
                    HttpWebResponse response = (HttpWebResponse)req2.EndGetResponse(res);
                    using (Stream stream2 = response.GetResponseStream())
                    {
                        StreamReader reader = new StreamReader(stream2);
                        string resStr = reader.ReadToEnd();
                        action(resStr);
                    }
                }
                catch (Exception)
                {

                    action("network anomaly");//請求失敗,網絡異常
                }
               
            }), req1);
        }
    }

 下面是判斷手機的網絡狀態的代碼web

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佈局,有四個欄目,分別是 首頁,熱門分類,知識庫,(我的中心)暫時沒作,後期加上。json

首先說首頁,主要是抓取博客園首頁文章列表,而後分析頁面後,加載到ListBox中。這裏有個我所認爲的難點:到頁面滾動到底部的時候自動加載下一頁。找了好多資料,最後仍是找到了,先把主要代碼貼出來windows

 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

 

未打完,也要收工。一是東西太多了, 原本打算分幾回寫的,後來以爲太麻煩了。二是,本人表達能力有限,看不明白的直接看源碼吧,源碼有註釋哦。

相關文章
相關標籤/搜索