Saturday, May 27, 2017

Triggers in WPF

Triggers are used to change the property value of UI elements on the basics of some condition change or some event fire.

Triggers are used in styles and allow you to dynamically change the property value of a UI element.
when some condition satisfied then trigger make changes in the property.
So we can say Trigger are used to change the visual effect/behavior of control on change of property value or some event fire, it can change the visual appearance of a framework element.

We can understand it by some simple example :

  1. We have a button in our wpf window and if mouse hover on the button then background of button should be red and as mouse hover out it revert to previous color.
  2. We have a text box in the window and when it's value is red it's background color become red other wise normal.
The properties changed by triggers are automatically reset to their previous value when the triggered condition is no longer satisfied. Triggers are optimized for transient states which are expected to change and return to original state, such as IsPressed on Button and IsSelected on ListBoxItem. The Property of interest must be a dependency property.

We must specify the property and value in trigger otherwise it throw exception.

There are main three triggers
  • Property Trigger
    • MultiTrigger
  • Data Trigger
    • MultiDataTrigger
  • Event Trigger
Property Trigger

In Property trigger,when some UIElement property i.e. dependency property of a control change then the setters inside the trigger execute.
For creating the property trigger for a control we need to create the trigger in its style.

e.g. property trigger can be used to change the foreground color of button when mouse hover over the button.


<Window x:Class="MVVMBasics.PropertyTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PropertyTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}" x:Key="TriggerTextBoxStyle" >
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Foreground" Value="Red"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <TextBox Name="btnColor" Text="Test Property Triggers" Style="{StaticResource TriggerTextBoxStyle}" HorizontalAlignment="Left"
                Width="150" Height="30" Margin="50"></TextBox>
    </Grid>
</Window>








in the above example trigger is created in "TriggerTextBoxStyle" style, on change in proeprty IsMouseOver when it is true the setter set the background to red.
we can put multiple setter for this trigger or we can put multiple trigger inside this trigger collection.
<Window x:Class="MVVMBasics.PropertyTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PropertyTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}" x:Key="TriggerTextBoxStyle" >
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Foreground" Value="Red"></Setter>
                    <Setter Property="Background" Value="YellowGreen"></Setter>
                    <Setter Property="FontWeight" Value="Bold"></Setter>
                </Trigger>
                <Trigger Property="Text" Value="wpf">
                    <Setter Property="Foreground" Value="White"></Setter>
                    <Setter Property="Background" Value="Red"></Setter>
                    <Setter Property="FontWeight" Value="ExtraBlack"></Setter>
                </Trigger>

            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <TextBox Name="btnColor" Text="Test Property Triggers" Style="{StaticResource TriggerTextBoxStyle}" HorizontalAlignment="Left"
                Width="150" Height="30" Margin="50"></TextBox>
    </Grid>

</Window>



MultiTrigger

Some time we need to set the values of property when more then one conditions satisfy, MultiTrigger fulfill this feature.
MultiTrigger depends upon multiple properties and will execute when all conditions are satisfy.
E.g.




<Window x:Class="MVVMBasics.PropertyTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PropertyTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}" x:Key="TriggerTextBoxStyle" >
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="Text" Value="wpf"></Condition>
                        <Condition Property="IsMouseOver" Value="true"></Condition>
                    </MultiTrigger.Conditions>
                    <MultiTrigger.Setters>
                        <Setter Property="Foreground" Value="White"></Setter>
                        <Setter Property="Background" Value="Red"></Setter>
                        <Setter Property="FontWeight" Value="ExtraBlack"></Setter>
                    </MultiTrigger.Setters>
                </MultiTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <TextBox Name="btnColor" Text="wpf" Style="{StaticResource TriggerTextBoxStyle}" HorizontalAlignment="Left"
                Width="150" Height="30" Margin="50"></TextBox>
    </Grid>

</Window>


DataTrigger


In property trigger we use Dependency Property in conditions but In the data Trigger are used with Property value that is bind with DP property.

e.g. TextBox has Text DP property and Text DP is bind with Data CLR property of some ViewModel so Property Trigger use Text in condition while DataTrigger use Data Property in Condition.

