Windows Phone 7 - 學習Live SDK - 2
在<Windows Phone 7 - 學習Live SDK>一文中介紹了操作Live SDK基本的觀念與參數的使用方式,
因此,本篇內容將著重在實作的範例上,話不多說,本篇主要說明透過Live SDK來存取Skydrive與Calendar為例。
〉範例1 – 存取SkyDrive:
往下針對Skydrive的存取範例,需先定義「Scopes」,讓Live Connect知道需要提供存取的範圍,接下來
使用「Path」才能真正取得我們要的內容
[定義Scopes]
需要加上wl.skydrive、wl.skydrive_update、wl.photos,這樣才能讀取/存取行事曆,並且取得/存取Skydrive中的內容。
1: //加上wl.skydrive, wl.skydrive_update, wl.photos,才能R/W Skydrive的內容。
2: <my:SignInButton Name="btnLogin"
3: Scopes="wl.signin wl.basic wl.offline_access wl.skydrive wl.skydrive_update"
4: SessionChanged="btnLogin_SessionChanged"
5: HorizontalAlignment="Left"
6: ClientId="00000000480715FF"
7: />
有關Scope的定義,即會出現在登入Live Connection時出現。
a. 取得自己的所有SkyDrvice資料夾清單;
a-1. 為SignInButton的SessionChanged註冊GetCompleted:
1: private void btnLogin_SessionChanged(object sender, LiveConnectSessionChangedEventArgs e)
2: {
3: if (e != null && e.Session != null && e.Status == LiveConnectSessionStatus.Connected)
4: {
5: this.gLiveClient = new LiveConnectClient(e.Session);
6: this.gLiveClient.GetCompleted += OnGetConnectionCompleted;
7: //註冊處理上傳的事件
8: this.gLiveClient.UploadCompleted += new EventHandler<LiveOperationCompletedEventArgs>(gLiveClient_UploadCompleted);
9: this.gLiveClient.UploadProgressChanged += new EventHandler<LiveUploadProgressChangedEventArgs>(gLiveClient_UploadProgressChanged);
10: //用戶在Skydrive中的資料夾。它能包括:photos、videos、audios、files與子資料夾的組合資訊。
11: this.gLiveClient.GetAsync("/me/skydrive/files", null);
12: gActionTarget = "/me/skydrive/files";
13: }
14: else
15: {
16: this.gLiveClient = null;
17: if (e.Error != null)
18: MessageBox.Show(e.Error.Message.ToString());
19: }
20: }
a-2. 取得回傳結果;
1: {
2: "data": [
3: {
4: "id": "folder.d3b0749cf3ca9d66.D3B0749CF3CA9D66!965",
5: "from": {
6: "name": "Pou",
7: "id": ""
8: },
9: "name": "Home page photos",
10: "description": null,
11: "parent_id": "folder.d3b0749cf3ca9d66",
12: "upload_location": "https://apis.live.net/v5.0/folder.d3b0749cf3ca9d66.D3B0749CF3CA9D66!965/files/",
13: "is_embeddable": true,
14: "count": 1,
15: "link": "https://skydrive.live.com/redir.aspx?cid\u003dd3b0749cf3ca9d66\u0026page\u003dview\u0026resid\u003dD3B0749CF3CA9D66!965\u0026parid\u003dD3B0749CF3CA9D66!262",
16: "type": "album",
17: "shared_with": {
18: "access": "Just me"
19: },
20: "created_time": "2008-12-09T14:13:51+0000",
21: "updated_time": "2008-12-09T16:20:28+0000"
22: }, {
23: "id": "folder.d3b0749cf3ca9d66.D3B0749CF3CA9D66!1313",
24: "from": {
25: "name": "Pou Lin",
26: "id": "d3b0749cf3ca9d66"
27: },
28: "name": "Android",
29: "description": null,
30: "parent_id": "folder.d3b0749cf3ca9d66",
31: "upload_location": "https://apis.live.net/v5.0/folder.d3b0749cf3ca9d66.D3B0749CF3CA9D66!1313/files/",
32: "is_embeddable": true,
33: "count": 6,
34: "link": "https://skydrive.live.com/redir.aspx?cid\u003dd3b0749cf3ca9d66\u0026page\u003dview\u0026resid\u003dD3B0749CF3CA9D66!1313\u0026parid\u003dD3B0749CF3CA9D66!262",
35: "type": "album",
36: "shared_with": {
37: "access": "Just me"
38: },
39: "created_time": "2011-08-21T16:50:51+0000",
40: "updated_time": "2011-08-21T17:00:14+0000"
41: }
42: ]
43: }
a-3. 將回傳結果實作至ListBox上;
1: private void OnGetConnectionCompleted(object sender, LiveOperationCompletedEventArgs e)
2: {
3: if (e.Error == null)
4: {
5: //識別與建立Skydrive的主目錄清單
6: if (gActionTarget.ToLower().Contains("skydrive") == true)
7: {
8: BuildListItems(e, lstFolders);
9: return;
10: }
11: //識別與建立指定目錄下的所有清單
12: if (gActionTarget.ToLower().Contains("files") == true)
13: {
14: BuildListItems(e, lstFiles);
15: return;
16: }
17: }
18: else
19: {
20: if (e.Error != null)
21: MessageBox.Show(e.Error.Message.ToString());
22: }
23: }
b. 進入指定資料夾,並顯示所有檔案;
要注意:「type」它可能為album、folders(需實際遞回才能取得檔案)、files。
b-1. 實作ListBox的SelectionChanged,根據選定的folders載入所有檔案:
1: private void lstFolder_SelectionChanged(object sender, SelectionChangedEventArgs e)
2: {
3: //取得指定folder中的files,格式:/FOLDER_ID/files
4: string tId = ((ListDataItem) lstFolders.SelectedItem).id;
5: gActionTarget = string.Format("/{0}/files", tId);
6: this.gLiveClient.GetAsync(gActionTarget);
7: }
b-2. 取得回傳結果:
1: {
2: "data": [
3: {
4: "id": "file.d3b0749cf3ca9d66.D3B0749CF3CA9D66!668",
5: "from": {
6: "name": "Pou Lin",
7: "id": ""
8: },
9: "name": "Silverlight.part3.rar",
10: "description": "",
11: "parent_id": "folder.d3b0749cf3ca9d66.D3B0749CF3CA9D66!667",
12: "size": 38496350,
13: "upload_location": "https://apis.live.net/v5.0/file.d3b0749cf3ca9d66.D3B0749CF3CA9D66!668/content/",
14: "comments_count": 0,
15: "comments_enabled": false,
16: "is_embeddable": true,
17: "source": "http://storage.live.com/s1pAmWLDzrPy7YKhrWFHXDxUtV0pK5uWNEwRj0lXnfWDdVI33dZ8aq46eneItDTE9sIySw0ojB9-CtpAxjvI5SNxkLpmeRfb_pjNVcVJgnUtlDnr0iGo54AEkKAeNPI8_j1-icgwqzLFuY/Silverlight.part3.rar:Binary,Default/Silverlight.part3.rar",
18: "link": "https://skydrive.live.com/redir.aspx?cid\u003dd3b0749cf3ca9d66\u0026page\u003dview\u0026resid\u003dD3B0749CF3CA9D66!668\u0026parid\u003dD3B0749CF3CA9D66!667",
19: "type": "file",
20: "shared_with": {
21: "access": "Just me"
22: },
23: "created_time": "2008-07-16T14:18:36+0000",
24: "updated_time": "2008-07-16T14:18:36+0000"
25: }, {
26: "id": "file.d3b0749cf3ca9d66.D3B0749CF3CA9D66!669",
27: "from": {
28: "name": "Pou Lin",
29: "id": "d3b0749cf3ca9d66"
30: },
31: "name": "Silverlight.part1.rar",
32: "description": "",
33: "parent_id": "folder.d3b0749cf3ca9d66.D3B0749CF3CA9D66!667",
34: "size": 50000000,
35: "upload_location": "https://apis.live.net/v5.0/file.d3b0749cf3ca9d66.D3B0749CF3CA9D66!669/content/",
36: "comments_count": 0,
37: "comments_enabled": false,
38: "is_embeddable": true,
39: "source": "http://storage.live.com/s1pAmWLDzrPy7YKhrWFHXDxUtV0pK5uWNEwRj0lXnfWDdVI33dZ8aq46eneItDTE9sIySw0ojB9-CtpAxjvI5SNxkLpmeRfb_pjNVcVJgnUtlDnr0iGo54AEkKAeNPI8_j1-icgwqzLFuY/Silverlight.part1.rar:Binary,Default/Silverlight.part1.rar",
40: "link": "https://skydrive.live.com/redir.aspx?cid\u003dd3b0749cf3ca9d66\u0026page\u003dview\u0026resid\u003dD3B0749CF3CA9D66!669\u0026parid\u003dD3B0749CF3CA9D66!667",
41: "type": "file",
42: "shared_with": {
43: "access": "Just me"
44: },
45: "created_time": "2008-07-16T14:21:57+0000",
46: "updated_time": "2008-07-16T14:21:57+0000"
47: }, {
48: "id": "file.d3b0749cf3ca9d66.D3B0749CF3CA9D66!670",
49: "from": {
50: "name": "Pou Lin",
51: "id": ""
52: },
53: "name": "Silverlight.part2.rar",
54: "description": "",
55: "parent_id": "folder.d3b0749cf3ca9d66.D3B0749CF3CA9D66!667",
56: "size": 50000000,
57: "upload_location": "https://apis.live.net/v5.0/file.d3b0749cf3ca9d66.D3B0749CF3CA9D66!670/content/",
58: "comments_count": 0,
59: "comments_enabled": false,
60: "is_embeddable": true,
61: "source": "http://storage.live.com/s1pAmWLDzrPy7YKhrWFHXDxUtV0pK5uWNEwRj0lXnfWDdVI33dZ8aq46eneItDTE9sIySw0ojB9-CtpAxjvI5SNxkLpmeRfb_pjNVcVJgnUtlDnr0iGo54AEkKAeNPI8_j1-icgwqzLFuY/Silverlight.part2.rar:Binary,Default/Silverlight.part2.rar",
62: "link": "https://skydrive.live.com/redir.aspx?cid\u003dd3b0749cf3ca9d66\u0026page\u003dview\u0026resid\u003dD3B0749CF3CA9D66!670\u0026parid\u003dD3B0749CF3CA9D66!667",
63: "type": "file",
64: "shared_with": {
65: "access": "Just me"
66: },
67: "created_time": "2008-07-16T14:25:24+0000",
68: "updated_time": "2008-07-16T14:25:24+0000"
69: }
70: ]
71: }
注意<File>物件,支援的屬性非常多,通常看到有些可以存取SkyDrive的App都會透過它的屬性「source」
提供下載的能力。
b-3. 實作開啟PDF檔案;
1: private void lstFiles_SelectionChanged(object sender, SelectionChangedEventArgs e)
2: {
3: //識別如果為pdf,則開啟
4: if (((ListDataItem)lstFiles.SelectedItem).source.Contains("pdf") == true)
5: {
6: //使用WebBrowserTask下載檔案
7: WebBrowserTask browseToPDF = new WebBrowserTask();
8: browseToPDF.Uri = new Uri(((ListDataItem)lstFiles.SelectedItem).source, UriKind.Absolute);
9: browseToPDF.Show();
10: }
11: }
c. 上傳一份Word檔案,並使用微軟的SkyDrive來開啟;
c-1. 上傳放在專案中的Word檔案至指定的目錄;
1: private void btnUploadFiles_Click(object sender, RoutedEventArgs e)
2: {
3: //從XAP檔中取得要上傳的資料,並且轉成Stream
4: string tWordFile = "WP7LiveSDK;component/Resources/buyPhone.docx";
5: Stream tStream = App.GetResourceStream(new Uri(tWordFile, UriKind.Relative)).Stream;
6:
7: //使用UploadAsync只能指定me/skydrive
8: this.gLiveClient.UploadAsync("/me/skydrive", "購買手機指南.docx", tStream);
9: }
c-2. 回傳的結果;
1: {
2: "id": "file.d3b0749cf3ca9d66.D3B0749CF3CA9D66!1334",
3: "source": "http://storage.live.com/s1pAmWLDzrPy7aLwHnbiXvDGmiZGU1qyzktJbpZGSNVNF1AsP1u2gVcaJjSEm8auRYUcmXf3TyZoJQUnbHN7xIeuo59CY4kGwWVM1p_ufBySJIWRSvx0yuPKA/%E8%B3%BC%E8%B2%B7%E6%89%8B%E6%A9%9F%E6%8C%87%E5%8D%97.docx:Binary,Default/%E8%B3%BC%E8%B2%B7%E6%89%8B%E6%A9%9F%E6%8C%87%E5%8D%97.docx"
4: }
c-3. 處理上傳完畢的事件;
1: void gLiveClient_UploadCompleted(object sender, LiveOperationCompletedEventArgs e)
2: {
3: if (e.Error == null)
4: {
5: MessageBox.Show("Upload Async成功,請重新載入資料夾!");
6: }
7: else
8: {
9: this.gLiveClient = null;
10: if (e.Error != null)
11: MessageBox.Show(e.Error.Message.ToString());
12: }
13: }
d. 執行畫面;
======
〉範例2 - 存取Calendar:
往下針對Calendar的存取範例,需先定義「Scopes」,讓Live Connect知道需要提供存取的範圍,接下來
使用「Path」才能真正取得我們要的內容;
[定義Scopes]
需要加上wl.calendars、wl.calendars_update、wl.events_create,這樣才能讀取/存取行事曆,並且取得/存取
行事曆中的事件。
1: //加上wl.calendars wl.calendars_update wl.events_create,才能R/W行事曆的內容。
2: <my:SignInButton Name="btnLogin"
3: Scopes="wl.signin wl.basic wl.offline_access wl.calendars wl.calendars_update wl.events_create"
4: SessionChanged="btnLogin_SessionChanged"
5: HorizontalAlignment="Left"
6: ClientId="00000000480715FF"
7: />
有關Scope的定義,即會出現在登入Live Connection時出現。
a. 取得用戶的所有Calendar項目,並且顯示成清單;
a-1. 為SignInButton的SessionChanged註冊GetCompleted與PostCompleted處理常式;
1: private void btnLogin_SessionChanged(object sender, LiveConnectSessionChangedEventArgs e)
2: {
3: if (e != null && e.Session != null && e.Status == LiveConnectSessionStatus.Connected)
4: {
5: this.gLiveClient = new LiveConnectClient(e.Session);
6: //註冊處理取得Live Connection Data完成的事件
7: this.gLiveClient.GetCompleted += OnGetConnectionCompleted;
8: //註冊處理取得Post完成的事件
9: this.gLiveClient.PostCompleted += OnPostCompleted;
10: //暫存用於判斷要處理對象為:calendars或events
11: gActionTarget = "/me/calendars";
12: //取得用戶的行事曆
13: this.gLiveClient.GetAsync("/me/calendars", null);
14: }
15: else
16: {
17: this.gLiveClient = null;
18: if (e.Error != null)
19: MessageBox.Show(e.Error.Message.ToString());
20: }
21: }
a-2. 取得回傳的結果:
1: {
2: "data": [
3: {
4: "id": "calendar.d3b0749cf3ca9d66.7ca1c238865546548896ca63720668f3",
5: "name": "Work Calendar",
6: "description": "",
7: "created_time": "2012-03-31T03:16:58+0000",
8: "updated_time": "2012-03-31T03:16:58+0000",
9: "from": {
10: "name": "Pou",
11: "id": ""
12: },
13: "is_default": false,
14: "subscription_location": null,
15: "permissions": "owner"
16: }, {
17: "id": "calendar.d3b0749cf3ca9d66.947c72bb3655411f8603f592cd172351",
18: "name": "My Calendar",
19: "description": null,
20: "created_time": "2008-03-20T18:09:42+0000",
21: "updated_time": "2010-01-03T15:49:48+0000",
22: "from": {
23: "name": "Pou",
24: "id": ""
25: },
26: "is_default": true,
27: "subscription_location": null,
28: "permissions": "owner"
29: }
30: ]
31: }
a-3. 針對取得的結果,將可用的行事曆放入ListBox
1: private void OnGetConnectionCompleted(object sender, LiveOperationCompletedEventArgs e)
2: {
3: //this.gLiveClient.GetCompleted -= OnGetConnectionCompleted;
4: if (e.Error == null)
5: {
6: //識別是否為行事曆的資料格式
7: if (gActionTarget.ToLower().Contains("calendar") == true && gActionTarget.ToLower().Contains("event") == false)
8: {
9: BuildListItems(e, lstCalendar);
10: return;
11: }
12: //識別是否指定行事曆的事件
13: if (gActionTarget.ToLower().Contains("event") == true)
14: {
15: BuildListItems(e, lstItems);
16: return;
17: }
18: }
19: else
20: {
21: if (e.Error != null)
22: MessageBox.Show(e.Error.Message.ToString());
23: }
24: }
b. 取得指定行事曆的項目清單;
b-1. 針對ListBox註冊SelctionChanged的事件,並且根據選定的Calendar要求取得事件清單;
1: private void lstCalendar_SelectionChanged(object sender, SelectionChangedEventArgs e)
2: {
3: //取得指定的calendar id與組成/CALENDAR_ID/events的path
4: string tId = ((ListDataItem)lstCalendar.SelectedItem).id;
5: gActionTarget = string.Format("/{0}/events", tId);
6: //要求取得事件清單
7: this.gLiveClient.GetAsync(gActionTarget);
8: }
b-2. 取得事件清單的結果:
1: {
2: "data": [
3: {
4: "id": "event.d3b0749cf3ca9d66.947c72bb3655411f8603f592cd172351.ec6a67459e1942a582a14d276c66b6c8",
5: "name": "新約會1",
6: "description": "加一個新約會到預設的行事曆裡 - 1",
7: "calendar_id": "calendar.d3b0749cf3ca9d66.947c72bb3655411f8603f592cd172351",
8: "from": {
9: "name": "Pou",
10: "id": ""
11: },
12: "start_time": "2012-03-31T16:00:34+0800",
13: "end_time": "2012-04-03T16:00:34+0800",
14: "location": null,
15: "is_all_day_event": false,
16: "is_recurrent": false,
17: "recurrence": null,
18: "reminder_time": null,
19: "availability": "busy",
20: "visibility": "public",
21: "created_time": "2012-03-31T08:00:46+0000",
22: "updated_time": "2012-03-31T08:00:46+0000"
23: }, {
24: "id": "event.d3b0749cf3ca9d66.947c72bb3655411f8603f592cd172351.73241c65e42c40fbac5fbe38d4a1eb8a",
25: "name": "新約會2",
26: "description": "加一個新約會到預設的行事曆裡 - 2",
27: "calendar_id": "calendar.d3b0749cf3ca9d66.947c72bb3655411f8603f592cd172351",
28: "from": {
29: "name": "Pou Lin",
30: "id": "d3b0749cf3ca9d66"
31: },
32: "start_time": "2012-03-31T16:07:23+0800",
33: "end_time": "2012-04-03T16:07:23+0800",
34: "location": null,
35: "is_all_day_event": false,
36: "is_recurrent": false,
37: "recurrence": null,
38: "reminder_time": null,
39: "availability": "busy",
40: "visibility": "public",
41: "created_time": "2012-03-31T08:07:26+0000",
42: "updated_time": "2012-03-31T08:07:26+0000"
43: }
44: ]
45: }
c. 新增事件至自己或指定的Calendar;
c-1. 建立要加入的path,將事件加入其中;
1: private void btnAddPEvent_Click(object sender, RoutedEventArgs e)
2: {
3: //增加事件至指定的Calendar
4: //string tPostPath = string.Format(@"/{0}/events",
5: // ((CalendarItem)lstCalendar.SelectedItem).id);
6: //增加事件至預設的Calendar
7: string tPostPath = "/me/events";
8: //增加事件的body
9: DataEntity.EventEntity tEvent = new DataEntity.EventEntity();
10: tEvent.name = "新約會";
11: tEvent.description = "加一個新約會到預設的行事曆裡";
12: tEvent.start_time = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
13: tEvent.end_time = DateTime.UtcNow.AddDays(3).ToString("yyyy-MM-ddTHH:mm:ssZ");
14: tEvent.location = "";
15: tEvent.is_all_day_event = false;
16: tEvent.availability = "busy";
17: tEvent.visibility = "public";
18:
19: //採用Post把資料送出去
20: this.gLiveClient.PostAsync(tPostPath, tEvent.ToJSON());
21: }
在這邊要注意新增事件的start_time與end_time的時間格式為:ISO 8601。
c-2. 新增成功的訊息;
1: {
2: "id": "event.d3b0749cf3ca9d66.947c72bb3655411f8603f592cd172351.ec6a67459e1942a582a14d276c66b6c8",
3: "name": "新約會",
4: "description": "加一個新約會到預設的行事曆裡",
5: "calendar_id": "calendar.d3b0749cf3ca9d66.947c72bb3655411f8603f592cd172351",
6: "from": {
7: "name": "Pou",
8: "id": ""
9: },
10: "start_time": "2012-03-31T16:00:34+0800",
11: "end_time": "2012-04-03T16:00:34+0800",
12: "location": null,
13: "is_all_day_event": false,
14: "is_recurrent": false,
15: "recurrence": null,
16: "reminder_time": null,
17: "availability": "busy",
18: "visibility": "public",
19: "created_time": "2012-03-31T08:00:46+0000",
20: "updated_time": "2012-03-31T08:00:46+0000"
21: }
c-3. 透過OnPostCompleted事件來處理回傳的結果;
1: private void OnPostCompleted(object sender, LiveOperationCompletedEventArgs e)
2: {
3: if (e.Error == null)
4: {
5: //識別是否存在16個參數,代表成功;
6: if (e.Result.Keys.Count == 16)
7: {
8: string tMsg = string.Format("created success!! \nid:{0}", e.Result["id"]);
9: MessageBox.Show(tMsg);
10: }
11: }
12: else
13: {
14: if (e.Error != null)
15: MessageBox.Show(e.Error.Message.ToString());
16: }
17: }
d. 執行畫面;
[注意]
1. 利用UploadAsync上傳檔案至Skydrvie,不可以指定上傳的資料夾;
=>指定的話,錯誤:「Could not determine the upload location. Make sure the path points to a file resource id.」;
2. 要上傳檔案至指定的目錄的話,需改用POST的方式,透過REST與AccessToken的搭配來上傳檔案;
[範例程式]
======
本篇介紹二個我比較常用到的功能,其他關於存取Contacts、Album等資源的部分,其實就大同小異了。
希望這二篇的介紹都對大家有所幫助。研究的心得我覺得幫忙處理掉OAuth蠻方便的,加上有參數與資料
實體的操作,讓整個程式在設計上更有結構與分割性。
References:
‧Windows Phone 7 学习使用Live SDK & Windows Phone 7 – 学习使用Live SDK
‧Live Connect Downloads & Folders and Files (重要)
‧In C#, given a DateTime object, how do I get a ISO 8601 date in string format?
‧How to get and edit the default Styles of the Silverlight for WP7 Toolkit controls
‧How to: Serialize and Deserialize JSON Data (重要)
‧DataContractJsonSerializer in .NET 3.5
‧Convert objects to JSON in C# using JavaScriptSerializer
‧How to Get Files From Resources in Silverlight 2.0 & Issue: read zip using Application.GetResourceStream
‧File upload to skydrive (重要) & Skydrive API for WP7
‧SkyDrive usage through Live SDK on Windows Phone