本文章是由機器翻譯。

移動應用程式

Windows Phone 開發工具入門

Joshua Partlow

下載代碼示例

我和你們大多數人一樣,過去一年多來被大量宣傳 Droid 功能的廣告所淹沒,就好像它是後世界末日的終結者。我一直關注 T-Mobile My Touch 商業廣告。我看到幾篇有關 Apple 已銷售了多少 iPhone 應用程式的文章。

但與你們中的大多數人不同的是,我還在過去一年裡無數遍地告訴家人和朋友:是的,我的確在研發手機,但這一款手機與眾不同。

所以說實話,當 Steve Ballmer 和 Joe Belfiore 在西班牙巴賽隆納召開的移動通信全球世界大會 (MWC) 上發佈 Windows Phone 7 時,我的心情非常激動。2010 年 2 月 15 日雷德蒙德時間上午 6 時,我和幾百位同事(有一些仍穿著睡衣)一起坐在Microsoft 會議室裡,翹首以待 Belfiore 演示我們新版手機 (microsoft.com/presspass/press/2010/feb10/02-15mwc10pr.mspx) 的現場直播。在未來幾年裡,我可能會看到很多產品的推出,但我確信這次將是其中一個里程碑。這是迄今為止我在 Microsoft 所經歷過的最激動人心的時刻。

我將在這篇文章中向您介紹 Windows Phone 7 應用程式平臺,也希望您能夠瞭解 Windows Mobile 應用程式開發令人興奮的潛能所在。具體來說,我將介紹該應用程式平臺的基本元件,使您對 Windows Phone 開發人員工具有個大概瞭解,並指導您創建一個能夠訪問 Web 服務的 Windows Phone 應用程式。

推陳出新

憑藉 Windows Phone 7,Microsoft 改變了移動領域格局。除了能夠閱讀電子郵件和文檔外,人們還期待手機能夠成為生活中不可或缺的一部分。您可以通過手機聽音樂、共用照片和視頻,以及與朋友保持聯絡。顯然,商業使用者也對 Facebook 感興趣,而青少年則熱衷於流覽網站。我知道,這並不那麼令人驚訝,但它確實反映出人們期望手機在生活中所起的角色正在發生轉變。

作為潛在客戶,我希望您在看了 Belfiore 的演示後就有了購買手機的打算。更為重要的是,作為開發人員,我希望您對應用程式抱有更大的興趣。畢竟,要在競爭激烈的移動市場中脫穎而出,僅僅開發一款新的作業系統是不夠的。如果我們的前提是,使用者希望手機能夠將工作和個人生活以一種令人興奮的全新方式融合在一起,那麼,這將需要將該作業系統與能夠實現此目標的卓越的應用程式構成生態系統相結合。

我不會在手機的介紹上花費過多時間,因為我相信,您可以在喜好的博客上找到更詳細的資訊,相反,我會在您作為開發人員來說可能會遇到的兩個主要問題上進行詳細探討:什麼是 Windows Phone 7 的 Microsoft 應用程式平臺,以及如何開始構建應用程式?

開發人員的新領域

好吧,如果 MWC 只是為 Windows Phone 7 的推出開了個頭,那麼,遊戲開發人員大會 (GDC) 和 MIX10 則使整個故事畫上圓滿的句號。在 GDC 和 MIX 上,Microsoft 宣佈,Windows Phone 7 應用程式平臺基於 Silverlight 和 XNA Framework。如果您過去進行過 Windows Mobile 的開發,那麼就會知道這標誌著與之前作業系統版本的本質區別。

那麼,為何要有所改變呢?在我看來,Microsoft 的強項在於其豐富的產品套件,在將這些產品結合在一起後,其獲得了前所未有的成功。在 Windows Phone 7 之前,移動開發可能只是利用了部分 Microsoft 資產,遠不及您現在所看到的那麼多。

XNA Framework 的設計初衷是要讓開發人員能夠開發出可以在桌面電腦、遊戲機和手機上都比較耐玩且影響力大的 2D 和 3D 遊戲。該框架圍繞廣泛的硬體集而設計,其中包括 Xbox 遊戲機的圖形功能和 Zune HD 的感測器和觸摸功能。此外,其設計理念中還包括了聯網遊戲設置。

Silverlight 是針對基於 Web 的媒體和高效率應用程式的 Microsoft 桌面平臺。此平臺在與 Expression Blend 結合使用時,可用於創建引人注目的 UI,此 UI 既可單獨使用也可附加到 Web 服務中。

