本文章是由機器翻譯。

UI 最前線

完成電子書讀取程式

查爾斯 Petzold

下載程式碼範例

之前有 Kindles 和 Nooks 和 iPads 智慧型手機。 未能 HTML、 PDF、 XPS、 EPUB、 MOBI 及 Plucker。 有個偶數個人所擁有的電腦之前,但是沒有專案 Gutenberg。成立於 1971 由 Michael s。壓縮戰術 (歿最近 64 歲) 專案 Gutenberg 是輕鬆的數位化的公用網域書籍最舊的集合。相較於為 1500 萬封或讓文字中累積的 Google 活頁簿時,大約 35000 書籍的庫存看起來像是 quaint,而專案 Gutenberg 會保持珍貴的資源,以存取經典房車。

Gutenberg 活頁簿專案現在可用於許多的 rtf 格式,但有多年的重點是完全在純文字上,合理假設正在該多資訊文字格式來吧,然後移但純文字是不限次數。我五個月前,當我需要簡單但實質的文字檔來示範如何重新編頁的邏輯撰寫為 Windows Phone,我已開啟專案的 Gutenberg.As 來的資料行開始變得增強這段程式碼,在它自己的生命週期所花費的專案。程式現在已經演變為 Windows Phone,可讓您存取專案的 Gutenberg 程式庫的全能的電子書讀取器。我稱之為 Phree 活頁簿讀取器,讀成"可用的活頁簿讀取器 」,並 rhyming"的電子書讀取器 」,但拼法的 [電話] 的"ph"與 —,可以從 Windows Phone 服務商場免費下載。像往常一樣,您也可以下載程式的原始程式碼,從 MSDN Magazine 的網站。

類別目錄和 Web 服務

有很多方式可以建置一個大型的應用程式。有些開發人員喜歡由上至下的方法開頭的整體結構,並逐漸實作更詳細的程式碼。有人比較喜歡開頭會結合為更強大的組件的低階常式由下而上的處理程序。

我通常是混合兩種方法,主要的目標,是取得項目 — 任何項目,最快的方式運作。即使只是稍微功能的基本架構的程式可以讓我很重要的正面意見使我,並當我使用程式時,所需的增強功能變得明顯。

如果您讀過本專欄的過去六個月,就會知道我先前的電子書讀者已限制為只有一個活頁簿或最近,四個活頁簿。這些書是為應用程式的可執行檔做為內容結合在一起。此方法可讓我完全集中在避免雜亂的工作來搜尋書籍標題和製作者的網頁,以及甚至牽扯問題,被讓使用者透過下載書籍的閱讀方式。但是,我知道我必須最後符合這些挑戰。

專案 Gutenberg 網站 (gutenberg.org),讓其他應用程式可以執行類似的搜尋嘗試讓它方便使用者搜尋並下載的書籍,但它不會實作透過公開 Web 服務。

每個活頁簿儲存在專案 Gutenberg 所識別的整數 id。如果程式知道特定書籍的識別碼,它可以下載 XML 檔案在 gutenberg.org/ebooks/N.rdf,其中 n 是 ID 編號。這個資源描述的格式或 RDF,檔案通常約 10 KB 的大小,都是的因此包含書名、 作者及其他資訊,以及連結到活頁簿本身以數種不同的格式。可說這個檔案是很好,如果您知道您想要的活頁簿中,ID 編號,但不是好。

專案 Gutenberg 也讓使用完整的類別目錄全部書本的 gutenberg.org/feeds/catalog.rdf.zip 在其集合中。它約 9 mb 的大小,並 unzips 到 200 MB 的 XML 檔案。此類別目錄中的資訊十分相似,但並不相等,個別的 RDF 檔案中的資訊。類別目錄的新版本的每天都會建立,當新的活頁簿加入至專案的 Gutenberg 物品欄。

一開始我以為我的電子書器無法下載整個類別目錄,以電話,並將它儲存在隔離儲存區進行搜尋之用,但我擔心大小。比方說,平均字是 5 個字元,並使用空格分隔的單字所以 50000 word 活頁簿以純文字格式需要只有 300 KB 的儲存空間。解壓縮的目錄中,相較之下,會佔用超過 6000 書籍相同的儲存量!

我再發生另一個問題: 我無法開啟,並包含一般讀取類別目錄檔案。NET 版本 XmlReader 藉由將 XmlReaderSettings 的 ProhibitDtd 屬性設定為 false。Silverlight 的版本 XmlReader choked 上的檔案,以及沒有設定 XmlReaderSettings 的 DtdProcessing 屬性的但 — 或任何其他我試著 — 正常運作。

