środa, 12 grudnia 2012

70-511 Rozdział 5 - Szablony kontrolek WPF

Kontrolki WPF zostały przygotowane w ten sposób, aby łatwo można modyfikować ich wygląd. Definicję wyglądu oddzielono całkowicie od kodu definiującego funkcjonalność.
Szablony kontrolek tworzone są w XAML-u. Szablon zawiera kompletny opis wyglądu danej kontrolki.
Przykładowy szablon dla przycisku możemy zdefiniować następująco:

Code:
        <Button>
            <Button.Template>
                <ControlTemplate>
                    <Rectangle Fill="Red" />
                </ControlTemplate>
            </Button.Template>
        </Button>

Definicja szablonu zawarta jest w elemencie <ControlTemplate>. 
Ważnym aspektem jest umożliwienie nadawania zawartości (Content) przycisku. Aby przywrócić tą funkcjonalność, należy w szablonie dodać specjalną kontrolkę przeznaczoną do wyświetlania zawartości - ContentPresenter:

Code:
        <Button Content="Button!">
            <Button.Template>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid>
                        <Rectangle Fill="Red">
                        </Rectangle>
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                    </Grid>
                </ControlTemplate>
            </Button.Template>
        </Button>

W przypadku gdy korzystamy z kontrolki ContentPresenter musimy w definicji ControlTemplate umieścić dla jakiego typu definiujemy ContentPresenter-a.

Szablony najczęściej definiujemy jako zasoby (w celach użycia w wielu miejscach):

Code:
<Window.Resources>
        <ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
            <Grid>
                <Rectangle Fill="Red">
                </Rectangle>
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Grid>
        </ControlTemplate>
    </Window.Resources>
    <Grid>
        <Button Content="Button!" Template="{StaticResource ButtonTemplate}" />
    </Grid>




Triggery
Zmiana wyglądu kontrolki to nie wszystko. Kolejnym elementem podczas definiowania wyglądu kontrolki jest jej zachowanie się podczas interakcji z użytkownikiem. Jeżeli przyjrzymy się przyciskowi to w momencie gdy na niego najeżdżamy kursorem, zostaje podświetlony.
Zachowania tego typu definiują Triggery. ControlTemplate zawiera kolekcję obiektów typu Trigger.
Definicja Trigger-ów dla kontrolki przycisku:

Code:
        <ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
            <Grid>
                <Rectangle Name="rectangle" Fill="Red">
                </Rectangle>
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter TargetName="rectangle" Value="Yellow" Property="Fill" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

Do zapamiętania:
  • Triggery odwołują się do konkretnych nazwanych elementów szablonu
  • Szablon musi być zdefiniowany jako pierwszy w kodzie XAML
  • Trigery mogą zawierać animacje
Warto w tym miejscu zauważyć jedną rzecz. Po napisaniu poniższego kodu:

Code:
       <Button Content="Button!" Background="Blue">
           <Button.Template>
               <ControlTemplate TargetType="{x:Type Button}">
                   <Grid>
                        <Rectangle Fill="Red"></Rectangle>
                        <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"></ContentPresenter>
                    </Grid>
                </ControlTemplate>
           </Button.Template>
       </Button>

przycisk nie zmienił koloru wypełnienia na niebieski. Aby możliwe było przypisanie koloru do naszego prostokąta należy skorzystać ze specjalnego rodzaju bindowania - bindowania do szablonu - Template Binding. Składnia {TemplateBinding <PropertyName>}. PropertyName - nazwa właściwości kontrolki. Tak więc TemplateBinding przekazuje wartość ustawioną na kontrolce do właściwości w szablonie.

 Poniżej przykład w jaki sposób sprawić żeby nasz klawisz miał kolor taki, jaki ustawimy we właściwości Background:

Code:
       <Button Content="Button!" Background="Blue">
           <Button.Template>
               <ControlTemplate TargetType="{x:Type Button}">
                   <Grid>
                        <Rectangle Fill="{TemplateBinding Background}"></Rectangle>
                        <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"></ContentPresenter>
                    </Grid>
                </ControlTemplate>
           </Button.Template>
       </Button>

Efekt:


W przypadku TemplateBinding istnieje problem z obiektami typu Freezable (np. obiekt Brush - pędzel). Aby ominąć ten problem można zastosować trik polegający na wykorzystaniu bindowania RelativeSource:

Code:
       <Button Content="Button!">
           <Button.Background>
               <LinearGradientBrush StartPoint="0, 0" EndPoint="1, 1">
                   <GradientStop Color="Blue" Offset="0" />
                   <GradientStop Color="Chartreuse" Offset="0.5" />
               </LinearGradientBrush>
           </Button.Background>
           <Button.Template>
               <ControlTemplate TargetType="{x:Type Button}">
                   <Grid>
                        <Rectangle Name="recBackground" Fill="{TemplateBinding Background}" />
                        <Ellipse Name="ellipse" Fill="Red"></Ellipse>
                       <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
                   </Grid>
                   <ControlTemplate.Triggers>
                       <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="ellipse" Property="Fill" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"></Setter>
                       </Trigger>
                   </ControlTemplate.Triggers>
                </ControlTemplate>
           </Button.Template>
       </Button>

Dzięki temu zabiegowi elipsa po najechaniu będzie mieć taki sam kolor jak tło.
Dodatkowo możemy za pomocą stylów, nadać taki sam szablon dla wszystkich klawiszy w oknie:

Code:
<Style TargetType="{x:Type Button}">
    <Setter Property="Template" Value="{StaticResource ButtonTemplate}" />
</Style>



Pobieranie stylów kontrolek WPF
Szablon kontrolki możemy definiować od początku, bądź też pobrać go w wersji domyślnej i dostosować do naszych potrzeb. Kod pozwalający pobrać szablon kontrolki:

Code:
            using (var file = new FileStream("template.xml", FileMode.CreateNew))
            {
                XamlWriter.Save(btnMyButton.Template, file);
            }


Brak komentarzy:

Prześlij komentarz