XNA Framework 和 Silverlight 本身就是十分強健的平臺。但在手機開發時將二者結合起來,則開發水準會達到全新的高度,這使得您可以開發出能夠輕鬆利用移動設備功能並具有漂亮 UI 和出色圖形的應用程式。

正如我之前在 Windows Phone 7 開發週期中使用 Silverlight 和 XNA 應用程式時所體驗到的那樣,我很快就認定這是一個很好的發展方向。雖然我接觸這兩個平臺以及託管代碼的時間不長,但開發視覺效果超棒的應用程式時的速度之快讓我印象深刻。

這一全新應用程式平臺的另一個值得關注的特性是,硬體標準化以及以程式設計方式對其進行訪問的標準化。具體而言,另一個來自 MIX 的公告是, Windows Phone 將支援開發人員能夠以統一和可靠的方式訪問的一組核心硬體。為什麼這很重要?以前,開發運行在多款手機上的應用程式比較困難,原因是最終必須要創建設備特定的應用程式版本。如果不進行大量的返工,一些手機將無法運行您的應用程式,或者,因為其不支援您的應用程式所需的功能而根本就不工作。

使用 Windows Phone 7,您將不必考慮運行應用程式的手機是否支援位置服務這個問題了 — 所有手機都將支援位置服務。將不存在手機是否具有加速感應器以及您是否可以對其進行訪問的問題 — 所有手機都將具備加速感應器,訪問將是一致的。您將不必考慮手機是否支援觸摸功能這個問題了 — 所有手機都將支援觸摸功能,而且訪問將是一致的。我不想過多解釋,您應該明白我的意思了。

通過 Windows Phone 7 應用程式平臺,您將能夠開發出單一的應用程式,並知曉在您的手機上測試的功能可以運行在所有手機上。Windows Phone 上仍會區分硬體,但還存在核心硬體基礎,您的應用程式將能夠依賴此基礎運行。

有關 Windows Phone 硬體和該應用程式平臺的體系結構的詳細資訊,請參閱 MSDN 上有關該應用程式平臺和硬體的概述:msdn.microsoft.com/library/ff402531(v=VS.92)msdn.microsoft.com/library/ff637514(v=VS.92)

入門

好了,我們已經簡要介紹了這一應用程式平臺,現在,讓我們來探討下如何在其上進行開發吧。當前在 Beta 版中,可以從 Windows Phone 開發人員門戶 (developer.windowsphone.com) 下載 Windows Phone 開發人員工具。如果沒有安裝 Visual Studio,開發人員工具會隨 Visual Studio 2010 Express for Windows Phone 提供。如果安裝了 Visual Studio 2010,該工具將直接與之集成。不管採取哪種方式,您都會具備針對 Windows Phone 7 進行開發所需的全部元件。

開發人員工具包括 Windows Phone Emulator 和 Microsoft Expression Blend for Windows Phone。這不是最終版,但 Beta 版可以明確顯示啟動時您將具備的元件。您可能需要在 Beta 版與最終版工具之間對代碼做出一些改動,但這些更改應當是輕微的,或者至少有完整的說明。

我已經使用 Visual Studio 2010 Express for Windows Phone 安裝了這些工具的 Beta 版,並將運用於以下示例中。如果希望從較為簡單的教程開始,您可以查看 MSDN 上的“Windows Phone 入門指南”: msdn.microsoft.com/library/ff402529(v=VS.92)

那麼,創建什麼呢?我知道,您迫切希望看到的是一般的“hello world”或“make that flashlight”應用程式,但是,在這裡,我將與您分享我曾參與的一個有趣小專案的一部分。

在 MIX,我碰巧參加了一個有關 Windows Azure 專案的講座:Microsoft Codename “Dallas” (microsoft.com/windowsazure/dallas)。Dallas 基本上是一個市場,在這裡有興趣為其應用程式獲取資料的開發人員和希望銷售 Web 服務的提供商進行交易。該服務目前正處於第二個社區技術預覽 (CTP) 階段,您可以利用此線上門戶和提供的一系列免費試用資料來源對服務提供的內容進行體驗。雖然當前的提供商還不是很多,但仍有許多東西值得一試。我個人發現,NASA 提供的有關火星任務的圖像資料非常有趣,如果能創建出一個可以流覽火星漫遊圖片的 Windows Phone 應用程式,那感覺一定很棒。

我必須提醒您,此處包含和提供下載的代碼僅做示例之用,如果希望運行此代碼,您需要註冊 Dallas CTP 以獲取帳戶金鑰和使用者 ID,在我的代碼中,這兩項都是保留空白 (microsoft.com/windowsazure/developers/dallas)。

創建專案