之後多 contemplation,我決定寫我自己裝載在網站上的 Web 服務。Web 服務會從專案 Gutenberg 該站台時,取得類別目錄檔案 unzips 它、 將之開啟,會剖析該動態和本機 「 平面 」 的格式儲存的精簡版本 — 每本書的一個文字行,供快速搜尋。

當然,的每當您要處理的其他人的資料,也舉足輕重的其資料結構。我的 Web 服務會實作具有指定標題和作者單字的引數為搜尋的方法,並傳回最多 25 個實例型別的我呼叫 GutenbergBook。這個類別會併入取自類別目錄項目,包括標題 (與有時兩個標題),零或多個 「 建立 」 作者,可能是共同作者的書籍的相關資訊和零或多個提供者 (例如轉譯器和編輯器)。

也包含在 Gutenberg 目錄是"易記標題,"這通常會併入在標題與作者,而何者為限制為 50 個字元。此易記的標題似乎適用於顯示搜尋結果給使用者,以及讀取它時,找出活頁簿。

但是這個易記的標題並不一定那麼好記。它是最適合用於簡短的標題,例如"Emma 由陳珮雯 Austen,",但通常是較長的時間標題的缺點。例如,Gutenberg 類別目錄包含不同的版本與愛德華 Gibbon 著名的歷史門外漢,大量的 12 項目,而所有的 12 已被截斷成 50 個字元相同易記的標題: 「 歷程記錄的拒絕和改的羅馬 E."

這表示對我來說如果我真的打算使用此好記的標題來識別已下載的通訊錄,我必須為使用者提供某種方式來加以編輯以變得更有意義,例如"拒絕和羅馬星辰帝國,磁碟區 3"。

前端的樞紐分析表

至少,在需要顯示一份已下載的書籍與搜尋畫面下載更多的書籍電子書讀者的前端。看來我這兩個項目會樞紐分析表控制項的一部分,用於多重螢幕呈現的格式不是可瀏覽的網頁 Windows Phone 程式常用的控制項。

Phree 活頁簿讀取器的前端的樞紐分析表控制項有五個項目,以下列順序: bedside、 媒體櫃、 搜尋、 要求和約。

雖然搜尋在樞紐分析的第三個項目,則會在開始新的使用者。如所示圖 1、 您在輸入標題文字或作者的字,而且它會呼叫 Web 服務。25 瀏覽人數最多會傳回,並顯示在清單方塊。每個點擊識別身分證字號,並在專案的 Gutenberg 類別目錄中易記的標題。


