[C#][WINDOWS PHONE] 關於頁面處理的相關小細節(改變初始頁面與頁面間傳遞參數)

這幾天開始把原來的RSS Reader APP程式多加頁面後,發現了一些小問題。網路上或許還算是好找。

但是我稍微整理一下,其實Pou’s blog兩篇文章有相當清楚的解釋

在此只把常遇到的兩個問題整理一下:

  1. 如何改變初始頁面(How to change default page on Windows Phone)
    修改文件”WMAppManifest.xml”以下程式碼:
<Tasks>
  <DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
</Tasks>
  1. 如何在頁面中傳遞參數(How to pass parameter over pages on Windows Phone)

在頁面間傳遞參數可以把它當成是網頁的GET模式(就是?Param_1=value_1&Param_2=value_2)

在原來的頁面可以用以下的指令傳遞

string mylogin = "/Page2.xaml";
mylogin += "?Param1=" + "VALUE1";
mylogin += "&Param2=" + "VALUE2";

if (!String.IsNullOrWhiteSpace(mylogin))
{
	this.NavigationService.Navigate(new Uri(mylogin, UriKind.Relative));
}

再接收的Page2就必須要有以下的方式去接受參數

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
            //Get parameter
            string myParam1 = NavigationContext.QueryString["Param1"];
            string myParam2 = NavigationContext.QueryString["Param2"];
}

這樣就可以了~~~

參考網頁:

