Vytváření stylů aplikací pomocí XAML

Aplikace .NET Multi-Platform App UI (.NET MAUI) často obsahují více ovládacích prvků, které mají stejný vzhled. Aplikace může mít například více Label instancí se stejnými možnostmi písma a možnostmi rozložení:

<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" />

V tomto příkladu má každý Label objekt identické hodnoty vlastností pro řízení vzhledu textu zobrazeného objektem Label. Nastavení vzhledu jednotlivých ovládacích prvků ale může být opakované a náchylné k chybám. Místo toho lze vytvořit styl, který definuje vzhled a pak se použije u požadovaných ovládacích prvků.

Úvod do stylů

Aplikaci lze stylem Style pomocí třídy seskupit kolekci hodnot vlastností do jednoho objektu, který se pak dá použít na více vizuálních prvků. To pomáhá snížit opakované značky a umožňuje snadnější změně vzhledu aplikací.

I když jsou styly navržené primárně pro aplikace založené na XAML, dají se také vytvořit v jazyce C#:

  • Style objekty vytvořené v XAML jsou obvykle definovány v ResourceDictionary kolekci Resources ovládacího prvku, stránky nebo Resources kolekce aplikace.
  • Style objekty vytvořené v jazyce C# jsou obvykle definovány ve třídě stránky nebo ve třídě, ke které lze globálně přistupovat.

Výběr místa, kde se má definovat Style dopad, kde se dá použít:

  • Style instance definované na úrovni řízení lze použít pouze pro ovládací prvek a jeho podřízené položky.
  • Style Instance definované na úrovni stránky lze použít pouze na stránku a na její podřízené položky.
  • Style Instance definované na úrovni aplikace je možné použít v celé aplikaci.

Každý Style objekt obsahuje kolekci jednoho nebo více Setter objektů s každým Setter objektem PropertyValuea . Jedná se Property o název svázatelné vlastnosti prvku, na který je styl použit, a Value je hodnota, která se použije na vlastnost.

Každý Style objekt může být explicitní nebo implicitní:

  • ExplicitníStyle objekt je definován zadáním TargetType a x:Key hodnotou a nastavením vlastnosti cílového elementu Style na x:Key odkaz. Další informace najdete v tématu Explicitní styly.
  • ImplicitníStyle objekt je definován zadáním pouze .TargetType Objekt Style se pak automaticky použije u všech prvků tohoto typu. Podtřídy podtřídy však TargetType nemají automaticky použitou Style . Další informace najdete v tématu Implicitní styly.

Při vytváření Stylevlastnosti TargetType se vždy vyžaduje. Následující příklad ukazuje explicitní styl:

<Style x:Key="labelStyle" TargetType="Label">
    <Setter Property="HorizontalOptions" Value="Center" />
    <Setter Property="VerticalOptions" Value="Center" />
    <Setter Property="FontSize" Value="18" />
</Style>

Chcete-li použít Styleobjekt , musí být VisualElement cílový objekt, který odpovídá TargetType hodnotě Stylevlastnosti :

<Label Text="Demonstrating an explicit style" Style="{StaticResource labelStyle}" />

Styly nižší v hierarchii zobrazení mají přednost před těmi, které jsou definované výš. Například nastavení Style , které se nastaví Label.TextColor na Red úrovni aplikace, se přepíše stylem na úrovni stránky, který se nastaví Label.TextColor na Green. Podobně se styl na úrovni stránky přepíše stylem na úrovni ovládacího prvku. Kromě toho, pokud Label.TextColor je nastavena přímo na vlastnost ovládacího prvku, má přednost před všemi styly.

Styly nereagují na změny vlastností a po dobu trvání aplikace zůstávají beze změny. Aplikace však můžou reagovat na změny stylu dynamicky za běhu pomocí dynamických prostředků. Další informace najdete v tématu Dynamické styly.

Explicitní styly

Chcete-li vytvořit Style na úrovni stránky, ResourceDictionary je třeba přidat na stránku a potom do ní ResourceDictionarylze zahrnout jednu nebo více Style deklarací . A Style je explicitní zadáním jeho deklarace x:Key atributu, který mu dává popisný klíč v ResourceDictionary. Explicitní styly se pak musí použít u konkrétních vizuálních prvků nastavením jejich Style vlastností.

Následující příklad ukazuje explicitní styly v objektech ResourceDictionarystránky a použité na objekty stránky 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>

V tomto příkladu ResourceDictionary definuje tři styly, které jsou explicitně nastaveny na objekty stránky Label . Každý Style se používá k zobrazení textu v jiné barvě a zároveň k nastavení velikosti písma a možností vodorovného a svislého rozložení. Každá Style se použije na jinou Label nastavením vlastností Style pomocí StaticResource rozšíření značek. Kromě toho, zatímco poslední Label má nastavenou Style sadu, přepíše TextColor také vlastnost na jinou Color hodnotu.

Implicitní styly

