Reason 4. Triggers
Earlier I introduced a series of posts entitled
10 reasons to consider WPF for your next desktop application. If you haven't read the intro yet, better head on back and
read it first.
Triggers are basically a way of applying a value to a property of an object when an event occurs or a particular condition is satisfied.
Let's look at an example. Again, we'll be using the product of the
previous reason and build on that (including the changes made in the post about
my dirty little secret).
We're going to pimp our listbox some more. In this scenario, I want to draw attention to my best books and somehow want to highlight books that have a customer rating of 5. Let's look at how to do this with a DataTrigger (a type of trigger).
<DataTemplate x:Key="listTemplate">
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding CustomerRating}" Value="5" >
<Setter TargetName="_bookName" Property="TextBlock.FontWeight" Value="Bold" />
<Setter TargetName="_ratingBar" Property="src:RatingBar.Fill" Value="Red" />
</DataTrigger>
</DataTemplate.Triggers>
<!-- snipped for brevity -->
<TextBlock x:Name="_bookName" Text="{Binding Name}" />
<src:RatingBar x:Name="_ratingBar" Value="{Binding CustomerRating}" ... />
As you can see, we've added a new DataTrigger to our DataTemplate's Triggers collection. This DataTrigger is bound to the CustomerRating and is waiting for a Value of 5 before it will 'fire'. This is when the Setters inside are applied.
A Setter is a pretty simple idea - it sets the value of a property. In the example above we set the FontWeight of the TextBlock (with the name _bookName) to Bold.
We also have a second Setter that changes the Fill of our new RatingBar to Red.
Et Voila!

Too easy. There are more, and perhaps more useful scenarios where Triggers can help you. It is a very common requirement that we have one part of our view disabled based upon the state of another part. For example, in our example UI the textboxes on the left should be disabled if no books are selected in the listbox.

This makes sense right? You don't want you user typing when we're not bound to an object. All we need to do is disable (set IsEnabled=False) on the GroupBox containing the listboxes based on the SelectedIndex listbox:
<GroupBox Header="Book Details" DataContext="{Binding ElementName=_lstBooks, Path=SelectedItem}" Margin="3" Grid.Column="1" >
<GroupBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=_lstBooks, Path=SelectedIndex}" Value="-1">
<Setter Property="GroupBox.IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</GroupBox.Style>

To achieve this we simply use a DataTrigger within the style of the GroupBox. And it works a treat, even if your listbox supports deletion (i.e. when you delete an item from the list of books, if this means an item is no longer selected in the listbox then the GroupBox will be disabled). To prove this I've added some simple functionality to add and remove books to the list.
Why not have a play with the
Reason 4 ClickOnce Sample.
I'll put the code up for download at the end of the series.
PS - Just for fun, I made the Orange RatingBar interactive. You can click and drag it and actually change the value of the CustomerRating.