الجمعة، 27 مايو 2011

Triggers in WPF


Triggers
Triggers have a collection of Setters just like Style (and/or collections of Trigger Actions). But whereas a Style applies its values unconditionally, a trigger performs its work based on one or more conditions.

Recall that there are three types of triggers:
  • Property Triggers get active, when a property gets a specified value.
  • Event Triggers get active, when a specified event is fired.
  • Data Triggers get active, when a binding expression reaches a specified value.
FrameworkElement, Style, DataTemplate, and ControlTemplate all have a Triggers collection, but whereas Style and the template classes accept all three types, FrameworkElement only accepts event triggers.
Fortunately, Style happens to be the logical place to put triggers even if you had a choice because of the ease in sharing them and their direct tie to the visual aspects of elements.

Property trigger
A property trigger activates a list of setters when a property gets a specified value. If the value changes the trigger undoes the setters.

Example #1
    <Grid>
        <Grid.Resources>
            <Style x:Key="styleWithTrigger" TargetType="Rectangle">
                <Setter Property="Fill" Value="LightGreen" />
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Fill" Value="Red" />
                    Trigger>
                Style.Triggers>
            Style>

           
        Grid.Resources>
        <Rectangle Style="{StaticResource styleWithTrigger}">Rectangle>
    Grid>

Example #2
The following update to buttonStyle makes the rotation only happen when the mouse pointer is hovering over the Button (and sets the Foreground to Black rather than White):

 

 <Grid>
        <Grid.Resources>
            <Style x:Key="buttonStyle" TargetType="{x:Type Button}">
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="RenderTransform">
                            <Setter.Value>
                                <RotateTransform Angle="10"/>
                            Setter.Value>
                        Setter>
                        <Setter Property="Foreground" Value="Black"/>
                    Trigger>
                Style.Triggers>
                <Setter Property="FontSize" Value="22"/>
                <Setter Property="Background" Value="Purple"/>
                <Setter Property="Foreground" Value="White"/>
                <Setter Property="Height" Value="50"/>
                <Setter Property="Width" Value="50"/>
                <Setter Property="RenderTransformOrigin" Value=".5,.5"/>
            Style>


        Grid.Resources>

        <Button Style="{StaticResource buttonStyle}" Width="150" Height="50" Content="OK" />
    Grid>

  
Data Triggers
Data triggers are just like property triggers, except that they can be triggered by any .NET property rather than just dependency properties. (The Setters inside a data trigger are still restricted to setting dependency properties, however.)
To use a data trigger, add a DataTrigger object to the Triggers collection and specify the property/value pair.
To support plain .NET properties, you specify the relevant property with a Binding rather than a simple property name.
Regardless of what element you are binding and the nature of your data source, each binding always follows the model illustrated by the following figure:


The following TextBox has a Style that triggers the setting of IsEnabled based on the value of its Text property, which is not a dependency property. When Text is the string “disabled,” IsEnabled is set to false (which is admittedly an unusual application of a data trigger):



The TextBox Style’s data trigger disables it when its text is “disabled.
<StackPanel Width="200">
        <StackPanel.Resources>
            <Style TargetType="{x:Type TextBox}">
                <Style.Triggers>
                    <DataTrigger
Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}"
Value="disabled">
                        <Setter Property="IsEnabled" Value="False"/>
                    DataTrigger>
                Style.Triggers>
                <Setter Property="Background"
Value="{Binding RelativeSource={RelativeSource Self}, Path=Text}"/>
            Style>
        StackPanel.Resources>
        <TextBox Margin="3"/>
    StackPanel>




Example #2


Here is one example of data trigger. We have a student class and this class contains the student name and grade information.

If we want to change the color of the row if student fail, then we can do it with data trigger. Here is simple XAML code to apply perform this.


namespace WpfApplication23
{
    public partial class MainWindow : Window

    {

         public MainWindow()

         {

             InitializeComponent();
         }

         private void Window_Loaded(object sender, RoutedEventArgs e)

         {

             lstView.Items.Add(new Student("Ahmed", "Fail"));

             lstView.Items.Add(new Student("Ali", "Pass"));

             lstView.Items.Add(new Student("Mohamed", "Pass"));

             lstView.Items.Add(new Student("Omar", "Pass"));

             lstView.Items.Add(new Student("Dina", "Fail"));

             lstView.Items.Add(new Student("Ola", "Pass"));

         }

     }

     public class Student

     {
        public Student(String name, String grade)

         {
             StudentName = name;

             Grade = grade;
         }

       public String StudentName
        { set; get; }
         public String Grade
         { set; get; }
     }
 }

And here's the XAML
    <Window x:Class="WpfApplication23.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

     Title="Data Trigger Demo" Height="300" Width="400" Loaded="Window_Loaded">

        <Window.Resources>

            <Style TargetType="{x:Type ListViewItem}">

                <Style.Triggers>

                    <DataTrigger Binding="{Binding Grade}" Value="Fail">

                        <Setter Property="Background" Value="Red"/>

                        <Setter Property="Foreground" Value="White"/>

                    DataTrigger>

                Style.Triggers>

            Style>

        Window.Resources>

        <Grid>

            <ListView Name="lstView">

                <ListView.View>

                    <GridView>

                        <GridViewColumn Width="180" Header="Student Name" DisplayMemberBinding="{Binding Path = StudentName}">GridViewColumn>

                        <GridViewColumn Width="180" Header="Grade" DisplayMemberBinding="{Binding Path = Grade}">GridViewColumn>

                    GridView>
                ListView.View>
            ListView>
        Grid>
    Window>


Expressing More Complex Logic with Triggers
The logic expressed with the previous triggers has been of the form “when property=value, set the following properties.” But more powerful options exist:
 Multiple triggers can be applied to the same element (to get a logical OR).
Multiple properties can be evaluated for the same trigger (to get a logical AND).

Logical OR
Because Style.Triggers can contain multiple triggers, you can create more than one with the exact same Setters to express a logical OR relationship:

   <Window x:Class="WpfApplication23.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

     Title="Data Trigger Demo" Height="300" Width="400" >

    <Window.Resources>
        <Style x:Key="buttonStyle" TargetType="{x:Type Button}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="RenderTransform">
                        <Setter.Value>
                            <RotateTransform Angle="10"/>
                        Setter.Value>
                    Setter>
                    <Setter Property="Foreground" Value="Black"/>
                Trigger>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="RenderTransform">
                        <Setter.Value>
                            <RotateTransform Angle="10"/>
                        Setter.Value>
                    Setter>
                    <Setter Property="Foreground" Value="Black"/>
                Trigger>
            Style.Triggers>
        Style>
    Window.Resources>
    <Button Content="Button" Height="23" Name="button1" Width="75" Style="{StaticResource buttonStyle}" />
Window>

Logical AND

To express a logical AND relationship, you can use a variation of Trigger called MultiTrigger, or a variation of DataTrigger called MultiDataTrigger. MultiTrigger and MultiDataTrigger have a collection of Conditions that contain the information you would normally put directly inside a Trigger or DataTrigger. Therefore, you can use MultiTrigger as follows:
So we just need to update to the following code
      <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsMouseOver" Value="True"/>
                        <Condition Property="IsFocused" Value="True"/>
                    MultiTrigger.Conditions>
                    <Setter Property="RenderTransform">
                        <Setter.Value>
                            <RotateTransform Angle="10"/>
                        Setter.Value>
                    Setter>
                    <Setter Property="Foreground" Value="Black"/>
                MultiTrigger>
            Style.Triggers>



0 التعليقات: