Triggers and selectors in WPF templating
If you’ve worked with WPF for any significant length of time, you’ll be used to using styles and templates to describe how to present an object in the user interface. But what if you want to have the presentation change according to circumstances? WPF provides two ways of doing this: triggers and selectors.
Triggers provide a way to selectively modify the presentation based on data values. For example, a trigger could specify that an Image element should be hidden if the Picture property is null, or that a TextBlock should be drawn in grey if the IsEnabled property is false.
Selectors allow more complex logic and more radical changes. A selector allows you to choose different DataTemplates or Styles depending on custom logic. For example, in a heterogeneous ItemsControl, you might choose whether to use a TextBlock or TextBox-based template depending on whether the item is read-only or read-write.
Superficially this makes selectors an attractive option when the different presentations have got substantially different structure, or when the logic for when the different presentations should be used is more complicated than “some property equals some value.” But there’s a catch with selectors that means you can only use them in very specific cases.
The problem is that selectors run only once, when WPF has to determine a template for the object. After that, it’s up to the template to update itself, using triggers. So a selector should only consider immutable aspects of the object. For example, it’s appropriate for a selector to consider the type of the object, or a read-only discriminator. But if you use a selector to switch templates depending on whether the BankBalance property is positive or negative, you’ll be in for a disappointment. If the BankBalance value starts out as positive, then changes to negative, any controls that have already selected the “positive” template will continue to display the “positive” template. By contrast, if you’d used a single template with triggers, the “negative” settings would have been applied when the BankBalance went negative.
This might seem to put you in a bind if you want the template to update as data changes, but need more sophisticated logic than the “does some property equal some value” which is all that triggers support.
Fortunately, you can get around this by using a DataTrigger. Although a DataTrigger still performs an equality test, you can use an IValueConverter to convert the raw value into a classifier that you can then match for equality. For example, you could write an IsNegativeValueConverter which returns true for negative values and false for non-negative values. Your DataTrigger can then have a Binding of {Binding BankBalance, Converter={…}}, with a Value of true to activate the “negative” setters.
This works fine for DataTemplates, but what about Styles or ControlTemplates? Suppose you want to style a TextBox so that it turns red if its Text property, considered as a number, is negative? Well, DataTrigger will still do the job, but you need to find the right binding source. In this case, RelativeSource.Self gives you access to the control being styled or templated. So in our Style.Triggers or ControlTemplate.Triggers collection, we would create a DataTrigger with a Binding of {Binding Text, RelativeSource={RelativeSource Self}, Converter={…}}.
This does seem a bit unnatural: why should we use a plain Trigger for simple matches and a DataTrigger with a magic binding for more complex matches? It would be nice if some future version of WPF supported converters on plain Triggers. But for now the DataTrigger/RelativeSource.Self trick allows us to realise the sophisticated logic of selectors in the live world of triggers.
One Response to “Triggers and selectors in WPF templating”
Leave a Reply
![]()
BrainDump (1)
Community Code (1)
Events (6)
General (31)
Lab Samples (2)
LightSpeed (132)
MegaPack (3)
News (48)
Products (64)
Projects (4)
Screencast (6)
SharePoint (1)
Silverlight (5)
Silverlight Elements (12)
SimpleDB Management Tools (11)
Visual Studio (4)
VS File Explorer (5)
WPF (31)
WPF Diagramming (14)
WPF Elements (22)
WPF Property Grid (24)
![]()
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007



Tagged as 

Posted by Ivan Towlson on 24 March 2008



[...] in WPF templates is achievable in two main ways: triggers and selectors. In this example, it’s probably okay to use a selector, because the user’s [...]