WPF Trigger Properties - wpf

I am fairly new to WPF and I am currently working with triggers. I have a question regarding a simple trigger. By simple trigger, I mean one that watches for a change in a dependency property and uses a setter to change the style.
Example:
<Style.Triggers>
<Trigger Property="Control.IsFocused" Value ="True">
<Setter Property=" Control.Foreground" Value =" DarkRed" />
</Trigger>
</Style.Triggers>
All examples I have seen have used the following trigger properties:
<Trigger Property="Control.IsFocused" Value ="True">
<Trigger Property="Control.IsMouseOver" Value ="True">
<Trigger Property="Button.IsPressed" Value ="True">
Question:
Are these the only trigger properties available? If not, what others exist?
I have searched online but to no avail. Maybe someone could shed some light on this.

These are not the only properties that you can use in your Triggers, however, they are common examples because they are easily understandable and easy to demonstrate.
In truth, you can have your Trigger watch any DependencyProperty, but because it is "triggered" when the value changes (and matches the Value you tell it to watch for), it only makes sense to use properties that will change at runtime, often from user action (such as focus, mouse over, pressed, etc). Only certain DependencyProperties actual change value under these circumstances, so not all of them make sense to use in Triggers.
Microsoft has added several DependencyProperties to the standard controls so that you can easily create triggers based on changes. However you can also create your own controls with your own DependencyProperties and have triggers that respond when your custom DependencyProperties change.
Keep in mind, PropertyTriggers are only one flavor of Trigger in WPF. There are also EventTriggers and DataTriggers and MultiTriggers. These other triggers fire based on events or changes in data, or in the case of MultiTriggers multiple property (or data) values.
Is there something specific you're trying to do with Triggers? This other answer provides a good explanation of what each type of trigger does.

There are multiple types of triggers in WPF, but the two most commonly used are regular Triggers and DataTriggers
Both types of triggers will watch a value, and when it changes to match the specified Value then they apply your Style Setters.
Regular triggers can be used for any Dependency Property of the object. This includes properties like Text, Visibility, Background, etc in addition to the more commonly triggered properties that you specified: IsFocused, IsMouseOver, and IsPressed.
Note that per the MSDN page about Trigger.Property, you don't need to specify the class name prefix if the Style or Template containing the trigger has it's TargetType property set
An easy way to remember it is if you can bind the property, you can set a Trigger on it.
DataTriggers are triggers that watch a bound value instead of a Dependency Property. They allow you to watch a bound expression, and will react when that binding evaluates equal to your Value.
For example, you could set a DataTrigger on "{Binding Value}" or "{Binding ElementName=MyTextBox, Path=IsChecked}". You can even use Converters with DataTriggers, such as
<DataTrigger
Binding="{Binding SomeInt, Converter={StaticResource IsGreaterThanZero}}"
Value="True">

Use this code for better experience with trigger in wpf.
<Window x:Class="DataBinding.Trigger2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Trigger2" Height="500" Width="500">
<Window.Resources>
<Style TargetType="Button">
<Style.Setters>
<Setter Property="FontFamily" Value="Tahoma"></Setter>
<Setter Property="FontSize" Value="15"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
<Setter Property="Height" Value="25"></Setter>
<Setter Property="Width" Value="100"></Setter>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Purple"></Setter>
<Setter Property="Foreground" Value="DarkCyan"></Setter>
<Setter Property="FontFamily" Value="Franklin Gothic"></Setter>
<Setter Property="FontSize" Value="10"></Setter>
<Setter Property="FontWeight" Value="Normal"></Setter>
<Setter Property="Height" Value="50"></Setter>
<Setter Property="Width" Value="200"></Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="FontFamily" Value="Calibri"></Setter>
<Setter Property="FontSize" Value="25"></Setter>
<Setter Property="FontWeight" Value="Heavy"></Setter>
<Setter Property="Height" Value="100"></Setter>
<Setter Property="Width" Value="400"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="Green"></Setter>
<Setter Property="Foreground" Value="Violet"></Setter>
<Setter Property="FontFamily" Value="Times New Roman"></Setter>
<Setter Property="FontSize" Value="20"></Setter>
<Setter Property="FontWeight" Value="Thin"></Setter>
<Setter Property="Height" Value="250"></Setter>
<Setter Property="Width" Value="250"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Button>It's a Magic.</Button>

