Udostępnij przez


Style w XAML

Wygląd aplikacji można dostosować na wiele sposobów przy użyciu platformy XAML. Style umożliwiają ustawianie właściwości kontrolki i ponowne używanie tych ustawień w celu zapewnienia spójnego wyglądu w wielu kontrolkach.

WinUI i style

Począwszy od winUI 2.2, użyliśmy interfejsu WinUI do dostarczania nowych aktualizacji stylu wizualizacji w naszych składnikach interfejsu użytkownika. Jeśli zauważysz, że interfejs użytkownika nie jest aktualizowany do najnowszych stylów, pamiętaj o aktualizacji do najnowszego pakietu NuGet WinUI.

Począwszy od wersji WinUI 2.6, udostępniamy nowe style dla większości kontrolek oraz nowy system wersjonowania, który pozwala w razie potrzeby powrócić do poprzednich stylów kontrolek. Zachęcamy do używania nowych stylów, ponieważ lepiej pasują do kierunku projektowania systemu Windows. Jeśli jednak twój scenariusz nie może obsługiwać nowych stylów, poprzednie wersje są nadal dostępne.

Możesz zmienić wersję stylu, ustawiając właściwość ControlsResourcesVersion na elemencie XamlControlsResources, który włączasz w Application.Resources podczas korzystania z WinUI w wersji 2. ControlsResourcesVersion jest ustawiony domyślnie na wartość wyliczenia Version2.

Ustawienie tej wartości na Version1 powoduje, że XamlControlsResources ładuje poprzednie wersje stylów zamiast nowych stylów używanych przez najnowszą wersję WinUI. Zmiana tej właściwości w czasie wykonywania nie jest obsługiwana, a funkcja ponownego ładowania programu VisualStudio nie będzie działać; jednak po odbudowaniu aplikacji zobaczysz zmianę stylów kontrolek.

<Application.Resources>
    <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" 
                           ControlsResourcesVersion="Version1"/>
</Application.Resources>

Podstawy stylu

Użyj stylów, aby wyodrębnić ustawienia właściwości wizualizacji do zasobów wielokrotnego użytku. Oto przykład pokazujący 3 przyciski ze stylem, który ustawia właściwości BorderBrush, BorderThickness i Foreground . Stosując styl, możesz ustawić, aby kontrolki były takie same bez konieczności oddzielnego ustawiania tych właściwości dla każdej kontrolki.

Zrzut ekranu przedstawiający trzy stylowe przyciski ułożone obok siebie.

Styl można zdefiniować bezpośrednio w kodzie XAML dla kontrolki lub jako zasób do ponownego użycia. Zdefiniuj zasoby w pliku XAML pojedynczej strony w pliku App.xaml lub w osobnym pliku XAML słownika zasobów. Plik XAML słownika zasobów może być współdzielony między aplikacjami, a w jednej aplikacji można połączyć więcej niż jeden słownik zasobów. Gdy zasób jest zdefiniowany, określa zakres, w którym można go użyć. Zasoby na poziomie strony są dostępne tylko na stronie, na której są zdefiniowane. Jeśli zasoby z tym samym kluczem są zdefiniowane zarówno w pliku App.xaml, jak i na stronie, zasób na stronie zastępuje zasób w pliku App.xaml. Jeśli zasób jest zdefiniowany w osobnym pliku słownika zasobów, jego zakres jest określany przez miejsce, do którego odwołuje się słownik zasobów.

W definicji stylu potrzebny jest atrybut TargetType oraz kolekcja co najmniej jednego elementu Setter. Atrybut TargetType jest ciągiem określającym typ FrameworkElement , do którego ma być stosowany styl. Wartość TargetType musi określać typ pochodny FrameworkElementzdefiniowany przez środowisko uruchomieniowe systemu Windows lub dostępny typ niestandardowy w zestawie referencyjnym. Jeśli spróbujesz zastosować styl do kontrolki, a typ kontrolki nie jest zgodny z atrybutem TargetType stylu, który próbujesz zastosować, wystąpi wyjątek.

