【WPF學習】第三十五章 資源字典


  如果希望在多個項目之間共享資源,可創建資源字典。資源字典只是XAML文檔,除了存儲希望使用的資源外,不做其他任何事情。

一、創建資源字典

  下面是一個資源字典示例,它包含一個資源:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ImageBrush x:Key="TileBrush" TileMode="Tile"
                    ViewportUnits="Absolute" Viewport="0 0 32 32"
                ImageSource="happyface.jpg" Opacity="0.3"></ImageBrush>
</ResourceDictionary>

  當為應用程序添加資源字典時,務必將Build Action設置為Page(與其他任意XAML文件一樣)。這樣可保證為了獲得最佳性能而將資源字典編譯為BAML。不過,將資源字典的Build Action設置為Resource也是非常完美的,這樣它會被嵌入到程序集中,但不會被編譯。當然,在運行時解析它的速度要稍慢一些。

二、使用資源字典

  為了使用資源字典,需要將其合並到應用程序某些位置的資源集合中。例如,可在特定窗口中執行此操作,但通常將其合並到應用程序的資源集合中。如下所示:

<Application x:Class="Resources.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="Menu.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="AppBrushes.xaml"/>
                <ResourceDictionary Source="WizardBrushes.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

  上面的標記通過明確創建ResourceDictionary對象進行工作。資源集合總是ResourceDictionary對象,但這只是需要明確指向細節從而可以設置ResourceDictionary.MergedDictionaries屬性的一種情況。如果不執行這一步驟,MergedDictionaries屬性將為空。

  MergedDictionaries是ResourceDictionary對象的一個集合,可使用該集合提供自己希望使用的資源的集合。這個示例中有兩個資源集合:一個在AppBrusheds.xaml資源字典中定義,另一個在WizardBrushes.xaml中定義。

  如果希望添加自己的資源並合並到資源字典中,只需要在MergedDictionaries部分之前或之后放置資源就可以了,如下所示:

<Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="AppBrushes.xaml"/>
                <ResourceDictionary Source="WizardBrushes.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <ImageBrush x:Key="GraphicalBrush1"></ImageBrush>
            <ImageBrush x:Key="GraphicalBrush2"></ImageBrush>
        </ResourceDictionary>
    </Application.Resources>

  使用資源字典的一個原因是為了定義一個或多個可重用的應用程序“皮膚",可將”皮膚“應用到控件上。另一個原因是為了存儲需要被本地化的內容。

三、在程序集之間共享資源

  如果希望在多個應用程序之間共享資源字典,可復制並分發包含資源字典的XAML文件。這是最簡單的方法,但這樣不能對版本進行任何控制。更有條理的方法是將資源字典編譯到單獨的類庫程序集中,並分發組件。

  當共享包含一個或多個資源字典的編譯過的程序集時,還需要面對另一個挑戰——需要有一種方法提取所希望的資源並在應用程序中使用資源。為此,可使用兩種方法。最直觀的解決方法是使用代碼創建合適的ResourceDictionary對象。例如,如果類庫程序集中有名為ReusableDictionary.xaml的資源字典,那么可使用下面的代碼手動創建該資源字典:

ResourceDictionary resourceDictionary=new ResourceDictionary();
resourceDictionary.Source=new Uri("ResourceLibrary;component/ReusableDictionary.xaml",UriKind.Relative);

  上面的代碼片段使用了在本章前面介紹的pack URI語法。它構造了一個相對URI,該URI指向另一個程序集中名為ReusableDictionary.xaml的編譯過的XAML資源。一旦創建ResourceDictionary對象,就可以從集合中手動檢索所需的資源了:

