盡管ResourceDictionary和系統級別的資源適合於作為數據存在於對象中, 然而,並不是所有的資源都能很好的滿足這個模型。能夠處理二進制流通常是很 有用的。例如,圖像,聲頻和視頻,都是有效地二進制的代表,但是這些資源在 xaml內都沒有相應的標簽,而且畢竟這些對象通常表現為底層數據的包裝。標記 語言本身代表了一種挑戰:xaml頁面必須編譯到我們的應用程序中。因此,需要 一種處理二進制流的方法。
WPF並未引進任何新技術處理二進制數據。.NET框架已經提供了處理內嵌二進 制流的機制,WPF只是簡單使用了這個技術。
最底層的流支持你內嵌資源流到任何的編譯文件中。提供內嵌到編譯器的文 件是一種簡單的方式。在Visual Studio 2005中,你可以通過設置一個文件的 Build Action屬性來支持內嵌資源。:復制該文件的內容,作為一個內嵌流放入 編譯文件中。使用Assembly的GetManifestResourceStream方法,可以在運行期 獲取到這個流,正如示例6-25所示:
示例6-25
Assembly asm = Assembly.GetExecutingAssembly( );
Stream s = asm.GetManifestResourceStream("StreamName");
這種方式的內嵌流稱為“資源清單”。WPF最終依賴於這種資源內嵌機制,可 以通過System.Resources命名空間的ResourceManager類直接使用。這是建立在 內嵌資源系統上,附加兩個特點:本地化和在一個底層流中按名字存儲多個流的 能力。ResourceManager允許我們按照名字尋找資源,這將要嘗試根據UI文化定 位最合適的資源,更多細節將在下一部分描述。
按照規定,一個WPF的應用程序或組件將其所有資源放入一個單獨的資源清單 的中,稱之為Appname.g.resources,其中Appname是程序或組件的名稱(不包含 擴展名)。這個單獨的資源流包含二進制的資源,可以通過ResourceManager獲 取到。示例6-26展示了如何獲取一個資源名稱的清單。
示例6-26
static List<string> GetResourceNames(Assembly asm,
System.Globalization.CultureInfo culture) {
string resourceName = asm.GetName( ).Name + ".g";
ResourceManager rm = new ResourceManager(resourceName, asm);
ResourceSet resourceSet = rm.GetResourceSet(culture, true, true);
List<string> resources = new List<string>( );
foreach (DictionaryEntry resource in resourceSet) {
resources.Add((string) resource.Key);
}
rm.ReleaseAllResources( );
return resources;
}
讓我們通過這段代碼,著眼於一個典型的應用程序內部的發現資源。圖6-6展 示了一個WPF工程的Visual Studio 2005解決方案管理器視圖。這個工程包含了 通常的定義了應用程序的MyApp.xaml文件,一個定義了用戶界面的Window1.xaml 文件(在一個包含多個窗體和頁面的應用程序中,你可以看到更多xaml文件)。 這個工程還包括一個Images目錄,其中有兩張圖片。正如你在圖6-6下半部分的 屬性面板中看到的,Sunset.jpg的Build Action屬性已經設置為Resource。當你 添加一個bmp圖片到解決方案中時,在解決方案管理器視圖的上下文菜單,選擇 Add--New Item…或者Add—Existing Item…,那麼這個圖片的Build Action屬 性會自動設置為Resource。對於Wheel.jpg也是同樣的設置。
圖6-6
如果我們調用示例6-26中的ResourceNames函數並且打印出其返回值,可以看 到下列輸出:
myapp.baml
window1.baml
image/wheel.jpg
image/sunset.jpg
正如你看到的,所有的bmp文件都在上面列出了。你可以在任意元素中通過指 定URL的方式使用這些內嵌的圖片,正如示例6-27展示的。這裡使用了相對URL路 徑,表明這個Image元素使用的是本地資源。相對URL不僅可以用於圖片文件與應 用程序在同一目錄,而且可以作為一個內嵌資源。既然圖片數據可以內嵌在二進 制程序的資源流中,那麼沒有必要將其轉移到一個獨立的包含圖片數據的文件中 了。
示例6-27
<Image Source="images/wheel.jpg" />
上述資源列表還顯示了myapp.baml和window1.baml兩個資源,對應到相應的 兩個xaml文件。
BAML是xaml文件的二進制表現形式。Xaml在編譯期間被編譯成BAML格式有兩 個原因。首先,BAML比xaml更加顯著的簡捷,所以你的可執行文件比xaml文件要 小得很多。其次,BAML在設計上更易於閱讀,支持UI加載的速度更快——相對於 xaml的語法解析。
在一個WPF工程中,任意具有Build Action的頁面文件都是xaml形式。這將編 譯成BAML,並被內嵌為一個資源。
因為圖片,BAML文件,以及任意的內嵌二進制資源都使用ResourceManager機 制,這為應用程序的本地化提供了一個方法。