Każdy element Setter wymaga właściwości i wartości. Te ustawienia właściwości wskazują, do której właściwości kontrolki ma zastosowanie ustawienie, oraz wartość ustawioną dla tej właściwości. Można ustawić Setter.Value za pomocą składni atrybutu lub elementu właściwości. W tym miejscu kod XAML przedstawia styl zastosowany do przedstawionych wcześniej przycisków. W tym języku XAML dwa pierwsze elementy Setter używają składni atrybutów, ale ostatnia Setterdla właściwości BorderBrush używa składni elementu właściwości. W przykładzie nie jest używany atrybut x:Key, więc styl jest stosowany do przycisków w sposób niejawny. Stosowanie stylów niejawnie lub jawnie zostało wyjaśnione w następnej sekcji.

<Page.Resources>
    <Style TargetType="Button">
        <Setter Property="BorderThickness" Value="5" />
        <Setter Property="Foreground" Value="Black" />
        <Setter Property="BorderBrush" >
            <Setter.Value>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Yellow" Offset="0.0" />
                    <GradientStop Color="Red" Offset="0.25" />
                    <GradientStop Color="Blue" Offset="0.75" />
                    <GradientStop Color="LimeGreen" Offset="1.0" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
    </Style>
</Page.Resources>

<StackPanel Orientation="Horizontal">
    <Button Content="Button"/>
    <Button Content="Button"/>
    <Button Content="Button"/>
</StackPanel>

Stosowanie niejawnego lub jawnego stylu

Jeśli zdefiniujesz styl jako zasób, istnieją dwa sposoby zastosowania go do kontrolek:

  • Niejawnie, poprzez określenie tylko TargetType dla stylu .
  • Jawnie, określając TargetType i atrybut x:Key atrybutu dla stylu , a następnie ustawiając właściwość Style kontrolki docelowej z rozszerzeniem znaczników {StaticResource} odwołanie, które używa jawnego klucza.

Jeśli styl zawiera atrybut x:Key, można zastosować go tylko do kontrolki, ustawiając właściwość Style kontrolki na styl z kluczem. Natomiast styl bez atrybutu x:Key jest automatycznie stosowany do każdej kontrolki typu docelowego, która w przeciwnym razie nie ma jawnego ustawienia stylu.

Poniżej przedstawiono dwa przyciski, które demonstrują niejawne i jawne style.

niejawnie i jawnie stylizowane przyciski.

W tym przykładzie pierwszy styl ma atrybut x:Key, a jego typ docelowy to Przycisk. Właściwość stylu pierwszego przycisku jest ustawiona na ten klucz, dlatego styl jest zastosowany jawnie. Drugi styl jest stosowany niejawnie do drugiego przycisku, ponieważ jego typ docelowy to Przycisk , a styl nie ma atrybutu x:Key.

<Page.Resources>
    <Style x:Key="PurpleStyle" TargetType="Button">
        <Setter Property="FontFamily" Value="Segoe UI"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="Foreground" Value="Purple"/>
    </Style>

    <Style TargetType="Button">
        <Setter Property="FontFamily" Value="Segoe UI"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="RenderTransform">
            <Setter.Value>
                <RotateTransform Angle="25"/>
            </Setter.Value>
        </Setter>
        <Setter Property="BorderBrush" Value="Green"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="Foreground" Value="Green"/>
    </Style>
</Page.Resources>

<Grid x:Name="LayoutRoot">
    <Button Content="Button" Style="{StaticResource PurpleStyle}"/>
    <Button Content="Button"/>
</Grid>

Używanie stylów bazowych

