2013. április 23., kedd

Wpf #10 Trigger

Egy program fejlesztése során számos alkalommal fordul elő, hogy egy adott tulajdonság megváltoztatása csak bizonyos esemény hatására kell, hogy megtörténjen. Az adott esemény lehet az oldal betöltődése, de lehet akár egy tetszőlegesen tárolt változó egy előre meghatározott értékének felvétele.

A Wpf alatt erre szolgál a trigger, amelyből három féle létezik.
Property trigger: amely akkor aktivizálódik, ha egy DependencyProperty értéke megváltozik.
Data trigger: amely akkor aktivizálódik, ha egy normál .Net tulajdonság értéke megváltozik
Event trigger: amely tetszőleges Routed Event hatására aktivizálódik

A DependencyProperty hasonló a normál tulajdonságokhoz. Egy Wpf elem számos DependencyProperty-vel rendelkezik. Pl. Width, Height.
Mivel egy adott elem megjelenítését számos tulajdonság határozza meg, könnyen belátható, hogy néhány elem kirajzolása szinte  felfalná az összes memóriát.
A DependencyProperty ennek megakadályozására lett kitalálva.
Az adott elem összes tulajdonsága egy alapértékkel rendelkezik, amely csak egyszer kerül eltárolásra egy programban. Minden esetben, amikor egy elem tulajdonsága felülírásra kerül (pl Width="100") akkor  csak ez az érték kerül külön tárolásra.
Számos események látszó tulajdonság is DependencyProperty-ként kerül eltárolásra. Ilyen pl. az IsMouseOver amely a nevéből adódóan a kurzort figyeli, és amennyiben az adott elem fölött található, akkor true értéket vesz fel.

A Routed Event nagyon leegyszerűsítve megfelel egy tetszőleges eseménynek. Pl: Loaded vagy Click.

A triggerek elhelyezése az adott elemhez definiált stíluson belül történik. A beállításokat továbbra is setter elemek végzik, akárcsak egy normál stílus esetén. Mivel az adott elem tulajdonságának triggerel történő beállítása a stíluson keresztül történik, ezért az elem azonos tulajdonságát is kötelezően a stílusban kell megadni.

Egy trigger definíciója az alábbihoz hasonló:
<Grid>
 <Grid.Resources>
  <Style TargetType="{x:Type Button}" x:Key="MyButton">
   <Style.Triggers>
    <trigger>
       trigger által megkívánt teendők
    </trigger>
   </Style.Triggers>
  </Style>
 </Grid.Resources>
 
 <Button Style="{StaticResource MyButton}"/>
 
</Grid>

Egy tetszőleges Resource-ban deklarálásra kerül az adott elemhez tartozó stílus. Jelen esetben egy Button. A stíluson belül deklarálásra kerül a trigger, amely a három különöző trigger esetén más néven kerül bevezetésre.

Az adott elem stílusát beállítva a trigger élesítésre kerül, és a feltételeknek megfelelő pillanatban kifejti a hatását.

Event trigger

Egy Wpf elem számos esemény kezelésére képes. Ilyen pl.: Loaded vagy Click.
Amennyiben egy esemény meghívásra kerül a trigger aktiválódik.  
Az event triggereket animációk irányítására lehet használni.
Az alábbi példa a Button betöltésekor indít egy animációt, amely a Button szélességét változtatja meg 100-ról 200-ra 2 másodperc alatt.

<Grid>
 <Grid.Resources>
  <Style TargetType="{x:Type Button}" x:Key="MyButton">
   <Style.Triggers>
    <EventTrigger RoutedEvent="Loaded">
     <BeginStoryboard>
      <Storyboard>
       <DoubleAnimation From="100" To="200"  Duration="0:0:2" Storyboard.TargetProperty="Width"/>
      </Storyboard>
     </BeginStoryboard>
    </EventTrigger>
   </Style.Triggers>

   <Setter Property="Width" Value="100"/>
   <Setter Property="Height" Value="20"/>
  </Style>
 </Grid.Resources>
 
 <Button Style="{StaticResource MyButton}"  Content="Click"/>
 