Chcete-li vytvořit Style na úrovni stránky, ResourceDictionary je třeba přidat na stránku a potom do ní ResourceDictionarylze zahrnout jednu nebo více Style deklarací . A Style je implicitní zadáním atributu x:Key . Styl se pak použije v elementech vizuálu oboru, které přesně odpovídají TargetType prvkům, ale ne na prvky odvozené z TargetType hodnoty.

Následující příklad kódu ukazuje implicitní styl stránky ResourceDictionarya použitý na objekty stránky Entry :

<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>

V tomto příkladu ResourceDictionary definuje jeden implicitní styl, který je implicitně nastaven na objekty stránky Entry . Slouží Style k zobrazení modrého textu na žlutém pozadí a zároveň k nastavení dalších možností vzhledu. Přidá Style se do stránky ResourceDictionary bez zadání atributu x:Key . Style Proto se použije na všechny Entry objekty implicitně, protože odpovídají TargetType vlastnosti Style přesně. Na objekt se Style však nepoužije CustomEntry , což je podtřída Entry. Kromě toho čtvrtý Entry přepisuje BackgroundColor a TextColor vlastnosti stylu na různé Color hodnoty.

Použití stylu u odvozených typů

Vlastnost Style.ApplyToDerivedTypes umožňuje použít styl na ovládací prvky, které jsou odvozeny od základního typu odkazovaného vlastností TargetType . Proto nastavením této vlastnosti true povolíte jeden styl cílit na více typů za předpokladu, že typy jsou odvozeny od základního typu zadaného ve TargetType vlastnosti.

Následující příklad ukazuje implicitní styl, který nastaví barvu Button pozadí instancí na červenou:

<Style TargetType="Button"
       ApplyToDerivedTypes="True">
    <Setter Property="BackgroundColor"
            Value="Red" />
</Style>

Umístění tohoto stylu na úrovni ResourceDictionary stránky způsobí, že se použije pro všechny objekty na stránce a také u všech Button ovládacích prvků odvozených z Button. Pokud však ApplyToDerivedTypes vlastnost zůstala bez nastavení, styl by se použil pouze na Button objekty.

Globální styly

Styly je možné definovat globálně tak, že je přidáte do slovníku prostředků aplikace. Tyto styly se pak dají využívat v celé aplikaci a pomáhají vyhnout se duplikaci stylu napříč stránkami a ovládacími prvky.

Následující příklad ukazuje Style definovaný na úrovni aplikace:


<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>

V tomto příkladu ResourceDictionary definuje jeden explicitní styl, buttonStylekterý se použije k nastavení vzhledu Button objektů.

Poznámka

Globální styly můžou být explicitní nebo implicitní.

Následující příklad ukazuje stránku, která využívá buttonStyle objekty stránky 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>

Dědičnost stylu

Styly můžou dědit z jiných stylů, aby se snížila duplicita a povolilo opakované použití. Toho dosáhnete nastavením Style.BasedOn vlastnosti na existující Style. V JAZYCE XAML toho lze dosáhnout nastavením BasedOn vlastnosti na StaticResource rozšíření značek, které odkazuje na dříve vytvořené Style.

Styly, které dědí ze základního stylu, můžou zahrnovat Setter instance pro nové vlastnosti nebo je použít k přepsání setter ze základního stylu. Kromě toho styly, které dědí ze základního stylu, musí cílit na stejný typ nebo typ, který je odvozen od typu, na který cílí základní styl. Pokud například základní styl cílí View na objekty, styly založené na základním stylu mohou cílit na View objekty nebo typy odvozené z View třídy, jako Label jsou a Button objekty.

Styl může dědit pouze ze stylů na stejné úrovni nebo vyšší v hierarchii zobrazení. To znamená, že:

  • Styl na úrovni aplikace může dědit pouze z jiných stylů na úrovni aplikace.
  • Styl na úrovni stránky může dědit ze stylů na úrovni aplikace a dalších stylů na úrovni stránky.
  • Styl na úrovni ovládacího prvku může dědit ze stylů na úrovni aplikace, stylů na úrovni stránek a dalších stylů na úrovni ovládacího prvku.

Následující příklad ukazuje explicitní dědičnost 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>

V tomto příkladu baseStyle cílí View objekty a nastaví vlastnosti HorizontalOptions a VerticalOptions vlastnosti. Není baseStyle nastaven přímo u žádných ovládacích prvků. labelStyle Místo toho zdědíte a buttonStyle nastavíte další hodnoty vlastností s možností vazby. Objekty labelStyle a buttonStyle objekty se pak nastaví na Label a .Button

Důležité

Implicitní styl lze odvodit z explicitního stylu, ale explicitní styl nelze odvodit z implicitního stylu.

Dynamické styly

