《101 Windows Phone 7 Apps》讀書筆記-TODO LIST

來源:互聯網
上載者:User

課程內容

ØPivot控制項

ØContext Menu

ØData Contract Attributes

 

    TODO List使得我們能夠快速、簡單並且有效地管理工作。我們不僅可以用帶顏色的五角星和具體的描述來標記的任務,而且也可以用多種方式來進行過濾,比如,按照已經到期的任務、今天需要完成的任務或者帶星級的任務來對任務進行過濾。在瀏覽“已經完成”的工作清單時,我們也可以對任務進行撤銷。一般情況下,我們尋找所關心的任務時,會觸發過濾器。

    相對於本書的其他應用程式而言,TODO List包含的代碼更多,主要是由List管理所帶來的。List管理組件括任務的瀏覽、任務明細的查看、任務的排序、建立或刪除任務以及任務的編輯。該應用程式總共有5頁,包括首頁面、建立/編輯任務頁面、設定頁面和協助頁面。該應用程式涉及的任務管理的頁面設計和代碼可以很容易地移植到其他類似的任務管理應用中。但是,TODO List應用的主要目的是展示pivot控制項。Pivot是Windows Phone 7平台引入的兩個獨具特色的控制項之一(另一個就是下一章介紹的panorama控制項)。

 

The Pivot Control

    Pivot是一個接受使用者點擊的控制項,我們可以在Pivot上進行水平的滑動,或者通過點擊header來切換不同的視圖。這種類型的控制項已經被內建到Mail、 Calendar和Settings頁面,而且它還被很多其他內建的應用所使用,包括Internet Explorer、Maps、Marketplace、Music + Videos、People和Pictures。

    Pivot控制項可以對同一個資料集顯示過濾後的視圖(比如Mail應用);對同一個資料集顯示不同的視圖(比如Calendar應用);或者是為獨立的資料集提供簡單的、可切換的視圖(比如Settings應用程式中,application是一個資料集,而settings就是一個它的視圖)。但是,Pivot控制項並不會用於任務所包含步驟的順序顯示,比如建立工程的使用者嚮導介面。一般情況下,Pivot控制項佔據整個頁面,除了那種需要應用程式欄或者狀態列的應用。

    就像list box和list picker控制項一樣,Pivot是一個items控制項。雖然Pivot類中Items集合可以添加任意的對象,但是其類型只能是PivotItem的對象或者是資料對象。

    PivotItem是一個簡單的內容控制項,它具有Content和Header屬性。雖然這兩個屬性可以設定為任意值,但是一般情況下,Content被設定為panel,就像一個包含了複雜使用者介面的grid控制項一樣;而Header一般被設定為一個字串。

    在“Windows Phone Application”類型的項目中,預設不包含對pivot 和 panorama類型控制項的引用!

    雖然pivot 和panorama類型控制項的命名空間(Microsoft.Phone.Controls)和PhoneApplicationPage等其他常用的控制項類似,但是它們是定義在Microsoft.Phone.Controls的二進位集中(而PhoneApplicationPage是定義在Microsoft.Phone二進位集中)。

    在使用pivot 和panorama控制項時,需要添加對Microsoft.Phone.Controls.dll的引用。如果我們在Visual Studio中建立工程時,以“Windows Phone Pivot Application” 或 “Windows Phone Panorama Application”類型為模板,那麼工程中就預設添加了對Microsoft.Phone.Controls.dll的引用。同樣,如果我們在Visual Studio的Add New Item中,選擇了“Windows Phone Pivot Application” 或 “Windows Phone Panorama Application”,那麼工程就會自動添加對Microsoft.Phone.Controls.dll的引用。

    以下是設計應用程式時,pivot控制項需遵循的三條設計指導原則:

➔ 除特有的名稱之外,Header中的文本應該小寫。

➔ 正如前文所述,不要試圖使用pivot控制項來設計連續的使用者必須完成任務。

➔ 在單個pivot控制項中,不要使用超過7個頁面。

A Pivot without PivotItems

    在沒有PivotItes的情況下,Pivot是停用。Pivot利用該控制項來存放每個記錄的頭和內容。因此,如果我們嘗試使用其他不同的UI元素時,應用程式會拋出“Element is already the child of another element”的異常。但這不是問題,因為沒有理由不使用PivotItems,它可以包含任何對象,所以我們可以將需要的內容嵌入其中。我們還可以將非可視化的資料對象添加到Pivot中,使用ItemTemplate和HeaderTemplate屬性來設定合適的格式。

 