</Grid>

Az event trigger a stíluson belül az EventTrigger deklarációval határozható meg. A RoutedEvent attributum segítségével adható meg a figyelni kívánt esemény (Loaded).
Mivel az event trigger animációk irányítására szolgál, ezért egy storyboard megadása szükséges.
Ebben a storyboard-ban kell minden animációt deklarálni amelyet az adott elem meghatározott eseményekor le kell játszani.

Property trigger

A Wpf-ben a property trigger az alapértelmezésű trigger. Bármely DependencyProperty megfigyelhető vele.

Az alábbi példa ezt szemlélteti
<Grid>
 <Grid.Resources>
  <Style x:Key="MyButton" TargetType="{x:Type Button}">
   <Style.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
     <Setter Property="Width" Value="200"/>
    </Trigger>
   </Style.Triggers>
   
   <Setter Property="Width" Value="100"/>
   <Setter Property="Height" Value="20"/>
  </Style>
 </Grid.Resources>
 
 <Button Style="{StaticResource MyButton}" Content="Click"/>
 
</Grid>

Az előző példától eltérően a stíluson belül egy szimpla Trigger kerül deklarálásra.
A Property tulajdonság határozza meg, hogy mely DependencyProperty-t kell figyelni, a Value pedig azt az értéket tartalmazza, amely esetén a triggernek aktiválódnia kell.

Data trigger

Segítségével tetszőleges tulajdonság értéke megfigyelhető. A megfigyelt tulajdonságnak olyan osztályban kell lennie, amely megvalósítja az INotifyPropertyChanged Interface-t, valamint a tulajdonságnak elérhetőnek kell lennie a DataContext-en keresztül.

Az alábbi példa egy boolean típusú tulajdonság felhasználásával változtatja meg a Button szélességét.
Ebben az esetben kódot is kell írni a megjelenítés mögé.

<Grid>
 <Grid.Resources>
  <Style x:Key="MyButton" TargetType="{x:Type Button}">
   <Style.Triggers>
    <DataTrigger Binding="{Binding ChangeWidth}" Value="True">
     <Setter Property="Width" Value="200"></Setter>
    </DataTrigger>
   </Style.Triggers>

   <Setter Property="Width" Value="100"/>
   <Setter Property="Height" Value="20"/>
  </Style>
 </Grid.Resources>

 <Button Style="{StaticResource MyButton}" Content="Just a button"/>

 <Button VerticalAlignment="Bottom" Height="20" Content="Change Width" Click="ButtonBase_OnClick"/>
</Grid>

A trigger-t a stíluson belül a DataTrigger deklarációval kell megkezdeni.  A Binding értékadásával lehet beállítani a figyelni kívánt tulajdonságot, a Value szerepe itt is az itt megadott érték figyelése.

public partial class DataTrigger : Window, INotifyPropertyChanged
{
 private bool _changeWidth;
 public bool ChangeWidth
 {
  get { return _changeWidth; }
  set { _changeWidth = value; OnPropertyChanged("ChangeWidth"); }
 }

 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 public event PropertyChangedEventHandler PropertyChanged;
 public void OnPropertyChanged(string propertyName)
 {
  if (PropertyChanged != null)
   PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
 }

 // --------------------------------------------------------------------

 public DataTrigger()
 {
  InitializeComponent();
  ChangeWidth = false;
  DataContext = this;
 }

 private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
 {
  ChangeWidth = !ChangeWidth;
 }
}

Fordítás után az alul található gomb a ChangeWidth tulajdonság értékét változtatja, és a trigger ennek függvényében változtatja a gomb szélességét.

MultiTrigger - VAGY kapcsolat

Egy trigger nem feltétlenül csak egy bizonyos feltétel meglététől aktiválódhat. Előfordulhat, hogy ugyanaz a trigger több más - egymástól teljesen független - feltétel megléte esetén is kell, hogy végrehajtsa a megkívánt beállításokat.

