Udostępnij za pośrednictwem


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 lub Resources 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 i x:Key oraz przez ustawienie właściwości elementu Style docelowego na x: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 obiektu TargetType 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 Greenwartość . 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 , buttonStylektó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 Separatorklasy stylów , Roundedi 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 truewartość , 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:

Zrzut ekranu przedstawiający kontrolki BoxViews stylizowany z klasami stylów.

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.