Aby ułatwić zachowanie stylów i optymalizowanie ponownego użycia stylu, można utworzyć style dziedziczone z innych stylów. Użyj właściwości BasedOn , aby utworzyć dziedziczone style. Styl dziedziczony z innych stylów musi być przeznaczony dla tego samego typu kontrolki lub kontrolki, która wywodzi się z typu wyznaczonego przez styl podstawowy. Jeśli na przykład styl podstawowy dotyczy kontrolki ContentControl, style oparte na tym stylu mogą dotyczyć kontrolki ContentControl lub typów, które wywodzą się z kontrolki ContentControl, takich jak Button i ScrollViewer. Jeśli wartość nie jest ustawiona w stylu, na którym jest oparty, jest odziedziczona ze stylu podstawowego. Aby zmienić wartość stylu podstawowego, styl oparty na nim nadpisuje tę wartość. W następnym przykładzie przedstawiono przyciski Button i CheckBox ze stylami dziedziczącymi z tego samego stylu bazowego.

stylizowane przyciski usign oparte na stylach.

Styl podstawowy jest stosowany do ContentControl, i ustawia właściwości Heighti Width. Style oparte na tym stylu to CheckBox i Button, które pochodzą z ContentControl. Style oparte na ustawieniu różnych kolorów dla właściwości BorderBrush i Foreground. (Zwykle nie umieszczasz obramowania wokół pola wyboru. Robimy to tutaj, aby pokazać efekty stylu.

<Page.Resources>
    <Style x:Key="BasicStyle" TargetType="ContentControl">
        <Setter Property="Width" Value="130" />
        <Setter Property="Height" Value="30" />
    </Style>

    <Style x:Key="ButtonStyle" TargetType="Button"
           BasedOn="{StaticResource BasicStyle}">
        <Setter Property="BorderBrush" Value="Orange" />
        <Setter Property="BorderThickness" Value="2" />
        <Setter Property="Foreground" Value="Red" />
    </Style>

    <Style x:Key="CheckBoxStyle" TargetType="CheckBox"
           BasedOn="{StaticResource BasicStyle}">
        <Setter Property="BorderBrush" Value="Blue" />
        <Setter Property="BorderThickness" Value="2" />
        <Setter Property="Foreground" Value="Green" />
    </Style>
</Page.Resources>

<StackPanel>
    <Button Content="Button" Style="{StaticResource ButtonStyle}" Margin="0,10"/>
    <CheckBox Content="CheckBox" Style="{StaticResource CheckBoxStyle}"/>
</StackPanel>

Łatwe korzystanie z narzędzi do pracy ze stylami

Szybkim sposobem stosowania stylów do kontrolek jest kliknięcie prawym przyciskiem myszy kontrolki na powierzchni projektowej XAML programu Microsoft Visual Studio i wybranie pozycji Edytuj styl lub Edytuj szablon (w zależności od kontrolki, którą klikasz prawym przyciskiem myszy). Następnie możesz zastosować istniejący styl, wybierając opcję Zastosuj zasób, lub zdefiniować nowy styl, wybierając opcję Utwórz pusty. Jeśli tworzysz pusty styl, możesz zdefiniować go na stronie, w pliku App.xaml lub w osobnym słowniku zasobów.

Lekka stylizacja

Zastępowanie pędzli systemowych zazwyczaj odbywa się na poziomie aplikacji albo strony. W każdym przypadku zmiana koloru wpłynie na wszystkie kontrolki, które odwołują się do tego pędzla, ponieważ w XAML wiele kontrolek może korzystać z tego samego pędzla systemowego.

Zrzut ekranu przedstawiający dwa przyciski: jeden w stanie spoczynku i jeden z uproszczonym zastosowanym stylem.

<Page.Resources>
    <ResourceDictionary>
        <ResourceDictionary.ThemeDictionaries>
            <ResourceDictionary x:Key="Light">
                 <SolidColorBrush x:Key="ButtonBackground" Color="Transparent"/>
                 <SolidColorBrush x:Key="ButtonForeground" Color="MediumSlateBlue"/>
                 <SolidColorBrush x:Key="ButtonBorderBrush" Color="MediumSlateBlue"/>
            </ResourceDictionary>
        </ResourceDictionary.ThemeDictionaries>
    </ResourceDictionary>
</Page.Resources>

W przypadku stanów, takich jak PointerOver (wskaźnik znajduje się nad przyciskiem), PointerPressed (przycisk został wywołany), lub Disabled (przycisk jest nieaktywny). Te zakończenia są dołączane do oryginalnych nazw stylów Lightweight: ButtonBackgroundPointerOver, ButtonForegroundPressed, ButtonBorderBrushDisableditp. Zmodyfikowanie tych pędzli zapewni również spójne kolorowanie kontrolek motywu aplikacji.

Umieszczenie tych przesłonięć pędzla na poziomie App.Resources spowoduje zmianę wszystkich przycisków w całej aplikacji, a nie na jednej stronie.

Styl poszczególnych kontrolek

W innych przypadkach zmiana pojedynczej kontrolki na jednej stronie tylko tak, aby wyglądała w określony sposób, bez zmiany innych wersji tej kontrolki, jest wymagana:

Zrzut ekranu przedstawiający trzy stylowe przyciski ułożone jeden na drugim.

<CheckBox Content="Normal CheckBox" Margin="5"/>
<CheckBox Content="Special CheckBox" Margin="5">
    <CheckBox.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary x:Key="Light">
                    <SolidColorBrush x:Key="CheckBoxForegroundUnchecked"
                        Color="Purple"/>
                    <SolidColorBrush x:Key="CheckBoxForegroundChecked"
                        Color="Purple"/>
                    <SolidColorBrush x:Key="CheckBoxCheckGlyphForegroundChecked"
                        Color="White"/>
                    <SolidColorBrush x:Key="CheckBoxCheckBackgroundStrokeChecked"  
                        Color="Purple"/>
                    <SolidColorBrush x:Key="CheckBoxCheckBackgroundFillChecked"
                        Color="Purple"/>
                </ResourceDictionary>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </CheckBox.Resources>
</CheckBox>
<CheckBox Content="Normal CheckBox" Margin="5"/>

Miałoby to wpływ tylko na ten "Specjalny CheckBox" na stronie, gdzie znajduje się ta kontrolka.

Kontrolki niestandardowe

Podczas tworzenia własnych kontrolek niestandardowych, które mogą być wizualnie i/lub funkcjonalnie dopasowane do naszych wbudowanych kontrolek, rozważ użycie niejawnych stylów i lekkich zasobów stylizacji, aby zdefiniować własną zawartość. Możesz użyć zasobów bezpośrednio lub utworzyć nowy alias dla zasobu.

Bezpośrednie używanie zasobów sterujących

Jeśli na przykład piszesz kontrolkę, która wygląda jak przycisk, możesz bezpośrednio odwołać się do zasobów przycisku, w następujący sposób:

<Style TargetType="local:MyCustomControl">
  <Setter Property="Background" Value="{ThemeResource ButtonBackground}" />
  <Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}" />