Related

WPF ComboBox remove highlight effect without overriding entire style

I'm new to WPF and have run into a bit of a problem. I am trying to remove the blue gradient effect on a combobox (e.g. when the user mouses over it) in order to create a more flat UI aesthetic, but I haven't been able to figure out how. Most of the solutions I've seen while googling involve doing somthing like:
<Style x:Key="myComboBox" TargetType="{x:Type ComboBox}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<!-- and then the rest of the style re-implements the combobox from scratch... -->
That seems a bit much just to remove one minor effect. I've also tried doing things like:
<Style x:Key="myComboBox" TargetType="{x:Type ComboBox}">
<Setter Property="Background" Value="LightGray"/>
<Setter Property="Foreground" Value="LightGray"/>
<Setter Property="BorderBrush" Value="DarkGray"/>
<Setter Property="Focusable" Value="False" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightGray"/>
</Trigger>
</Style.Triggers>
But that doesn't seem to have any effect either. Does anyone know what setting I might change to remove the hover effect?

Background color of selected DataGridRow not working / how to combine with AlternationIndex?

I'm trying to style a DataGrid, this includes styling DataGridRow as well. What I want is having an alternating background behavior on my rows (say, White/Grey); when a row is selected, the background should be YellowGreen. Somehow the following code is not working, but I'm sure using DataGridCell for the selection part would work; I'd just like to know why this isn't doing it:
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="DataGridRow.AlternationIndex" Value="0">
<Setter Property="Background" Value="{StaticResource EnBWLichtgrau}"/>
</Trigger>
<Trigger Property="DataGridRow.AlternationIndex" Value="1">
<Setter Property="Background" Value="White"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="DataGridRow.AlternationIndex" Value="0"/>
<Condition Property="DataGridRow.IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Background" Value="Pink"/>
</MultiTrigger.Setters>
</MultiTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type DataGrid}">
<Setter Property="AlternationCount" Value="2"/>
<Setter Property="BorderBrush" Value="{StaticResource EnBWAnthrazitgrau}"/>
<Setter Property="HeadersVisibility" Value="Column"/>
</Style>
Maybe some setters override the MultiTrigger setters, maybe something else, I don't know. The MultiTrigger isn't really necessary right now, but even a simple Trigger on IsSelected doesn't work this way.
As I said, I could probably go over to styling DataGridCell, but the "why" is what I'm interested in :-) Thanks!
EDIT: I tried using DataGridCell instead for the IsSelected part and it works as expected. But what if I wanted the selected row background color to be different depending on the AlternationIndex of the DataGridRow the cell is in? Is there some way to get the value of this index inside the DataGridCell style definition e.g.?

WpfToolkit AutoCompleteBox style trigger IsFocused NOT firing

