WPF DataTriggers & MultiDataTriggers

 

Not quiet a DataTrigger

Recently I was doing some WPF work and was trying to customize the display of a UserControl  based on a dependency property (DP) of that same UserControl . This post will outline what I learnt about DataTriggers and MultiDataTriggers while completing the task.

The first goal was to adjust the vertical alignment of two elements. I have created a simple UserControl  containing two elements to demonstrate this, namely an image and a caption.  When creating an instance of this UserControl  I want to be able to specify the position of the caption relative to the image (i.e. on top of or below). To achieve this I added the CaptionVerticalAlignment DP to the code behind.  The intended use of this property is to describe the vertical alignment of the text (i.e. Top or Bottom).  Specifying anything else results in an ArgumentException :

To modify the style of the text box I query the value of the same DP in the xaml through a RelativeSource  data binding:

Specifing RelativeSource  as the binding type means that I want to bind to an element that is relative to the target.  The target in this case is a TextBox .  By specifying AncestorType , the RelativeSource  mode defaults to FindAncestor  and the ancestor type that it searches for is a UserControl .  This binding source is useful in situations where you have nested elements.  Carry on reading for an alternative to FindAncestor … (oh the suspense!)

DataTrigger

I could create another DP that specifies the alignment of the image, or I could re-use the caption alignment DP to link the image’s alignment to the that of the caption.  A  DataTrigger  supports this operation.  This time I specify ElementName  as the binding type.  I prefer this type of binding to the RelativeSource  binding as it is more readable in my opinion as well as more explicit about the element to bind to.  From what I have read online there isn’t much between the two types of binding in terms of performance:

Depending on what vertical alignment I choose, I get one of the following results:

ImageAndCaption

MultiDataTrigger

DataTriggers are very useful if you want to query a single condition, however if you want to query multiple conditions then you need to use a MultiDataTrigger .  The second goal of my task involved modifying an image style based on two conditions.  In my contrived example I have two navigation arrows for scrolling left and right.  I want to adjust the style of the cursor depending on the arrow that it has highlighted.  The two conditions that I need to query are whether the mouse is highlighting the arrow, and which direction the arrow is facing.  In this case I use both bindings types from above to do the same binding (sure why not eh?).  This time however I specify self as the RelativeSource  rather than using AncestorType .  Incidentally I could have used the same RelativeSource  for the binding in the TextBox  style above as well which would have been more concise:

In the example I hovered the cursor over the left arrow which resulted in the cursor changing to the scroll west cursor because of the direction of the arrow.  The arrow image itself also changes once the mouse cursor hovers over it:

DirectionArrow

MultiDataTriggers  support short cutting condition checks.  Therefore if the first condition fails, subsequent conditions won’t be checked since the binary AND operation is used when checking the results of each condition.  One drawback of using MultiDataTriggers is that they can’t be debugged.  If debugging is required you could use a Converter  along with a MultiBinding  – take a look on MSDN for an example.

Summary

This blog post demonstrates the usefulness of both the DataTrigger  and MultiDataTrigger  for customising a UI based on user interaction.  I have also provided examples of various data binding methods to add to your arsenal.

Source Code

The source code can be found on Bitbucket.

Tagged , , . Bookmark the permalink.

Leave a Reply

Your e-mail address will not be published. Required fields are marked *