WPF Animating when a Property value Changes

Writing business applications means you rarely have to play with animation. But when you do you want to do it very quickly and painlessly because it’s definitely not your core focus in developing. Recently I had a change request to make a search results panel slide into view rather than just appearing when the user types in some search text. This was deemed necessary to attract the user’s eye to the recently shown panel as otherwise it can easily go unnoticed. I was determined to do this in Xaml as it should be straight forward and the knowledge learned in doing this would save me much time in the future.

Using Routed Events

My first thought was, sweet I’ll just have a BeginStoryboard in the Panel’s Triggers when it becomes Visible. Unfortunately WPF controls don’t have Shown and Hidden routed events so I had to go for Loaded and Unloaded.

<Border 
    x:Name="SearchResultsPanel" 
    MinHeight="150" 
    MaxHeight="300" 
    Grid.Column="1" 
    Visibility="Collapsed" 
    VerticalAlignment="Bottom" 
    Background="{StaticResource Brush_LightBlueGradient}" 
    Margin="0,0,0,-180" 
    BorderBrush="Black" 
    BorderThickness="1">
    <Border.Triggers>
        <EventTrigger RoutedEvent="Loaded">
            <BeginStoryboard>...</BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Unloaded">
            <BeginStoryboard>...</BeginStoryboard>
        </EventTrigger>
    </Border.Triggers>

Putting the animation on the Loaded event worked fine, but then the trouble came with Unloaded… The control would disappear without waiting for my "slide out" animation to complete. Ok, back to the drawing board.

Using a Trigger on the Panel

Ok, I thought, I’ll add a trigger referencing the Search Text’s value, and show or hide based on whether it is empty. I tried this…

<Border.Triggers>
    <Trigger SourceName="QuickSearchText" Property="TextBox.Text" Value="">
        <Setter Property="Control.Background" Value="Red"/>
    </Trigger>
</Border.Triggers>

Which gave me a run-time error stating that the following:

"Triggers collection members must be of type EventTrigger."

Right so a Triggers collection can’t have a Trigger object in it… sounds like a coding pattern has not been followed here. Why didn’t they call the property EventTriggers then? This would have been much more intuitive for a developer! Anyway so the only other way is to define triggers using a Style.

<Border.Style>
    <Style>
        <Style.Triggers>
            <Trigger SourceName="QuickSearchText" Property="TextBox.Text" Value="">
                <Setter Property="Control.Background" Value="Red"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</Border.Style>

I’m all full of hope now, thinking "Yes, WPF really is powerful and fairly straight-forward once you know what to do".  Umm… obviously I still don’t know what to do because now I get a compile-time error:

"SourceName property cannot be set within Style.Triggers section"

If a SouceName can’t be set in a Style.Triggers, where the f*** can it be set? Ok, I can’t set a SourceName so that means I need to move this trigger to the Search text box’s styles to test I simple wanted to set the Panel’s background to red, just to take out any variables of animation.

<TextBox.Style>
    <Style>
        <Style.Triggers>
            <Trigger Property="Text" Value="">
                <Setter TargetName="SearchResultsPanel" Property="Control.Background" 
Value="Red"/> </Trigger> </Style.Triggers> </Style> </TextBox.Style>

Now we’re cooking with gas right??? Wrong… Compile-time error:

"TargetName property cannot be set on a Style Setter."

It’s at this point I wanted to crawl up into the foetal position and suck on my thumb, if it weren’t for my niggling desire to press on and understand why these stupid constraints exist!!

To be continued…

Advertisements
  1. #1 by John on August 20, 2008 - 4:05 am

    @Right so a
    Triggers collection can\’t have a Trigger object in it… sounds like a
    coding pattern has not been followed here. Why didn\’t they call the
    property EventTriggers then?Adam Nathan explains that this is only a temporary limitation of WPF, and will be fixed in future versions.  See Page 55 of WPF Unleashed:WARNING!
    Don\’t be fooled by an element\’s Triggers collection!
    FrameworkElement\’s Trigger property is a read/write collection of
    TriggerBase items (the common base class for all three types of
    triggers), so it looks like an easy way to attach property triggers to
    controls such as Button. Unfortunately, this collection can only
    contain event triggers in version 3.0 of WPF, simply because the WPF
    team didn\’t have time to implement this support. Attempting to add a
    property trigger (or data trigger) to the collection causes an
    exception to be thrown at run-time.

  2. #2 by Ramon on September 26, 2008 - 10:06 pm

    About "property cannot be set within Style.Triggers section". Adam Nathan described that the WPF team didn\’t have time to implement triggers properly for WPF v3.0. But this was almost two years ago and still there is no change in WPF v3.5 SP1. This problem bugs me very often. Using the Style workaround is no option in real-life applications, because I often apply a general style to the control and therefore I cannot use a style that only specifies the triggers.

  3. #3 by Unknown on December 19, 2008 - 6:15 am

    I was just trying to do a similar thing and ended up following the same exact pattern as you did and received all the same errors. I was hoping that you figured it out, but guess not. So basically the triggers are still broken as of 12/18/2008. Back to C# code…

  4. #4 by David Piepgrass on May 27, 2011 - 8:04 am

    All I wanted to do was have an ellipse turn yellow when the mouse is over it. I got this to work with a Trigger inside an Ellipse.Style element (after help from StackOverflow) but this doesn’t work if the mouse is over something that is drawn on top of the ellipse.

    To work around this problem, I tried three of the same things you did and got the same three errors. Did you find a workaround yet?

  5. #5 by Sumanth on March 14, 2012 - 1:26 am

    Try defining a Style in the application window resource for the panel. Use data Triggers by binding to concerned controls property value inside Style Triggers.

    using setter, set the background to your interested value.

    Hope this solves !!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: