Megosztás a következőn keresztül:


Mik azok a stílusok és sablonok?

A Windows Presentation Foundation (WPF) stílusa és templatingja olyan funkciókra hivatkozik, amelyek lehetővé teszik a fejlesztőknek és tervezőknek, hogy vizuálisan lenyűgöző effektusokat és egységes megjelenést hozzanak létre a termékükhöz. Egy alkalmazás megjelenésének testreszabásakor erős stílus- és sablonozási modellt szeretne, amely lehetővé teszi a megjelenés karbantartását és megosztását az alkalmazásokon belül és közöttük. A WPF biztosítja ezt a modellt.

A WPF-stílusmodell másik funkciója a megjelenítés és a logika elkülönítése. A tervezők csak az XAML használatával dolgozhatnak az alkalmazások megjelenésén, ugyanakkor, amikor a fejlesztők a C# vagy a Visual Basic használatával dolgoznak a programozási logikán.

Ez az áttekintés az alkalmazás stílusára és sablonozására összpontosít, és nem tárgyalja az adatkötési fogalmakat. További információ az adatkötésről: Adatkötés áttekintése.

Fontos megérteni az erőforrásokat, amelyek lehetővé teszik a stílusok és sablonok újrafelhasználását. Az erőforrásokról további információt az XAML-erőforrások áttekintésében talál.

Minta

Az áttekintésben megadott mintakód egy egyszerű fényképböngésző alkalmazáson alapul, az alábbi ábrán látható.

Styled ListView

Ez az egyszerű fényképminta stílust és sablonozást használ a vizuálisan lenyűgöző felhasználói élmény teremtésére. A minta két TextBlock elemet és egy ListBox vezérlőelemet tartalmaz, amelyek a képek listájához vannak kötve.

A teljes mintáért lásd a Bevezetés a stílusokhoz és a sablonmintákhoz című részt.

Stílusok

A Style-t úgy tekintheti, mint egy kényelmes módot, amellyel a tulajdonságértékek egy készletét több elemre alkalmazhatja. Bármilyen olyan elemhez használhat stílust, amely a FrameworkElement-ból vagy a FrameworkContentElement-ből származik, például Window vagy Button.

A stílus deklarálása leggyakrabban erőforrásként történik egy XAML-fájl Resources szakaszában. Mivel a stílusok erőforrások, ugyanazokat a hatókörkezelési szabályokat tartják be, amelyek az összes erőforrásra vonatkoznak. Egyszerűen fogalmazva, ahol deklarál egy stílust, az befolyásolja, hogy hol alkalmazható a stílus. Ha például az alkalmazásdefiníció XAML-fájljának gyökérelemében deklarálja a stílust, a stílus bárhol használható az alkalmazásban.

A következő XAML-kód például két stílust deklarál egy TextBlock, az egyik automatikusan alkalmazva van az összes TextBlock elemre, a másikra pedig kifejezetten hivatkozni kell.

<Window.Resources>
    <!-- .... other resources .... -->

    <!--A Style that affects all TextBlocks-->
    <Style TargetType="TextBlock">
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="FontFamily" Value="Comic Sans MS"/>
        <Setter Property="FontSize" Value="14"/>
    </Style>
    
    <!--A Style that extends the previous TextBlock Style with an x:Key of TitleText-->
    <Style BasedOn="{StaticResource {x:Type TextBlock}}"
           TargetType="TextBlock"
           x:Key="TitleText">
        <Setter Property="FontSize" Value="26"/>
        <Setter Property="Foreground">
            <Setter.Value>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Offset="0.0" Color="#90DDDD" />
                        <GradientStop Offset="1.0" Color="#5BFFFF" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

Íme egy példa a fent deklarált stílusok használatára.

<StackPanel>
    <TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
    <TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>

Stílusos szövegblokkok

További információ: Stílus létrehozása vezérlőelemekhez.

ControlTemplates

A WPF-ben a ControlTemplate egy vezérlő megjelenését határozza meg. A vezérlők szerkezetét és megjelenését egy új ControlTemplate definiálásával és vezérlőelemhez való hozzárendelésével módosíthatja. A sablonok sok esetben elegendő rugalmasságot biztosítanak, hogy ne kelljen saját egyéni vezérlőket írnia.

