Tworzenie stylów aplikacji przy użyciu języka XAML
Aplikacje interfejsu użytkownika aplikacji wieloplatformowej platformy .NET (.NET MAUI) często zawierają wiele kontrolek, które mają identyczny wygląd. Na przykład aplikacja może mieć wiele Label wystąpień, które mają te same opcje czcionek i opcje układu:
<Label Text="These labels"
HorizontalOptions="Center"
VerticalOptions="Center"
FontSize="18" />
<Label Text="are not"
HorizontalOptions="Center"
VerticalOptions="Center"
FontSize="18" />
<Label Text="using styles"
HorizontalOptions="Center"
VerticalOptions="Center"
FontSize="18" />
W tym przykładzie każdy Label obiekt ma identyczne wartości właściwości do kontrolowania wyglądu tekstu wyświetlanego Labelprzez obiekt . Jednak ustawienie wyglądu poszczególnych kontrolek może być powtarzające się i podatne na błędy. Zamiast tego można utworzyć styl definiujący wygląd, a następnie zastosowany do wymaganych kontrolek.
Wprowadzenie do stylów
Aplikację można stylować przy użyciu Style klasy , aby zgrupować kolekcję wartości właściwości w jeden obiekt, który następnie można zastosować do wielu elementów wizualizacji. Pomaga to zmniejszyć powtarzające się znaczniki i umożliwia łatwiejsze zmianę wyglądu aplikacji.
Chociaż style są przeznaczone głównie dla aplikacji opartych na języku XAML, można je również utworzyć w języku C#:
- Style obiekty utworzone w języku XAML są zwykle definiowane w obiekcie ResourceDictionary przypisanym do
Resources
kolekcji kontrolki, strony lubResources
kolekcji aplikacji. - Style obiekty utworzone w języku C# są zwykle definiowane w klasie strony lub w klasie, do której można uzyskać dostęp globalnie.
Wybieranie miejsca definiowania Style wpływu, w którym można go użyć:
- Style wystąpienia zdefiniowane na poziomie kontroli można stosować tylko do kontrolki i jej elementów podrzędnych.
- Style wystąpienia zdefiniowane na poziomie strony można stosować tylko do strony i do jej elementów podrzędnych.
- Style wystąpienia zdefiniowane na poziomie aplikacji można stosować w całej aplikacji.
Każdy Style obiekt zawiera kolekcję co najmniej jednego Setter obiektu, z których każda Setter ma obiekt Property
i Value
. Jest Property
to nazwa właściwości możliwej do powiązania elementu, do którego jest stosowany styl, a Value
wartość jest stosowana do właściwości .
Każdy Style obiekt może być jawny lub niejawny:
- Jawny obiekt jest definiowany przez określenie
TargetType
wartości ix:Key
oraz przez ustawienie właściwości elementu Style docelowego nax:Key
odwołanie. Style Aby uzyskać więcej informacji, zobacz Jawne style. - Obiekt niejawny Style jest definiowany przez określenie tylko obiektu
TargetType
. Następnie Style obiekt zostanie automatycznie zastosowany do wszystkich elementów tego typu. Jednak podklasy obiektuTargetType
nie są Style automatycznie stosowane. Aby uzyskać więcej informacji, zobacz Niejawne style.
Podczas tworzenia Styleobiektu właściwość jest zawsze wymagana TargetType
. W poniższym przykładzie pokazano jawny styl:
<Style x:Key="labelStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="FontSize" Value="18" />
</Style>
Aby zastosować Styleobiekt , obiekt docelowy musi być obiektem zgodnym VisualElement z wartością TargetType
właściwości elementu Style:
<Label Text="Demonstrating an explicit style" Style="{StaticResource labelStyle}" />
Style niższe w hierarchii widoków mają pierwszeństwo przed zdefiniowanymi wyżej. Na przykład ustawienie wartości ustawianej Style Label.TextColor
na Red
poziomie aplikacji zostanie zastąpione przez styl na poziomie strony ustawiony Label.TextColor
na Green
wartość . Podobnie styl na poziomie strony zostanie zastąpiony stylem poziomu sterowania. Ponadto jeśli Label.TextColor
właściwość kontrolki jest ustawiana bezpośrednio, ma to pierwszeństwo przed dowolnymi stylami.
Style nie reagują na zmiany właściwości i pozostają niezmienione przez czas trwania aplikacji. Jednak aplikacje mogą reagować na zmiany stylu dynamicznie w czasie wykonywania przy użyciu zasobów dynamicznych. Aby uzyskać więcej informacji, zobacz Style dynamiczne.
Style jawne
Aby utworzyć obiekt Style na poziomie strony, należy dodać element do strony, ResourceDictionary a następnie dodać co najmniej jedną Style deklarację do elementu ResourceDictionary. Element jest Style jawny, podając jego deklarację x:Key
atrybutu, który daje mu klucz opisowy w obiekcie ResourceDictionary. Style jawne należy następnie stosować do określonych elementów wizualizacji, ustawiając ich Style właściwości.
W poniższym przykładzie pokazano jawne style w obiektach strony ResourceDictionaryi zastosowane do obiektów strony Label :
<ContentPage ...>
<ContentPage.Resources>
<Style x:Key="labelRedStyle"
TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="FontSize" Value="18" />
<Setter Property="TextColor" Value="Red" />
</Style>
<Style x:Key="labelGreenStyle"
TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="FontSize" Value="18" />
<Setter Property="TextColor" Value="Green" />
</Style>
<Style x:Key="labelBlueStyle"
TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="FontSize" Value="18" />
<Setter Property="TextColor" Value="Blue" />
</Style>
</ContentPage.Resources>
<StackLayout>
<Label Text="These labels"
Style="{StaticResource labelRedStyle}" />
<Label Text="are demonstrating"
Style="{StaticResource labelGreenStyle}" />
<Label Text="explicit styles,"
Style="{StaticResource labelBlueStyle}" />
<Label Text="and an explicit style override"
Style="{StaticResource labelBlueStyle}"
TextColor="Teal" />
</StackLayout>
</ContentPage>
W tym przykładzie zdefiniowano ResourceDictionary trzy style, które są jawnie ustawione na obiektach strony Label . Każdy Style z nich służy do wyświetlania tekstu w innym kolorze, a także ustawiania rozmiaru czcionki oraz opcji układu poziomego i pionowego. Każda Style z nich jest stosowana do innej Label metody, ustawiając jej Style właściwości przy użyciu StaticResource
rozszerzenia znaczników. Ponadto, podczas gdy finał Label ma ustawioną Style wartość, zastępuje TextColor
również właściwość inną Color wartością.
Style niejawne
Aby utworzyć obiekt Style na poziomie strony, należy dodać element do strony, ResourceDictionary a następnie dodać co najmniej jedną Style deklarację do elementu ResourceDictionary. Element a Style jest niejawny, nie określając atrybutux:Key
. Następnie styl zostanie zastosowany w elementach wizualizacji zakresu, które TargetType
pasują dokładnie, ale nie do elementów, które pochodzą z TargetType
wartości.
Poniższy przykład kodu przedstawia niejawny styl w obiektach strony ResourceDictionaryi zastosowany do obiektów stronyEntry:
<ContentPage ...>
<ContentPage.Resources>
<Style TargetType="Entry">
<Setter Property="HorizontalOptions" Value="Fill" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="BackgroundColor" Value="Yellow" />
<Setter Property="FontAttributes" Value="Italic" />
<Setter Property="TextColor" Value="Blue" />
</Style>
</ContentPage.Resources>
<StackLayout>
<Entry Text="These entries" />
<Entry Text="are demonstrating" />
<Entry Text="implicit styles," />
<Entry Text="and an implicit style override"
BackgroundColor="Lime"
TextColor="Red" />
<local:CustomEntry Text="Subclassed Entry is not receiving the style" />
</StackLayout>
</ContentPage>
W tym przykładzie definiuje ResourceDictionary pojedynczy niejawny styl, który jest niejawnie ustawiany na obiektach strony Entry . Element Style służy do wyświetlania niebieskiego tekstu na żółtym tle, a jednocześnie ustawia inne opcje wyglądu. Element Style jest dodawany do strony ResourceDictionary bez określania atrybutu x:Key
. W związku z Style tym obiekt jest stosowany do wszystkich Entry obiektów niejawnie, ponieważ są one zgodne z TargetType
właściwością Style dokładnie. Jednak obiekt Style nie jest stosowany do CustomEntry
obiektu, który jest podklasą Entry. Ponadto czwarty Entry zastępuje BackgroundColor
właściwości i TextColor
stylu do różnych Color wartości.
Stosowanie stylu do typów pochodnych
Właściwość Style.ApplyToDerivedTypes
umożliwia zastosowanie stylu do kontrolek, które pochodzą z typu podstawowego, do którego odwołuje TargetType
się właściwość . W związku z tym ustawienie tej właściwości w taki sposób, aby true
umożliwiało korzystanie z wielu typów w jednym stylu, pod warunkiem, że typy pochodzą z typu podstawowego określonego TargetType
we właściwości .
W poniższym przykładzie pokazano niejawny styl, który ustawia kolor Button tła wystąpień na czerwony:
<Style TargetType="Button"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="Red" />
</Style>
Umieszczenie tego stylu na poziomie ResourceDictionary strony spowoduje zastosowanie go do wszystkich Button obiektów na stronie, a także do wszystkich kontrolek, które pochodzą z elementu Button. Jeśli ApplyToDerivedTypes
jednak właściwość nie została ustawiona, styl zostanie zastosowany tylko do Button obiektów.
Style globalne
Style można definiować globalnie, dodając je do słownika zasobów aplikacji. Te style można następnie używać w całej aplikacji i pomóc uniknąć duplikowania stylów między stronami i kontrolkami.
W poniższym przykładzie pokazano zdefiniowany na Style poziomie aplikacji:
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Styles"
x:Class="Styles.App">
<Application.Resources>
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="HorizontalOptions"
Value="Center" />
<Setter Property="VerticalOptions"
Value="CenterAndExpand" />
<Setter Property="BorderColor"
Value="Lime" />
<Setter Property="CornerRadius"
Value="5" />
<Setter Property="BorderWidth"
Value="5" />
<Setter Property="WidthRequest"
Value="200" />
<Setter Property="TextColor"
Value="Teal" />
</Style>
</Application.Resources>
</Application>
W tym przykładzie zdefiniowano pojedynczy jawny styl , buttonStyle
który będzie używany do ustawiania wyglądu Button obiektów.ResourceDictionary
Uwaga
Style globalne mogą być jawne lub niejawne.
W poniższym przykładzie pokazano stronę korzystającą z buttonStyle
obiektów strony Button :
<ContentPage ...>
<StackLayout>
<Button Text="These buttons"
Style="{StaticResource buttonStyle}" />
<Button Text="are demonstrating"
Style="{StaticResource buttonStyle}" />
<Button Text="application styles"
Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage>
Dziedziczenie stylu
Style mogą dziedziczyć z innych stylów w celu zmniejszenia duplikacji i ponownego użycia. Można to osiągnąć, ustawiając Style.BasedOn
właściwość na istniejącą Stylewartość . W języku XAML można to osiągnąć, ustawiając BasedOn
właściwość na StaticResource
rozszerzenie znaczników, które odwołuje się do wcześniej utworzonego Styleelementu .
Style dziedziczone po stylu podstawowym mogą zawierać Setter wystąpienia dla nowych właściwości lub użyć ich do zastąpienia zestawów ze stylu podstawowego. Ponadto style dziedziczone z stylu podstawowego muszą być przeznaczone dla tego samego typu lub typu, który pochodzi z typu objętego stylem podstawowym. Na przykład jeśli obiektami docelowymi View stylu podstawowego są style oparte na stylu podstawowym, mogą być obiektami docelowymi View lub typami pochodzącymi z View klasy, takimi jak Label i Button obiekty.
Styl może dziedziczyć tylko po stylach na tym samym poziomie lub wyższym w hierarchii widoków. To oznacza, że:
- Styl na poziomie aplikacji może dziedziczyć tylko z innych stylów na poziomie aplikacji.
- Styl na poziomie strony może dziedziczyć style na poziomie aplikacji i inne style na poziomie strony.
- Styl poziomu sterowania może dziedziczyć style na poziomie aplikacji, style na poziomie strony i inne style na poziomie sterowania.
W poniższym przykładzie pokazano jawne dziedziczenie stylu:
<ContentPage ...>
<ContentPage.Resources>
<Style x:Key="baseStyle"
TargetType="View">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
</Style>
</ContentPage.Resources>
<StackLayout>
<StackLayout.Resources>
<Style x:Key="labelStyle"
TargetType="Label"
BasedOn="{StaticResource baseStyle}">
<Setter Property="FontSize" Value="18" />
<Setter Property="FontAttributes" Value="Italic" />
<Setter Property="TextColor" Value="Teal" />
</Style>
<Style x:Key="buttonStyle"
TargetType="Button"
BasedOn="{StaticResource baseStyle}">
<Setter Property="BorderColor" Value="Lime" />
<Setter Property="CornerRadius" Value="5" />
<Setter Property="BorderWidth" Value="5" />
<Setter Property="WidthRequest" Value="200" />
<Setter Property="TextColor" Value="Teal" />
</Style>
</StackLayout.Resources>
<Label Text="This label uses style inheritance"
Style="{StaticResource labelStyle}" />
<Button Text="This button uses style inheritance"
Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage>
W tym przykładzie baseStyle
obiekty docelowe View i ustawiają HorizontalOptions
właściwości i VerticalOptions
. Kontrolka baseStyle
nie jest ustawiana bezpośrednio na żadnych kontrolkach. labelStyle
Zamiast tego i buttonStyle
dziedziczyć z niego, ustawiając dodatkowe wartości właściwości możliwe do powiązania. Obiekty labelStyle
i buttonStyle
są następnie ustawiane na obiektach Label i Button.
Ważne
Niejawny styl może pochodzić z jawnego stylu, ale jawny styl nie może pochodzić z niejawnego stylu.
Style dynamiczne
Style nie reagują na zmiany właściwości i pozostają niezmienione przez czas trwania aplikacji. Na przykład po przypisaniu Style elementu wizualnego do elementu wizualnego, jeśli jeden z Setter obiektów zostanie zmodyfikowany, usunięty lub nowy Setter dodany, zmiany nie zostaną zastosowane do elementu wizualizacji. Jednak aplikacje mogą reagować na zmiany stylu dynamicznie w czasie wykonywania przy użyciu zasobów dynamicznych.
Rozszerzenie DynamicResource
znaczników jest podobne do StaticResource
rozszerzenia znaczników, w przypadku którego oba używają klucza słownika do pobierania wartości z klasy ResourceDictionary. Jednak podczas wykonywania StaticResource
pojedynczego wyszukiwania DynamicResource
słownika element utrzymuje link do klucza słownika. W związku z tym, jeśli wpis słownika skojarzony z kluczem zostanie zastąpiony, zmiana zostanie zastosowana do elementu wizualizacji. Umożliwia to wprowadzanie zmian stylu środowiska uruchomieniowego w aplikacji.
W poniższym przykładzie przedstawiono style dynamiczne :
<ContentPage ...>
<ContentPage.Resources>
<Style x:Key="baseStyle"
TargetType="View">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
<Style x:Key="blueSearchBarStyle"
TargetType="SearchBar"
BasedOn="{StaticResource baseStyle}">
<Setter Property="FontAttributes" Value="Italic" />
<Setter Property="PlaceholderColor" Value="Blue" />
</Style>
<Style x:Key="greenSearchBarStyle"
TargetType="SearchBar">
<Setter Property="FontAttributes" Value="None" />
<Setter Property="PlaceholderColor" Value="Green" />
</Style>
</ContentPage.Resources>
<StackLayout>
<SearchBar Placeholder="SearchBar demonstrating dynamic styles"
Style="{DynamicResource blueSearchBarStyle}" />
</StackLayout>
</ContentPage>
W tym przykładzie SearchBar obiekt używa DynamicResource
rozszerzenia znaczników, aby ustawić Style nazwę blueSearchBarStyle
. Następnie SearchBar może mieć zaktualizowaną Style definicję w kodzie:
Resources["blueSearchBarStyle"] = Resources["greenSearchBarStyle"];
W tym przykładzie blueSearchBarStyle
definicja jest aktualizowana w celu używania greenSearchBarStyle
wartości z definicji. Po wykonaniu tego kodu obiekt zostanie zaktualizowany tak, SearchBar aby używał Setter obiektów zdefiniowanych w pliku greenSearchBarStyle
.
Dziedziczenie stylu dynamicznego
Nie można osiągnąć wyprowadzania stylu dynamicznego przy użyciu Style.BasedOn
właściwości . Style Zamiast tego klasa zawiera BaseResourceKey
właściwość , którą można ustawić na klucz słownika, którego wartość może się dynamicznie zmieniać.
W poniższym przykładzie przedstawiono dziedziczenie stylu dynamicznego :
<ContentPage ...>
<ContentPage.Resources>
<Style x:Key="baseStyle"
TargetType="View">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
<Style x:Key="blueSearchBarStyle"
TargetType="SearchBar"
BasedOn="{StaticResource baseStyle}">
<Setter Property="FontAttributes" Value="Italic" />
<Setter Property="TextColor" Value="Blue" />
</Style>
<Style x:Key="greenSearchBarStyle"
TargetType="SearchBar">
<Setter Property="FontAttributes" Value="None" />
<Setter Property="TextColor" Value="Green" />
</Style>
<Style x:Key="tealSearchBarStyle"
TargetType="SearchBar"
BaseResourceKey="blueSearchBarStyle">
<Setter Property="BackgroundColor" Value="Teal" />
<Setter Property="CancelButtonColor" Value="White" />
</Style>
</ContentPage.Resources>
<StackLayout>
<SearchBar Text="SearchBar demonstrating dynamic style inheritance"
Style="{StaticResource tealSearchBarStyle}" />
</StackLayout>
</ContentPage>
W tym przykładzie SearchBar obiekt używa StaticResource
rozszerzenia znaczników, aby odwołać się Style do nazwy tealSearchBarStyle
. Spowoduje to Style ustawienie niektórych dodatkowych właściwości i użycie BaseResourceKey
właściwości do odwołania blueSearchBarStyle
. DynamicResource
Rozszerzenie znaczników nie jest wymagane, ponieważ tealSearchBarStyle
nie ulegnie zmianie, z wyjątkiem tego, z którego Style pochodzi. tealSearchBarStyle
W związku z tym utrzymuje link do blueSearchBarStyle
elementu i jest aktualizowany po zmianie stylu podstawowego.
Definicję blueSearchBarStyle
można zaktualizować w kodzie:
Resources["blueSearchBarStyle"] = Resources["greenSearchBarStyle"];
W tym przykładzie blueSearchBarStyle
definicja jest aktualizowana w celu używania greenSearchBarStyle
wartości z definicji. Po wykonaniu tego kodu obiekt zostanie zaktualizowany tak, SearchBar aby używał Setter obiektów zdefiniowanych w pliku greenSearchBarStyle
.
Klasy stylów
Klasy stylów umożliwiają stosowanie wielu stylów do kontrolki bez uciekania się do dziedziczenia stylu.
Klasę stylu można utworzyć, ustawiając Class
właściwość na wartość , Style string
która reprezentuje nazwę klasy. Zaletą tej funkcji jest definiowanie jawnego stylu za pomocą atrybutu x:Key
, polega na tym, że wiele klas stylów można zastosować do klasy VisualElement.
Ważne
Wiele stylów może współdzielić tę samą nazwę klasy, pod warunkiem, że są przeznaczone dla różnych typów. Dzięki temu wiele klas stylów, które są identycznie nazwane, mają na celu różne typy.
W poniższym przykładzie przedstawiono trzy BoxView klasy stylów i klasę VisualElement stylu:
<ContentPage ...>
<ContentPage.Resources>
<Style TargetType="BoxView"
Class="Separator">
<Setter Property="BackgroundColor"
Value="#CCCCCC" />
<Setter Property="HeightRequest"
Value="1" />
</Style>
<Style TargetType="BoxView"
Class="Rounded">
<Setter Property="BackgroundColor"
Value="#1FAECE" />
<Setter Property="HorizontalOptions"
Value="Start" />
<Setter Property="CornerRadius"
Value="10" />
</Style>
<Style TargetType="BoxView"
Class="Circle">
<Setter Property="BackgroundColor"
Value="#1FAECE" />
<Setter Property="WidthRequest"
Value="100" />
<Setter Property="HeightRequest"
Value="100" />
<Setter Property="HorizontalOptions"
Value="Start" />
<Setter Property="CornerRadius"
Value="50" />
</Style>
<Style TargetType="VisualElement"
Class="Rotated"
ApplyToDerivedTypes="true">
<Setter Property="Rotation"
Value="45" />
</Style>
</ContentPage.Resources>
</ContentPage>
W tym przykładzie Separator
klasy stylów , Rounded
i Circle
każdy zestaw właściwości ustawia BoxView określone wartości. Klasa Rotated
stylu ma TargetType
wartość VisualElement, co oznacza, że można ją zastosować tylko do VisualElement wystąpień. Jednak jej ApplyToDerivedTypes
właściwość jest ustawiona na true
wartość , co gwarantuje, że można ją zastosować do wszystkich kontrolek pochodzących z VisualElementklasy , takich jak BoxView. Aby uzyskać więcej informacji na temat stosowania stylu do typu pochodnego, zobacz Stosowanie stylu do typów pochodnych.
Klasy stylów można używać, ustawiając StyleClass
właściwość kontrolki, która jest typu IList<string>
, na listę nazw klas stylów. Klasy stylów zostaną zastosowane, pod warunkiem, że typ kontrolki jest zgodny TargetType
z klasami stylów.
W poniższym przykładzie przedstawiono trzy BoxView wystąpienia, z których każda jest ustawiona na różne klasy stylów:
<ContentPage ...>
<ContentPage.Resources>
...
</ContentPage.Resources>
<StackLayout>
<BoxView StyleClass="Separator" />
<BoxView WidthRequest="100"
HeightRequest="100"
HorizontalOptions="Center"
StyleClass="Rounded, Rotated" />
<BoxView HorizontalOptions="Center"
StyleClass="Circle" />
</StackLayout>
</ContentPage>
W tym przykładzie pierwszy BoxView jest stylizowany na separator linii, podczas gdy trzeci BoxView jest okrągły. Drugi BoxView ma do niego dwie klasy stylów, które dają zaokrąglone rogi i obracają je o 45 stopni:
Ważne
Do kontrolki można zastosować wiele klas stylów, ponieważ StyleClass
właściwość jest typu IList<string>
. W takim przypadku klasy stylów są stosowane w kolejności rosnącej listy. W związku z tym, gdy wiele klas stylów ustawi identyczne właściwości, właściwość w klasie stylów, która znajduje się na najwyższym stanowisku listy, będzie mieć pierwszeństwo.