</Style>

Aliasowanie zasobów do nowych nazw

Alternatywnie, jeśli wolisz tworzyć własne zasoby, należy aliasować te nazwy niestandardowe do domyślnych zasobów styli uproszczonej.

Na przykład styl kontrolki niestandardowej może mieć specjalne definicje zasobów:

<Style TargetType="local:MyCustomControl">
  <Setter Property="Background" Value="{ThemeResource MyCustomControlBackground}" />
  <Setter Property="BorderBrush" Value="{ThemeResource MyCustomControlBorderBrush}"/>
</Style>

W słowniku zasobów lub w definicji głównej można podłączyć uproszczone zasoby stylistyczne do niestandardowych:

<ResourceDictionary.ThemeDictionaries>
    <ResourceDictionary x:Key="Default">
        <StaticResource x:Key="MyCustomControlBackground" ResourceKey="ButtonBackground" />
        <StaticResource x:Key="MyCustomControlBorderBrush" ResourceKey="ButtonBorderBrush" />
    </ResourceDictionary>        
    <ResourceDictionary x:Key="Light">
        <StaticResource x:Key="MyCustomControlBackground" ResourceKey="ButtonBackground" />
        <StaticResource x:Key="MyCustomControlBorderBrush" ResourceKey="ButtonBorderBrush" />
    </ResourceDictionary>
    <ResourceDictionary x:Key="HighContrast">
        <StaticResource x:Key="MyCustomControlBackground" ResourceKey="ButtonBackground" />
        <StaticResource x:Key="MyCustomControlBorderBrush" ResourceKey="ButtonBorderBrush" />
    </ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>

Wymagane jest użycie elementu ThemeDictionary , który jest zduplikowany trzy razy w celu prawidłowego obsługi trzech różnych zmian motywu (Default, Light, HighContrast).

Ostrzeżenie

Jeśli przypiszesz zasób uproszczonego stylu do nowego aliasu, a także ponownie zdefiniuj zasób uproszczonego stylu, dostosowanie może nie zostać zastosowane, jeśli wyszukiwanie zasobów nie jest w prawidłowej kolejności. Na przykład, jeśli przesłonisz ButtonBackground w miejscu, które jest sprawdzane przed znalezieniem MyCustomControlBackground, to przesłonięcie zostanie pominięte.

Unikaj zmiany stylu elementów sterujących

Interfejs WinUI 2.2 lub nowszy zawiera nowe style i szablony dla kontrolek WinUI i systemowych.

Najlepszym sposobem, aby zachować aktualną wersję naszych najnowszych stylów wizualnych, jest użycie najnowszego pakietu WinUI 2 i uniknięcie niestandardowych stylów i szablonów (nazywanych również ponownym tworzeniem szablonów). Style są nadal wygodnym sposobem spójnego stosowania zestawu wartości między kontrolkami w aplikacji. W tym celu pamiętaj, aby opierać się na naszych najnowszych stylach.

W przypadku kontrolek systemowych używających stylów WinUI (przestrzeń nazwWindows.UI.Xaml.Controls) ustaw BasedOn="{StaticResource Default<ControlName>Style}", gdzie <ControlName> jest nazwą kontrolki. Przykład:

<Style TargetType="TextBox" BasedOn="{StaticResource DefaultTextBoxStyle}">
    <Setter Property="Foreground" Value="Blue"/>
</Style>

W przypadku kontrolek WinUI 2 (Microsoft.UI.Xaml.Controls przestrzeń nazw) domyślny styl jest definiowany w metadanych, więc pomijaj BasedOn.

Kontrolki pochodne

Jeśli utworzysz niestandardową kontrolkę z istniejącej kontrolki XAML, nie uzyska domyślnie stylów WinUI 2. Aby zastosować style WinUI 2:

  • Utwórz nowy Style z TargetType ustawionym na kontrolkę niestandardową.
  • Oprzyj styl na domyślnym stylu kontrolki, z której pochodzi.

Jednym z typowych scenariuszy jest utworzenie nowej kontrolki z biblioteki ContentDialog. W tym przykładzie pokazano, jak utworzyć nowy styl, który stosuje DefaultContentDialogStyle do niestandardowego okna dialogowego.

<ContentDialog
    x:Class="ExampleApp.SignInContentDialog"
    ... >

    <ContentDialog.Resources>
        <Style TargetType="local:SignInContentDialog" BasedOn="{StaticResource DefaultContentDialogStyle}"/>
        ...
    </ContentDialog.Resources> 
    <!-- CONTENT -->
</ContentDialog>        

Właściwość szablonu

Ustawiacz stylów może być użyty dla właściwości Template kontrolki , a w rzeczywistości stanowi to większość typowego stylu XAML i zasobów XAML aplikacji. Omówiono to bardziej szczegółowo w temacie Szablony sterowania.