創建火星漫遊圖像檢視器的第一步是創建一個 Windows Phone 應用程式專案。啟動 Visual Studio 2010 for Windows Phone 的 Express 版本,您將看到一個標準的 Visual Studio 起始頁。在此處,您可以選擇“新建專案”,這將允許您從多個不同的專案範本中進行選擇。如果只安裝了 Windows Phone 開發人員工具,您的清單可能僅限於 Silverlight for Windows Phone 和 XNA Game Studio 4.0。

我從 Silverlight 範本中選擇了一個 Windows Phone 應用程式,並將我的專案命名為 MarsImageViewer。Visual Studio 將從此利用其神奇功能為您生成一個專案。

如果之前使用過 Windows Presentation Foundation (WPF) 或 Silverlight,則您應該不會對看到的內容感到陌生。您會看到一個具有流行手機外觀的設計圖面、一個具有一些基本控制項的工具箱以及多個具有其相關 C# 代碼分離檔的 XAML 檔(參見圖 1)。如果想瞭解基於 Windows 的 Silverlight 和 XNA 與基於 Windows Phone 的 Silverlight 和 XNA 的具體差異,可參閱 MSDN 上的“Windows Phone 框架概述”:msdn.microsoft.com/library/ff402528(v=VS.92)

圖 1 Visual Studio 中的初始 Windows Phone 專案

理解 XAML

與使用 Silverlight 相同,Windows Phone 應用程式範本提供了一個 App.xaml 檔和一個 MainPage.xaml 檔,這是您的應用程式的核心。對此我將不再詳述,因為它們與其 Silverlight 中的對應項的工作原理基本一樣,但是,在繼續創建應用程式之前,我要指出兩個關鍵的不同之處。

第一個不同之處在預設的 App.xaml 檔中。您會注意到,雖然自動生成的代碼大部分與在桌面 Silverlight 專案中的一樣,但其中有一部分包含了一個 PhoneApplicationService 物件:

<shell:PhoneApplicationService 
  Launching="Application_Launching" Closing="Application_Closing" 
  Activated="Application_Activated" Deactivated="Application_Deactivated"/>

在 Windows Phone 開發人員工具的 Bata 版中,有一個新的執行模型,用於支配應用程式的行為;這一標記部分以及 App.xaml.cs 中的隱藏代碼是該模型與眾不同之處之一。如果想更好地瞭解 Windows Phone 應用程式及該物件的行為,可參閱 MSDN 上的主題“Windows Phone 的執行模型”:msdn.microsoft.com/library/ff769557(VS.92)

第二個不同之處在 MainPage.xaml 檔中,實際上就是我將要開始創建應用程式的地方。如果仔細看,該檔大部分與 Silverlight 類似,但對於功能表列有一個注釋掉的 XAML 部分。該功能表列是一個系統控制項,可用來公開按鈕和功能表項目。它不但可簡化應用程式的創建,還有助於保持手機應用程式的一致性,因為其外觀和行為與手機核心應用程式中使用的完全一樣。我將修改此範本標記以創建我的功能表列,您也可以使用 C# 為頁面創建一個功能表列(請參閱 msdn.microsoft.com/library/ff431786(VS.92) 以瞭解詳細資訊)。

創建功能表列

創建功能表列的第一步是找到要使用的圖示。您可以創建自己的圖示,也可以選用開發人員工具附帶的圖示。預設情況下,可在 C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.0\Icons\(對於 64 位 Windows)和 C:\Program Files\Microsoft SDKs\Windows Phone\v7.0\Icons\(對於 32 位 Windows)找到包含的圖示。這些圖示確實值得選擇,因為它們與手機的外觀相匹配。

在選取了所需的圖像後,在您的專案中創建一個 Images 資料夾並將圖示添加至其中。然後,設置每個圖示的屬性:“生成操作”應當是“內容”,“複製到輸出目錄”應當是“始終複製”,如圖 2 所示。

圖 2 將圖像資源添加至專案

接下來,取消功能表列標記的注釋並針對您的應用程式進行修改。在本例中,必需的操作是創建兩個按鈕及其相關事件處理常式。具體而言,我創建了兩個分別用於檢索下一張和上一張照片的按鈕。我還向 XAML 添加了一個按一下事件並允許 Visual Studio 生成事件處理常式。功能表列 XAML 現在看起來應當如圖 3 中的代碼所示。

图 3 配置菜单栏

