Stiller ve şablonlar (WPF .NET)

Windows Presentation Foundation (WPF) stil oluşturma ve oluşturma, geliştiricilerin ve tasarımcıların görsel olarak etkileyici etkiler ve ürünleri için tutarlı bir görünüm oluşturmasına izin vermenizi sağlamak için bir özellik paketine başvurur. Bir uygulamanın görünümünü özelleştirerek uygulamaların içinde ve arasında görünümün bakımını ve paylaşımını sağlayan güçlü bir stil ve templating modeline sahip olmak istersiniz. WPF bu modeli sağlar.

WPF stil modelinin bir diğer özelliği de sunum ve mantık ayrımıdır. Tasarımcılar, geliştiricilerin C# veya Visual Basic kullanarak programlama mantığı üzerinde çalışmasına ek olarak yalnızca XAML kullanarak bir uygulamanın görünümü üzerinde Visual Basic.

Bu genel bakış, uygulamanın stil ve templating yönlerine odaklanır ve veri bağlama kavramlarını açıklamaz. Veri bağlama hakkında bilgi için bkz. Veri Bağlamaya Genel Bakış.

Stillerin ve şablonların yeniden kullanılmasına olanak sağlayan kaynakları anlamak önemlidir. Kaynaklar hakkında daha fazla bilgi için bkz. XAML kaynaklarına genel bakış.

Önemli

.NET 6 ve .NET 5 için Masaüstü Kılavuzu belgeleri (.NET Core 3.1 dahil) hazır aşamasındadır.

Örnek

Bu genel bakışta sağlanan örnek kod, aşağıdaki çizimde gösterilen basit bir fotoğraf tarama uygulamasını temel alınarak verilmektedir.

Styled ListView

Bu basit fotoğraf örneği, görsel olarak çekici bir kullanıcı deneyimi oluşturmak için stil ve templating kullanır. Örnekte iki TextBlock öğe ve ListBox görüntü listesine bağlı bir denetim vardır.

Tam örnek için bkz. Stil Oluşturma ve Örnek Oluşturma'ya Giriş.

Stiller

birden çok öğeye Style bir özellik değerleri kümesi uygulamak için kullanışlı bir yol olarak düşünebilirsiniz. veya veya gibi bir öğesinden türeyen herhangi FrameworkElement bir FrameworkContentElement öğede stil WindowButton kullanabilirsiniz.

Bir stilin bildirilma en yaygın yolu, Resources bir XAML dosyasındaki bölümünde kaynak olarakdır. Stiller kaynaklar olduğundan, tüm kaynaklar için geçerli olan aynı uygulama kurallarına uyarlar. Basitçe ifade gerekirse, stili bildirenler, stilin uygulana yerlerini etkiler. Örneğin, stili uygulama tanımı XAML dosyanın kök öğesinde belirtirsiniz, stil uygulamanın herhangi bir yerinde kullanılabilir.

Örneğin, aşağıdaki XAML kodu için biri tüm öğelere otomatik olarak uygulanan ve diğeri açıkça başvurulması gereken iki TextBlockTextBlock stil bildirer.

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

Burada yukarıda belirtilen stillerin bir örneği kullanılmıştır.

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

Styled textblocks

Daha fazla bilgi için bkz. Denetim için stil oluşturma.

ControlTemplates

WPF'de, ControlTemplate denetimin görünümü tanımlar. Yeni bir tanımlayarak ve bir denetime ataarak denetimin yapısını ControlTemplate ve görünümünü değiştirebilirsiniz. Çoğu durumda şablonlar, kendi özel denetimlerinizi yazmak zorunda olmadığınız için size yeterli esneklik sağlar.

Her denetimin Control.Template özelliğine atanmış varsayılan bir şablonu vardır. Şablon, denetimin görsel sunumunu denetimin özellikleriyle bağlar. XAML'de bir şablon tanımladığınız için, kod yazmadan denetimin görünümünü değiştirebilirsiniz. Her şablon, gibi belirli bir denetim için Button tasarlanmıştır.

Genellikle bir şablonu bir Resources XAML dosyasının bölümünde kaynak olarak bildirebilirsiniz. Tüm kaynaklarda olduğu gibi, bu kurallar da geçerlidir.