Minden vezérlőhöz tartozik egy alapértelmezett sablon a Control.Template tulajdonsághoz. A sablon összekapcsolja a vezérlő vizuális megjelenítését a vezérlő képességeivel. Mivel az XAML-ben definiál egy sablont, kód írása nélkül módosíthatja a vezérlő megjelenését. Mindegyik sablon egy adott vezérlőhöz készült, például egy Button-hoz.

Gyakran deklarál egy sablont erőforrásként egy XAML-fájl Resources szakaszában. Mint minden erőforrás esetében, a hatókörkezelési szabályok is érvényesek.

A vezérlősablonok sokkal több szerepet játszanak, mint a stílusok. Ennek az az oka, hogy a vezérlősablon átírja a teljes vezérlő vizuális megjelenését, míg egy stílus egyszerűen alkalmazza a tulajdonságmódosításokat a meglévő vezérlőre. Mivel azonban a vezérlő sablonja a Control.Template tulajdonság beállításával van alkalmazva, stílus használatával definiálhat vagy állíthat be sablont.

A tervezők általában lehetővé teszik egy meglévő sablon másolatának létrehozását és módosítását. A Visual Studio WPF tervezőjében például válasszon egy CheckBox vezérlőelemet, majd kattintson a jobb gombbal, és válassza Sablon szerkesztése>Másolat létrehozásalehetőséget. Ez a parancs létrehoz egy stílust, amely meghatározza a sablon.

<Style x:Key="CheckBoxStyle1" TargetType="{x:Type CheckBox}">
    <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual1}"/>
    <Setter Property="Background" Value="{StaticResource OptionMark.Static.Background1}"/>
    <Setter Property="BorderBrush" Value="{StaticResource OptionMark.Static.Border1}"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type CheckBox}">
                <Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Border x:Name="checkBoxBorder" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                        <Grid x:Name="markGrid">
                            <Path x:Name="optionMark" Data="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z " Fill="{StaticResource OptionMark.Static.Glyph1}" Margin="1" Opacity="0" Stretch="None"/>
                            <Rectangle x:Name="indeterminateMark" Fill="{StaticResource OptionMark.Static.Glyph1}" Margin="2" Opacity="0"/>
                        </Grid>
                    </Border>
                    <ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="HasContent" Value="true">
                        <Setter Property="FocusVisualStyle" Value="{StaticResource OptionMarkFocusVisual1}"/>
                        <Setter Property="Padding" Value="4,-1,0,0"/>

... content removed to save space ...

A sablonok másolatának szerkesztésével megtudhatja, hogyan működnek a sablonok. Új üres sablon létrehozása helyett egyszerűbb szerkeszteni egy másolatot, és módosítani a vizualizáció néhány aspektusát.

Lásd példaként: Sablon létrehozása vezérlő.

Sablonkötés

Észrevehette, hogy az előző szakaszban definiált sablonerőforrás a TemplateBinding Markup bővítménythasználja. A TemplateBinding egy optimalizált formája a sablonforgatókönyvekhez készült kötéseknek, amely hasonló a {Binding RelativeSource={RelativeSource TemplatedParent}}használatával készült kötéshez. TemplateBinding akkor hasznos, ha a sablon egyes részeit a vezérlő tulajdonságaihoz köti. Például minden vezérlő rendelkezik egy BorderThickness tulajdonságot. Egy TemplateBinding segítségével kezelheti, hogy a sablon mely elemére van hatással ez a vezérlőbeállítás.

ContentControl és ItemsControl

Ha egy ContentPresenter a ControlTemplate-en belül egy ContentControl-ben van deklarálva, akkor a ContentPresenter automatikusan kapcsolódik a ContentTemplate és a Content tulajdonságokhoz. Hasonlóképpen, egy ItemsPresenterControlTemplate található ItemsControl automatikusan kötődik a ItemTemplate és Items tulajdonságokhoz.

Adatsablonok

Ebben a mintaalkalmazásban van egy ListBox vezérlő, amely a fényképek listájához van kötve.

<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
         Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>

Ez a ListBox jelenleg a következőképpen néz ki.