<phone:PhoneApplicationPage.ApplicationBar>
  <shell:ApplicationBar 
    IsVisible="True" IsMenuEnabled="False">
    <shell:ApplicationBarIconButton 
      x:Name="appbar_BackButton" 
      IconUri="/Images/appbar.back.rest.png" 
      Text="Back" 
      Click="appbar_BackButton_Click">
    </shell:ApplicationBarIconButton>
    <shell:ApplicationBarIconButton 
      x:Name="appbar_ForwardButton" 
      IconUri="/Images/appbar.
next.rest.png" 
      Text="Next" 
      Click="appbar_ForwardButton_Click">
    </shell:ApplicationBarIconButton>
  </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

在開始關注隱藏代碼之前,我還花了點時間指定了應用程式標題和頁面名稱,並向 MainPage.xaml 的根網格添加了圖像控制項,如圖 4 所示。 這應當使設計圖面如圖 5 所示,其中您會注意到一個由四個圓圈構成的空白功能表列。

圖 4 MainPage.xaml

<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
  <TextBlock x:Name="ApplicationTitle" 
    Text="MarsImageViewer" 
    Style="{StaticResource PhoneTextNormalStyle}"/>
  <TextBlock x:Name="PageTitle" 
    Text="Images" 
    Margin="-3,-8,0,0" 
    Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>

<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentGrid" Grid.Row="1">
  <Image Height="300" 
    HorizontalAlignment="Left" 
    Margin="36,104,0,0" 
    Name="MarsImage" 
    Stretch="Fill" 
    VerticalAlignment="Top" 
    Width="400" />
</Grid>

圖 5 配置好的設計圖面

定義了應用程式介面後,現在可以收集一些火星漫遊圖像。Dallas 門戶設計初衷是方便使用者使用,允許使用者體驗查詢。它還為您提供適合的 Web 服務 URL,向您演示如何添加參數並為查詢提供適當的標題資訊。

我通過該門戶發現,NASA Web 服務允許基於參數的圖像資訊查詢或通過圖像 ID 檢索特定的 JPEG 圖像。對於此程式而言,這意味著以上兩個操作都是必需的。首先,查詢圖像資訊,資訊中包含圖像 ID。其次,分析針對這些圖像 ID 返回的 XML,這些 ID 之後可用於檢索特定圖像。

呼叫休斯頓 ...我的意思是,Dallas

下麵我們就開始。在預設的 MainPage.xaml.cs 檔中,我為三個命名空間添加了 using 語句:

using System.Xml.Linq;
using System.IO;
using System.Windows.Media.Imaging;

然後,通過按右鍵“解決方案管理器”中的“引用”、選擇“添加引用”、選擇“System.Xml.Linq”並按一下“確定”,我添加了一個到 System.Xml.Linq DLL 的引用。 通過 System.Xml.Linq,可以訪問有助於從流載入 XML 而後通過 LINQ 查詢該 XML 的類。 如果您不熟悉 LINQ,不用擔心;該示例使用了最少量的 LINQ to XML,您始終可以通過 MSDN 瞭解更多詳細資訊。

我還為該頁面創建了兩個私有變數。 IEnumerable of XElement 物件調用條目以存儲 LINQ to XML 查詢的結果,並調用一個整數索引以跟蹤我關注的圖片。 然後,我修改了 MainPage 構造函數以將該索引初始化到 0 並調用一個 getImageIDs 函數:

private IEnumerable<XElement> entries;
  private int index;

  // Constructor
  public MainPage() {
    InitializeComponent();

    index = 0;
    getImageIDs();
  }

getImageIDs 函數旨在啟動從 Web 服務檢索圖像資訊。 該函數使用 Web 服務 URL 和 WebClient 啟動圖像資訊的非同步請求:

private void getImageIDs() {
  Uri serviceUri = new Uri("https://api.sqlazureservices.com/NasaService.svc/MER/Images?missionId=1&$format=raw");
  WebClient recDownloader = new WebClient();
  recDownloader.Headers["$accountKey"] = "<Your account key>";
  recDownloader.Headers["$uniqueUserID"] = "<Your user ID>";
  recDownloader.OpenReadCompleted += 
    new OpenReadCompletedEventHandler(recDownloader_OpenReadCompleted);
  recDownloader.OpenReadAsync(serviceUri);
}

您會注意到,為簡便起見,我已經將 missionId 參數硬編碼為 1,在本例中表示 Opportunity 任務。 理想情況下,該參數和其他參數應當由使用者動態定義。

對於任何非同步請求,您都需要一個處理常式。 該處理常式會在資料請求完成時調用。 然後,它將使用返回的流與一些基本的 LINQ to XML 訪問返回的 XML 中的所有“條目”標記;“條目”是每個圖像記錄的開始標記:

