WPF Value Converters, Styles, Triggers, DataTemplates, ControlTemplates - Luento 13

Selvitetään mitä ovat seuraavat asiat WPF:ssä: Value Converters, tyylit, Triggers, DataTemplatet, ControlTemplatet.

Luentoesimerkki (luento13_2012.zip

Value Converters

Peritään oma luokka IValueConverter-luokasta:

    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class BoolToVisibilityConverter : IValueConverter
    {
        // muunnos bool-tyypistä visibility-tyyppiin
        public object Convert(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            bool arvo = (bool)value;
            if ( arvo ) return Visibility.Visible;
            return Visibility.Hidden;
        }

        // muunnos visibility-tyypistä bool-tyyppiin
        public object ConvertBack(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            Visibility arvo = (Visibility)value;
            if (arvo == Visibility.Hidden) return false;
            if (arvo == Visibility.Collapsed) return false;
            return true;
        }
    }

Käytetään XAMLissa seuraavasti:

<Window x:Class="luento13_2012.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" xmlns:oma="clr-namespace:luento13_2012">
    <Window.Resources>
<!-- otetaan oma konvertteri käyttöön ja määritellään sille avain -->
        <oma:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
    </Window.Resources>
    <Grid>
        <CheckBox Content="Neliö" Height="16" HorizontalAlignment="Left" Margin="12,54,0,0" Name="checkBox1" VerticalAlignment="Top" />
        <Rectangle Margin="0,-200,0,0" Width="100" Height="100" Visibility="{Binding ElementName=checkBox1, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" Fill="#FFC14D4D"></Rectangle>
    </Grid>
</Window>

Resources

Resourceja voi määritellä XAMLissa lähes minkä tahansa elementin yhteyteen. Mitä korkeammalle tasolle puussa resurssi on määritelty sitä laajemmalti sitä voidaan käyttää.

Resurssiin viitataan joko staattisena (StaticResource) tai dynaamisena (DynamicResource) sen mukaan onko resurssi käytettävissä jo ohjelman käynnistysvaiheessa vaiko vasta myöhemmin tai muuttuuko se ohjelman ajon aikana.

Resursseja voi määritellä myöx app.xaml-tiedostoon jolloin ne ovat käytössä kaikissa projektin osissa

Tyylit

Tyyleillä saadaan helposti yhtenäinen ulkoasu kaikille kontrolleille. vrt. CSS-tyylit

Määritellään tyyli:

    <Window.Resources>
<!-- Määritellään oma tyyli checkbox-elementeille -->
        <Style x:Key="CheckBoxTyyli" TargetType="{x:Type CheckBox}">
            <Setter Property="Background" Value="#FFD6D6EB" />
            <Setter Property="FontFamily" Value="Verdana" />
            <Setter Property="FontSize" Value="14" />
            <Setter Property="FontWeight" Value="ExtraBold" />
            <Setter Property="HorizontalAlignment" Value="Left" />
            <Setter Property="VerticalAlignment" Value="Top" />
            <Setter Property="Height" Value="16" />
        </Style>
        <!-- Perintä toimii myös -->
        
        <Style x:Key="ErikoisCheckBoxTyyli"  BasedOn="{StaticResource CheckBoxTyyli}" TargetType="CheckBox">
            <Setter Property="FontSize" Value="34" />
            <Setter Property="Height" Value="40" />
        </Style>
        <!-- Oletustyyli kaikille buttoneille -->
        <Style TargetType="Button">
            <Setter Property="FontSize" Value="24" />
            <Setter Property="Height" Value="34" />
        </Style>
   </Window.Resources>

Käytetään tyyliä:

<CheckBox Style="{StaticResource CheckBoxTyyli}" Content="Ympyrä" Margin="10,10,0,0" Name="checkBox2"  />

Tyylin voi asettaa myös koodissa:

Style style = this.FindResource("LabelTyyli") as Style;
label1.Style = style;

Triggerit

Triggerien avulla voidaan tehdä tapahtumista riippuvaisia tyylejä, datatemplateja ym.

<Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Foreground" Value="Yellow"/>
                </Trigger>
            </Style.Triggers>

Samaan tapaan voidaan havainnollistaa virheitä syötteiden kohdalla:

           <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip"
                        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>

Data Templating

DataTemplaten avulla voidaan määritellä miten jokin tietty luokka esitetään. Apuna voidaan käyttää DataTriggereitä

        <DataTemplate DataType="{x:Type oma:Henkilo}">
            <Border BorderThickness="1" BorderBrush="Gray"
            Padding="7" Name="border" Margin="3"  HorizontalAlignment="Stretch">
                <StackPanel Orientation="Horizontal" Name="panel">
                    <TextBlock Margin="2" Text="{Binding Path=Etunimi}" Name="textBlockEtunimi"/>
                    <TextBlock Margin="2" Text="{Binding Path=Sukunimi}" Name="textBlockSukunimi"/>
                </StackPanel>
            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=Sukunimi}" Value="Doe">
                    <DataTrigger.Setters>
                        <Setter Property="BorderBrush" Value="DodgerBlue" TargetName="border" />
                        <Setter Property="BorderThickness" Value="3"  TargetName="border" />
                        <Setter Property="Padding" Value="5" TargetName="textBlockEtunimi"/>
                        <Setter Property="Padding" Value="5" TargetName="textBlockSukunimi"/>
                    </DataTrigger.Setters>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=Sukunimi}" Value="Lahtonen">
                    <Setter Property="BorderBrush" Value="Black"  TargetName="border" />
                    <Setter Property="BorderThickness" Value="5"  TargetName="border" />
                    <Setter Property="Padding" Value="15" TargetName="textBlockEtunimi"/>
                    <Setter Property="Padding" Value="15" TargetName="textBlockSukunimi"/>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>

ControlTemplate

Komponentin ulkoasu voidaan uusia kokonaan ilman, että tarvitsee luoda omaa komponenttia.

Uutta ulkoasua määritellessä on muistettava muutettavan kontrollin normaali toiminta ja siihen liittyvät erityisyydet. esim. painikkeessa on muistettava esittää painikkeen sisältö ja listboxissa listboxiin lisätyt elementit.

ContentPresenter

ItemsPresenter

<Style TargetType="HeaderedItemsControl">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
        <StackPanel>
          <Grid>
            <Rectangle Fill="{TemplateBinding Background}"/>
            <ContentPresenter ContentSource="Header"/>
          </Grid>
          <Grid>
            <Rectangle Stroke="{TemplateBinding BorderBrush}"/>
            <ItemsPresenter Margin="2,0,0,0"/>
          </Grid>
        </StackPanel>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

TemplateBinding sitoo komponentin sisäisten komponenttien ominaisuuksia komponentin ominaisuuksiksi.

<Grid Width="{TemplateBinding Width}" Height="{TemplateBinding
Height}">

Virheilmoituksista saadaan havainnollisempia:

        <Style TargetType="TextBox">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Foreground="Red" FontSize="20" Text="!"/>
                            <Border BorderBrush="Red" BorderThickness="2">
                                <AdornedElementPlaceholder />
                            </Border>
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip"
                        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>

Käyttäjien kommentit

Kommentoi Lisää kommentti
Kurssimateriaalien käyttäminen kaupallisiin tarkoituksiin tai opetusmateriaalina ilman lupaa on ehdottomasti kielletty!
http://appro.mit.jyu.fi/gko/luennot/luento13/
© Tommi Lahtonen (tommi.j.lahtonen@jyu.fi) <http://hazor.iki.fi/>
2016-01-13 18:19:13
Informaatioteknologia - Jyväskylän yliopiston informaatioteknologian tiedekunta