[C#][Windows Phone][JSON]如何用C#完成一個簡單的Google Reader APP(下)


3. 瀏覽全部尚未閱讀的列表

接上篇文章,接下來會開始講解如何去獲得使用者所有標籤(Label)的文章。

一開始首先一樣是先提供這裡會用到的相關Google Reader API的講解

> > [https://www.google.com/reader/api/0/unread-count?allcomments=true&output=json&ck=12121&client=scroll](https://www.google.com/reader/api/0/unread-count?allcomments=true&output=json&ck=12121&client=scroll) > >

你就可以在瀏覽器上面獲得你要的資訊。你如果有登入你可能會獲得像是以下的一些資料。

接下來是取得資料的相關原始碼:

public void GetGoogleReaderUnReadCount()
        {
            string auth_params = string.Format("https://www.google.com/reader/api/0/unread-count?allcomments=true&output=json&ck=" + DateTime.Now.Ticks.ToString() + "&client=scroll");

            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(auth_params);
            httpRequest.Method = "GET";
            httpRequest.Headers["Authorization"] = "GoogleLogin auth=" + UserAuth;
            httpRequest.Headers["Cookie"] = "SID=" + UserSid;
            httpRequest.BeginGetResponse(new AsyncCallback(ResponseCallbackInner), httpRequest);
        }

抓回資料後,就開始要去parse這些資料,這邊會用到大量的JSON相關技巧,我也盡量試著解釋清楚一點給大家知道。首先,會拿到以下的資料,以下是以我的資訊當作範例~跟你拿到的可能會有點差異。

{
"max":1000,
"unreadcounts":[
	{
		"id":"user/-/label/教學網站",
		"count":9,
		"newestItemTimestampUsec":"1335595557150290"
	},
	{
		"id":"user/-/label/Funny",
		"count":83,
		"newestItemTimestampUsec":"1335621983685977"
	},
	{
		"id":"user/-/label/專業評論",
		"count":38,
		"newestItemTimestampUsec":"1335617137314302"
	}
}

這些資料就是JSON的資料,關於JSON是甚麼與JSON.NET該怎麼使用的部分,網路上有許多相關的程式碼,我這裡就不詳述了。

根據上面資料排序的結果,我們需要去抓unreadcounts下面的子結點,而他的資料格式如下:

public class ServerUnreadResult //JSON
        {
            public string id { get; set; }
            public string count { get; set; }
            public string newestItemTimestampUsec { get; set; }
        }

所以在我們程式碼中,就是可以依照以下的安排:

private void ParseUnreadList(string responseString)
        {
            //JSON Parse
            JObject googleSearch = JObject.Parse(responseString);

            // get JSON result objects into a list
            IList<JToken> results = googleSearch["unreadcounts"].Children().ToList();

            // serialize JSON results into .NET objects
            IList<ServerUnreadResult> searchResults = new List<ServerUnreadResult>();
            foreach (JToken result in results)
            {
                ServerUnreadResult searchResult = JsonConvert.DeserializeObject<ServerUnreadResult>(result.ToString());

                //Parse the label name
                // ex: user/06771113693638414260/label/Win8
                string LabelID = searchResult.id;
                string[] arrs = LabelID.Split('/');
                if (!arrs[0].Contains("user"))
                    continue;
                LabelID = arrs[3];
	// Add to Your arrary...
	.......
            }
        }

開始講解這段的程式碼,主要就是第7行的部分可以直接選取到unreadcounts子結點下面所有的內容。然後再針對所有子結點開始DeserializeObject,這樣就可以把所有資料填入到ServerUnreadResult 所產生的類別資料中。這裡主要需要的是標籤名稱與尚未讀取的文章數目。

4. 打開某個標籤(Label)內去看裡面還沒閱讀的文章

當你知道某個標籤內有多少文章,使用者就應該可以點選該標籤去看某個標籤內的所有文章。所以我們需要開始去處理如何查詢某個標籤內所有尚未閱讀的文章。

接下來的部分有點小複雜的是,因為傳回來的JSON資料會相當的多,所以可能需要一些工具去幫助你了解JSON資料。個人推薦http://json.parser.online.fr/這個網站,他可以把你JSON回傳得資料展開。可以幫助你看清楚資料裡面的階層關係。

跟之前的介紹一樣,一開始先提供相關鏈結:

> > [http://www.google.com/reader/api/0/stream/contents/user/"](http://www.google.com/reader/api/0/stream/contents/user/") + UserInfoClass.userId + "/label/"+sLabel+"?n=15&ck=" + DateTime.Now.Ticks.ToString() + "&client=scroll&format=json&xt=user/" + UserInfoClass.userId + "/state/com.google/read > >

跟之前的指令一樣你只要把UserInfoClass.userId換成你的ID還有把DateTime.Now.Ticks.ToString() 換成任何一個隨意的值。你就可以在瀏覽器上面獲得你要的資訊。這裡有一個參數要特別講解。

> > &xt=user/-/state/com.google/read > >

這個參數就是幫你把你讀過的部分去除掉,也就是挑選你”尚未閱讀的部分”。

此外另外一個參數n=15 就是顯是你要幾筆資料,你可以將前一個動作所取出來所有尚未讀取的文章放在這裡,預設值是給20。

接下來就是提供給大家相關的程式碼的部分:

public void GetATOMbyLabel(string sLabel)
        {
            string auth_params = string.Format("http://www.google.com/reader/api/0/stream/contents/user/" + UserInfoClass.userId + "/label/"+sLabel+"?n=15&ck=" + DateTime.Now.Ticks.ToString() + "&client=scroll&format=json&xt=user/" + UserInfoClass.userId + "/state/com.google/read");

            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(auth_params);
            httpRequest.Method = "GET";
            httpRequest.Headers["Authorization"] = "GoogleLogin auth=" + UserAuth;
            httpRequest.Headers["Cookie"] = "SID=" + UserSid;
            httpRequest.BeginGetResponse(new AsyncCallback(ResponseCallback), httpRequest);
        }

這邊沒有太多程式碼的部分需要說明。

接下來就要處理回傳的JSON資料,這僅僅是一筆的資料如下,由於資料有點大量,我盡量刪除不需要的部分:

{
"direction":"ltr",
"id":"user/-/label/Apple",
"title":"在 Google 閱讀器中取得 Evan Lin 的「Apple」",
"continuation":"COGG3sTqta8C",
"self":[
{
"href":"http://www.google.com/reader/api/0/stream/contents/user/-/label/Apple?nu003d15u0026cku003d2323232323u0026clientu003dscrollu0026formatu003djson"
}
],
"author":"Evan Lin",
"updated":1334555570,
"items":[
{
"id":"tag:google.com,2005:reader/item/f1c6c6aed52d2682",
"title":"【限時免費】Moco Cam:復古底片當道,LOMO 鏡頭隨你拍,超過20種濾鏡效果,原價0.99,限時免費下載中",
"alternate":[
{
"href":"http://funiphone.pixnet.net/blog/post/37297964",
"type":"text/html"
}
],
"content":{
"direction":"ltr",
"content":"u003cpu003eu003cimg srcu003d"http://pic.pimg.tw/funiphone/1334549031-3221087701_q.png" altu003d"" widthu003d"150"u003eu003cimg srcu003d"http://pic.pimg.tw/funiphone/1334549497-4194937028_n.png" altu003d"" widthu003d"450"u003eu003c/pu003enu003cpu003e u003c/pu003enu003cpu003e u003c/pu003enu003cpu003eu003ca hrefu003d"http://itunes.apple.com/app/moco-cam-camera-lens-effects/id371271476?mtu003d8"u003eu003cimg styleu003d"display:block;margin-left:auto;margin-right:auto" srcu003d"http://pic.pimg.tw/funiphone/1310632558-92007661eba0bc5e489df3d66cfff9b9.jpg?vu003d1310632559" altu003d"按此下載.jpg"u003eu003c/au003eu003c/pu003enu003cpu003eu003cimg srcu003d"http://a1.mzstatic.com/us/r1000/059/Purple/b6/38/6b/mzl.fgzqmjnx.320x480-75.jpg" altu003d"iPhone Screenshot 1" widthu003d"280"u003e u003cimg srcu003d"http://a5.mzstatic.com/us/r1000/038/Purple/ff/8a/7c/mzl.fzmsyokn.320x480-75.jpg" altu003d"iPhone Screenshot 3" widthu003d"280"u003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:14pt"u003eu003cspanu003e【目前售價:u003cspan styleu003d"color:#ff0000"u003e限時免費u003c/spanu003eu003c/spanu003eu003cspanu003e】u003c/spanu003eu003c/spanu003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:14pt"u003e【檔案大小:5.0 MB】u003c/spanu003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:large"u003eMoco Cam (Camera Lens Effects) 限時免費的好用鏡頭濾鏡軟體,這個App介面十分簡單,但支援超過20幾種濾鏡。原價0.99美金,限時免費中,喜歡用iPhone、iPad等iOS裝置照相拍照的話,可以趁限免時下載此程式App。u003c/spanu003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:large"u003e(下為 iTunes 上的玩家評價)u003c/spanu003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:large"u003eu003cimg titleu003d"89" srcu003d"http://pic.pimg.tw/funiphone/1334549972-1765202292.png" altu003d"89" borderu003d"0"u003e u003c/spanu003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:large;color:#0000ff"u003eFun iPhone(APP玩家)評分:★★★u003c/spanu003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:large"u003eu003cbru003eu003c/spanu003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:large"u003e此相機修圖程式的首頁介面非常簡單,其實也有點陽春。按下方咖啡色方塊可進入程式。u003c/spanu003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:large"u003eu003cimg srcu003d"http://a5.mzstatic.com/us/r1000/030/Purple/29/f7/f2/mzl.xxifelxh.320x480-75.jpg" altu003d"" widthu003d"320"u003eu003c/spanu003eu003c/pu003enu003cpu003eu003cspan styleu003d"font-size:large"u003e要選擇 take a photo 相機照相或直接從手機相簿中選擇想加入濾鏡的圖片u003c/spanu003eu003c/pu003e u003cdivu003eu003ca hrefu003d"http://funiphone.pixnet.net/blog/post/37297964"u003e(繼續閱讀...)u003c/au003eu003cimg srcu003d"http://pixanalytics.com/pa.gif?tu003dfront_blog_feedu0026amp;document.URLu003dhttp://funiphone.pixnet.net/blog/post/37297964"u003eu003c/divu003e"
},
"origin":{
"streamId":"feed/http://funiphone.pixnet.net/blog/feed/rss",
"title":"Fun iPhone 愛瘋玩家 (APP玩家):: 痞客邦 PIXNET ::",
"htmlUrl":"http://funiphone.pixnet.net/blog"
}
}
}

這邊資料有點多,我盡量去分開講。這裡大家會用到一些資料內容主要有以下的資料。

  • [“alternate”][“href”]: 這是這篇文章原來的網址,可以用來展開到瀏覽器用。

  • [“origin”][“streamId”]: 這個是這個feed的ID,之後在標記閱讀會用到

提供程式碼之前,一樣的我們需要把資料先宣告成類別如下:

public class ServerLabelATOMResult //JSON
        {
            public string id { get; set; }
            public string title { get; set; }
        }

        public class ServerLabelATOMResult2 //JSON
        {
            public string href { get; set; }
            public string type { get; set; }
            //public string content { get; set; }
        }

接下來就提供程式碼的部分:

private void ParseLabelATOM(string responseString)
        {
            //JSON Parse
            JObject googleSearch = JObject.Parse(responseString);

            // get JSON result objects into a list
            IList<JToken> results = googleSearch["items"].Children().ToList();

            // serialize JSON results into .NET objects
            IList<ServerLabelATOMResult> searchResults = new List<ServerLabelATOMResult>();
            foreach (JToken result in results)
            {
                ServerLabelATOMResult searchResult = JsonConvert.DeserializeObject<ServerLabelATOMResult>(result.ToString());
                string newsID = searchResult.id;
                string feedID = result["origin"]["streamId"].ToString();
                string feedTitle = result["origin"]["title"].ToString();

                ///// Get the link of this news.
                string sLink = "";
                IList<JToken> results2 = result["alternate"].Children().ToList();
                foreach (JToken result2s in results2)
                    sLink = result2s["href"].ToString();
	//Add to your data set here
            }
        }

這裡要特別講解一下,由於JSON裡面的LIST 主要是處理多個資料集(LIST)的方式,就如同對應到JSON的

> > ":[" > >

所以在這裡的[“alternate”][“href”]必須當作是多個資料,雖然Google本身也只有包了一個資料集而已,也就是說雖然Google裡面只有”href”與”http”共一個資料集(LIST)但是我們還是得這樣處理他,不然拿不到資料。這個部分也弄了很久,在此分享給大家。

5. 打開該文章網站並且將其標記已經閱讀(mark as read)

這邊的部分就請參照我之前的文章,在這裡就不再詳述了。

[C#][Windows Phone][JSON]如何用C#完成一個簡單的Google Reader APp(上)

這個禮拜初,最後總算弄好標記閱讀(Mark Read)後,Google Reader App總算也完成了。不過由於接下來可能會把一些時間拿去研究iOS。最後決定把這部份的研究做一個總整理。這一篇文章會包括以下的技術:

  • Google API 在Windows Phone 7.1上面的相關使用

  • 對於Google Reader API的JSON的相關使用

  • 一些簡單的Windows Phone原始碼(source code)的討論

關於RSS Reader App:

首先我想在這裡先稍微整理一下,一個簡單的RSS Reader的Windows Phone APP是相當簡單的。其實只要會簡單的Webclient加上去使用內建的資料格式就可以完成,這裡微軟也提供完整的原始碼與介紹。本篇介紹的部分主要都是專注在Google Reader的部分。

Google Reader API:

由於我是在Windows Phone上面做開發(Windows Phone 7.1)所以無法直接使用Google Data上面的相關API,在這裡也要特別解釋,如果你只是WPF或是一般Windows程式~ 你可以直接使用Google Data而不需要一步步的完成Google Reader API的部分,在這裡把之前文章列過的Google Reader API整理一次:

一個簡單Google Reader APP的流程:

接下來我會用碼個Google Reader 會使用到的流程來介紹該如何去撰寫,首先一個Google Reader APP會有以細的流程:

  1. 登入,也就是登入你的Google Reader 帳號

  2. 取得登入者的相關資訊

  3. 瀏覽全部尚未閱讀的列表

  4. 打開某個標籤(Label)內去看裡面還沒閱讀的文章

  5. 打開該文章網站並且將其標記已經閱讀(mark as read)

接下來我會針對以下的部分,開始整理一些原始碼:

1. 登入,也就是登入你的Google Reader 帳號
在這裡會使用到基本的Google 登入部分,你可以直接在你的瀏覽器上頭打入以下的鏈結。

> > [https://www.google.com/reader/api/0/token?ck=212121212&client=scroll](https://www.google.com/reader/api/0/token?ck=212121212&client=scroll) > >

稍微解釋一下參數:

> > ck: 就是時間標記(timestamp),你可以用DateTime.Now.Ticks.ToString()拿到 > > > > client:先填入scroll的方式 > >

如果你已經登入過的話,一樣會有一樣的結果

public void LoginGoogleReader()
        {
            string email = "YOUR_EMAIL";
            string passwd = "YOUR_PASSWORD";
            string auth_params = string.Format("https://www.google.com/accounts/ClientLogin?accountType=HOSTED_OR_GOOGLE&Email=" + email + "&Passwd=" + passwd + "&service=reader&source=J-MyReader-1.0");
            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(auth_params);
<font color="#ff0000">            httpRequest.Method = "POST";</font>
            RequestState myRequestState = new RequestState();
            myRequestState.request = httpRequest;
            IAsyncResult result =
                (IAsyncResult)httpRequest.BeginGetResponse(new AsyncCallback(AuthRespCallback), myRequestState);
        }

但是你也需要去把登入回來的SID與AuthID去parse出來,以下提供相關方法:

private void ParseLogin(string responseString)
        {
            string[] arrs = responseString.Split('n');
            foreach (string arr in arrs)
            {
                //Such as follows, but we only need Auth and SID
                //SID=DQAAALcAAACH5nzd2xVxumGUJGjoTT9DblBfAuI1Sj-6Evtu_91q8Fkbis_S1qv66-vatdUe9HMqqELN3AijrD-CiQyzqJtr_XgTtJIDnfDeVmoGjtsSpkyIB4sES5slrOkTvRJd67dG0tlwTih8btejcPqAVYCJMD6f-a-x3PHa2JQ-Ehsh-rtjNzW6y7Riqosyawffvg4DPbtvUJFsIsum8d32EQ_XuxmUM7NFuhwW5OG8aw3lLO_jO0fLaznl7n5DfCC61KSAn
                //LSID=DQAAALkAAAAAeAUiJHtt2vL41E3bfMAJwE_waG3qEtAgEsv-Il0xXznDCdm-Z_jQZ4Log9DbGqTMd1-t08udWBJWeQ9VDG0uOC4H5nB0zJ_WGv1E17v3EVeveemKvpu9eN2YBkQlr6hMtZlZWyAb5w0uwAx6kPdXnnuuYC4o0RHv2em0CrOAFzpNYZvLOhuB_veFZ9bsnPy6GP0_HHQGe2o3dJsoJK_DKyq85QteslDzcQySldfwNGUy46Q4HLKhZZPDrjnO_eUn
                //Auth=DQAAALgAAAAAeAUiJHtt2vL41E3bfMAJta7kSZRtYIzGfm8uJU_jVFjmIFbYYL9WaLS7Xj3xqdwLOrzrBipqL8ItZks4Hf71NY2yTyZnAIG5ysrlA9kCcoZGDDqo3ib9avvgC4pPwXB2uQ3rBYt0gqYs28DkEX6fDD4S3j_NwBESynhOUhcTKqhN3pYX1VfH6uU4285yV7O3w7NKfF8kkTOEFl5toztOwnA4JWnbC5Rjb_gMXKmKnzayTMevgO_XfGWqqNa8x5Mn"	string
                string[] tmp = arr.Split('=');
                if (tmp[0] == "Auth")
                {
                    UserAuth = tmp[1];
                }
                else if (tmp[0] == "SID")
                {
                    UserSid = tmp[1];
                }
            }
        }

記得把UserAuth與UserSid要儲存下來,之後每一個動作都需要。

2. 取得登入者的相關資訊

登入以後我們需要去取得使用者的ID,這樣主要也是給我們去找尋標籤(Label)或是做一些使用者的相關功能來使用。

如同之前一樣,你也可以在你的瀏覽器上面打入以下的鏈結來看結果:

> > [https://www.google.com/reader/api/0/user-info?format=json&ck=121212122&client=scroll](https://www.google.com/reader/api/0/user-info?format=json&ck=121212122&client=scroll) > >

這裡多了一個參數,也就是JSON的輸出格式

> > format: 如果不是寫joson會傳回XML資料 > >

你打出來的使用者資訊應該會像以下的資料一樣:

{
"userId":"XXX",
"userName":"XXX",
"userProfileId":"XXX",
"userEmail":"[email protected]",
"isBloggerUser":true,
"signupTimeSec":1188451343,
"publicUserName":"XXX",
"isMultiLoginEnabled":true
}

而我們需要的也只有userProfileId,接下來先給大家如何去抓取ID的程式碼:

public void GetUserInformation()
        {
            string auth_params = string.Format("https://www.google.com/reader/api/0/user-info?format=joson&ck=" + DateTime.Now.Ticks.ToString() + "&client=scroll");

            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(auth_params);
            httpRequest.Method = "GET";
            httpRequest.Headers["Authorization"] = "GoogleLogin auth=" + UserAuth;
            httpRequest.Headers["Cookie"] = "SID=" + UserSid;
            httpRequest.BeginGetResponse(new AsyncCallback(ResponseCallbackInner), httpRequest);
        }

在這裡會使用到之前抓的兩個參數UserAuth以及UserSid記得要填到Header之內不然都會得到error 400。

如果正確的拿到資料的話,我也提供利用JSON來抓取資料的方式。

public class ServerUserInfo //JSON
        {
            public string userId { get; set; }
            public string userName { get; set; }
            public string userProfileId { get; set; }
            public string userEmail { get; set; }
            public string isBloggerUser { get; set; }
            public string signupTimeSec { get; set; }
            public string publicUserName { get; set; }
            public string isMultiLoginEnabled { get; set; }
        }


private void ParseUserInfo(string responseString)
        {
            UserInfoClass = JsonConvert.DeserializeObject<ServerUserInfo>(responseString);
            staUserID = UserInfoClass.userId;
        }

看到了嗎?這就是JSON神奇的地方,你只要一行程式碼就可以去把所有資料提到你的資料UserInfoClass(是class ServerUserInfo 產生的)中。

先寫到這個部分,接下來就是瀏覽標籤(Label)與找到文章內容的部分…

[C#][Windows Phone]利用WebCLient去完成Google Reader標記閱讀(Mark as read)

上一篇文章有講解利用HttpWebRequest的方式來完成Google Reader中的標記閱讀,但是因為edit-tag本身就不屬於太消耗時間的動作。與其去用HttpWebRequest的非同步的方式,不如使用容易又好用的WebClient,所以我就把我原來程式碼做了一點修改。

 public void MarkArticleAsRead()
        {
            CurrentTransType = Transaction_Type.MARK_AS_READ;
            string auth_params = string.Format("https://www.google.com/reader/api/0/edit-tag?client=scroll&format=joson&ck=" + DateTime.Now.Ticks.ToString());

            string postData = "";
            postData += "&i=tag:google.com,2005:reader/item/fa42c976c848ecf4";
            postData += "&a=user/-/state/com.google/read";
            postData += "&s=feed/http://funiphone.pixnet.net/blog/feed/rss";
            // Note the token must get within 30 mins
            postData += "&T=//mUESPUMtDyZh6BaFXd-CqQ";


            WebClient wc = new WebClient();
            wc.Headers["Content-type"] = "application/x-www-form-urlencoded";
            wc.Headers["Authorization"] = "GoogleLogin auth=" + UserAuth;
            wc.Headers["Cookie"] = "SID=" + UserSid;
            try
            {
                wc.UploadStringAsync(new Uri(auth_params), "POST", postData);
            }
            catch (WebException e)
            {
                //handle error if any
            }
        }
<font face="Georgia">幾個需要注意的地方如下:</font>
  • UserAuth與UserSid 需要先對Google API做login的部分
  • Content-type是必須要先填成這樣,我試過uff8會失敗~

[C#][Windows Phone]如何使用Google reader API標記已經閱讀 (mark as read)

雖然網路上沒有完整使用C#與Windows Phone 7.1的範例,不過還是盡量用中文來寫這篇吧。其實網路上英文的資料應該也不少,不論是pyrfeed這裡的Google API列表,還是Unofficial Google Reader API或是R2 google reader on Google code。不過要完整的C#還有Windows Phone 7.1的sample code我也是想辦法K了半天這三份API文件然後不斷的測試,在這裡就列出一些片段的程式碼。

public void MarkArticleAsRead(string newID)
{
            string auth_params = string.Format("https://www.google.com/reader/api/0/edit-tag?client=scroll&format=joson&ck=" + DateTime.Now.Ticks.ToString());

            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(auth_params);
            httpRequest.Method = "POST";
            httpRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
            httpRequest.Headers["Authorization"] = "GoogleLogin auth=" + UserAuth;
            httpRequest.Headers["Cookie"] = "SID=" + UserSid;
            httpRequest.BeginGetRequestStream(new AsyncCallback(GetPostRequestStreamCallback), httpRequest);
        }    

不過這裡有一些需要注意的是SID與auth ID需要另外區擷取,這在我其他文章提到。不過接下來就是重點的部分。也就是post data該如何填、該放哪些資料。

 private static void GetPostRequestStreamCallback(IAsyncResult asynchronousResult)
        {
            HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;

            // End the operation
            Stream postStream = request.EndGetRequestStream(asynchronousResult);
            string postData = "";
            postData += "&i=tag:google.com,2005:reader/item/fa42c976c848ecf4";
            postData += "&a=user/-/state/com.google/read";
            postData += "&s=feed/http://funiphone.pixnet.net/blog/feed/rss";
            // Note the token must get within 30 mins
            postData += "&T=//mUESPUMtDyZh6BaFXd-CqQ" + LoginToken;

            // Convert the string into a byte array.
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);

            // Write to the request stream.
            postStream.Write(byteArray, 0, postData.Length);
            postStream.Close();

            // Start the asynchronous operation to get the response
            request.BeginGetResponse(new AsyncCallback(GetPostResponseCallback), request);
        }

在這裡也要注意的是Token需要再30分鐘之內取得~ 建議是呼叫之前馬上去取得token來使用。還有這裡的參數”a=”user 之後有user id 需要填,在這裡就不列出來。 &i=要填的是news 的id,還有&s=要填的是rss ID,你可以在另外一個參數”http://www.google.com/reader/api/0/stream/contents/user” 去取得。最後是結果的部分:

private static void GetPostResponseCallback(IAsyncResult asynchronousResult)
        {
            HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;

            // End the operation
            HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
            Stream streamResponse = response.GetResponseStream();
            StreamReader streamRead = new StreamReader(streamResponse);
            string responseString = streamRead.ReadToEnd();
            // "responseString" should be "OK" if post succucess

            // Close the stream object
            streamResponse.Close();
            streamRead.Close();
            response.Close();
        }

這裡重要的是~ 如果這篇文章被mark as read你就會得到OK,但是如果之前已經mark as read你就會得到一個exception,這是需要注意的。

目前先寫到這裡~ 找時間把全部的流程跑一次~ 順便講解一下JSON的部分。

[Windows Phone][C#]最近寫了一個Windows Phone的Google Reader APP

本篇文章應該會用中文撰寫到完,接續著我前幾篇的文章,我一共寫了幾篇跟Google Reader溝通有關的文章。也讓我來仔細敘述當初為何會有這些文章的出現吧。

大概是兩個月前XDite大大在plurk po了一篇 “我要在一個月之內把Reeder幹出來” (大概是這樣吧!雖然我忘記原文了,而且大大好像後來也刪除了)。其實那一篇我看了以後很震撼~ 對喔!! 可以利用完全仿製另外一個商用APP的方式來練功。

於是我也開始撰寫APP,由於我自己只有iPhone,但是卻沒有任何MAC的電腦可以給我提供開發的環境,也只好拿公司最容易找到工具。Microsoft的 Visual Studio來撰寫Windows Phone。

一路上從四月才開始把專案建起來到現在,從完全不會寫Windows Phone到搞定Data Binding、知道如何使用Lambda與Delegate、也慢慢把Windows Phone原件搞懂,當然好久沒摸的WPF也開始拿回來K了一陣,到最後的LINQ、JSON(這個方便應該之後會寫一篇文章來做個說明)。其實寫好一個Google Reader App能夠學習的APP技巧真的不少,在這裡也稍微列一下:

  • 為了登入Google API的服務, 一開始要學習的就是如何去處理網路溝通的方式,面對的就是 HttpWebRequest與WebClient。 當然這篇文章也幫助我很多。在這時候一併就把Lanbda與Delegate 的觀念學起來,畢竟你得要處理threading與UI呈現的問題。

  • 登入Google Reader API之後就沒事情了嗎? 還要好好的去處理溝通過來得資料,這裡你當然可以乖乖的使用XML的方式或是直接跳到JSON的方式。 還好之前學習的Linq與JSON就派上用場。不過Google Reader的JSON資料也怪怪的~ 為了去處理這些東西~也讓我對JSON的觀念更佳的清楚了。

  • 抓回來的Label列表與文章列表要如何處理呢?這時候又要跟WPF裡面的ListBox開始奮戰,這時候你又得跟Data Binding還有WPF XAML的語法來奮鬥。

  • 別忘了最後~ 由於你需要離線閱讀還以記錄使用者的登入資訊。這時候又要跟Local database on Windows Phobne來奮鬥。不過這個算簡單的,畢竟LinQ步算是太難入門的東西。

到目前為止利用自己上班剩餘時間,大概忙了三個禮拜的結果,目前已經可以登入與看文章。由於在今天好不容易把Google Reader裡面的設定閱讀(mark it as read)也搞定了。 現在也才可以寫篇文章做點記錄。不過接下來才是Reeder令人激賞的好用地方,我也先把自己的TODO 列一下:

  • 順暢與讀體驗與文章下載(裡面包含著完全不影響使用者閱讀的離線下載)

  • 將你喜歡的文章轉載到各個社群媒體Facebook,Evernote…. 等 (希望懂了JSON可以讓之後的路更順暢)

  • 使用者介面得更加美化 (這是我的盲點~~~~~)

好啦!! 今天也總算把基本功能都完成了! 繼續努力了~~~