private void recDownloader_OpenReadCompleted(
  object sender, OpenReadCompletedEventArgs e) {
  if (e.Error == null) {
    Stream responseStream = e.Result;
    XNamespace ns = "http://www.w3.org/2005/Atom";
    XElement marsStuff = XElement.Load(responseStream);
    entries = marsStuff.Elements(ns + "entry");
    string imageID = 
      (string)entries.ElementAt<XElement>(index).Element(
      ns + "title").Value;
    getImage(imageID);
  }
}

產生的集合將存儲到 IEnumerable of XElement 物件(條目)中,我之前已對這些物件進行了聲明。 通過 LINQ to XML 的最終位,該處理常式之後將為條目中第一個 XElement 檢索 title 標記的值。 該 XML 架構中 title 標記的值碰巧與圖像 ID 對應,該 ID 隨後將傳入 getImage 函數。

getImage 函數類似于 getImageIDs 函數。 唯一的區別是使用的 Web 服務 URL。 This function asynchronously retrieves a stream to the image identified by the ID parameter. 然後,其處理常式使用該流設置我在 MainPage.xaml 中定義的圖片控制項的源(參見圖 6)。

图 6 检索图像

private void getImage(string ID) {
  Uri serviceUri = new Uri(
    "https://api.sqlazureservices.com/NasaService.svc/MER/Images/" + 
    ID + "?$format=raw");
  WebClient imgDownloader = new WebClient();
  imgDownloader.Headers["$accountKey"] = "<Your account key>";
  imgDownloader.Headers["$uniqueUserID"] = "<Your user ID>";
  imgDownloader.OpenReadCompleted += 
    new OpenReadCompletedEventHandler(imgDownloader_OpenReadCompleted);
  imgDownloader.OpenReadAsync(serviceUri);
}

private void imgDownloader_OpenReadCompleted(
  object sender, OpenReadCompletedEventArgs e) {
  if (e.Error == null) {
    Stream imageStream = e.Result;
    BitmapImage imgsrc = new BitmapImage();
    imgsrc.SetSource(imageStream);
    MarsImage.Source = imgsrc;
  }
}

扣上按鈕

這個時候,應用程式的剩餘部分就非常簡單了,只需要實現針對功能表列按鈕自動生成的事件處理常式即可。 這些就是將要用於向前或向後流覽火星漫遊圖片的按鈕。 正如您所見,我基本上只是重用了 getImage 函數並添加了一些邏輯,以控制碼方式更改條目集合中目前記錄的索引。 下麵是後退按鈕的處理常式:

private void appbar_BackButton_Click(
  object sender, EventArgs e) {
  if (index > 0) {
    index--;
    XNamespace ns = "http://www.w3.org/2005/Atom";
    string imageID = (string)entries.ElementAt<
      XElement>(index).Element(ns + "title").Value;
    getImage(imageID);
  }
}

前進按鈕處理常式完全一樣,除了其索引:

The forward button handler is pretty much the same, except for its indexing:
if ((index + 1) < entries.Count<XElement>()) {
  index++;
  ...

您現在可以使用包含的 Windows 模擬器運行該程式。從“標準”工具列上的目標設備功能表選取 Windows Phone 7 Emulator。按 F5,程式生成並部署至該模擬器(參見圖 7)。

圖 7 在模擬器中運行應用程式

準備啟動

該示例相對簡單,但是我希望您通過它對於開發人員工具及其在將應用程式整合至 Windows Phone 方面的易用性能有個大致的瞭解。Windows Phone 7 可以帶來很多可能性,建議您多花點時間仔細鑽研一番。

關於此應用程式平臺的功能,您在此處的所見僅僅是窺豹一斑。我給出的簡單應用程式即是證明。再使用一個按鈕和大約 12 行代碼,您就可以在 Microsoft.Xna.Framework.Media 命名空間使用 MediaLibrary 類,以將給定照片保存到媒體庫中(參見 msdn.microsoft.com/library/ff769549(v=VS.92))。

是的,沒錯 — 您可以從基於 Windows Phone Silverlight 的應用程式使用 XNA API。遺憾地是,有關應用程式中 Silverlight 和 XNA API 的相互交錯,以及更多內容,只能留待日後再進行探討了。更多深入的、針對性更強的文章、文檔和示例,請訪問 MSDN:msdn.microsoft.com/library/ff402535(v=VS.92)

Joshua Partlow 是 Windows Phone 7 團隊中的一名程式師。他為創建 Windows Phone 的 OEM 撰寫手機啟動流程、設備驅動程式開發和應用程式開發文檔。

衷心感謝以下技術專家對本文的審閱:Windows Phone 7 團隊