I am using the latest version of WPF Toolkit. I am trying to style an AutoCompleteBox and I can't seem to get the "IsFocused" trigger to work. Basically I want it to behave like my TextBox style so I made one for the AutoCompleteBox. I even tried assigning my TextBox style to the TextBoxStyle property of the AutoCompleteBox and I still never see the IsFocused trigger fire.
I did try playing around in the code behind and noticed that if I override OnGotFocus and OnLostFocus those never get called. But if I wire some event handlers to the GotFocus and LostFocus events, THEN I finally see something happen. If wiring to the events is the only way to see the IsFocused change then that seems like an ugly hack. Is there some work around for this or something I should do different?
My TexBox Style
<Style TargetType="TextBox" x:Key="TextBoxStyle">
<Setter Property="Background" Value="{StaticResource TextBoxBackground}"/>
<Setter Property="Foreground" Value="{StaticResource Foreground}"/>
<Setter Property="CaretBrush" Value="{StaticResource Foreground}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
<ScrollViewer x:Name="PART_ContentHost" Margin="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundSelected}"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundSelected}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My AutoCompleteBox Style
<Style TargetType="WpfToolkitInput:AutoCompleteBox" x:Key="AutoCompleteBoxStyle">
<Setter Property="Background" Value="{StaticResource TextBoxBackground}"/>
<Setter Property="Foreground" Value="{StaticResource Foreground}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="TextBoxStyle" Value="{StaticResource TextBoxStyle}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundSelected}"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundSelected}"/>
</Trigger>
</Style.Triggers>
Any ideas?
Thank you for your time!
I was unsuccessful in finding an elegant solution to the problem. I ended up inheriting from AutoCompleteBox and performing my logic with the event handlers.
public class AutoCompleteTextBox : AutoCompleteBox
...
public AutoCompleteTextBox()
{
// Register the event handler for GotFocus.
base.GotFocus += this.AutoCompleteTextBoxGotFocus;
// Register the event handler for LostFocus.
base.LostFocus += this.AutoCompleteTextBoxLostFocus;
}
Nothing fancy here. I just made my own type. The only thing I do is wire up the got and lost focused event handlers in the constructor. I'm not sure why but the IsFocused trigger does not pick up these events. Also, if you try to override these: "OnGotFocus" or "OnLostFocus", they don't work either. So the only way I could find if the AutoCompleteBox is focused is to register directly to the event. If someone comes across this in the future and has a better way, please comment.

wpf DataGrid Loses its Row Selection when the focus is lost

I have come accross a very strange behavior with the DataGrid. I have following Trigger on the DataGridRow
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource SelectionBackgroundBrush}"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
Initially when the row is selected, I get the behavior from the above trigger. However, after selection, if the DataGrid loses focus (say for example I click some other button on window) the Foreground property loses its value, but the background remains as specified in the trigger. Has anyone ever come accross this behavior, or there is some problem with my code above (or elsewhere in my applicaion for that matter). Any workarounds for the above issue ?
I've used DataGridCell instead of DataGridRow and it works for me
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected" Value="True">
<Setter Property="BorderBrush" Value="#CCDAFF" />
<Setter Property="Background" Value="#3399ff"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
Hope it helps someone!

DataGridCell.IsEditMode?

How Can I know if the DataGridCell is currently in edit mode (not IsSelected), I mean, for example a DataGridTextColumn cell is clicked it becomes a TextBox and not a TextBlock, that's what I call IsEditMode.
I wanna set a trigger-setter for this mode.
EDIT:
I tried to set a general style for DataGridCell.IsEditing but it doesn't seem to do anything.
Here is a snippet of my current code:
<Style TargetType="{x:Type tk:DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{x:Null}"/>
</Trigger>
<Trigger Property="IsEditing" Value="True">
<Setter Property="BorderBrush" Value="#FF62B6CC"/>
<Setter Property="Background" Value="#FFF4F4F4"/>
</Trigger>
</Style.Triggers>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderThickness" Value="0.5"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
</Style>
Thanks.
Here's how to do it:
<Trigger Property="IsEditing" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text, Mode=TwoWay, UpdateSourceTrigger=Default}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
then style the textbox as you please
If you take a look at DataGridCell.cs file, IsEditing should be good way to find out if cell is in edit mode. But you can't set this property from style, because there is local value assignment in DataGridCell class (which has higher priority from style setter).
So, the answer would be: it should work from trigger, but it will not from the style setter.
Update: Shimmy, it really works. Snoop your application, make sure DataGridCell is using your implicit style. Select DataGridCell in the tree, and check its background property. Every time you go in Edit mode it is updated. But you don't see it, by default, since TextBox doesn't inherit Background property. But that's another story. I think you can tweak CellEditingTemplate to make it working.
The proper way to turn on edit mode is to find the DataGridCell's parent DataGrid and call BeginEdit() on that. If you set it directly, you're sidestepping a lot of DataGrid goo that maintains proper state transitions.

Resources