ListBox sablon alkalmazása előtt

A legtöbb vezérlő rendelkezik valamilyen tartalomtípussal, és ez a tartalom gyakran olyan adatokból származik, amelyekhez kötéssel rendelkezik. Ebben a mintában az adatsor a fényképek listája. WPF-ben a DataTemplate segítségével határozzuk meg az adatok vizuális megjelenítését. Alapvetően az határozza meg, hogy az adatok hogyan néznek ki a renderelt alkalmazásban, hogy mit teszel bele a DataTemplate-ba.

A mintaalkalmazásban minden egyéni Photo objektum rendelkezik egy Source típusú sztringgel, amely meghatározza a kép fájlútvonalát. A fényképobjektumok jelenleg fájlútvonalakként jelennek meg.

public class Photo
{
    public Photo(string path)
    {
        Source = path;
    }

    public string Source { get; }

    public override string ToString() => Source;
}
Public Class Photo
    Sub New(ByVal path As String)
        Source = path
    End Sub

    Public ReadOnly Property Source As String

    Public Overrides Function ToString() As String
        Return Source
    End Function
End Class

Ahhoz, hogy a fényképek képekként jelenjenek meg, egy DataTemplate kell létrehoznia erőforrásként.

<Window.Resources>
    <!-- .... other resources .... -->

    <!--DataTemplate to display Photos as images
    instead of text strings of Paths-->
    <DataTemplate DataType="{x:Type local:Photo}">
        <Border Margin="3">
            <Image Source="{Binding Source}"/>
        </Border>
    </DataTemplate>
</Window.Resources>

Figyelje meg, hogy a DataType tulajdonság hasonló a TargetTypeStyle tulajdonságához. Ha a DataTemplate az erőforrások szakaszban található, és megadja a DataType tulajdonságot egy típushoz, de kihagy egy x:Key-t, a DataTemplate alkalmazásra kerül, valahányszor ez a típus megjelenik. Mindig lehetősége van arra, hogy a DataTemplate-t hozzárendelje egy x:Key-hez, majd StaticResource-ként állítsa be olyan tulajdonságokhoz, amelyek DataTemplate típusokat vesznek fel, mint például a ItemTemplate tulajdonság vagy a ContentTemplate tulajdonság.

Lényegében a fenti példában szereplő DataTemplate meghatározza, hogy amikor van egy Photo objektum, az Image-ként jelenik meg egy Border-on belül. Ezzel a DataTemplatemostantól így néz ki az alkalmazás.

Fénykép képe

Az adat sablon modell más funkciókat is kínál. Például, ha olyan gyűjteményadatokat jelenít meg, amelyek más gyűjteményeket tartalmaznak, mint például egy HeaderedItemsControl típus, amely Menu-et vagy TreeView-t használ, akkor ott van a HierarchicalDataTemplateis. Egy másik adat-sablonozási funkció a DataTemplateSelector, amely lehetővé teszi, hogy egyéni logika alapján egy DataTemplate-et válasszon. További információért lásd a Data Templating Overviewdokumentumot, amely részletesen tárgyalja a különböző adatsablonozási funkciókat.

Kiváltó okok

Az eseményindító beállítja a tulajdonságokat, vagy elindítja a műveleteket, például egy animációt, amikor egy tulajdonság értéke megváltozik, vagy amikor egy esemény létre van hozva. Style, ControlTemplateés DataTemplate mind rendelkeznek Triggers tulajdonságokkal, amelyek eseményindítókat tartalmazhatnak. Az eseményindítóknak számos típusa van.

PropertyTriggers

Az a Trigger, amely tulajdonságértékeket állít be, vagy egy tulajdonság értékén alapuló műveleteket indít el, tulajdonság-eseményindítónak nevezzük.

A tulajdonság-eseményindítók használatának bemutatásához az egyes ListBoxItem részben áttetszővé teheti, kivéve, ha ki van választva. Az alábbi stílus egy OpacityListBoxItem értékét 0.5értékre állítja. Ha azonban a IsSelected tulajdonság true, a Opacity1.0értékre van állítva.