Denetim şablonları bir stilden çok daha fazlasını içerir. Bunun nedeni denetim şablonunun denetimin tamamının görsel görünümünü yeniden yazması ve stilde özellik değişikliklerini mevcut denetime uygulamasıdır. Ancak Control.Template özelliği ayarlayarak bir denetimin şablonu uygulandığından, şablon tanımlamak veya ayarlamak için bir stil kullanabilirsiniz.

Tasarımcılar genellikle mevcut bir şablonun kopyasını oluşturmanızı ve değiştirmenizi sağlar. Örneğin, WPF tasarımcısında Visual Studio seçin ve ardından sağ tıklayıp Şablonu düzenle Kopya CheckBoxCheckBox>> Bu komut, şablonunu tanımlayan bir stil oluşturur.

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

Şablonun bir kopyasını düzenlemek, şablonların nasıl çalışta olduğunu öğrenmenin harika bir yoludur. Yeni bir boş şablon oluşturmak yerine, bir kopyayı düzenlemek ve görsel sunumun birkaç yönlerini değiştirmek daha kolaydır.

Bir örnek için bkz. Denetim için şablon oluşturma.

Templatebinding

Önceki bölümde tanımlanan şablon kaynağının TemplateBinding İşaretleme Uzantısını kullandığını fark etmişsinizdir. , ile oluşturulmuş bağlamaya benzer şekilde şablon senaryoları için TemplateBinding bağlamanın iyileştirilmiş bir biçimidir. {Binding RelativeSource={RelativeSource TemplatedParent}} TemplateBinding , şablonun bölümlerini denetimin özelliklerine bağlama açısından yararlıdır. Örneğin, her denetimin bir özelliği BorderThickness vardır. Şablonda TemplateBinding bu denetim ayarından hangi öğenin etkilendiğini yönetmek için kullanın.

ContentControl ve ItemsControl

içinde ContentPresenter bir ControlTemplate bildirilirse, ContentControl ve ContentPresenter özelliklerine otomatik olarak ContentTemplateContent bağlar. Benzer şekilde, ItemsPresenter içinde olan ControlTemplate bir, ve ItemsControl özelliklerine otomatik olarak ItemTemplateItems bağlanacaktır.

DataTemplates

Bu örnek uygulamada, bir ListBox fotoğraf listesine bağlı bir denetim var.

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

Bu ListBox şu anda aşağıdaki gibi görünüyor.

ListBox before applying template

Çoğu denetimde bir tür içerik vardır ve bu içerik genellikle bağlamanız gereken verilerden gelir. Bu örnekte veriler fotoğrafların listesidir. WPF'de, verilerin DataTemplate görsel gösterimini tanımlamak için kullanırnız. Temel olarak, bir içine ne DataTemplate koysanız, işlenen uygulamada verilerin nasıl göründüğünü belirler.

Örnek uygulamamızda her özel Photo nesne, Source görüntünün dosya yolunu belirten dize türünde bir özellik içerir. Şu anda fotoğraf nesneleri dosya yolları olarak görünür.

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

Fotoğrafların görüntü olarak görünmesi için kaynak olarak DataTemplate bir oluşturmanız gerekir.

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

özelliğinin DataType özelliğine benzer TargetType olduğunu Style unutmayın. kaynaklarınız kaynaklar bölümünde ise, özelliğini bir tür olarak belirttiğinizde ve atlarsanız, bu tür DataTemplateDataType her x:KeyDataTemplate görüntülendiğinde uygulanır. Her zaman ile atama seçeneğiniz vardır ve ardından özelliği veya özelliği gibi türleri alan özellikler için olarak DataTemplatex:KeyStaticResourceDataTemplateItemTemplateContentTemplate ayarlayın.

Temel olarak, yukarıdaki örnekte nesnesi her olduğunda nesnesinin içinde DataTemplatePhoto olarak görünmesi gerektiğini ImageBorder tanımlar. Bu DataTemplate ile, uygulamamız artık şu şekilde görünüyor.

Photo image

