.NET 多平台應用程式 UI (.NET MAUI) 資源字典是 .NET MAUI 應用程式所使用的資源庫。 儲存在 ResourceDictionary 中的一般資源包括樣式、控制項範本、資料範本、轉換器和色彩。
zh-TW: 儲存在 ResourceDictionary 的 ResourceDictionary XAML 資源可以透過使用 StaticResource 或 DynamicResource 標記延伸來參考並應用於元素。 在 C# 中,您也可以在 ResourceDictionary 中定義資源,然後使用字串型索引器參考並套用至元素。
提示
在 Visual Studio 中,使用程式碼後置檔案的 XAML 檔案可以透過 .NET MAUI ResourceDictionary(XAML)項目範本新增至您的專案。
建立資源
每個衍生的 VisualElement 物件都有一個屬性 Resources,該屬性是可以包含資源的 ResourceDictionary。 同樣地,Application 衍生物件具有 Resources 屬性,這是一個 ResourceDictionary,可以包含資源。
.NET MAUI 應用程式只能包含衍生自 Application 的單一類別,但通常會使用衍生自 VisualElement 的許多類別,包括頁面、佈局和視圖。 這些物件中的任何一個都可以將其 Resources 屬性設定為包含資源的 ResourceDictionary。 選擇將特定的 ResourceDictionary 放置於何處會影響資源的使用地點:
- 檢視中附加到ResourceDictionary的資源,例如Button或Label,只能應用於該特定對象。
- 資源字典附屬於佈局中的資源,例如 StackLayout 或 Grid,可以應用於該佈局及其所有子系。
- 在頁面層級定義的資源可以應用到頁面及其所有子項。
- 在應用程式層級定義的資源可以在整個應用程式中套用。
除了隱含樣式之外,資源字典中的每個資源都必須具有以 x:Key 屬性定義的唯一字符串鍵。
下列 XAML 顯示的是在應用程式層級的 App.xaml 檔案中定義的資源:
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceDictionaryDemo.App">
<Application.Resources>
<Thickness x:Key="PageMargin">20</Thickness>
<!-- Colors -->
<Color x:Key="AppBackgroundColor">AliceBlue</Color>
<Color x:Key="NavigationBarColor">#1976D2</Color>
<Color x:Key="NavigationBarTextColor">White</Color>
<Color x:Key="NormalTextColor">Black</Color>
<!-- Images -->
<x:String x:Key="BackgroundImage">background</x:String>
<x:String x:Key="MenuIcon">menu.png</x:String>
<x:String x:Key="SearchIcon">search.png</x:String>
<!-- Implicit styles -->
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor"
Value="{StaticResource NavigationBarColor}" />
<Setter Property="BarTextColor"
Value="{StaticResource NavigationBarTextColor}" />
</Style>
<Style TargetType="ContentPage"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>
</Application.Resources>
</Application>
在此範例中,資源字典定義了一項Thickness資源、多項Color資源,以及兩項未命名的Style資源。
重要
在 Resources 屬性元素標記之間直接插入資源會自動建立 ResourceDictionary 物件。 不過,把所有資源放在選擇性的 ResourceDictionary 標籤之間也是有效的。
取用資源
每個資源都有一個透過x:Key屬性指定的索引鍵,該索引鍵會成為ResourceDictionary中的字典索引鍵。 鍵是用來從 ResourceDictionary 使用 StaticResource 或 DynamicResource XAML 標記擴展來參考資源。
StaticResource 標記擴展與 DynamicResource 標記擴展類似,因為兩者都使用字典索引鍵從資源字典中參考值。 不過,當 StaticResource 標記延伸執行單一字典查閱時,DynamicResource 標記延伸則會維護與字典鍵的連結。 因此,如果替換與鍵相關聯的字典項目,則將變更應用於視覺元素。 這可讓應用程式進行運行時間資源變更。 若需有關標記擴展的詳細資訊,請參閱 XAML 標記擴展。
下列 XAML 範例示範如何取用資源,並在 StackLayout (例如:StackLayout 堆疊佈局) 定義其他資源:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceDictionaryDemo.MainPage"
Title="Main page">
<StackLayout Margin="{StaticResource PageMargin}"
Spacing="6">
<StackLayout.Resources>
<!-- Implicit style -->
<Style TargetType="Button">
<Setter Property="FontSize" Value="14" />
<Setter Property="BackgroundColor" Value="#1976D2" />
<Setter Property="TextColor" Value="White" />
<Setter Property="CornerRadius" Value="5" />
</Style>
</StackLayout.Resources>
<Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries." />
<Button Text="Navigate"
Clicked="OnNavigateButtonClicked" />
</StackLayout>
</ContentPage>
在此範例中,ContentPage 物件會使用在應用程式層級的資源字典中定義的隱含樣式。
StackLayout 物件會取用應用程式層級資源字典中定義的PageMargin 資源,而 Button 物件會取用資源字典中定義的StackLayout 隱含樣式。 這會導致下列螢幕快照所示的外觀:
使用資源字典資源。
重要
單一頁面特有的資源不應包含在應用層級的資源字典中,因為這樣的資源將會在應用程式啟動時被分析,而不是當頁面需要時。 如需詳細資訊,請參閱減少應用程式資源字典大小。
資源查閱行為
當資源使用 StaticResource 或 DynamicResource 標記延伸引用時,會發生下列查閱程序。
- 對於設定屬性的元素,會在資源字典中檢查其要求的鍵是否存在。 如果找到要求的索引鍵,則會傳回其值,而且查閱程式會終止。
- 如果找不到匹配項目,查找程序會向上遍歷可視化樹狀結構,並檢查每個父元素的資源字典。 如果找到要求的索引鍵,則會傳回其值,而且查閱程式會終止。 否則,進程會往上繼續,直到到達根元素為止。
- 如果在根元素找不到匹配項,則會檢查應用程式層級資源字典。
- 如果仍然找不到相符項目,
XamlParseException就會擲出。
因此,當 XAML 剖析器遇到 StaticResource 或 DynamicResource 標記延伸時,它會透過向上遍歷可視化樹狀結構來搜尋並使用找到的第一個匹配索引鍵。 如果此搜尋在頁面結束,且索引鍵仍未找到,則 XAML 剖析器會搜尋附加於 ResourceDictionary 物件的 App。 如果仍然找不到索引鍵,就會引發例外狀況。
覆寫資源
當資源分享索引鍵時,可視化樹狀結構中較低定義的資源會優先於較高定義的資源。 例如,將 AppBackgroundColor 資源在應用層級設定為 AliceBlue,將會被頁面層級的 AppBackgroundColor 資源設定為 Teal 覆寫。 同樣地,頁面層級的AppBackgroundColor資源將會被版面配置或檢視層級的AppBackgroundColor資源覆寫。
獨立資源字典
ResourceDictionary 也可以建立為獨立的 XAML 檔案,而該檔案不依賴程式碼後置檔案。 若要建立獨立ResourceDictionary檔案,請使用ResourceDictionary項目範本將新檔案新增至專案,並刪除其程式代碼後置檔案。 然後,在 XAML 檔案中,從檔案開頭附近的 ResourceDictionary 標記中移除 x:Class 屬性。 此外,在 XML 標頭後面新增 <?xaml-comp compile="true" ?> ,以確保 XAML 會編譯。
ResourceDictionary 也可以作為獨立的 XAML 檔案來建立,而不需要代碼後置檔案的支援。 若要建立獨立的 ResourceDictionary,請將新的 ResourceDictionary 檔案新增至專案,使用 .NET MAUI ResourceDictionary (XAML) 專案項目範本,然後刪除其程式代碼後置檔案。 然後,在 XAML 檔案中,從ResourceDictionary標籤在檔案剛開始的標籤中移除x:Class屬性。 根據預設,獨立ResourceDictionary會編譯其XAML,除非在XML標頭之後指定<?xaml-comp compile="false" ?>。
注意
獨立的ResourceDictionary必須設定建置動作為MauiXaml。
下列 XAML 範例顯示一個名為 MyResourceDictionary.xaml 的單獨 ResourceDictionary:
<?xml version="1.0" encoding="UTF-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ResourceDictionaryDemo">
<DataTemplate x:Key="PersonDataTemplate"
x:DataType="local:Person">
<ViewCell>
<Grid RowSpacing="6"
ColumnSpacing="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Name}"
TextColor="{StaticResource NormalTextColor}"
FontAttributes="Bold" />
<Label Grid.Column="1"
Text="{Binding Age}"
TextColor="{StaticResource NormalTextColor}" />
<Label Grid.Column="2"
Text="{Binding Location}"
TextColor="{StaticResource NormalTextColor}"
HorizontalTextAlignment="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ResourceDictionary>
在此範例中,ResourceDictionary 包含單一資源,這是類型為 DataTemplate 的物件。 MyResourceDictionary.xaml 可以通过合併到另一個資源字典來使用。
合併資源字典
資源字典可以藉由將一或多個 ResourceDictionary 物件合併成另一個 ResourceDictionary。
合併本地資源字典
本機ResourceDictionary檔案可以透過建立一個ResourceDictionary物件,其中的Source屬性被設置為具有資源的 XAML 檔案的檔名,以合併到另一個ResourceDictionary。
<ContentPage ...>
<ContentPage.Resources>
<!-- Add more resources here -->
<ResourceDictionary Source="MyResourceDictionary.xaml" />
<!-- Add more resources here -->
</ContentPage.Resources>
...
</ContentPage>
此語法不會具現化 Source 屬性時,不需要程式代碼後置檔案,而且 x:Class 屬性可以從 MyResourceDictionary.xaml 檔案的根標籤中移除。
重要
ResourceDictionary.Source屬性只能從 XAML 設定。
從其他組件合併資源字典
ResourceDictionary也可以藉由將它加入 至 的ResourceDictionary屬性,將其合併至MergedDictionaries另一個 ResourceDictionary 。 不論它們所在的組件為何,這項技術都允許合併資源字典。 合併來自外部程式集的資源字典需要將 ResourceDictionary 的建置動作設為 MauiXaml,並具有程式碼後置檔案,以及在檔案的根標籤中定義 x:Class 屬性。
警告
ResourceDictionary 類別也定義了 MergedWith 屬性。 不過,這個屬性已被取代,不應再使用。
下列程式碼範例顯示將兩個資源字典新增至頁面層級的 MergedDictionaries 集合中的範例:
<ContentPage ...
xmlns:local="clr-namespace:ResourceDictionaryDemo"
xmlns:theme="clr-namespace:MyThemes;assembly=MyThemes">
<ContentPage.Resources>
<ResourceDictionary>
<!-- Add more resources here -->
<ResourceDictionary.MergedDictionaries>
<!-- Add more resource dictionaries here -->
<local:MyResourceDictionary />
<theme:DefaultTheme />
<!-- Add more resource dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Add more resources here -->
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
在此範例中,來自相同元件的資源字典,以及外部元件的資源字典,會合併到頁面層級資源字典中。 此外,您也可以在MergedDictionaries屬性元素標籤中新增其他ResourceDictionary物件,以及這些標籤以外的其他資源。
重要
在ResourceDictionary中只能有一個MergedDictionaries屬性元素標籤,但您可以根據需要在其中放置盡可能多的ResourceDictionary物件。
當合併的 ResourceDictionary 資源擁有相同的 x:Key 屬性值時,.NET MAUI 採用以下的資源優先順序:
- 限定於資源字典的資源。
- 透過
MergedDictionaries集合合併的資源字典中所包含的資源,會以MergedDictionaries屬性中列出的反向順序排列。
提示
如果應用程式包含多個大型資源字典,則搜尋資源字典可能是需要大量計算的工作。 因此,為了避免不必要的搜尋,您應該確保應用程式中的每一個頁面都只會使用適合頁面的資源字典。
從程式碼中使用基於 XAML 的資源字典
XAML 中定義的資源字典可以在程式碼中取用,前提是該資源字典由程式碼後置檔案支援。 在 Visual Studio 中,XAML 型檔案搭配程式代碼後置檔案,可以透過 .NET MAUI ResourceDictionary (XAML) 項目範本新增至您的專案。
程式碼後置所支援之資源辭典的螢幕快照。
由後置代碼檔案支援的 XAML 資源字典接著可以從 C# 取用,方法是將它們新增至 MergedDictionaries 合併字典的集合:
Resources.MergedDictionaries.Add(new MyMauiApp.Resources.Styles.MyColors());
Resources.MergedDictionaries.Add(new MyMauiApp.Resources.Styles.MyStyles());
從程式代碼依金鑰存取資源
您可以從程式代碼存取資源字典中的資源,就像任何其他字典一樣。
下列範例示範如何從頁面的資源字典擷取和套用資源:
// Retrieve the Primary color value which is in the page's resource dictionary
var hasValue = Resources.TryGetValue("Primary", out object primaryColor);
if (hasValue)
{
myLabel.TextColor = (Color)primaryColor;
}
這是建議的方法,可確保如果 .NET MAUI 無法從程式代碼擷取資源,就不會拋出 KeyNotFoundException。 當合併的資源字典是由 XAML 檔案中定義的資源和內嵌資源所組成時,就可能發生此情況。 如需詳細資訊,請參閱 GitHub 議題 #11214。
注意
若要從程式代碼擷取全應用程式資源,請存取 App.Current.Resources 資源字典。