WPF'de stiller ve şablonlar

Windows Presentation Foundation (WPF) stil oluşturma ve şablon oluşturma, geliştiricilerin ve tasarımcıların ürünleri için görsel olarak cazip efektler ve tutarlı bir görünüm oluşturmasına olanak sağlayan bir özellik paketine başvurur. Bir uygulamanın görünümünü özelleştirirken, uygulamalar içinde ve uygulamalar arasında görünümün bakımını ve paylaşımını sağlayan güçlü bir stil ve şablon oluşturma modeli istiyorsunuz. WPF bu modeli sağlar.

WPF stil modelinin bir diğer özelliği de sunu ve mantığın ayrılmasıdır. Tasarım Aracı, geliştiricilerin C# veya Visual Basic kullanarak programlama mantığı üzerinde çalıştığı aynı anda yalnızca XAML kullanarak uygulamanın görünümü üzerinde çalışabilir.

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

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

Örnek

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

Styled ListView

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

Örneğin tamamı için bkz . Stil Oluşturma ve Şablon Oluşturma Örneğine Giriş.

Stiller

bir Style özelliğini, birden çok öğeye bir özellik değerleri kümesi uygulamak için kullanışlı bir yol olarak düşünebilirsiniz. veya gibi Window bir öğesinden FrameworkElementFrameworkContentElement türetilen herhangi bir Buttonöğede stil kullanabilirsiniz.

Stil bildirmenin en yaygın yolu, XAML dosyasının Resources bölümündeki bir kaynaktır. Stiller kaynak olduğundan, tüm kaynaklar için geçerli olan aynı kapsam kurallarına uyarlar. Basitçe ifade edin, bir stili bildirdiğiniz yer, stilin uygulanabileceği yeri etkiler. Örneğin, stili uygulama tanımı XAML dosyanızın kök öğesinde bildirirseniz, stil uygulamanızın herhangi bir yerinde kullanılabilir.

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

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

Yukarıda kullanılmakta olduğu bildirilen stillerin bir örneği aşağıda verilmiştir.

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

Styled textblocks

ControlTemplates

WPF'de, ControlTemplate denetimin görünümü denetimin görünümünü tanımlar. Yeni ControlTemplate bir tanımlayıp bir denetime atayarak denetimin yapısını ve görünümünü değiştirebilirsiniz. Çoğu durumda şablonlar, kendi özel denetimlerinizi yazmanız gerekmeyecek kadar esneklik sağlar.

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

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

Denetim şablonları bir stilden çok daha karmaşıktır. Bunun nedeni, denetim şablonunun denetimin tamamının görsel görünümünü yeniden yazması, stilin ise var olan denetime özellik değişikliklerini uygulamasıdır. Ancak, denetimin şablonu Control.Template özelliği ayarlanarak uygulandığından, şablon tanımlamak veya ayarlamak için bir stil kullanabilirsiniz.

Tasarım Aracı genellikle var olan bir şablonun kopyasını oluşturmanıza ve değiştirmenize olanak sağlar. Örneğin, Visual Studio WPF tasarımcısında bir CheckBox denetim seçin ve sağ tıklayıp Şablonu>düzenle Kopya oluştur'u seçin. Bu komut, şablonu 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ıştığını öğrenmenin harika bir yoludur. Yeni boş bir şablon oluşturmak yerine, bir kopyayı düzenlemek ve görsel sununun birkaç yönünü değiştirmek daha kolaydır.

Örnek için bkz . Denetim için şablon oluşturma.

Templatebinding

Önceki bölümde tanımlanan şablon kaynağının TemplateBinding İşaretlemeyi Uzantısını kullandığını fark etmiş olabilirsiniz. , TemplateBinding ile yapılan bağlamaya benzer şekilde şablon senaryoları için en iyi duruma getirilmiş bir bağlama biçimidir {Binding RelativeSource={RelativeSource TemplatedParent}}. TemplateBinding , şablonun bölümlerini denetimin özelliklerine bağlamak için kullanışlıdır. Örneğin, her denetimin bir BorderThickness özelliği vardır. Şablondaki hangi öğenin bu denetim ayarından etkilendiğini yönetmek için bir TemplateBinding kullanın.

ContentControl ve ItemsControl

içinde bir ContentPresenter bildirilirseContentControlControlTemplate, ContentPresenter ve Content özelliklerine ContentTemplate otomatik olarak bağlanır. Benzer şekilde, ItemsPresenter içinde olan bir ItemsControl ve özelliklerine ItemsItemTemplateControlTemplate otomatik olarak bağlanır.