Styly nereagují na změny vlastností a po dobu trvání aplikace zůstávají beze změny. Například po přiřazení Style elementu vizuálu, pokud některý z Setter objektů změní, odebere nebo přidá nový Setter , změny se na prvek vizuálu nepoužijí. Aplikace však můžou reagovat na změny stylu dynamicky za běhu pomocí dynamických prostředků.

Rozšíření DynamicResource značek je podobné StaticResource rozšíření značek v tom, že obě používají klíč slovníku k načtení hodnoty z ResourceDictionary. I když StaticResource ale provedete vyhledávání s jedním slovníkem, DynamicResource zachová se odkaz na klíč slovníku. Proto pokud je položka slovníku přidružená ke klíči nahrazena, změna se použije u vizuálního prvku. To umožňuje provádět změny stylu modulu runtime v aplikaci.

Následující příklad ukazuje dynamické styly:

<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>

V tomto příkladu objekt používá DynamicResource rozšíření značek k nastavení pojmenovaného StyleblueSearchBarStyle.SearchBar Pak SearchBar může mít Style její definici aktualizovanou v kódu:

Resources["blueSearchBarStyle"] = Resources["greenSearchBarStyle"];

V tomto příkladu blueSearchBarStyle se definice aktualizuje tak, aby používala hodnoty z greenSearchBarStyle definice. Při spuštění tohoto kódu se aktualizuje tak, SearchBar aby používal Setter objekty definované v greenSearchBarStyle.

Dynamická dědičnost stylu

Odvození stylu z dynamického stylu nelze dosáhnout pomocí Style.BasedOn vlastnosti. Style Místo toho třída obsahuje BaseResourceKey vlastnost, která může být nastavena na klíč slovníku, jehož hodnota může dynamicky změnit.

Následující příklad ukazuje dědičnost dynamického stylu:

<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>

V tomto příkladu SearchBar objekt používá StaticResource rozšíření značek k odkazování na pojmenovanou StyletealSearchBarStyle. Tím Style se nastaví některé další vlastnosti a vlastnost použije BaseResourceKey k odkaz na blueSearchBarStyle. Rozšíření DynamicResource značek není povinné, protože tealSearchBarStyle se nezmění, s výjimkou Style odvozených z nich. tealSearchBarStyle Proto udržuje odkaz na blueSearchBarStyle a aktualizuje se, když se změní základní styl.

Definici blueSearchBarStyle je možné aktualizovat v kódu:

Resources["blueSearchBarStyle"] = Resources["greenSearchBarStyle"];

V tomto příkladu blueSearchBarStyle se definice aktualizuje tak, aby používala hodnoty z greenSearchBarStyle definice. Při spuštění tohoto kódu se aktualizuje tak, SearchBar aby používal Setter objekty definované v greenSearchBarStyle.

Třídy stylů

Třídy stylů umožňují použití více stylů u ovládacího prvku, aniž by se uchýlily k dědičnosti stylů.

Třídu stylu lze vytvořit nastavením Class vlastnosti na Style hodnotu string , která představuje název třídy. Výhodou této nabídky je definování explicitního stylu pomocí atributu x:Key , že na určitou VisualElementtřídu stylů lze použít více tříd stylů .

Důležité

Více stylů může sdílet stejný název třídy za předpokladu, že cílí na různé typy. To umožňuje více tříd stylů, které jsou identicky pojmenované, pro cílení na různé typy.

Následující příklad ukazuje tři BoxView třídy stylů a VisualElement třídu 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>

V tomto příkladu Separatortřídy , a RoundedCircle styl každé set BoxView vlastnosti na konkrétní hodnoty. Třída Rotated stylu má možnost TargetTypeVisualElement, což znamená, že lze použít pouze u VisualElement instancí. Jeho ApplyToDerivedTypes vlastnost je však nastavena na true, což zajišťuje, že lze použít na všechny ovládací prvky odvozené z VisualElement, například BoxView. Další informace o použití stylu u odvozeného typu naleznete v tématu Použití stylu u odvozených typů.

Třídy stylů lze využívat nastavením StyleClass vlastnosti ovládacího prvku, který je typu IList<string>, na seznam názvů tříd stylů. Třídy stylů se použijí za předpokladu, že typ ovládacího prvku odpovídá TargetType třídám stylu.

Následující příklad ukazuje tři BoxView instance, z nichž každá je nastavená na různé třídy stylů:

<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>    

V tomto příkladu je první BoxView stylován tak, aby byl oddělovač čar, zatímco třetí BoxView je kruhový. BoxView Druhá má dvě třídy stylu použité na něj, které dávají zaokrouhlené rohy a otočit ho o 45 stupňů:

Screenshot of BoxViews styled with style classes.

Důležité

U ovládacího prvku lze použít více tříd stylu, protože StyleClass vlastnost je typu IList<string>. V takovém případě se třídy stylů použijí ve vzestupném pořadí seznamu. Pokud tedy více tříd stylů nastaví stejné vlastnosti, bude mít přednost vlastnost ve třídě stylu, která je v nejvyšší pozici seznamu.