The Main Page

    TODO List的首頁面使用了Pivot控制項。它包含了5個pivot items,圖26.1顯示了第一次運行應用程式時,狀態為空白的情況。

圖26.1 五個初始化狀態的Pivot item頁面

➔ 由於Pivot需要唯一的命名空間,因此需要使用一個獨立的XML命名空間。常用的XML命名空間的首碼為:controls。

➔ 使用Pivot意味著應用程式處於全屏狀態,所以它包含了一個Title屬性,就像普通的page header一樣,我們可以使用它來顯示應用程式的名稱。該控制項在顯示應用的標題方面模仿的很不錯,但需要注意的是位置和字型大小有些不一樣。幸好,我們可以對Title的外觀進行自訂。Title是一個類型對象,所以我們可以將它設定為UI中的任意元素,而不只是一個簡單的字串。或者,我們可以使用TitleTemplate屬性來自訂它的外觀。圖26.2顯示了TitleTemplate對於標題字串的作用效果。在Windows Phone以後的發布中,如果Silverlight支援本地文字間距排版的話,可能會處理好這個問題。但是從目前來看,應用自訂模板是無法實現的。

圖26.2 使用者自訂標題對預設的Pivot標題外觀進行了細微的改變

➔ Pivot同時也提供HeaderTemplate屬性來自訂每個pivot item的標題。但是,預設的標題與系統內建的應用是相吻合的,所以大多數應用程式一般不會使用該屬性。如果我們想做標題的自訂,比如在每個標題中放入文本和圖片,那麼這個屬性就有用武之地了。

➔ 每個pivot item包含一個text block控制項(在顯示列表為空白時顯示)和一個嵌入list box的grid控制項。在list box中的每條記錄內嵌了圖片,或者對文本進行了修飾。

➔ 前四個list box擁有相同的item模板,該模板被稱為DataTemplate。但是,“done” pivot頁面的list box使用了它自身的模板,26.3所示,該模板加入了檢查標記和刪除線的效果。

圖26.3 “done” list box中的item模板加入了檢查標記和刪除線效果。

➔ 兩種模板利用Silverlight for Windows Phone Toolkit中的ContextMenu元素,在每個item中加入了操作功能表。在使用操作功能表時,我們只需要將ContextMenuService.ContextMenu屬性設定為接收使用者touch-and-hold手勢的元素。在使用者保持touch-and-hold手勢一秒鐘以後,操作功能表就顯示我們添加在菜單中的內容。詳見圖26.4。

圖26.4 “Do the dishes”的操作功能表展示了三種不同的任務選項。

    在Windows案頭平台上,操作功能表通常包含了對預設的item的單擊處理,而且還可以加粗顯示。在Windows Phone平台上,操作功能表不應該包含預設的單擊處理。相反,操作功能表應該保留給那些無法通過頁面方法觸發的行為。比如,本例中的操作功能表並沒有顯示“view details”,因為對於每條記錄的單擊行為就已經完成了這個功能。遵循這條設計原則,不僅使得我們應用程式的操作功能表與系統內建的應用程式相一致,而且也節約了寶貴的螢幕顯示資源。

    儘管TODO List應用中沒有用到下面的Pivot控制項事件,但是它們對於動態Pivot頁面非常有用:

➔ SelectionChanged:當前螢幕上的Pivot頁面切換時觸發。

➔ LoadingPivotItem:一個Pivot頁面第一次顯示前觸發。

➔ LoadedPivotItem:一個Pivot頁面第一次顯示後觸發。

➔ UnloadingPivotItem:將一個Pivot頁面從Pivot頁面集合中刪除前觸發。

➔ UnloadedPivotItem:將一個Pivot頁面從Pivot頁面集合中刪除後觸發。

    Pivot控制項的頁面延時載入機制提高了程式啟動的效能,但在很多流行的應用中,都使用以上這些事件來提高程式效能,甚至是它們自身的pivotitem虛擬化機制。

 

MainPage.xaml.cs