DataTemplates

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

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

ListBox before applying template

Denetimlerin çoğu bir tür içeriğe sahiptir ve bu içerik genellikle bağlandığınız verilerden gelir. Bu örnekte veriler fotoğrafların listesidir. WPF'de, verilerin görsel gösterimini tanımlamak için bir DataTemplate kullanırsınız. Temel olarak, içine yerleştirdiğiniz DataTemplate veriler işlenen uygulamada nasıl görüneceğini belirler.

Örnek uygulamamızda her özel Photo nesnenin, görüntünün dosya yolunu belirten dize türünde bir Source özelliği vardır. Ş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 bir DataTemplate oluşturursunuz.

<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 TargetTypeStylebenzer olduğuna dikkat edin. kaynağınız DataTemplate kaynaklar bölümündeyse, özelliğini bir türe belirttiğinizde DataType ve atladığınızda x:Key, DataTemplate bu tür her görüntülendiğinde uygulanır. her zaman öğesini ile atama DataTemplate ve ardından özellik veya özellik gibi ItemTemplate türleri alan DataTemplate özellikler için olarak StaticResource ayarlama seçeneğiniz ContentTemplatex:Key vardır.

Temelde, DataTemplate yukarıdaki örnekte, bir Photo nesne olduğunda içinde olarak ImageBordergörünmesi gerektiğini tanımlar. bu DataTemplateile, uygulamamız artık şöyle görünür.

Photo image

Veri şablon oluşturma modeli diğer özellikleri sağlar. Örneğin, veya TreeViewHierarchicalDataTemplategibi Menu bir HeaderedItemsControl tür kullanarak diğer koleksiyonları içeren koleksiyon verilerini görüntülüyorsanız, vardır. Başka bir veri şablon oluşturma özelliği, özel mantığa göre kullanmak üzere bir DataTemplate seçmenize olanak tanıyan özelliğidirDataTemplateSelector. Daha fazla bilgi için bkz . Farklı veri şablon oluşturma özellikleri hakkında daha ayrıntılı bir tartışma sağlayan Veri Şablonuna Genel Bakış.

Tetikleyiciler

Tetikleyici özellikleri ayarlar veya bir özellik değeri değiştiğinde veya bir olay tetiklendiğinde animasyon gibi eylemleri başlatır. Style, ControlTemplateve DataTemplate tümünün tetikleyici Triggers kümesi içerebilen bir özelliği vardır. Birkaç tetikleyici türü vardır.

PropertyTriggers

Trigger Özellik değerlerini ayarlayan veya bir özelliğin değerine göre eylemler başlatan bir özellik tetikleyicisi olarak adlandırılır.

Özellik tetikleyicilerinin nasıl kullanılacağını göstermek için, seçilmediği sürece her ListBoxItem birinin kısmen saydam olmasını sağlayabilirsiniz. Aşağıdaki stil, değerini ListBoxItem olarak 0.5ayarlarOpacity. IsSelected Ancak özelliği olduğundatrue, Opacity olarak ayarlanır1.0.

<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 Trigger kullanılır, ancak sınıfın Trigger eylemleri gerçekleştirmek için tetikleyiciyi etkinleştiren ve ExitActions özelliklerine de sahip EnterActions olduğunu unutmayın.

özelliğinin MaxHeight olarak ayarlandığına ListBoxItem75dikkat edin. Aşağıdaki çizimde, üçüncü öğe seçili öğedir.

Styled ListView

EventTriggers ve Görsel Taslaklar

Başka bir tetikleyici türü, EventTriggerbir olayın oluşumuna göre bir eylem kümesi başlatan türüdür. Örneğin, aşağıdaki EventTrigger nesneler fare işaretçisi içine girdiğinde ListBoxItemözelliğinin ikinci bir sürenin MaxHeight üzerindeki 0.2 bir değere 90 animasyon ekleneceğini belirtir. Fare öğeden uzaklaştığında, özellik saniyelik bir süre 1 boyunca özgün değere döner. Animasyon için bir To değer belirtmenin MouseLeave gerekli olmadığını unutmayın. Bunun nedeni, animasyonun özgün değeri izleyebilebilmesidir.

<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 . Görsel Taslaklara genel bakış.

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

Styling sample screenshot

MultiTriggers, DataTriggers ve MultiDataTriggers