cmd.Background=(Brush)resourceDictionary["TileBrush"];

  然而,不必手動指定資源。當加載新的資源字典時,窗口中的所有DynamicResource引用都會被自動重新評估。

  如果不想編寫任何代碼,還有另一種選擇。可使用ComponentResourceKey標記擴展,該標記擴展是專門針對這種情況而設計的。使用ComponentResourceKey為資源創建鍵名。通過執行這一步驟,告知WPF准備在程序集之間共享資源。

  在繼續執行任何操作前,需要確保已經為資源字典提供了正確的名稱。為了讓這種技巧生效,必須將資源字典放置到generic.xaml文件中,並且必須將該文件放到應用程序文件夾的Themes子文件夾中。generic.xaml文件中的資源被認為是默認主題的一部分,並且它們總是可用的。

  下圖顯示了合理的文件組織方式,頂部的項目名為ResourceLibray,generic.xaml文件被放在正確的文件夾中。底部的項目名為Resources。該項目有指向ResourceLibrary項目的引用,所以該項目可使用ResourceLibray項目中包含的資源。

 

  下一步是為存儲在ResourceLibray程序集中希望共享的資源創建名。當使用ComponentResourceKey時,需要提供兩部分信息:類庫程序集中類的引用和描述性的資源ID。類引用是WPF允許的其他程序集共享資源的關鍵部分。當使用資源時,需要提供相同的類引用和資源ID。

  該類的實際外觀並不重要,它不需要包含代碼。定義該類型的程序集就是ComponentResourceKey將要從中查找資源的程序集。

  下面是generic.xaml文件的完整標記,它包含了一個單獨資源——一個使用不同圖形的ImageBrush對象:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ResourceLibrary"
    >

 
    <ImageBrush
      x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:CustomResources}, ResourceId=SadTileBrush}"
      TileMode="Tile"
      ViewportUnits="Absolute" Viewport="0 0 32 32"
      ImageSource="ResourceLibrary;component/sadface.jpg" Opacity="0.3">
    </ImageBrush>

</ResourceDictionary>

  如果眼光敏銳的話,將在該例中發現一個意外細節。ImageSource屬性不在被設置為圖像名(sadface.jpg),而是使用更復雜的相對URI,明確地指示圖像時ResourceLibray組件的一部分。這是必須的步驟,因為將在其他應用程序中使用該資源。如果只是使用圖像名,應用程序就會在它自己的資源中查找圖像。真正需要的是指定存儲圖像的組件的相對URI。

  現在已經創建了資源字典,可在另一個應用程序中使用它了。首先,確保已經為類庫程序集定義了前綴,如下所示:

<Window x:Class="Resources.ResourceFromLibrary"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:res="clr-namespace:ResourceLibrary;assembly=ResourceLibrary"
    Title="ResourceFromLibrary" Height="300" Width="300"    
    >

  然后可使用包含ComponentResourceKey的DynamicResource(這是合理的,因為ComponentResourceKey是資源名)。在使用資源字典的應用程序中使用ComponentResourceKey,就是在類庫中使用的ComponentResourceKey。在此,提供了對同一個類的引用和相同的資源ID。唯一的區別是可能使用不同的XAML名稱空間前綴。該例使用res前綴而不是local前綴。從而強調CustomResources類是在另一個程序集中定義的這樣一個事實:

<Button Background="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type res:CustomResources}, ResourceId=SadTileBrush}}"
            Padding="5" Margin="5"
            FontWeight="Bold" FontSize="14">
            A Resource From ResourceLibrary</Button>

  現在該例完成了。但還可以采用一個附加步驟,使資源更容易使用。可定義一個靜態屬性,讓它返回需要使用的正確ComponentResourceKey。通常在組件的類中定義該屬性,如下所示:

public class CustomResources
    {
        public static ComponentResourceKey SadTileBrush
        {
            get
            {
                return new ComponentResourceKey(
                    typeof(CustomResources), "SadTileBrush");
            }
        }
    }

  現在可使用Static標記擴展訪問該屬性並應用資源,而不必在標記中使用很長的ComponentResourceKey:

<Button Background="{DynamicResource {x:Static res:CustomResources.SadTileBrush}}"
        Padding="5" Margin="5"
        FontWeight="Bold" FontSize="14">
      A Resource From ResourceLibrary
    </Button>

  在本質上,這種便捷方法與前面介紹的SystemXxx類使用相同的技術。例如,當檢索SystemColors.WindowTextBrushKey時,所接受的也是正確的資源鍵對象。唯一的區別是,它是私有SystemResourceKey(而不是ComponentResourceKey)的一個實例。這兩個類都繼承自ResourceKey抽象類。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM