說實話最初看到Windows Phone 8 SDK我略感失望,因為這個坑了諾基亞,拋棄了無數Windows Phone 7使用者的新平台,並沒有和Windows 8的WinRT完全接軌,Windows Phone 8雖然運行著Windows 8的核心,但在開發上和Windows 8的WinRT的交集並不是很多,而Windows 8的開發,才像是全新的開始。比爾蓋茨前一陣還說Windows Phone和Windows最終會成為一個作業系統(參考連結1 連結2),但願這個夢早點實現,如果說WinRT就是微軟最終的夢,那麼Windows 8已經走在前列了(但是WinRT仍需大力開發使之更成熟強大),而Windows Phone 8隻能抱歉地說我還有一些路要走。
好了,吐槽了挺多,下面本文,我簡單講講Windows Phone 8和Windows 8(WinRT)的一個交集:檔案系統。
注意:Windows Phone 8的winmd在"C:\Program Files (x86)\Windows Phone Kits\8.0\Windows MetaData\Windows.winmd"中,而WinRT的檔案系統獨立在一個winmd檔案中:"C:\Windows\System32\WinMetadata\Windows.Storage.winmd"
Windows Phone 8的檔案系統可以看作是WinRT的子集,它們有共同的名稱,共同的命名空間,Windows Phone 8會剪掉某些類型的執行,而且已執行類型的限制相比WinRT也可能更多。比如Windows Phone 8中沒有PathIO和FileIO類型,還比如在Windows.Storage.Pickers命名空間中Windows Phone 8隻有FileOpenPicker為沒有WinRT的FolderPicker,顯然Windows Phone 8的限制更多,即便是都擁有的FileOpenPicker都如此。
但是它們核心元素還是一樣的,比如IStorageItem代表檔案系統對象:
還有新的Stream相互關聯類型:
這些在這兩個平台都幾乎是一樣的。
OK,現在就開始寫一個利用這個通用檔案系統的簡單小程式:輸出一個StorageFolder中的所有內容。為了最簡單化,介面上我們就用一個TextBlock用作輸出,然後加一個Loaded事件:
<TextBlock Name="tbl" Loaded="tbl_Loaded_1"/>
注意雖然在介面元素上Windows Phone 8和Windows 8(WinRT)都是使用XAML,但是Windows Phone 8的XAML是沿用Windows Phone 7以System.Windows命名空間為主的。而WinRT的XAML是以Windows.UI.Xaml命名空間為核心的。
注意還需要引用我們需要的相關命名空間(顯然後期Windows應用程式開發的命名空間開始有些淩亂了,記住以System開頭的通常是.NET中的類型,以Windows開頭的命名空間通常是WinRT架構相關的類型):
using Windows.ApplicationModel; //Package類型
using Windows.Storage; //StorageFolder等類型
using System.Threading.Tasks; //Task類型
using System.Text; //StringBuilder類型
接著開始定義主方法,我們通過最簡單的StorageFolder的GetFolders和GetFiles方法來遞迴輸出檔案夾內的所有內容(注意,Windows Phone 8和WinRT的開發都是非同步化驅動的):
//非同步輸出檔案夾資訊
static async Task ShowContentAsync(StringBuilder sb, StorageFolder dir, int indent)
{
//縮排相關變數
var currentIndentStr = new string(' ', indent);
var nextIndent = indent + 4;
var nextIndentStr = new string(' ', nextIndent);
//輸出當前檔案夾名稱
sb.Append(currentIndentStr);
sb.AppendLine("> " + dir.Name);
//輸出並遞迴子檔案夾
foreach (var folder in await dir.GetFoldersAsync())
await ShowContentAsync(sb, folder, nextIndent);
//輸出子檔案
foreach (var file in await dir.GetFilesAsync())
sb.AppendLine(nextIndentStr + file.Name);
}
最後在TextBlock的Loaded事件中加入調用代碼,注意需把它改成async方法。至於需要探索的檔案夾,我們選擇當前應用程式的安裝資料夾(通過Windows.ApplicationModel命名空間中的Package類型中的InstalledLocation屬性),也可以選擇其他預設授權訪問的檔案夾,比如應用程式本機資料檔案夾(通過Windows.Storage命名空間中的ApplicationData.Current.LocalFolder屬性):
//Loaded事件
private async void tbl_Loaded_1(object sender, RoutedEventArgs e)
{
//建立一個StringBuilder
var sb = new StringBuilder();
//把應用程式的安裝資料夾作為參數並運行方法
await ShowContentAsync(sb, Package.Current.InstalledLocation, 0);
//把結果設定到介面上的TextBlock
tbl.Text = sb.ToString();
}
注意雖然開發代碼是一樣的,但不同作業系統的應用程式必須經相應編譯器編譯,我們仍然是為兩個系統開發兩個程式,只不過代碼是一樣的。仍然需要Visual Studio 2012 Express for Windows 8和Visual Studio Express for Windows Phone分別建立並編譯工程。(當然比爾蓋茨的話要是實現的話,就不需要了。)
在Windows Phone 8下的運行結果:
在Windows 8(WinRT)的運行結果: