Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Interfejs użytkownika lub zasoby dla aplikacji można zdefiniować przy użyciu języka XAML. Zasoby to zazwyczaj definicje niektórych obiektów, których można użyć więcej niż raz. Aby później odwołać się do zasobu XAML, należy określić klucz zasobu, który działa jak jego nazwa. Można odwołać się do zasobu w całej aplikacji lub z dowolnej strony XAML w niej. Zasoby można zdefiniować przy użyciu elementu ResourceDictionary w środowisku uruchomieniowym systemu Windows XAML. Następnie możesz odwołać się do zasobów przy użyciu rozszerzenia znaczników StaticResource lub rozszerzenia znaczników ThemeResource .
Elementy XAML, które najczęściej chcesz zadeklarować jako zasoby XAML, obejmują Style, ControlTemplate, składniki animacji oraz podklasy Brush. W tym miejscu wyjaśniono, jak zdefiniować ResourceDictionary i zasoby z kluczem oraz jak zasoby XAML są powiązane z innymi zasobami, które definiujesz jako część swojej aplikacji lub pakietu aplikacyjnego. Objaśniamy również zaawansowane funkcje słownika zasobów, takie jak MergedDictionaries i ThemeDictionaries.
Wymagania wstępne
Solidne zrozumienie znaczników XAML. Zalecamy przeczytanie omówienie języka XAML.
Definiowanie i używanie zasobów XAML
Zasoby XAML to obiekty, które są wykorzystywane w znacznikach więcej niż raz. Zasoby są definiowane w ResourceDictionary, zazwyczaj w osobnym pliku lub w górnej części strony z kodem znaczników, jak poniżej.
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:String x:Key="greeting">Hello world</x:String>
<x:String x:Key="goodbye">Goodbye world</x:String>
</Page.Resources>
<TextBlock Text="{StaticResource greeting}" Foreground="Gray" VerticalAlignment="Center"/>
</Page>
W tym przykładzie:
-
<Page.Resources>…</Page.Resources>— definiuje słownik zasobów. -
<x:String>— definiuje zasób o kluczu "powitanie". - pl-PL:
{StaticResource greeting}— wyszukuje zasób z kluczem "greeting", który jest przypisany do właściwości Text w elemencie TextBlock.
Uwaga / Notatka
Nie należy mylić pojęć związanych z resourceDictionary z akcją kompilacji zasobu , plikami zasobów (resw) ani innymi "zasobami", które zostały omówione w kontekście tworzenia projektu kodu tworzącego pakiet aplikacji.
Zasoby nie muszą być ciągami; mogą być dowolnymi obiektami, takimi jak style, szablony, pędzle i kolory. Jednak kontrolki, kształty i inne FrameworkElementnie są dostępne do udostępniania, więc nie można ich zadeklarować jako zasobów wielokrotnego użytku. Aby uzyskać więcej informacji na temat udostępniania, zobacz w dalszej części tego tematu sekcję zasoby XAML muszą być udostępniane.
W tym miejscu zarówno pędzel, jak i ciąg znaków są deklarowane jako zasoby i używane przez kontrolki na stronie.
<Page
x:Class="SpiderMSDN.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<SolidColorBrush x:Key="myFavoriteColor" Color="green"/>
<x:String x:Key="greeting">Hello world</x:String>
</Page.Resources>
<TextBlock Foreground="{StaticResource myFavoriteColor}" Text="{StaticResource greeting}" VerticalAlignment="Top"/>
<Button Foreground="{StaticResource myFavoriteColor}" Content="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>
Wszystkie zasoby muszą mieć klucz. Zazwyczaj ten klucz jest ciągiem zdefiniowanym za pomocą x:Key="myString". Istnieje jednak kilka innych sposobów określania klucza:
- Style i ControlTemplate wymagają TargetType, i będą używać TargetType jako klucz, jeśli nie określono x:Key. W tym przypadku kluczem jest rzeczywisty obiekt Type, a nie ciąg. (Zobacz przykłady poniżej)
- DataTemplate zasobów, które mają TargetType, użyją TargetType jako klucza, jeśli nie określono x:Key. W tym przypadku kluczem jest rzeczywisty obiekt Type, a nie ciąg.
- x:Name można użyć zamiast x:Key. Jednak x:Name generuje również kod za polem dla zasobu. W związku z tym, x:Name jest mniej wydajny niż x:Key, ponieważ to pole musi zostać zainicjowane podczas ładowania strony.
Rozszerzenie znaczników StaticResource może pobierać zasoby tylko przy użyciu ciągu znaków (x:Key lub x:Name). Jednak w ramach XAML również wyszukiwane są niejawne zasoby stylu (te, które używają TargetType zamiast x:Key lub x:Name), gdy decyduje, który styl i szablon użyć dla kontrolki, która nie ma ustawionych właściwości Style i ContentTemplate lub ItemTemplate.
W tym miejscu styl
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Red"/>
</Style>
</Page.Resources>
<Grid>
<!-- This button will have a red background. -->
<Button Content="Button" Height="100" VerticalAlignment="Center" Width="100"/>
</Grid>
</Page>
Aby uzyskać więcej informacji na temat niejawnych stylów i sposobu ich działania, zobacz Kontrolki stylów i szablony kontrolek .
Wyszukiwanie zasobów w kodzie
Uzyskujesz dostęp do członków słownika zasobów, tak jak każdy inny słownik.
Ostrzeżenie
Podczas wyszukiwania zasobów w kodzie są przeglądane tylko zasoby w słowniku Page.Resources. W przeciwieństwie do rozszerzenia znaczników StaticResourcekod nie wraca do słownika Application.Resources, jeśli zasoby nie znajdują się w pierwszym słowniku.
W tym przykładzie pokazano, jak pobrać zasób redButtonStyle ze słownika zasobów strony:
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="Button" x:Key="redButtonStyle">
<Setter Property="Background" Value="red"/>
</Style>
</Page.Resources>
</Page>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Style redButtonStyle = (Style)this.Resources["redButtonStyle"];
}
}
MainPage::MainPage()
{
InitializeComponent();
Windows::UI::Xaml::Style style = Resources().TryLookup(winrt::box_value(L"redButtonStyle")).as<Windows::UI::Xaml::Style>();
}
Aby wyszukać zasoby dla całej aplikacji z kodu, użyj Application.Current.Resources, aby uzyskać słownik zasobów aplikacji, jak pokazano tutaj.
<Application
x:Class="MSDNSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SpiderMSDN">
<Application.Resources>
<Style TargetType="Button" x:Key="appButtonStyle">
<Setter Property="Background" Value="red"/>
</Style>
</Application.Resources>
</Application>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Style appButtonStyle = (Style)Application.Current.Resources["appButtonStyle"];
}
}
MainPage::MainPage()
{
InitializeComponent();
Windows::UI::Xaml::Style style = Application::Current().Resources()
.TryLookup(winrt::box_value(L"appButtonStyle"))
.as<Windows::UI::Xaml::Style>();
}
Możesz również dodać zasób aplikacji w kodzie.
Podczas wykonywania tej czynności należy pamiętać o dwóch kwestiach.
- Najpierw należy dodać zasoby, zanim każda strona spróbuje użyć zasobu.
- Po drugie, nie można dodać zasobów w konstruktorze aplikacji.
Możesz uniknąć obu problemów, jeśli dodasz zasób w metodzie Application.OnLaunched, tak jak pokazano tutaj.
// App.xaml.cs
sealed partial class App : Application
{
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
SolidColorBrush brush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 255, 0)); // green
this.Resources["brush"] = brush;
// … Other code that VS generates for you …
}
}
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
Frame rootFrame{ nullptr };
auto content = Window::Current().Content();
if (content)
{
rootFrame = content.try_as<Frame>();
}
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
Windows::UI::Xaml::Media::SolidColorBrush brush{ Windows::UI::ColorHelper::FromArgb(255, 0, 255, 0) };
Resources().Insert(winrt::box_value(L"brush"), winrt::box_value(brush));
// … Other code that VS generates for you …
Każdy element FrameworkElement może mieć element ResourceDictionary
FrameworkElement jest klasą bazową, z której dziedziczą kontrolki, i ma właściwość Resources. Dlatego można dodać lokalny słownik zasobów do dowolnego FrameworkElement.
W tym miejscu zarówno strona , jak i obiekt Border mają słowniki zasobów, a oba mają zasób o nazwie "powitanie". TextBlock o nazwie "textBlock2" znajduje się wewnątrz Border, więc wyszukiwanie zasobów zaczyna się od zasobów Border, następnie zasobów strony, a potem zasobów aplikacji. TextBlock będzie wyświetlać „Hola mundo”.
Aby uzyskać dostęp do zasobów tego elementu z kodu, użyj właściwości Resources tego elementu. Uzyskiwanie dostępu do zasobów FrameworkElementw kodzie zamiast w XAML powoduje, że przeszukiwanie odbywa się wyłącznie w tym słowniku, a nie w słownikach elementu nadrzędnego.
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:String x:Key="greeting">Hello world</x:String>
</Page.Resources>
<StackPanel>
<!-- Displays "Hello world" -->
<TextBlock x:Name="textBlock1" Text="{StaticResource greeting}"/>
<Border x:Name="border">
<Border.Resources>
<x:String x:Key="greeting">Hola mundo</x:String>
</Border.Resources>
<!-- Displays "Hola mundo" -->
<TextBlock x:Name="textBlock2" Text="{StaticResource greeting}"/>
</Border>
<!-- Displays "Hola mundo", set in code. -->
<TextBlock x:Name="textBlock3"/>
</StackPanel>
</Page>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
textBlock3.Text = (string)border.Resources["greeting"];
}
}
MainPage::MainPage()
{
InitializeComponent();
textBlock3().Text(unbox_value<hstring>(border().Resources().TryLookup(winrt::box_value(L"greeting"))));
}
Połączone słowniki zasobów
Połączony słownik zasobów łączy jeden słownik zasobów z innym, zwykle w innym pliku.
Porada Możesz utworzyć plik słownika zasobów w programie Microsoft Visual Studio, używając opcji Dodaj > Nowy element… > Słownik zasobów z menu Project.
W tym miejscu zdefiniujesz słownik zasobów w osobnym pliku XAML o nazwie Dictionary1.xaml.
<!-- Dictionary1.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MSDNSample">
<SolidColorBrush x:Key="brush" Color="Red"/>
</ResourceDictionary>
Aby użyć tego słownika, zintegrujesz go ze słownikiem swojej strony.
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
<x:String x:Key="greeting">Hello world</x:String>
</ResourceDictionary>
</Page.Resources>
<TextBlock Foreground="{StaticResource brush}" Text="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>
Oto, co dzieje się w tym przykładzie. W <Page.Resources>deklarujesz <ResourceDictionary>. Framework XAML niejawnie tworzy słownik zasobów dla ciebie, gdy dodajesz zasoby do <Page.Resources>; jednak w tym przypadku nie chcesz po prostu żadnego słownika zasobów, ale taki, który zawiera scalone słowniki.
Dlatego deklarujesz <ResourceDictionary>, a następnie dodajesz elementy do kolekcji <ResourceDictionary.MergedDictionaries>. Każdy z tych wpisów ma postać <ResourceDictionary Source="Dictionary1.xaml"/>. Aby dodać więcej niż jeden słownik, wystarczy dodać wpis <ResourceDictionary Source="Dictionary2.xaml"/> po pierwszym wpisie.
Po <ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries>możesz opcjonalnie umieścić dodatkowe zasoby w słowniku głównym. Używasz zasobów ze scalonego słownika tak samo jak zwykłego słownika. W powyższym przykładzie {StaticResource brush} znajduje zasób w słowniku podrzędnym/scalonym (Dictionary1.xaml), a {StaticResource greeting} znajduje swój zasób w słowniku strony głównej.
W sekwencji wyszukiwania zasobów, słownik MergedDictionaries jest sprawdzany dopiero po sprawdzeniu wszystkich innych zasobów z kluczami tego ResourceDictionary. Po przeszukaniu tego poziomu wyszukiwanie przenosi się do scalonych słowników, a każdy element w MergedDictionaries jest sprawdzany. Jeśli istnieje wiele scalonych słowników, te słowniki są sprawdzane w odwrotnej kolejności, w której są deklarowane w właściwości MergedDictionaries. W poniższym przykładzie, jeśli zarówno Dictionary2.xaml, jak i Dictionary1.xaml zadeklarują ten sam klucz, klucz z Dictionary2.xaml jest używany pierwszy, ponieważ jest ostatni w zestawie MergedDictionaries.
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
<ResourceDictionary Source="Dictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<TextBlock Foreground="{StaticResource brush}" Text="greetings!" VerticalAlignment="Center"/>
</Page>
W ramach dowolnego ResourceDictionarysłownik jest sprawdzany pod kątem unikalności klucza. Jednak ten zakres nie rozciąga się na różne elementy w plikach różnych MergedDictionaries.
Możesz użyć kombinacji sekwencji wyszukiwania i braku wymuszania unikalności klucza w zakresach scalonych słowników, aby utworzyć sekwencję wartości awaryjnych ResourceDictionary zasobów. Można na przykład przechowywać preferencje użytkownika dla określonego koloru pędzla w ostatnim scalanym słowniku zasobów w sekwencji, używając słownika zasobów, który synchronizuje się ze stanem aplikacji i danymi preferencji użytkownika. Jeśli jednak nie ma jeszcze żadnych preferencji użytkownika, możesz zdefiniować ten sam ciąg klucza dla zasobu ResourceDictionary w początkowym pliku MergedDictionaries i może służyć jako wartość rezerwowa. Pamiętaj, że wszelkie wartości podane w słowniku zasobów podstawowych są zawsze sprawdzane przed sprawdzeniem scalonych słowników, więc jeśli chcesz użyć techniki rezerwowej, nie zdefiniuj tego zasobu w słowniku podstawowym zasobów.
Zasoby motywu i słowniki motywów
ThemeResource jest podobny do StaticResource, ale gdy zmienia się motyw, wyszukiwanie zasobów jest oceniane ponownie.
W tym przykładzie ustawisz pierwszy plan TextBlock na wartość z bieżącego motywu.
<TextBlock Text="hello world" Foreground="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" VerticalAlignment="Center"/>
Słownik motywu to specjalny typ scalonego słownika, który zawiera zasoby, które różnią się w zależności od motywu, którego użytkownik używa obecnie na swoim urządzeniu. Na przykład motyw "jasny" może używać białego pędzla kolorów, natomiast motyw "ciemny" może używać ciemnego pędzla kolorów. Pędzel zmienia zasób, do którego się odnosi, ale poza tym kompozycja kontrolki używającej pędzla jako zasobu może być taka sama. Aby odtworzyć zachowanie przełączania motywu we własnych szablonach i stylach, zamiast używać MergedDictionaries jako właściwości scalania elementów z głównymi słownikami, użyj właściwości ThemeDictionaries.
Każdy element ResourceDictionary w ThemeDictionaries musi mieć wartość x:Key. Wartość to ciąg, który nazywa odpowiedni motyw, na przykład "Default", "Dark", "Light" lub "HighContrast". Zazwyczaj Dictionary1 i Dictionary2 definiują zasoby, które mają te same nazwy, ale różne wartości.
W tym miejscu użyjesz czerwonego tekstu dla motywu jasnego i niebieskiego tekstu dla motywu ciemnego.
<!-- Dictionary1.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MSDNSample">
<SolidColorBrush x:Key="brush" Color="Red"/>
</ResourceDictionary>
<!-- Dictionary2.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MSDNSample">
<SolidColorBrush x:Key="brush" Color="blue"/>
</ResourceDictionary>
W tym przykładzie ustawisz pierwszy plan TextBlock na wartość z bieżącego motywu.
<Page
x:Class="MSDNSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" x:Key="Light"/>
<ResourceDictionary Source="Dictionary2.xaml" x:Key="Dark"/>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Page.Resources>
<TextBlock Foreground="{StaticResource brush}" Text="hello world" VerticalAlignment="Center"/>
</Page>
W przypadku słowników motywów, aktywny słownik używany do wyszukiwania zasobów zmienia się dynamicznie, za każdym razem gdy rozszerzenie znaczników ThemeResource jest używane do dokonania odniesienia i system wykrywa zmianę motywu. Zachowanie wyszukiwania wykonywane przez system jest oparte na mapowaniu aktywnego motywu na x:Key określonego słownika motywu.
Przydatne może być zbadanie sposobu, w jaki słowniki motywów są ustrukturyzowane w domyślnych zasobach projektu XAML, które domyślnie korzystają z szablonów stosowanych przez Windows Runtime dla swoich kontrolek. Otwórz pliki XAML w folderze \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<wersji>zestawu SDK \Generic, używając edytora tekstowego lub środowiska IDE. Zwróć uwagę, jak słowniki motywów są definiowane najpierw w pliku generic.xaml i jak każdy słownik motywów definiuje te same klucze. Każdy z tych kluczy jest następnie przywoływany przez elementy kompozycji w różnych elementach kluczowych, które są poza słownikami motywów i zdefiniowane później w XAML. Istnieje również oddzielny plik themeresources.xaml do projektowania, który zawiera tylko zasoby motywu i dodatkowe szablony, a nie domyślne szablony kontrolek. Obszary motywu to duplikaty elementów widocznych w pliku generic.xaml.
Gdy używasz narzędzi projektowych XAML do edytowania kopii stylów i szablonów, narzędzia projektowe wyodrębniają sekcje z słowników zasobów projektowych XAML i umieszczają je jako lokalne kopie elementów słownika XAML, które są częścią aplikacji i projektu.
Aby uzyskać więcej informacji oraz listę zasobów specyficznych dla motywu i systemowych, dostępnych dla Twojej aplikacji, zapoznaj się z zasobami motywu XAML.
Sposób wyszukiwania dla odwołań do zasobów XAML
zachowanie wyszukiwania to termin opisujący, w jaki sposób system zasobów XAML próbuje znaleźć zasób XAML. Wyszukiwanie występuje, gdy klucz jest przywołyny jako odwołanie do zasobu XAML z miejsca w języku XAML aplikacji. Po pierwsze system zasobów ma przewidywalne zachowanie, w którym sprawdzi istnienie zasobu na podstawie zakresu. Jeśli zasób nie zostanie znaleziony w zakresie początkowym, zakres zostanie rozszerzany. Zachowanie wyszukiwania trwa w różnych lokalizacjach i zakresach, w których zasób XAML może być zdefiniowany przez aplikację lub przez system. Jeśli wszystkie możliwe próby wyszukiwania zasobów kończą się niepowodzeniem, często występuje błąd. Zwykle można wyeliminować te błędy podczas procesu programowania.
Sposób wyszukiwania dla odwołań do zasobów XAML rozpoczyna się od obiektu, gdzie rzeczywiste użycie jest zastosowane, i jego właściwości Resources. Jeśli ResourceDictionary istnieje, ten ResourceDictionary jest sprawdzany pod kątem elementu o żądanym kluczu. Ten pierwszy poziom wyszukiwania jest rzadko istotny, ponieważ zwykle nie definiuje się, a następnie odwołuje się do zasobu w tym samym obiekcie. W rzeczywistości właściwość Resources często nie istnieje tutaj. Odwołania do zasobów XAML można tworzyć z niemal dowolnego miejsca w języku XAML; Nie ograniczasz się do właściwości FrameworkElement podklas.
Następnie sekwencja wyszukiwania sprawdza następny obiekt nadrzędny w drzewie obiektów aplikacji. Jeśli istnieje FrameworkElement.Resources i przechowuje ResourceDictionary, żądany jest element słownika z określonym ciągiem klucza. Jeśli zasób zostanie znaleziony, sekwencja wyszukiwania zostanie zatrzymana, a obiekt zostanie przekazany do miejsca, w którym dokonano odniesienia. W przeciwnym razie mechanizm wyszukiwania przechodzi do następnego poziomu nadrzędnego w kierunku korzenia drzewa obiektów. Wyszukiwanie będzie kontynuowane rekursywnie w górę do momentu osiągnięcia głównego elementu XAML, wyczerpując wyszukiwanie wszystkich możliwych natychmiastowych lokalizacji zasobów.
Uwaga / Notatka
Typowym rozwiązaniem jest zdefiniowanie wszystkich natychmiastowych zasobów na poziomie głównym strony, zarówno w celu skorzystania z tego zachowania wyszukiwania zasobów, jak i jako konwencji stylu znaczników XAML.
Jeśli żądany zasób nie zostanie znaleziony w natychmiastowych zasobach, następnym krokiem wyszukiwania jest sprawdzenie właściwości Application.Resources. Application.Resources to najlepsze miejsce do umieszczania dowolnych zasobów specyficznych dla aplikacji, do których odwołuje się wiele stron w strukturze nawigacji aplikacji.
Ważne
Kolejność zasobów dodanych do elementu ResourceDictionary wpływa na kolejność ich stosowania. Słownik XamlControlsResources zastępuje wiele domyślnych kluczy zasobów i dlatego należy go najpierw dodać do Application.Resources, aby nie przesłaniał żadnych innych niestandardowych stylów ani zasobów w aplikacji.
Szablony kontrolek mają inną możliwą lokalizację w odnośniku referencyjnym: słowniki motywów. Słownik motywu jest pojedynczym plikiem XAML, który ma element ResourceDictionary jako główny. Słownik motywu może być scalonym słownikiem z Application.Resources. Słownik motywu może być również słownikiem motywu specyficznego dla niestandardowej kontrolki szablonowej.
Na koniec następuje przeszukiwanie zasobów platformy. Zasoby platformy obejmują szablony kontrolek zdefiniowane dla każdego motywu interfejsu użytkownika systemu i definiujące domyślny wygląd wszystkich kontrolek używanych dla interfejsu użytkownika w aplikacji Środowiska uruchomieniowego systemu Windows. Zasoby platformy obejmują również zestaw nazwanych zasobów odnoszących się do wyglądu i motywów dla całego systemu. Te zasoby są technicznie elementem MergedDictionaries, a tym samym są dostępne do przeszukiwania w XAML lub kodzie po załadowaniu aplikacji. Na przykład zasoby motywu systemu obejmują zasób o nazwie "SystemColorWindowTextColor", który udostępnia definicję Color, aby dopasować kolor tekstu aplikacji do koloru tekstu okna systemowego pochodzącego z systemu operacyjnego i preferencji użytkownika. Inne style XAML dla Twojej aplikacji mogą odnosić się do tego stylu, lub kod może pobrać wartość zasobu (i rzutować ją na kolor w przykładzie ).
Aby uzyskać więcej informacji i listę zasobów specyficznych dla motywu i zasobów systemowych, które są dostępne dla aplikacji systemu Windows korzystającej z języka XAML, zobacz zasoby motywu XAML.
Jeśli żądany klucz nadal nie zostanie znaleziony w żadnej z tych lokalizacji, wystąpi błąd/wyjątek analizy XAML. W pewnych okolicznościach wyjątek podczas parsowania XAML może być wyjątkiem występującym w czasie wykonania, który nie jest wykrywany ani przez akcję kompilacji znaczników, ani przez środowisko projektowe XAML.
Ze względu na zachowanie wyszukiwania warstwowego dla słowników zasobów można celowo zdefiniować wiele elementów zasobów, z których każda ma tę samą wartość ciągu co klucz, o ile każdy zasób jest definiowany na innym poziomie. Innymi słowy, mimo że klucze muszą być unikatowe w ramach danego ResourceDictionary, wymaganie unikatowości nie rozciąga się na całą sekwencję zachowania wyszukiwania. Podczas wyszukiwania tylko pierwszy taki obiekt, który został pomyślnie pobrany, jest używany dla odwołania do zasobów XAML, a następnie wyszukiwanie zatrzymuje się. Tego zachowania można użyć, aby zażądać zasobu XAML za pomocą tego samego klucza w różnych miejscach w kodzie XAML aplikacji, ale uzyskać różne zasoby z powrotem, w zależności od zakresu, z którego utworzono odwołanie do zasobów XAML, i jak zachowuje się to konkretne wyszukiwanie.
Przekazywanie odwołań w elemencie ResourceDictionary
Odwołania do zasobów XAML w określonym słowniku zasobów muszą odwoływać się do zasobu, który został już zdefiniowany za pomocą klucza, a ten zasób musi być wyświetlany leksykalnie przed odwołaniem do zasobu. Odwołania do przodu nie mogą być rozpoznane za pomocą odwołania do zasobów XAML. Z tego powodu, jeśli używasz odwołań do zasobów XAML z innego zasobu, musisz zaprojektować strukturę słownika zasobów, aby zasoby używane przez inne zasoby były definiowane najpierw w słowniku zasobów.
Zasoby zdefiniowane na poziomie aplikacji nie mogą odwoływać się do natychmiastowych zasobów. Jest to równoważne próbie odwołania w przód, ponieważ zasoby aplikacji są rzeczywiście przetwarzane jako pierwsze (po pierwszym uruchomieniu aplikacji i przed załadowaniem jakiejkolwiek zawartości strony nawigacyjnej). Jednak każdy zasób natychmiastowy może odwoływać się do zasobu aplikacji i może to być przydatna technika uniknięcia sytuacji związanych z odwołaniami przyszłymi.
Zasoby XAML muszą być współużytowalne
Aby obiekt istniał w ResourceDictionary, ten obiekt musi być współużytkowalny.
Udostępnianie jest wymagane, ponieważ gdy drzewo obiektów aplikacji jest konstruowane i używane w czasie wykonywania, obiekty nie mogą istnieć w wielu lokalizacjach w drzewie. Wewnętrznie system zasobów tworzy kopie wartości zasobów do użycia w grafie obiektów aplikacji, gdy każdy zasób XAML jest żądany.
Ogólnie ResourceDictionary i XAML środowiska uruchomieniowego systemu Windows obsługują te obiekty do współużytkowania:
- Style i szablony (Style i klasy pochodzące z FrameworkTemplate)
- Pędzle i kolory (klasy pochodzące z wartości Brushi Color)
- Typy animacji, w tym Storyboard
- Przekształcenia (klasy pochodzące z GeneralTransform)
- Matrix i Matrix3D
- wartości punktu
- Inne struktury związane z interfejsem użytkownika, takie jak Grubość i Promień Narożnika
- wewnętrzne typy danych XAML
Można również użyć typów niestandardowych jako zasobu z możliwością udostępniania, jeśli są zgodne z wymaganymi wzorcami implementacji. Takie klasy definiuje się w kodzie zapasowym (lub w składnikach środowiska uruchomieniowego), a następnie tworzy wystąpienie tych klas w języku XAML jako zasób. Przykłady to źródła danych obiektów i implementacje IValueConverter na potrzeby powiązania danych.
Typy niestandardowe muszą mieć konstruktor domyślny, ponieważ to analizator XAML używa go do utworzenia wystąpienia klasy. Typy niestandardowe używane jako zasoby nie mogą mieć klasy
Zakres użycia UserControl
Element UserControl ma szczególną sytuację podczas zachowania wyszukiwania zasobów, ponieważ posiada ono wrodzone pojęcia zakresu definicji i zakresu użycia. UserControl, który tworzy odwołanie do zasobu XAML z zakresu definicji, musi mieć możliwość obsługi wyszukiwania tego zasobu w ramach własnej sekwencji wyszukiwania zakresu definicji — czyli nie może uzyskać dostępu do zasobów aplikacji. Zakres użycia UserControl traktuje odwołanie do zasobu jako będące w sekwencji odnajdywania w kierunku głównego węzła strony użycia (podobnie jak inne odwołania do zasobów z obiektu w załadowanym drzewie obiektów) i umożliwia dostęp do zasobów aplikacji.
ResourceDictionary i XamlReader.Load
Można użyć ResourceDictionary jako katalogu głównego lub części danych wejściowych XAML dla metody XamlReader.Load. Można również uwzględnić odwołania do zasobów XAML w tym języku XAML, jeśli wszystkie takie odwołania są całkowicie samodzielnie zawarte w kodzie XAML przesłanym do załadowania.
XamlReader.Load analizuje XAML w kontekście, który nie jest świadomy istnienia jakichkolwiek innych obiektów ResourceDictionary, nawet Application.Resources. Ponadto nie używaj {ThemeResource} z poziomu kodu XAML przesłanego do XamlReader.Load.
Używanie elementu ResourceDictionary z kodu
Większość scenariuszy ResourceDictionary jest obsługiwana wyłącznie w języku XAML. Deklarujesz kontener ResourceDictionary oraz zasoby jako plik XAML lub zestaw węzłów XAML w pliku definicji interfejsu użytkownika. Następnie użyjesz odwołań do zasobów XAML, aby zażądać tych zasobów z innych części kodu XAML. Mimo to istnieją pewne scenariusze, w których aplikacja może chcieć dostosować zawartość ResourceDictionary przy użyciu kodu wykonywanego podczas działania aplikacji lub co najmniej wysłać zapytanie do zawartości ResourceDictionary, aby sprawdzić, czy zasób jest już zdefiniowany. Te wywołania kodu są wykonywane w wystąpieniu ResourceDictionary, dlatego należy najpierw pobrać jedno — natychmiastowe ResourceDictionary gdzieś w drzewie obiektów, pobierając FrameworkElement.Resourceslub Application.Current.Resources.
W kodzie języka C# lub Microsoft Visual Basic można odwoływać się do zasobu w danym ResourceDictionary przy użyciu indeksatora (Item). ResourceDictionary jest słownikiem ciągowym, więc indeksator używa klucza ciągu zamiast indeksu całkowitego. W kodzie rozszerzeń składników języka Visual C++ (C++/CX) użyj lookup.
W przypadku używania kodu do badania lub zmiany ResourceDictionarydziałanie interfejsów API, takich jak wyszukiwanie lub element, nie przechodzi z zasobów lokalnych do zasobów aplikacji; jest to zachowanie analizatora XAML, które ma miejsce tylko podczas wczytywania stron XAML. W czasie wykonywania zakres kluczy jest samodzielny dla wystąpienia ResourceDictionary, którego używasz w tym czasie. Jednak ten zakres obejmuje MergedDictionaries.
Ponadto, jeśli zażądasz klucza, który nie istnieje w ResourceDictionary, nie musi wystąpić błąd; wartość zwracana może być po prostu podana jako null. Jeśli jednak spróbujesz użyć zwróconych wartości null, nadal może wystąpić błąd, jeśli spróbujesz użyć zwróconej wartości null. Błąd pochodzi z setter-a właściwości, a nie z wywołania ResourceDictionary. Jedynym sposobem uniknięcia błędu byłoby, gdyby właściwość zaakceptowała null jako prawidłową wartość. Zwróć uwagę, jak to zachowanie kontrastuje z zachowaniem wyszukiwania XAML w czasie parsowania XAML, niepowodzenie w rozpoznaniu podanego klucza z XAML w czasie parsowania powoduje błąd parsowania XAML, nawet w przypadkach, gdy właściwość mogłaby przyjąć null.
Połączone słowniki zasobów są uwzględniane w zakresie indeksowania podstawowego słownika zasobów, który odnosi się do połączonego słownika w czasie wykonywania. Innymi słowy, można użyć item lub lookup słownika podstawowego, aby znaleźć wszystkie obiekty, które zostały faktycznie zdefiniowane w scalanego słowniku. W takim przypadku zachowanie wyszukiwania przypomina zachowanie wyszukiwania w czasie analizy XAML: jeśli istnieje wiele obiektów w scalonych słownikach, z których każdy ma ten sam klucz, zwracany jest obiekt z ostatnio dodanego słownika.
Możesz dodawać elementy do istniejącego ResourceDictionary, wywołując Add (C# lub Visual Basic) lub Insert (C++/CX). Możesz dodać elementy do natychmiastowych zasobów lub zasobów aplikacji. Każde z tych wywołań interfejsu API wymaga klucza, który spełnia wymagania, że każdy element w ResourceDictionary musi mieć klucz. Jednak elementy dodawane do ResourceDictionary w czasie wykonywania nie są istotne dla odwołań do zasobów XAML. Niezbędne wyszukiwanie odwołań do zasobów XAML występuje, gdy kod XAML jest najpierw analizowany podczas ładowania aplikacji (lub wykryto zmianę motywu). Zasoby dodane do kolekcji podczas działania programu nie są wtedy dostępne, a zmiana ResourceDictionary nie unieważnia już pobranego zasobu, nawet jeśli zmienisz wartość tego zasobu.
Można również usunąć elementy z ResourceDictionary w czasie wykonywania, tworzyć kopie niektórych lub wszystkich elementów lub innych operacji. Lista członków dla ResourceDictionary wskazuje, które interfejsy API są dostępne. Należy pamiętać, że ponieważ ResourceDictionary ma przewidywany interfejs API do obsługi jego podstawowych interfejsów kolekcji, opcje interfejsu API różnią się w zależności od tego, czy używasz języka C# lub Visual Basic, czy języka C++/CX.
ResourceDictionary i lokalizacja
Kod XAML ResourceDictionary może początkowo zawierać ciągi, które mają być zlokalizowane. Jeśli tak, przechowuj te ciągi jako zasoby projektu, a nie jako w ResourceDictionary. Wyjmij ciągi z języka XAML, a zamiast tego nadaj elementowi własnemu dyrektywy x:Uid wartości. Następnie zdefiniuj zasób w pliku zasobów. Podaj nazwę zasobu w formularzu XUIDValue.PropertyName i wartość zasobu ciągu, który powinien być zlokalizowany.
Wyszukiwanie zasobów niestandardowych
W przypadku zaawansowanych scenariuszy można zaimplementować klasę, która może mieć inne zachowanie niż zachowanie odnośnika do zasobów XAML opisane w tym temacie. W tym celu zaimplementujesz klasę CustomXamlResourceLoader, a następnie możesz uzyskać dostęp do tego zachowania, korzystając z rozszerzenia znaczników CustomResource dla odwołań do zasobów, zamiast używać StaticResource lub ThemeResource. Większość aplikacji nie będzie mieć scenariuszy, które tego wymagają. Aby uzyskać więcej informacji, zobacz CustomXamlResourceLoader.
Tematy pokrewne
Windows developer