Brush to Brush Animation Brush to Brush Animation wpf wpf

Brush to Brush Animation


Another possible way is, to create a custom animtion class that animate brushes.I found a simple way to do that by creating a class, derivated from AnimationTimeline. We can override some members in the custom class, among other things the AnimationTimeline.GetCurrentValue method. It returns a value depend on the animation progress and the start- and end value.

The simplest way is to create a VisualBrush and crossfade the start- with the end value with the Opacity property on a child control. The result is a class like the following:

public class BrushAnimation : AnimationTimeline{    public override Type TargetPropertyType    {        get        {            return typeof(Brush);        }    }    public override object GetCurrentValue(object defaultOriginValue,                                           object defaultDestinationValue,                                           AnimationClock animationClock)    {        return GetCurrentValue(defaultOriginValue as Brush,                               defaultDestinationValue as Brush,                               animationClock);    }    public object GetCurrentValue(Brush defaultOriginValue,                                  Brush defaultDestinationValue,                                  AnimationClock animationClock)    {        if (!animationClock.CurrentProgress.HasValue)            return Brushes.Transparent;        //use the standard values if From and To are not set         //(it is the value of the given property)        defaultOriginValue = this.From ?? defaultOriginValue;        defaultDestinationValue = this.To ?? defaultDestinationValue;        if (animationClock.CurrentProgress.Value == 0)            return defaultOriginValue;        if (animationClock.CurrentProgress.Value == 1)            return defaultDestinationValue;        return new VisualBrush(new Border()        {            Width = 1,            Height = 1,            Background = defaultOriginValue,            Child = new Border()            {                Background = defaultDestinationValue,                Opacity = animationClock.CurrentProgress.Value,            }        });    }    protected override Freezable CreateInstanceCore()    {        return new BrushAnimation();    }    //we must define From and To, AnimationTimeline does not have this properties    public Brush From    {        get { return (Brush)GetValue(FromProperty); }        set { SetValue(FromProperty, value); }    }    public Brush To    {        get { return (Brush)GetValue(ToProperty); }        set { SetValue(ToProperty, value); }    }    public static readonly DependencyProperty FromProperty =        DependencyProperty.Register("From", typeof(Brush), typeof(BrushAnimation));    public static readonly DependencyProperty ToProperty =        DependencyProperty.Register("To", typeof(Brush), typeof(BrushAnimation));}

You can use it as always in XAML:

<EventTrigger RoutedEvent="Loaded">    <BeginStoryboard>        <Storyboard >            <local:BrushAnimation Storyboard.TargetName="border"                                  Storyboard.TargetProperty="Background"                                   Duration="0:0:5" From="Red"                                   RepeatBehavior="Forever" AutoReverse="True" >                <local:BrushAnimation.To>                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">                        <GradientStop Color="#FF00FF2E" Offset="0.005"/>                        <GradientStop Color="#FFC5FF00" Offset="1"/>                        <GradientStop Color="Blue" Offset="0.43"/>                    </LinearGradientBrush>                </local:BrushAnimation.To>            </local:BrushAnimation>        </Storyboard>    </BeginStoryboard></EventTrigger>

or in code behind:

var animation = new BrushAnimation{    From = Brushes.Red,    To = new LinearGradientBrush (Colors.Green, Colors.Yellow, 45),    Duration = new Duration(TimeSpan.FromSeconds(5)),};animation.Completed += new EventHandler(animation_Completed);Storyboard.SetTarget(animation, border);Storyboard.SetTargetProperty(animation, new PropertyPath("Background"));var sb = new Storyboard();sb.Children.Add(animation);sb.Begin();

It is also possible to extend the BrushAnimation with constructor overloads etc., so it looks like a .NET given animation type.


You just need to use the color animation on the gradient stops of the gradient brush. Here is an example that animates a rectangle gradient using a storyboard.

    <Window    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    x:Class="GradientBrushAnimation.MainWindow"    x:Name="Window"    Title="MainWindow"    Width="640" Height="480">    <Window.Resources>        <Storyboard x:Key="Storyboard1">            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="rectangle">                <EasingColorKeyFrame KeyTime="0:0:2" Value="Red"/>            </ColorAnimationUsingKeyFrames>            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="rectangle">                <EasingColorKeyFrame KeyTime="0:0:2" Value="#FF71FF00"/>            </ColorAnimationUsingKeyFrames>        </Storyboard>    </Window.Resources>    <Window.Triggers>        <EventTrigger RoutedEvent="FrameworkElement.Loaded">            <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>        </EventTrigger>    </Window.Triggers>    <Grid x:Name="LayoutRoot">        <Rectangle x:Name="rectangle" Margin="78,102,292,144" Stroke="Black">            <Rectangle.Fill>                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">                    <GradientStop Color="Black" Offset="0"/>                    <GradientStop Color="White" Offset="1"/>                </LinearGradientBrush>            </Rectangle.Fill>        </Rectangle>    </Grid></Window>


You can animate the color of the brush if you have a template style in which you give the fill brush a name, like so:

<Rectangle Width="100" Height="100">  <Rectangle.Fill>    <SolidColorBrush x:Name="MyAnimatedBrush" Color="Orange" />  </Rectangle.Fill>  <Rectangle.Triggers>    <!-- Animates the brush's color to gray         When the mouse enters the rectangle. -->    <EventTrigger RoutedEvent="Rectangle.MouseEnter">      <BeginStoryboard>        <Storyboard>          <ColorAnimation            Storyboard.TargetName="MyAnimatedBrush"            Storyboard.TargetProperty="Color"            To="Gray" Duration="0:0:1" />        </Storyboard>      </BeginStoryboard>    </EventTrigger>    </Rectangle.Triggers></Rectangle>

As taken from MSDN