Ezt nevezik MultiTrigger-nek.
MultiTrigger-ből is többféle létezik (MultiTrigger, MultiDataTrigger), azonban a logikai VAGY kapcsolathoz az előbb megismert triggerek bármelyike felhasználható.

Az alábbi példa egy egyszerű VAGY kapcsolatot mutat be, amely során a Button szélessége megváltozik, ha az egérrel a kurzor felé kerül vagy ha a Button magassága 30 lesz.
Fordítás után a Button magasságát az alul található gomb segítségével lehet növelni.

<Grid>
 <Grid.Resources>
  <Style x:Key="MyButton" TargetType="{x:Type Button}">
   <Style.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
     <Setter Property="Width" Value="200"/>
    </Trigger>
    
    <Trigger Property="Height" Value="30">
     <Setter Property="Width" Value="200"/>
    </Trigger>
   </Style.Triggers>

   <Setter Property="Width" Value="100"/>
   <Setter Property="Height" Value="20"/>
  </Style>
 </Grid.Resources>

 <Button Name="Btn" Style="{StaticResource MyButton}" Content="Click"/>

 <Button VerticalAlignment="Bottom" Height="20" Content="Increment Height" Click="ButtonBase_OnClick"/>

</Grid>

A hozzá tartozó kód, amely az alsó gomb click eseményét kezeli.
public partial class MultiTrigger_Or : Window
{
 public MultiTrigger_Or()
 {
  InitializeComponent();
 }

 private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
 {
  Btn.Height += 10;
 }
}

A gomb megnyomására a középső Button magassága 10-el növekszik. Amint eléri a 30-at, a szélessége a triggerben megadott 200-ra változik. Majd miután 40-re növekszik visszaáll az eredeti értékre.

Itt fontos megjegyezni, hogy az eredeti értékre történő visszaállítással nem kell foglalkozni, azt a keretrendszer automatikusan elvégzi.

Egy trigger logikai VAGY kapcsolata számos további triggert tartalmazhat, ezáltal tetszőleges számú feltételhez köthető a kívánt beállítás aktiválása.

MultiTrigger - ÉS kapcsolat

Előfordulhat, hogy egy adott trigger aktiválódására csak több feltétel együttes megléte esetén van szükség. Erre szolgál a MultiTrigger.
A MutiTrigger csak DependencyProperty vizsgálatára jó.
Amennyiben .Net tulajdonságok vizsgálatára van szükség, úgy a MultiDataTrigger használata kell.

Az alábbi példában a Button szélessége csak abban az esetben változik meg, ha a Button magassága 30 és az egér is a gomb felett van.

<Grid>
 <Grid.Resources>
  <Style x:Key="MyButton" TargetType="{x:Type Button}">
   <Style.Triggers>
    <MultiTrigger>
     <MultiTrigger.Conditions>
      <Condition Property="IsMouseOver" Value="True"/>
      <Condition Property="Height" Value="30"/>
     </MultiTrigger.Conditions>

     <Setter Property="Width" Value="200"/>
    </MultiTrigger>

   </Style.Triggers>

   <Setter Property="Width" Value="100"/>
   <Setter Property="Height" Value="20"/>
  </Style>
 </Grid.Resources>

 <Button Name="Btn" Style="{StaticResource MyButton}" Content="Click"/>

 <Button VerticalAlignment="Bottom" Height="20" Content="Increment Height" Click="ButtonBase_OnClick"/>

</Grid>

A hozzá tartozó kód:
public partial class MultiTrigger_And : Window
{
 public MultiTrigger_And()
 {
  InitializeComponent();
 }

 private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
 {
  Btn.Height += 10;
 }
}

A MultiTrigger feltételeit egyesével meg kell adni a MultiTrigger Conditions tulajdonságában. Amennyiben minden feltétel teljesül a triger aktiválódik.

Nincsenek megjegyzések:

Megjegyzés küldése