<Window.Resources>
    <!-- .... other resources .... -->

    <Style TargetType="ListBoxItem">
        <Setter Property="Opacity" Value="0.5" />
        <Setter Property="MaxHeight" Value="75" />
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
                <Trigger.Setters>
                    <Setter Property="Opacity" Value="1.0" />
                </Trigger.Setters>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

Ez a példa egy Trigger használ egy tulajdonságérték beállításához, de vegye figyelembe, hogy a Trigger osztály olyan EnterActions és ExitActions tulajdonságokkal is rendelkezik, amelyek lehetővé teszik az eseményindítók számára a műveletek végrehajtását.

Vegye észre, hogy a MaxHeightListBoxItem tulajdonsága 75értékűre van beállítva. Az alábbi ábrán a harmadik elem a kijelölt elem.

Styled ListView

"Eseményindítók és Történetvázlatok"

Az eseményindító másik típusa a EventTrigger, amely egy esemény előfordulása alapján indít el egy műveletkészletet. Az alábbi EventTrigger objektumok például azt határozzák meg, hogy amikor az egérmutató belép a ListBoxItem-be, a MaxHeight tulajdonság 90 értékre animálódik egy 0.2 másodperces időtartam alatt. Amikor az egér elmozdul az elemtől, a tulajdonság egy 1 másodperces időszak alatt visszatér az eredeti értékhez. Vegye figyelembe, hogy nem szükséges To értéket megadni a MouseLeave animációhoz. Ennek az az oka, hogy az animáció képes nyomon követni az eredeti értéket.

<Style.Triggers>
    <Trigger Property="IsSelected" Value="True">
        <Trigger.Setters>
            <Setter Property="Opacity" Value="1.0" />
        </Trigger.Setters>
    </Trigger>
    <EventTrigger RoutedEvent="Mouse.MouseEnter">
        <EventTrigger.Actions>
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation
                        Duration="0:0:0.2"
                        Storyboard.TargetProperty="MaxHeight"
                        To="90"  />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger.Actions>
    </EventTrigger>
    <EventTrigger RoutedEvent="Mouse.MouseLeave">
        <EventTrigger.Actions>
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation
                        Duration="0:0:1"
                        Storyboard.TargetProperty="MaxHeight"  />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger.Actions>
    </EventTrigger>
</Style.Triggers>

További információért lásd a Storyboards áttekintését.

Az alábbi ábrán az egér a harmadik elemre mutat.

Stílusminta képernyőképe

MultiTriggers, DataTriggers és MultiDataTriggers

A Trigger és EventTriggermellett más típusú triggerek is léteznek. MultiTrigger lehetővé teszi a tulajdonságértékek beállítását több feltétel alapján. A DataTrigger és a MultiDataTrigger akkor használja, ha a feltétel tulajdonsága adathoz kötött.

Vizuális állapotok

A vezérlők mindig az adott állapotban vannak . Ha például az egér egy vezérlő felszíne fölé kerül, a vezérlő a MouseOveráltalános állapotának tekinthető. Egy meghatározott állapot nélküli vezérlőelemet a közös Normal állapotban lévőnek tekintünk. Az állapotok csoportokra vannak bontva, és a korábban említett állapotok az állapotcsoport CommonStatesrészét képezik. A legtöbb vezérlő két állapotcsoportból áll: CommonStates és FocusStates. A vezérlőelemre alkalmazott egyes állapotcsoportok közül a vezérlőelemek mindig az egyes csoportok egy-egy állapotában lesznek, például CommonStates.MouseOver és FocusStates.Unfocused. A vezérlőelemek azonban nem lehetnek ugyanabban a csoportban két különböző állapotban, például CommonStates.Normal és CommonStates.Disabled. Íme egy táblázat, amely a legtöbb vezérlő által felismert és használt állapotokat tartalmazza.

Vizualizációs állapot név VisualStateGroup név Leírás
Normal CommonStates Az alapértelmezett állapot.
MouseOver CommonStates Az egérmutató a vezérlő fölé van helyezve.
Pressed CommonStates A vezérlő be van nyomva.
Disabled CommonStates A vezérlő le van tiltva.
Focused FocusStates A vezérlő fókuszban van.
Unfocused FocusStates A vezérlő nincs fókuszban.