➔ Pivot控制項具有SelectedItem和SelectedIndex屬性,它表示了目前哪個Pivot頁面佔據了螢幕。TODO List應用將儲存當前的頁面,但它只是儲存元素的名稱,而非它的索引。我們可以通過這種方法來實現,那是因為本應用程式的設定頁面允許使用者隱藏除第一頁以外的任何Pivot頁面,這種隱藏其實就是將Pivot頁面從Pivot集合中移除。

    在Loading事件之前設定Pivot的SelectedItem或者SelectedIndex屬性會導致操作失敗!

    在OnNavigatedTo事件中設定Pivot的SelectedItem或者SelectedIndex屬性,這看上去很自然。但這是一個系統的Bug,到目前為止還沒有解決。在這個問題解決以後,使用Loading事件來設定選擇的頁面。

    設定Pivot的SelectedItem或者SelectedIndex屬性可以改變當前的頁面選擇!

    當我猜測這兩個屬性的使用方法時特別惱火。比如,當應用程式被啟用,我們想要Pivot恢複之前的狀態時(假設應用程式一直在運行),希望它能夠立即顯示之前選擇的頁面。一個變通的做法是,物理上改變Pivot頁面的順序,使得之前選擇的頁面永遠是第0個頁面,並且,不要再索引的基礎上寫代碼。

    設定Pivot頁面的可見度不會起到效果!

    暫時隱藏Pivot頁面的操作比較簡單,我們只要將它的Visibility屬性設定為Collapsed就可以了。但是,因為這個沒有起到作用,所以唯一隱藏Pivot頁面(並且不讓它佔據空間)的方法就是把它從Pivot頁面集合中刪除。

    根據Windows Phone設計原則,如果使用者有方法可以往空白的Pivot頁面中添加資訊的時候,我們不應該把這個Pivot頁面刪除。相反,我們應該顯示這個空白的Pivot頁面,或者是在上面放置一條說明性的資訊,就像TODO List中頁面的處理方式。

➔ 在OnNavigatedTo函數(在設定頁面中調整記錄的可見度以後,返回時調用該函數)中,Pivot裡面顯示的記錄根據當前的設定進行添加或者刪除。

➔ Pivot對於其頁面刪除的處理並不優雅。如果Pivot頁面被刪除,使得之前選擇的索引大於剛剛選擇的索引的話,會拋出ArgumentOutOfRangeException的異常。即使在刪除Pivot頁面之前,將SelectedIndex屬性設定為0,這種情況也會發生,推測這是由於舊頁面切換到新頁面時的動畫過渡引起的。這是Windows Phone將來的版本中需要解決的Bug。

    因此,針對這個問題,本應用程式在OnNavigatedFrom函數中,設定SelectedIndex為0。通過這種方法,即使使用者訪問設定頁面,在刪除Pivot頁面後快速返回首頁面,仍然有充足的時間來完成頁面的切換。所以,如果之前選擇的頁面被刪除,那麼Pivot會返回到第0個頁面。這是通過Loaded中的邏輯實現的,該邏輯在OnNavigatedTo執行以後,恢複選擇的頁面。

➔ “所有”的list box與 TaskList設定建立資料繫結,“已完成”的list box與DoneList設定建立資料繫結。剩餘的三個list box包含的是TaskList資料集過濾以後的資料。它們在RefreshLists中進行手動填充,因為對於過濾資料集的操作並沒有自動資料繫結機制。

➔ 操作功能表的開啟和關閉事件用來對操作功能表是否被開啟進行按需檢查。當這次點擊引起已經開啟的操作功能表被解散時,ListBox_SelectionChanged事件憑藉這個來忽略使用者對頁面的點擊。

➔ 由於操作功能表的處理是同一個函數,所以我們編寫的代碼必須對多個操作功能表均適用。寄件者將被使用者點擊的MenuItem發送給處理函數,所以它的DataContext屬性是用來擷取使用操作功能表模板的item。

   在處理操作功能表的點擊事件時,如何擷取點擊並且保持的菜單?

    對於放置在資料範本中的操作功能表,這個問題經常會被問到,那是因為沒有辦法把特定的功能表項目與資料對象聯絡起來。這個問題的答案是使用功能表項目的DataContext屬性。我們開始考慮DataContext時,想到的是把它設定為一個資料對象,但對於這種情況而言,擷取它的值是非常有用的。

    當使用者想要隱藏操作功能表時,注意不要像往常一樣處理點擊事件!

    理想情況下,系統為你處理這些,但事實是不會。在很多情況下,操作功能表開啟時,我們應該進行追蹤,這樣的話,我們可以合理地忽略那段時間裡面觸發的一些事件。操作功能表的開啟和關閉事件使得我們可以做到這一點。

 

