自從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
只需在頁面加載的時候註冊下事件就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 }
這些就是首頁欄目的主要代碼了,下面會把源碼貼出來,因此就不一一貼在這裏了。
綁定後列表後,就要綁定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 }
其次說熱門分類
熱門分類沒有作抓取,只是手工將博客園中的一級分類寫出來,把單擊事件裏傳遞對應的地址,到列表頁面。
列表頁面是採用的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 }
當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 }
突然以爲代碼太多了,先寫到這吧。 下班回家啦。
博客園的編輯器怎麼沒找到上傳附件的呢???
把源碼上傳到了雲盤裏, 下面是地址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
未打完,也要收工。一是東西太多了, 原本打算分幾回寫的,後來以爲太麻煩了。二是,本人表達能力有限,看不明白的直接看源碼吧,源碼有註釋哦。