Wintellect  

Browse by Tags

All Tags » expression blend   (RSS)

OK, so we've been through quite a series of iterations and refactoring for something simple: triggering a story board animation based on an event somewhere else. We used dependency and attached properties, we used custom behaviors, and now we're going to do it completely "out of the box."

I figured this one would be easiest to show as a video, so this is the first one I've posted to my blog. I don't have good audio so I used the "notepad" technique. What I'm showing is how to take a storyboard and trigger it based on an event fired by something else, using only what comes built-in with Blend. There is no code-behind and in fact the only XAML I edit is for the list boxes (sorry, I know there's a data tab but I still code HTML in notepad).

Here it is:

Click to View Video

Jeremy Likness

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.

Behavior in Expression Blend

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.

Trigger Properties in Expression Blend

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.

Jeremy Likness

This is one of those quirks that until you try it, you may not know it exists or what the answer is.

I am working on a WPF project and have a separate control library (actually, a module because I am using the Component Application Guidance/PRISM pattern). I pulled it into Expression Blend and was surprised to see that I had no "design" view. The option simply didn't exist/was grayed out in the menu.

So, I did some digging around and it turns out that because my controls file is just a C# class library, Expression doesn't know it is "allowed" to design the controls. To tell it this, you simply need to open your .csproj file that the XAML is in, then add this to the first PropertyGroup tag that you find:

<PropertGroup>
...
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
...
</PropertyGroup>

Just enter it exactly with the same Guids ... now close out of Expression, reload, and voila! you can now design.

Jeremy Likness