Supporting Data Types

    正如前文所述,TODO List應用程式控制著兩個設定任務集合。在我們理解這個應用程式如何運行時,需要認識三個重要的類。Task類用來展示首頁面list box中顯示的那些記錄。

➔ 首頁面的Item模板包含了每個任務中Title和Star屬性的值。所有的屬性顯示在任務明細和添加/編輯頁面中,DueDate屬性也用來工作清單的排序。

➔ 一方面,CreatedDate 和 ModifiedDate屬性設定為DateTimeOffset類型,而不是DateTime類型,這樣更加合理;另一方面,這也是為了與其他類型的匹配(我們可能會提出這樣的質疑,DueDate屬性應該設定為DateTime類型,它代表當前時區內的一個邏輯時間點,第20章中的Alarm Clock應用也使用了DateTime)。

➔ Star屬性的值是一個字串,它代表顏色(如紅色或者黃色)。這從API的角度來看顯得有些奇怪,但是它的確很實用,因為首頁面的item模板和任務明細頁面上的星標可以直接與屬性進行綁定,而不需要值轉換器。

➔ 屬性更改的通知確保資料繫結的使用者介面元素可以保持更新。這在首頁面和任務明細頁面中得到了體現。在首頁面中,由於編輯任務的緣故,使得只有“done”列表需要它。這會在接下來的“添加/編輯頁面”一節中介紹。

 

Settings.cs

➔ 前五個設定儲存了首頁面上Pivot控制項的狀態,下一項設定(CurrentTask)儲存了首頁面上選中的任務明細和添加/編輯任務頁面。

➔ 最重要的是最後兩項設定,即未完成的工作清單和已完成的工作清單。注意,這是兩個不同類型的集合。DoneList是一個任務基本的可觀察集合,不包含任何的排序,所以列表總是按照完成的先後次序排列。(如果使用者想要更改次序,他們需要首先將任務標記為“未完成”,然後再把任務標記為“完成”。)另一方面,TaskList是一個可觀察集合,它會按照DueDate屬性的值,對任務按照時間順序進行自動排序。因此,利用這個性質,對於首頁面上的每一個list box(除done list以外),不再需要額外的代碼來實現任務的排序了。

➔ 以上兩種list的可觀察特性是很重要的一點,因為在記錄內容被添加或者刪除時,首頁面依靠集合更改通知來使得“all”和“done”兩個列表中的內容保持更新。

 

SortedTaskCollection.cs

➔ 該類的實現中,需要重寫ObservableCollection的被保護的InsertItem方法,它最終會被Add和Insert方法調用。在實現時,它忽略了傳入的索引值,相反,它選擇了維持list需要的排序的索引值。這對於那些嘗試調用集合中帶特定索引值的Insert方法的人來說,顯得有些迷惑,但調用Add方法時,是沒有問題的。

➔ 在這個集合的實現中,最微妙的部分是CollectionDataContract屬性。該屬性在System.Runtime.Serialization二進位集的System.Runtime.Serialization命名空間中定義(預設的Windows Phone應用程式模板不包含對它的引用),它對於本應用程式中設定內容的序列化起有很大的作用。但是,其中的緣由很晦澀。因為SortedTaskCollection由ObservableCollection<Task>而來,就系統內建的序列化過程而言,這兩個類擁有相同的資料欄位名。但是,每種被序列化的類型必須有一個唯一的資料欄位名,因此,CollectionDataContract屬性分配一個給SortedTaskCollection(我們甚至不需要選擇一個顯式的名字就可以使它實現)。