Ha egy vezérlősablon gyökérelemén definiál egy System.Windows.VisualStateManager, animációkat indíthat el, amikor egy vezérlő egy adott állapotba lép. A VisualStateManager deklarálja, hogy a VisualStateGroup és a VisualState mely kombinációit kell figyelni. Amikor a vezérlő figyelt állapotba kerül, a VisualStateManager által definiált animáció elindul.

Az alábbi XAML-kód például a CommonStates.MouseOver állapotot figyeli a backgroundElementnevű elem kitöltőszínének animálásához. Amikor a vezérlő visszatér a CommonStates.Normal állapotba, a rendszer visszaállítja a backgroundElement nevű elem kitöltőszínét.

<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="CommonStates">
                <VisualState Name="Normal">
                    <ColorAnimation Storyboard.TargetName="backgroundElement"
                                    Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                    To="{TemplateBinding Background}"
                                    Duration="0:0:0.3"/>
                </VisualState>
                <VisualState Name="MouseOver">
                    <ColorAnimation Storyboard.TargetName="backgroundElement"
                                    Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                    To="Yellow"
                                    Duration="0:0:0.3"/>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        ...

További információ a storyboardokról: Storyboards Overview.

Megosztott erőforrások és témák

Egy tipikus WPF-alkalmazás több felhasználói felületi erőforrással is rendelkezhet, amelyek az alkalmazás egészére vonatkoznak. Együttesen ez az erőforráskészlet tekinthető az alkalmazás témájának. A WPF támogatást nyújt a felhasználói felület erőforrásainak témaként való csomagolásához egy erőforrás-szótár használatával, amely ResourceDictionary osztályként van beágyazva.

A WPF-témákat a WPF által bármely elem vizualizációinak testreszabására szolgáló stílus- és templatálási mechanizmussal lehet definiálni.

A WPF-témaerőforrások beágyazott erőforrás-szótárakban vannak tárolva. Ezeket az erőforrásszótárakat egy aláírt assemblybe kell beágyazni, és ez lehet ugyanaz az assembly, amelyben maga a kód található, vagy egy különálló, párhuzamos assembly. A WPF-vezérlőket tartalmazó szerelvény PresentationFramework.dllesetében a témaerőforrások egymás melletti szerelvények sorozatában találhatók.

A téma lesz az utolsó hely, ahol megkeresi az elem stílusát. A keresés általában azzal kezdődik, hogy felsétál az elemfára, és megkeres egy megfelelő erőforrást, majd megkeresi az alkalmazáserőforrás-gyűjteményt, és végül lekérdezi a rendszert. Ez lehetővé teszi az alkalmazásfejlesztők számára, hogy újradefiniálják bármely objektum stílusát a fa vagy az alkalmazás szintjén, mielőtt elérnék a témát.

Az erőforrásszótárakat egyedi fájlokként is definiálhatja, amelyek lehetővé teszik, hogy több alkalmazásban is újra felhasználhassa a témát. Felcserélhető témákat úgy is létrehozhat, hogy több erőforrásszótárat határoz meg, amelyek ugyanazokat az erőforrástípusokat biztosítják, de különböző értékeket tartalmaznak. Ezeknek a stílusoknak vagy más erőforrásoknak az alkalmazás szintjén történő újradefiniálása az ajánlott módszer egy alkalmazás testreszabásához.

Ha több erőforrást, köztük stílusokat és sablonokat szeretne megosztani az alkalmazások között, létrehozhat egy XAML-fájlt, és meghatározhat egy ResourceDictionary, amely egy shared.xaml fájlra mutató hivatkozást tartalmaz.

<ResourceDictionary.MergedDictionaries>
  <ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>

A shared.xamlmegosztása lehetővé teszi az alkalmazások vezérlőinek egységes megjelenését, mivel maga definiál egy ResourceDictionary-t, amely egy stílus- és ecseterőforrás-készletet tartalmaz.

További információ: Egyesített erőforrás-szótárak.

Ha témát hoz létre az egyéni vezérlőhöz, tekintse meg az Erőforrások definiálása témaszinten szakaszt a Vezérlő készítésének áttekintésecímű dokumentumban.

Lásd még