ve'e TriggerEventTriggerek olarak, başka tetikleyici türleri de vardır. MultiTrigger özellik değerlerini birden çok koşula göre ayarlamanıza olanak tanır. ve koşulunuzun özelliği veriye bağlı olduğunda kullanırsınız DataTriggerMultiDataTrigger .

Görsel Durumlar

Denetimler her zaman belirli bir durumdadır. Örneğin, fare bir denetimin yüzeyinin üzerinde hareket ettiğinde, denetimin ortak durumunda MouseOverolduğu kabul edilir. Belirli bir durumu olmayan bir denetimin ortak Normal durumda olduğu kabul edilir. Durumlar gruplara ayrılır ve daha önce bahsedilen durumlar durum grubunun CommonStatesbir parçasıdır. Çoğu denetimin iki durum grubu vardır: CommonStates ve FocusStates. Denetime uygulanan her durum grubunda, bir denetim her zaman ve FocusStates.Unfocusedgibi CommonStates.MouseOver her grubun tek bir durumundadır. Ancak, bir denetim ve CommonStates.Disabledgibi CommonStates.Normal aynı grup içinde iki farklı durumda olamaz. Çoğu denetimin tanıdığı ve kullandığı durumlardan oluşan bir tablo aşağıdadır.

VisualState Adı VisualStateGroup Adı Tanım
Normal Commonstates Varsayılan durum.
Mouseover Commonstates Fare işaretçisi denetimin üzerine yerleştirilir.
Basılı Commonstates Denetime basılır.
Devre Dışı Commonstates Denetim devre dışı bırakıldı.
Odaklı FocusStates Denetimin odağı vardır.
Odaklanmamış FocusStates Denetimin odağı yok.

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

Örneğin, aşağıdaki XAML kodu adlı backgroundElementöğenin dolgu rengine animasyon eklemek için durumunu izlerCommonStates.MouseOver. Denetim duruma döndüğünde CommonStates.Normal adlı backgroundElement öğenin dolgu rengi 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 Taslaklara Genel Bakış.

Paylaşılan kaynaklar ve temalar

Tipik bir WPF uygulamasının uygulama genelinde uygulanan birden çok kullanıcı arabirimi kaynağı olabilir. Toplu olarak, bu kaynak kümesi uygulamanın teması olarak kabul edilebilir. WPF, sınıf olarak kapsüllenmiş bir kaynak sözlüğü kullanarak ui kaynaklarını tema olarak paketleme desteği ResourceDictionary sağlar.

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

WPF tema kaynakları ekli kaynak sözlüklerinde depolanır. Bu kaynak sözlükleri imzalı bir derlemeye eklenmelidir ve kodun kendisiyle aynı derlemeye veya yan yana bir derlemeye eklenebilir. PresentationFramework.dll için WPF denetimleri içeren derleme, tema kaynakları yan yana derlemeler serisinde yer alır.

Tema, bir öğenin stilini ararken bakılması gereken son yer olur. Genellikle arama, öğe ağacına gidip uygun bir kaynağı arayarak başlar, ardından uygulama kaynak koleksiyonuna bakar ve son olarak sistemi sorgular. Bu, uygulama geliştiricilerine temaya ulaşmadan önce ağaç veya uygulama düzeyindeki herhangi bir nesnenin stilini yeniden tanımlama şansı verir.

Kaynak sözlüklerini, bir temayı birden çok uygulamada yeniden kullanmanıza olanak tanıyan tek tek dosyalar olarak tanımlayabilirsiniz. Aynı kaynak türlerini ancak farklı değerleri sağlayan birden çok kaynak sözlük tanımlayarak değiştirilebilir temalar da oluşturabilirsiniz. Bu stillerin veya diğer kaynakların uygulama düzeyinde yeniden tanımlanması, bir uygulamanın dış görünümünün belirlenmesi için önerilen yaklaşımdır.

Stiller ve şablonlar da dahil olmak üzere bir dizi kaynağı uygulamalar arasında paylaşmak için bir XAML dosyası oluşturabilir ve dosya başvurusu içeren bir shared.xaml dosya tanımlayabilirsinizResourceDictionary.

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

Bir uygulamadaki denetimlerin shared.xamltutarlı bir ResourceDictionary görünüme sahip olmasını sağlayan, stil ve fırça kaynakları kümesi içeren bir öğesini tanımlayan paylaşımıdı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ışının Tema düzeyinde kaynakları tanımlama bölümüne bakın.

Ayrıca bkz.