沒有這個屬性,在應用程式關閉或者休眠的時候,由於嘗試自動序列化應用程式的設定資訊,會拋出如下異常:

     Type‘System.Collections.ObjectModel.ObservableCollection`1[WindowsPhoneApp.Task]’ cannot be added to list of known types since another type ‘WindowsPhoneApp.SortedTaskCollection’ with the same data contract name

‘http://schemas.datacontract.org/2004/07/WindowsPhoneApp:ArrayOfTask’ is already present.

    注意,如果兩個列表都是SortedTaskCollection類型的話,即使沒有這個屬性,設定資訊可以正常序列化,因為沒有出現衝突。當然,在我們設計類的時候,可以設定這個屬性,一面將來出現一些不必要的麻煩。

    除了CollectionDataContract屬性是為集合類所設計之外,System.Runtime.Serialization也提供了DataContract屬性,它可以用在普通(非集合)類中使用。

    一般情況下,在資料無法序列化到隔離儲存空間或者頁面狀態的時候,我們得到的唯一提示就是:在應用程式再次啟動或者啟用的時候,資料不存在了。為了能夠看到資料序列化失敗的詳細異常資訊,我們可以在Visual Studio中將程式運行在debugger狀態下,並且將其設定為“捕獲所有首次出現的.NET異常”。我們可以在Exceptions選項(在Debug菜單下的Exceptions選項)的“Common Language Runtime Exceptions”附近,找到“Thrown”這個複選框,並且把它選中,這樣就可以實現上述功能了。

 

The Details Page

    任務明細頁面26.5所示,它是每項任務屬性最直接的體現。任務的標題被設定為頁面的標題,任務描述和日期資訊顯示在標題的下面。如果該條記錄被設定為星級,它也會顯示出來。為了方便,頁面的應用程式欄上放置了按鈕,可以實現首頁面中提供的操作功能表中的功能。

圖26.5 任務明細頁面,給出了包含星級和不包含星級的任務

➔ 為了處理描述資訊較長的情況,我們把它放在scroll viewer控制項中。而那個大的五角星是作為一個靜態背景,不隨著內容的滾動而滾動。

➔ 當前任務的各項屬性顯示,均用到了資料繫結。DateConverter與第21章“Passwords & Secrets”中描述的值轉換器類似,用來友好地顯示DateTimeOffset資料。本應用使用的值轉換器與之前的唯一不同,就在於其日期和時間之間,增加了“@”符號。

➔ 在OnNavigatedTo方法中,對顯示內容作了一些調整,使得在使用者點擊編輯按鈕將頁面導航到添加/編輯頁面、對記錄做了更改、儲存並且返回之後,當前頁面中的資訊能夠保持更新。在背後的cs代碼中,值轉換器可以用來避免更改兩個text block中的Visibility屬性,但這就有點略顯多餘。

 

The Add/Edit Page

    添加/編輯頁面看上去像完全不同的頁面:一個是用來添加新任務的頁面,另一個是用來編輯存在的任務,但由於它們之間的類似性,我們就在同一個頁面中實現了。圖26.6顯示了這個頁面中的添加和編輯的功能。

圖26.6 兩種不同模式下的添加/編輯頁面

➔ 該頁面利用了Silverlight for Windows Phone Toolkit中的三個控制項:list picker、date picker和time picker。List picker用來修飾每條任務,使它帶上合適的顏色,因為資料繫結與帶顏色的字串能夠自動匹配。詳見圖26.7所示。對於空值,該應用程式獲得其字串值為空白以後,使得資料繫結失敗,那麼顯示的矩形框中也就沒有填充了。

圖26.7 在List picker展開的時候,每條記錄的文字旁邊還顯示了五角星

➔ 該頁面儲存了每個控制項頁面狀態的當前值。在使用者輸入頁面資訊被打斷的情況下,這種處理方式就非常有用,而且對於時間日期控制項來說,這還是它的需求。因為這些控制項都會將螢幕導航到其他頁面,如果無法儲存並且恢複這些資訊的話,迴歸頁面時,無論之前是否選擇了時間和日期,填寫的表格資訊就被清空了。

➔ 如果在已完成工作清單中的項目被重新編輯了,那麼它們的值會被直接修改。如果工作清單中的項目被重新編輯了,那麼原來的任務被刪除,而一個新的任務會被加入。這麼做的目的就是為了工作清單中的記錄按照應完成的日期來排序。如果這個日期改變了,編輯集合中已存在的任務有可能會導致排序不準確。這就是為什麼任務的INotifyPropertyChanged實現只是為了滿足首頁面“done” list box控制項的更新;添加和刪除操作由可觀察的集合負責報告,所以propertychanged通知只在直接編輯操作中使用。

 

The Settings Page

    設定頁面26.8所示,它使得使用者能夠關閉除了“all”以外的所有Pivot頁面(頁面顯示了“all”複選框,但無法操作,這是為了表明這個頁面不能隱藏。)這個是設定頁面及其簡潔的表達,其痛點是支援首頁面中的Pivot頁隱藏。

圖26.8 設定頁面允許使用者隱藏除第一個以外的所有Pivot頁面

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.