What are the triggers?
You may be familiar with triggers in RDBMS. It performs some action whenever an event takes place, like Updating a table or something. It's the same concept in WPF: It is a response to an action.
Triggers are applied on styles or directly on controls, so you first need to learn what styles are. You can have a sneak peek at my article on
Styles.
And trigger can only be applied at runtime.
Basically, there are 3 types of triggers.
- Property Trigger: Applied based on control's property, such as IsMouseOver: value sets true is a mouse is over the control.
- Data Trigger: Applied based on binded data.
- Event Trigger: Applied based on an event, such as ButtonClick.
Let's learn about each of them.
- Property Trigger: One needs to use a Trigger tag to set the if condition.
Have a look at the following image to understand 3 things.
- What is an if condition,
- What are the values that are going to change if, if condition satisfies,
- And what conditions are unaffected if conditions satisfy or not.
MainWindow.xaml
- <Window x:Class="A.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:A"
- mc:Ignorable="d"
- Title="MainWindow" Height="180" Width="300">
- <Window.Resources>
-
- <Style x:Key="SubmitButtonStyle"
- BasedOn="{StaticResource {x:Type Button}}"
- TargetType="Button">
- <Setter Property="Height" Value="25"/>
- <Setter Property="Width" Value="150"/>
- <Setter Property="BorderThickness" Value="2"/>
- <Setter Property="BorderThickness" Value="2"/>
- <Setter Property="HorizontalAlignment" Value="Center"/>
- <Setter Property="VerticalAlignment" Value="Center"/>
-
- <Setter Property="Content" Value="Trigger Not Applied"/>
- <Setter Property="BorderBrush" Value="Black"/>
- <Setter Property="Background" Value="Gray"/>
- <Setter Property="Foreground" Value="Wheat"/>
- <Style.Triggers>
- <Trigger Property="IsMouseOver" Value="True">
-
- <Setter Property="Content" Value="Trigger Applied"/>
- <Setter Property="BorderBrush" Value="White"/>
- <Setter Property="Background" Value="Blue"/>
- <Setter Property="Foreground" Value="Black"/>
-
- </Trigger>
- </Style.Triggers>
- </Style>
-
- </Window.Resources>
- <Grid x:Name="MainGrid">
- <Button x:Name="ButtonStyleMe"
- Style="{StaticResource SubmitButtonStyle}"/>
- </Grid>
- </Window>
We are changing 4 properties: Content, BorderBrush, Background & Foreground of the Button. If IsMouseOver; i.e.. mouse is over the button, then properties defined inside a trigger will execute, else properties above the trigger will execute.
Note
The condition is only applied for these 4 properties; the rest are unaffected.
The following gif is the output of the above code. It will give you the idea of what is happening inside that xaml at runtime.
DataTrigger
One needs to use a DataTrigger tag to set an if condition.
Things we are updating in xaml,
- Add new checkbox: this will be bound with a property named as IsTriggerCheckBoxChecked & if checked it will set IsTriggerCheckBoxChecked's value to true.
- Let's change Button's behavior from PropertyTrigger to DataTrigger
- Add new string property named as TriggerChangeText, which will display the text after CheckBox is checked.
- Add a label to display if it is set by data trigger.
Updated MainWindow.xaml
- <Window x:Class="A.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:local="clr-namespace:A"
- mc:Ignorable="d"
- Title="MainWindow" Height="180" Width="300">
- <Window.Resources>
- <Thickness x:Key="MarginTop">0 5 0 0 </Thickness>
- <Style x:Key="SubmitButtonStyle"
- BasedOn="{StaticResource {x:Type Button}}"
- TargetType="Button">
- <Setter Property="Height" Value="25"/>
- <Setter Property="Width" Value="150"/>
- <Setter Property="BorderThickness" Value="2"/>
- <Setter Property="BorderThickness" Value="2"/>
- <Setter Property="HorizontalAlignment" Value="Center"/>
- <Setter Property="VerticalAlignment" Value="Center"/>
-
- <Setter Property="Content" Value="Trigger Not Applied"/>
- <Setter Property="BorderBrush" Value="Black"/>
- <Setter Property="Background" Value="Gray"/>
- <Setter Property="Foreground" Value="Wheat"/>
- <Style.Triggers>
- <DataTrigger Binding="{Binding IsTriggerCheckBoxChecked}" Value="True">
- <Setter Property="Content" Value="Trigger Applied"/>
- <Setter Property="BorderBrush" Value="Black"/>
- <Setter Property="Background" Value="LightBlue"/>
- <Setter Property="Foreground" Value="Black"/>
- </DataTrigger>
- </Style.Triggers>
- </Style>
-
- </Window.Resources>
- <Grid x:Name="MainGrid">
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- </Grid.RowDefinitions>
- <CheckBox x:Name="CheckBoxTrigger"
- IsChecked="{Binding IsTriggerCheckBoxChecked}"
- HorizontalAlignment="Center"
- Content="Apply Data Trigger?"/>
- <Button x:Name="ButtonStyleMe"
- Style="{StaticResource SubmitButtonStyle}"
- Margin="{StaticResource MarginTop}"
- Grid.Row="1"/>
- <Label x:Name="LabelTrigger"
- Content="{Binding TriggerChangeText}"
- Margin="{StaticResource MarginTop}"
- HorizontalAlignment="Center"
- Grid.Row="2">
- <Label.Style>
- <Style BasedOn="{StaticResource {x:Type Label}}"
- TargetType="Label">
- <Setter Property="Content" Value="Default value from XAML."/>
- <Style.Triggers>
- <DataTrigger Binding="{Binding IsTriggerCheckBoxChecked}" Value="True">
- <Setter Property="Content" Value="{Binding TriggerChangeText}"/>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </Label.Style>
- </Label>
- </Grid>
- </Window>
MVVM: MainWindowViewModel.cs
- using A.Entities;
- using Prism.Mvvm;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace A
- {
- class MainWindowViewModel : BindableBase
- {
- #region Properties
- private bool _isTriggerCheckBoxChecked;
-
- public bool IsTriggerCheckBoxChecked
- {
- get { return _isTriggerCheckBoxChecked; }
- set
- {
- if (value)
- {
- TriggerChangeText = "Applied with data trigger!";
- }
- SetProperty(ref _isTriggerCheckBoxChecked, value);
- }
- }
-
- private string _triggerChangeText;
-
- public string TriggerChangeText
- {
- get { return _triggerChangeText; }
- set { SetProperty(ref _triggerChangeText, value); }
- }
-
- #endregion
- }
- }
Run the project
The following gif will be the output.
Event Trigger
One needs to use an EventTrigger tag to set an if condition.
Let's add some simple animation on ButtonClick event.
Animation 1: Change the Button's background colour,
Animation 2: Increase & decrease the width of a Button.
- <Button x:Name="ButtonStyleMe"
- Margin="{StaticResource MarginTop}"
- Grid.Row="1">
- <Button.Style>
- <Style TargetType="Button"
- BasedOn="{StaticResource SubmitButtonStyle}">
- <Style.Triggers>
- <EventTrigger RoutedEvent="Button.Click">
- <EventTrigger.Actions>
- <BeginStoryboard>
- <Storyboard Storyboard.TargetProperty="Background.(SolidColorBrush.Color)" Duration="0:0:8">
- <ColorAnimation To="Gray" Duration="0:0:0"/>
- <ColorAnimation To="Coral" Duration="0:0:1"/>
- <ColorAnimation To="LightBlue" Duration="0:0:2"/>
- <ColorAnimation To="Salmon" Duration="0:0:3"/>
- <ColorAnimation To="White" Duration="0:0:4"/>
- <ColorAnimation To="Salmon" Duration="0:0:5"/>
- <ColorAnimation To="LightBlue" Duration="0:0:6"/>
- <ColorAnimation To="Coral" Duration="0:0:7"/>
- <ColorAnimation To="Gray" Duration="0:0:8"/>
- </Storyboard>
- </BeginStoryboard>
- <BeginStoryboard>
- <Storyboard Storyboard.TargetProperty="Width" Duration="0:0:8">
- <DoubleAnimationUsingKeyFrames>
- <LinearDoubleKeyFrame Value="150" KeyTime="0:0:0"/>
- <LinearDoubleKeyFrame Value="200" KeyTime="0:0:1"/>
- <LinearDoubleKeyFrame Value="250" KeyTime="0:0:2"/>
- <LinearDoubleKeyFrame Value="300" KeyTime="0:0:3"/>
- <LinearDoubleKeyFrame Value="350" KeyTime="0:0:4"/>
- <LinearDoubleKeyFrame Value="300" KeyTime="0:0:5"/>
- <LinearDoubleKeyFrame Value="250" KeyTime="0:0:6"/>
- <LinearDoubleKeyFrame Value="200" KeyTime="0:0:7"/>
- <LinearDoubleKeyFrame Value="150" KeyTime="0:0:8"/>
- </DoubleAnimationUsingKeyFrames>
- </Storyboard>
- </BeginStoryboard>
- </EventTrigger.Actions>
- </EventTrigger>
- </Style.Triggers>
- </Style>
- </Button.Style>
- </Button>
Code explanation
Inside an EventTrigger, you have to specify which routed event you want to have it triggered on.
Then specify your actions inside a EventTrigger.Actions tag.
I have added 2 StoryBoards each for every animation. The animation lasts for 8 seconds, then specify your actions on every second.
MainWindow.xaml
Now run your application. Output gif:
Looks amazing, we will learn more about animation & graphics in upcoming articles.
I sincerely hope you enjoyed this article and that you're inspired to apply what you've learned to your own applications.
Thank you for reading this article! I hope you understood the concept of Triggers in WPF.
Happy Coding!
Feel free to connect @