So far we've explored how to use dependency properties and attached properties to create reusable behaviors and triggers. I showed you recently how to refactor an attached property to use the Behavior
base class instead. Today, we'll look at the TriggerAction
that is also available in System.Windows.Interactivity
(either as a part of Expression Blend, or available through the Blend SDK).
If you recall in TextBox Magic, I used an attached property to define an attribute that, when set to true, would bind to the TextChanged
event and force data-binding to allow validation and binding without having to lose focus from the text box.
Because the action is tied to an event, it makes sense to refactor as a trigger action.
The first step is simply to build a class based on TriggerAction
which requires adding a reference to System.Windows.Interactivity
. Like the Behavior
class, the TriggerAction
can be strongly typed, so we will type it to the TextBox
:
public class TextBoxBindingTrigger : TriggerAction<TextBox>
{
}
The method you must override is the Invoke
method. This will be called when the action/event the trigger is bound to fires. If you recall from the previous example, we simply need to grab a reference to the binding and force it to update:
protected override void Invoke(object parameter)
{
BindingExpression binding = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
if (binding != null)
{
binding.UpdateSource();
}
}
That's it! We now have a trigger action that is ready to force the data binding. Now we just need to implement it with a text box and bind it to the TextChanged
event. In Expression Blend, the new action appears in the Behaviors section under assets.
You can click on the trigger and drag it onto an appropriate UI element. Because we typed our trigger to TextBox
, Blend will only allow you to drag it onto a TextBox. Once you've attached the trigger to a UI action, you can view the properties and set the appropriate event. In this case, we'll bind to the TextChanged
event.
Notice how the associated element defaults to the parent, but can be changed in Blend to point to any other TextBox available as well.
Of course, all of this can be done programmatically or through XAML as well. To add the trigger in XAML, simply reference both System.Windows.Interactivity
as well as the namespace for your trigger. Then, you can simply add to the TextBox
lik this:
...
<TextBox
Text="{Binding Name, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
Grid.Row="0" Height="30" Grid.Column="0" Margin="5" Width="200">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<local:TextBoxBindingTrigger/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
As you can see, this is a much more elegant way to create behaviors attached to events as it allows you to easily attach the trigger as well as define the event that the trigger is coupled with.