views:

327

answers:

2

Hi,

I have to change the color of a TextBlock to indicate whether the number is positive or negative - red for negative, blue for positive. I have done this by using a DataTrigger and a Converter which returns True/False whether the number is negative/positive. Next requirement is a bit trickier: when the number changes, perform a slow fade to indicate whether the number has increased or decreased from the previous value, and then it fades to whichever color indicates its current position as above.

What's the easiest way to accomplish this?

Thanks.

A: 

Hi Alberto,

Approach with triggers is correct, and to launch animation you can use Trigger.EnterAction.

Anvaka
A: 

I don't think the approach with Trigger.EnterAction will work. In order to apply a new animation you will have to specify Trigger.ExitAction that will remove the current animation and as a result the color reverts to its default. When you then start the new animation it will then animate from its default color (wich now has become the current color) to the new color. Binding the Animations From value to some dynamic value doesn't work because auf Freezable. I solved this propblem by introducing an attached property generates the animation on the fly animation from whatever color the object currently has to the spechified one:

<TextBlock Text="text">
    <local:AnimationHelper.Animation>
        <local:ConstantColorAnimation 
            TargetProperty="Foreground" 
            To="{Binding CurrentState, Converter={StaticResource stateToColor}}" 
            Speed="1.5" /> 
    </local:AnimationHelper.Animation>
</TextBlock Text="text">

This will animate the foreground of the TextBlock whenever the CurrentState property changes to the new color that is returned by the StateToColorConverter. This is from DataTemplate for a ViewModel that has a CurrentState property. IF you want it to bind directly to the text you would have to write a TextToColorConverter.

Here is an example of the relevant code for a ConstantColorAnimation:

private void CreateAnimation()
{
    if (this.ResolvedTargetProperty == null)
    {
        return;
    }
    var from = (Color)this.Context.GetValue(this.ResolvedTargetProperty);
    this.RemoveAnimation(this.ResolvedTargetProperty);
    if (this.Speed == 0)
    {
        this.Context.SetValue(this.ResolvedTargetProperty, from);
        return;
    }
    if (this.Speed < 0)
    {
        this.Context.SetValue(this.ResolvedTargetProperty, this.To);
        return;
    }
    var a = new ColorAnimation(
        from, this.To, new Duration(TimeSpan.FromSeconds(Math.Abs(this.To - from) / this.Speed)));
    this.Context.BeginAnimation(this.ResolvedTargetProperty, a);
}

Instead of rolling this all by yourself you could also use the Behavior Framework from Silverlight. AFAIK it is full compatible with WPF and you can use the assembly directly. You might even find a behavior, that already does what you need.

bitbonk
The thing is that the converter should be able to determine the previous state as well, in order to return the color to use in the animation - red if we have setup a value less than before; blue if we've setup a greater one.
Alberto
The codebehind of the attached property above does exactly this. Whenever "To" changes (because it is bound) it determines the current color and animates from there to the color.
bitbonk
I'll take a look, thanks.
Alberto