we can define the data trigger inside the style or in DataTemplate
Element name can also use in Data Trigger's Conditions.

Consider we have wpf window in which there is two TextBoxs first is Color Text





<Window x:Class="MVVMBasics.PropertyTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}" x:Key="TriggerTextBoxStyle" >
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=cbColor, Path=Text}" Value="Red">
                    <Setter Property="Foreground" Value="Red"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding ElementName=cbColor, Path=Text}" Value="BlueViolet">
                    <Setter Property="Foreground" Value="BlueViolet"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding ElementName=cbColor, Path=Text}" Value="Green">
                    <Setter Property="Foreground" Value="Green"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <ComboBox Name="cbColor" SelectedIndex="0" Width="100" HorizontalAlignment="Center" Margin="0,10,0,0">
            <ComboBoxItem Content="Red"></ComboBoxItem>
            <ComboBoxItem Content="BlueViolet"></ComboBoxItem>
            <ComboBoxItem Content="Green"></ComboBoxItem>
        </ComboBox>
        <TextBox x:Name="btnColor" Text="wpf" Style="{StaticResource TriggerTextBoxStyle}" HorizontalAlignment="Center"
              Width="150" Height="30"  Margin="0,20,0,0" />
    </StackPanel>

</Window>

We can not use element name binding with property Trigger


ViewModel property in DataTrigger


<Window x:Class="MVVMBasics.DataTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type Label}" x:Key="DataTriggerStyle" >
            <Setter Property="Background" Value="Green"></Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Age}" Value="35">
                    <Setter Property="Background" Value="Red"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <TextBox x:Name="btnAge" Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"
              Width="150" Height="30"  Margin="0,20,0,0" />
        <Label x:Name="btnColor" Style="{StaticResource DataTriggerStyle}" HorizontalAlignment="Center"
              Width="50" Height="30"  Margin="0,20,0,0" />
    </StackPanel>

</Window>


Code Behind

using System.ComponentModel;
using System.Windows;

namespace MVVMBasics
{
    /// <summary>
    /// Interaction logic for DataTriggerDemo.xaml
    /// </summary>
    public partial class DataTriggerDemo : Window, INotifyPropertyChanged
    {
        private int age;
        public int Age
        {
            get { return age; }
            set
            {
                age = value; OnPropertyChange("Age");
            }
        }
        public DataTriggerDemo()
        {
            InitializeComponent();
            this.DataContext = this;
        }
        public void OnPropertyChange(string propertyName)
        {
            PropertyChangedEventHandler propChange = PropertyChanged;
            if (propChange != null)
            {
                propChange(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}





MultiDataTrigger

In MultiDataTrigger Execute the set of setter collection on more then one condition satisfied.

<Window x:Class="MVVMBasics.DataTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MultiDataTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type Label}" x:Key="DataTriggerStyle" >
            <Setter Property="Background" Value="Green"></Setter>
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Name}" Value="wpf"></Condition>
                        <Condition Binding="{Binding Age}" Value="35"></Condition>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.Setters>
                        <Setter Property="Background" Value="Red"></Setter>
                    </MultiDataTrigger.Setters>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Label x:Name="lblName" Content="Name" HorizontalAlignment="Center"
              Width="67" Height="25"  />
            <TextBox x:Name="txtName" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"
              Width="67" Height="25"  Margin="5" />
        </StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Label x:Name="lblAge" Content="Age" HorizontalAlignment="Center"
              Width="67" Height="25"  />
            <TextBox x:Name="txtAge" Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"
              Width="67" Height="25"  Margin="5" />
        </StackPanel>
        <Label x:Name="lblColor" Style="{StaticResource DataTriggerStyle}" HorizontalAlignment="Center"
              Width="50" Height="30"  Margin="0,20,0,0" />
    </StackPanel>
</Window>




Event Trigger

Event Trigger are basically used when some routed event raised by some framework element.
It is Used to perform some Animation
We will continue this topic(Event Trigger) with my post WPF Animation very soon.