Veri templating modeli diğer özellikleri sağlar. Örneğin, veya gibi bir tür kullanan diğer koleksiyonları içeren koleksiyon verilerini görüntüleniyorsanız HeaderedItemsControlMenu , TreeViewHierarchicalDataTemplate vardır. Başka bir veri templating DataTemplateSelector özelliği, özel mantığa göre kullanmak üzere DataTemplate bir seçmenize olanak sağlayan özelliğidir. Daha fazla bilgi için, farklı veri templatingözellikleri hakkında daha ayrıntılı bir açıklama sağlayan Veri Templating'e Genel Bakış'a bakın.

Tetikleyiciler

Tetikleyici, bir özellik değeri değişirken veya bir olay tetiklendiğinde özellikleri ayarlar veya animasyon gibi eylemleri başlatır. Style, ControlTemplate ve DataTemplate tüm Triggers tetikleyicileri içeren bir özelliği vardır. Çeşitli tetikleyici türleri vardır.

PropertyTriggers

Özellik Trigger değerlerini ayarleyen veya bir özelliğin değerine göre eylemleri başlatan bir özellik tetikleyicisi olarak çağrılır.

Özellik tetikleyicilerini kullanmayı göstermek için, seçili olmadığı sürece her biri ListBoxItem kısmen saydam hale gelir. Aşağıdaki stil, değerini Opacity olarak ListBoxItem0.5 ayarlar. Ancak IsSelected özelliği true olduğunda olarak Opacity1.0 ayarlanır.

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

Bu örnekte bir özellik değeri ayarlamak için bir kullanılır, ancak sınıfının eylemleri gerçekleştirmek için tetikleyiciyi etkinleştiren ve TriggerTriggerEnterActionsExitActions özelliklerine de sahip olduğunu unutmayın.

özelliğinin MaxHeight olarak ayarlanmış ListBoxItem olduğunu 75 unutmayın. Aşağıdaki çizimde, üçüncü öğe seçili öğedir.

Styled ListView

EventTriggers ve Storyboards

Bir diğer tetikleyici türü EventTrigger de, bir olayın ortaya çıkmasını temel alan bir dizi eylem başlatan tetikleyicidir. Örneğin, aşağıdaki nesneler, fare işaretçisi içine girdiği zaman özelliğinin ikinci bir süre içinde değerine EventTriggerListBoxItem animasyon MaxHeight900.2 katarak olduğunu belirtir. Fare öğeden uzaklaşıyorsa, özelliği saniyelik bir süre boyunca özgün değere 1 geri döner. Animasyon için bir değer belirtmenin gerekli To olmadığını MouseLeave unutmayın. Bunun nedeni animasyonun özgün değeri takip etmektir.

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

Daha fazla bilgi için bkz. Storyboards'a genel bakış.

Aşağıdaki çizimde fare üçüncü öğeyi işaret ediyor.

Styling sample screenshot

MultiTriggers, DataTriggers ve MultiDataTriggers

ve Trigger 'ye EventTrigger ek olarak, başka tetikleyici türleri de vardır. MultiTrigger , özellik değerlerini birden çok koşulları temel alarak ayarlamaya olanak sağlar. DataTriggerMultiDataTrigger Koşulunuz özelliği veri ile bağlantılı olduğunda ve kullanın.

Görsel durumlar

Denetimler her zaman belirli bir durumda. Örneğin, fare bir denetimin yüzeyi üzerinde dolaştığında, denetim ortak bir durumunda olduğu kabul edilir MouseOver . Belirli bir durumu olmayan bir denetim, ortak durumda olduğu kabul edilir Normal . Durumlar gruplar halinde bozulur ve yukarıda bahsedilen durumlar durum grubunun bir parçasıdır CommonStates . Çoğu denetim iki durum grubuna sahiptir: CommonStates ve FocusStates . Bir denetime uygulanan her bir durum grubunda, bir denetim her bir grubun ve gibi her zaman bir durumdadır CommonStates.MouseOverFocusStates.Unfocused . Ancak, bir denetim aynı grup içindeki ve gibi iki farklı durumda olamaz CommonStates.NormalCommonStates.Disabled . Denetimlerin çoğu tarafından tanınmasına ve kullanımına yönelik bir eyalet tablosu aşağıda verilmiştir.