[圖 1 樞紐分析表控制項的 [搜尋] 項目

當使用者點選其中一個項目時,程式正導覽至下載網頁,如所示圖 2。此頁面會顯示從類別目錄所需的詳細資訊,並讓您下載的通訊錄。請注意 [參與者] 項目指出著名的轉譯器的俄羅斯文學也是一樣,Constance Garnett。


圖 2 下載頁面就緒,可供下載

當您開始下載活頁簿時,通常您會看到突然變更的檔案名稱。專案 Gutenberg 類別目錄包含所提供的各種格式的檔案名稱 — 包括慣用的格式符合我的需求,以 utf-8 編碼的純文字 — 但我發現有些檔案是空的或已損毀。在個別的 RDF 檔案的檔名的不同,更加可靠。因此 Phree 活頁簿讀取器開始下載活頁簿之前,它下載 RDF 檔案,並從所取得的檔案名稱。

下載活頁簿後,下載項目網頁會顯示按鈕,瀏覽至其他網頁。第一個按鈕可讓使用者變更什麼程式稱之為 「 顯示標題 」。此標題會在 Gutenberg 類別目錄中原本設為易記的標題,同時也是限制為 50 個字元。

第二個按鈕牽涉到章節符號。專案 Gutenberg 書籍不同的空白行,用以分隔章節編號。此選項可讓使用者變更該準則,並移除多餘的章節中斷點。

要求項目,在 [樞紐分析表控制項非常類似搜尋不同之處在於您只要輸入一個專案 Gutenberg ID 號碼活頁簿,而不是搜尋的詞彙。樞紐分析表控制項然後巡覽至檔案的下載頁面。

活頁簿時活頁簿都已下載,聯結程式庫,是在樞紐分析表控制項中的第二個項目,也會顯示在圖 3


[圖 3 樞紐分析表控制項的文件庫項目

此文件庫檢視會使用類別目錄項目,而不是顯示標題的標題和製作者資訊。書籍會依作者及頭銜。請點選其中一項來開始讀取該書籍的標題。請點一下 [問號,以查看完整的型錄資訊 (類似於下載網頁) 以及選擇性地編輯顯示標題和章節符號,或刪除活頁簿。

永遠不會發生任何的疑問,我覺得我想要依字母順序依作者 Phree 活頁簿讀取器程式庫。這正是我小說的產物書架上挑選的排列方式,但是我並不那麼 compulsive 有關標題的字母排序。可能有 Phree 的活頁簿讀取器人員比較喜歡不排列有點不同,文件庫的使用者,但我撰寫此程式多半是寄給我自己我真的不開放給交涉關於此問題,是啦 !

依作者及標題顯示活頁簿花很好的應用程式的清單方塊的群組。ItemsControl 的 Windows Presentation Foundation (WPF) 版本具有名為 GroupStyle,可讓您定義在 CollectionView 中的群組屬性的項目樣式的帥呆了屬性。在 Silverlight 中,您可以使用 CollectionViewSource,然後 Silverlight ItemsControl,雖然它不支援群組,不會有 GroupStyle。

相反地,我使用 ItemsControl 的作者,集合中所示的每個項目範本顯示作者的名稱,後面接著該作者的標題不可捲動的清單方塊的位置圖 4

[圖 4 文件庫的樞紐分析項目

<ScrollViewer Name="libraryScrollViewer"
              VerticalScrollBarVisibility="Auto">
  <ItemsControl Name="libraryItemsControl">
                     
    <!-- Assumes ItemsSource = AppSettings.Library.Authors -->
    <ItemsControl.ItemTemplate>
      <DataTemplate>
        <StackPanel>
          <!-- Creator -->
          <TextBlock Text="{Binding}"
                     FontWeight="Bold"
                     Margin="0 6" />
                                     
          <!-- Books -->
          <ListBox ItemsSource="{Binding Titles}"
                   ItemContainerStyle="{StaticResource listBoxItemStyle}"
                   SelectionChanged="OnLibraryListBoxSelectionChanged">
                                     
            <!-- Prevent scrolling of ListBox -->
            <ListBox.Style>
              <Style TargetType="ListBox">
                <Setter Property="ScrollViewer.VerticalScrollBarVisibility"
                        Value="Disabled" />
              </Style>
            </ListBox.Style>
                                     
            <ListBox.ItemTemplate>
              <DataTemplate>
                <Grid>
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                  </Grid.ColumnDefinitions>
 
                  <Grid Grid.Column="0"
                        Margin="12 6"
                        VerticalAlignment="Center">
                    <Polygon Fill="{StaticResource PhoneAccentBrush}"
                             Points="6 0, 47 0, 47 57, 41, 63, 0 63, 0 6" />
                    <Image Source="Images/BookIcon.png" />
                  </Grid>
                                                 
                  <!-- Book title -->
                  <TextBlock Grid.Column="1"
                             Text="{Binding}"
                             FontSize="{StaticResource
                               PhoneFontSizeMediumLarge}"
                             VerticalAlignment="Center"
                             TextWrapping="Wrap" />
                                                  
                  <!-- Info Button -->
                  <Button Content=" ? "
Grid.Column="2"
                          Tag="{Binding ID}"
                          VerticalAlignment="Center"
                          Click="OnInfoButtonClick" />
                </Grid>
              </DataTemplate>
            </ListBox.ItemTemplate>
          </ListBox>
        </StackPanel>
      </DataTemplate>
    </ItemsControl.ItemTemplate>
  </ItemsControl>
</ScrollViewer>

尋找這個配置的替代方案是待辦事項清單為 Phree 的活頁簿讀取器。我注意到,當我會累積在媒體櫃中的多個活頁簿時,初始載入時間開始降低,而我懷疑巢狀的清單方塊控制項的原因為何。

人員有時候會指向對方目前的 「 我的 bedside 資料表書籍。"為閱讀的書籍基於這個原因,第一個樞紐分析項目會標示為"bedside",並顯示最多六本書,最後讀取的時間與日期的遞減順序排序。它顯示的標題以識別每個活頁簿。

順便一提,Windows Phone 是跟燈關閉讀取在平台的妙招。

最後的樞紐分析項目被標示 「 關於 」,而且包含一些說明的相關資訊的程式,以及我過去通往 MSDN Magazine 的電子書讀取器相關的資料行。

對面樞紐

因為我已經開發此前端,我最大的工具牽涉到樞紐分析表控制項本身,並瀏覽離開並回到 [樞紐分析表控制項。

通常當程式啟動時,預設的 [樞紐分析項目應 bedside。程式應該要盡可能繼續讀取最近閱讀的書籍的簡單。不過,如果使用者沒有讀取任何活頁簿尚未,bedside 的清單會是空因此應該往上第一個文件庫檢視。如果使用者沒有下載任何活頁簿 — 或許是因為第一次執行這個程式時 — 搜尋的項目應該是預設值。

以程式設計方式控制 [樞紐分析表控制項被透過樞紐分析的 SelectedIndex 屬性設定。不過,已載入樞紐分析表控制項之前,無法設定這個屬性。但是,樞紐分析表控制項已載入後,將屬性設定有明顯滑動到該項目的 [樞紐分析表控制項的效果。我認為我偏好較不可見的轉換。

牽涉到樞紐分析表控制項的邏輯複雜的活頁簿會被下載時。如果使用者從 [搜尋] 項目巡覽到下載頁面,然後再按下電話的 [上一頁] 鍵,而不需下載的通訊錄瀏覽應該返回 [尋找] 項目。不過,如果活頁簿下載完畢後,再下載網頁應該回到文件庫的樞紐分析項目,如今已經列出活頁簿。如果活頁簿的下載,而且使用者選擇要直接跳到 [讀取] 檢視,然後瀏覽至 [首頁] 頁面的上一步應該會導致 bedside 的項目會被看見,一次顯示才剛拜讀過活頁簿。

我發現我自己使用的狀態字典內的 PhoneApplicationService 來追蹤已程式及一行行拆解。搜尋與樞紐分析項目設定狀態字典的項目,名為"downloadBook",巡覽至 [下載] 頁面上,而且該頁面設定"successfulDownload"或"successfulDownloadAndRead"字典項目根據之前要求使用者選擇與否,跳到 [讀取] 檢視。我不是很滿意這種 inelegance,或許在未來我會發現效果更好一點的項目。

像往常一樣,正在標記要刪除

很明顯地較大的程式,因此取得變得 nastier 正在標記要刪除的問題。請考慮搜尋畫面所示圖 1。我寫了 Web 服務傳回只有 25 瀏覽人數、 同時也允許以取得其他的 25,而每個額外的呼叫,依照螢幕上的 [下] 按鈕來觸發程式。最後可能有數百,甚至成千 —,請在清單方塊,取決於特定的搜尋條件中的項目。

這是正在標記要刪除的外邊區域的極佳範例。無法重新產生清單方塊中的所有資料,藉由呼叫 Web 服務,但所會花太多時間。必須儲存在清單方塊中的項目。但為何不想要儲存並還原在 OnNavigatedFrom 中的內容並 OnNavigatedTo 就會覆寫。這個搜尋控制項的一部分的樞紐分析項目,在程式的主要頁面上,以及有很多瀏覽進出沒有牽涉到正在標記要刪除此頁面。它是為開啟狀態儲存並還原在 [瀏覽的覆寫,但不是數千個項目在清單方塊中的小型物件。應用程式實際加以標記時,應該只能儲存清單方塊的內容。

對這個程式,我會嘗試與這麼精確的通用技巧 — 我在應用程式類別中定義一個名為 TombstoneObjects 屬性:

public IDictionary<string, object> TombstoneObjects { set; get; }

在程式中的任何地方的任何類別可使用此字典。SearchControl 類別會實作在上個月的專欄中討論過的 ITombstonable 介面。SaveState 方法中 (也稱為從 OnNavigationFrom 的覆寫 MainPage),控制項清單方塊的內容複製到清單物件,並將之儲存到 [TombstoneObjects 字典。在 RestoreState 方法中,它會還原內容的清單方塊中,但是只有,如果是空的清單方塊。

應用程式類別是負責儲存和還原狀態字典的 PhoneApplicationService TombstoneObjects 的內容,因為在 App 類別有其功能足以有效地執行這項操作。知道何時因為它已安裝 PhoneApplicationService 事件處理常式的程式正被標記。結果是幾乎沒有直接關聯的工作在如果程式尚未實際進行標記就會發生。

雖然我撰寫 Phree 書籍讀取器的 Windows Phone 7,當時我撰寫此我已經撰寫好的下一版的 beta 版本。在 Windows Phone 7.5,應用程式是標記頻率較低,因此務必雙向這些應用程式,以避免不必要的正在標記要刪除的工作。

說到下一版的 Windows Phone,我已經所累積我想我主旨來升級時,加入 Phree 活頁簿讀取器的功能的清單。也許我們可以看到在日後的專欄中的程式。

Charles Petzold* 是的 longtime 特約編輯* MSDN 雜誌。他最近使用的活頁簿,「 程式設計 Windows Phone 7"(微軟出版品,2010年),會提供免費的可下載在bit.ly/cpebookpdf

因為有到下列的技術專家來檢閱這份文件: Richard Bailey