VisualState adı VisualStateGroup adı Açıklama
Normal Ortak durumlar Varsayılan durum.
Gelme olayından Ortak durumlar Fare işaretçisi denetimin üzerine yerleştirilir.
Pressed Ortak durumlar Denetime basıldığında.
Devre dışı Ortak durumlar Denetim devre dışı bırakıldı.
Odaklı Odaklardaki durumlar Denetim odağa sahiptir.
Odaklanmadan gözetle Odaklardaki durumlar Denetimin odağı yok.

Bir System.Windows.VisualStateManager denetim şablonunun kök öğesinde bir tanımlayarak, bir denetim belirli bir duruma girdiğinde animasyonları tetikleyebilirsiniz. , VisualStateManager Hangi birleşimlerinin VisualStateGroup ve izlenecek olduğunu bildirir VisualState . Denetim bir izlenen duruma girdiğinde, tarafından tanımlanan animasyon VisaulStateManager başlatılır.

Örneğin, aşağıdaki XAML kodu, CommonStates.MouseOver adlı öğenin Fill rengine animasyon eklemek için durumu izler backgroundElement . Denetim CommonStates.Normal duruma döndüğünde adlı öğesinin Fill Color backgroundElement geri yüklenir.

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

        ...

Görsel Taslaklar hakkında daha fazla bilgi için bkz. görsel taslakları genel bakış.

Paylaşılan kaynaklar ve Temalar

Tipik bir WPF uygulamasında, uygulamanın tamamında uygulanan birden çok UI kaynağı olabilir. Toplu olarak, bu kaynak kümesi uygulama için tema olarak kabul edilebilir. WPF, sınıf olarak Kapsüllenen bir kaynak sözlüğü kullanarak, Kullanıcı arabirimi kaynaklarını bir tema olarak paketleme desteği sağlar ResourceDictionary .

WPF temaları, WPF 'nin herhangi bir öğenin görsellerini özelleştirmek için sunduğu stil oluşturma ve şablon oluşturma mekanizması kullanılarak tanımlanır.

WPF teması kaynakları, gömülü kaynak sözlüklerinde depolanır. Bu kaynak sözlüklerinin imzalı bir derleme içine katıştırılması ve kodun kendisi ya da yan yana bütünleştirilmiş kodda aynı derlemeye katıştırılması gerekir. PresentationFramework.dll için WPF denetimleri içeren bütünleştirilmiş kod, tema kaynakları ise yan yana derlemelerin bir dizisidir.

Tema, bir öğenin stilini ararken bakacağız son yer olur. Genellikle arama, uygun bir kaynak için arama öğesi ağacının ardından başlatılır, ardından uygulama kaynak koleksiyonuna bakar ve son olarak sistemi sorgular. Bu, uygulama geliştiricilere, temaya ulaşmadan önce ağaç veya uygulama düzeyindeki herhangi bir nesnenin stilini yeniden tanımlamayı sağlar.

Kaynak sözlüklerini birden çok uygulama genelinde bir temayı yeniden kullanmanıza imkan tanıyan tek tek dosyalar olarak tanımlayabilirsiniz. Aynı kaynak türlerini ve farklı değerleri sağlayan birden çok kaynak sözlüğü tanımlayarak, değiştirilebilir temalar da oluşturabilirsiniz. Uygulama düzeyindeki bu stilleri veya diğer kaynakları yeniden tanımlama, bir uygulamanın kaplama oluşturma için önerilen yaklaşımdır.

Stiller ve şablonlar dahil olmak üzere bir kaynak kümesini, uygulamalar arasında paylaşmak için bir XAML dosyası oluşturabilir ve bir ResourceDictionary dosyanın başvurusunu içeren bir tanımlayabilirsiniz shared.xaml .

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

Bu, bir shared.xamlResourceDictionary uygulama içindeki denetimlerin tutarlı bir görünüme sahip olmasını sağlayan bir stil ve fırça kaynakları kümesi içeren öğesini tanımlayan, öğesinin paylaşımdır.

Daha fazla bilgi için bkz. birleştirilmiş kaynak sözlükleri.

Özel denetiminiz için bir tema oluşturuyorsanız, Denetim yazma genel bakışkonusunun Tema düzeyinde kaynakları tanımlama bölümüne bakın.

Ayrıca bkz.