Community blog feed
How To Animate a Gradient Brush
- Blog
- VB & .NET Blogs @ vbCity
- Posted
- 05 Jul 2009 at 19:29
Summary
In the previous blog item in this series, I created a simple Animation in Visual Basic Code. This used a DoubleAnimation to animate the thickness of the gradient border. That example doesn't even begin to scratch the surface of what you can achieve with WPF Animation and - as you have seen demonstrated in the previous items - how you can include these animations in Windows Forms. In this part, we will look at a slightly more complex animation.
Post extract
In the previous blog item in this series, I created a simple Animation in Visual Basic Code. This used a DoubleAnimation to animate the thickness of the gradient border. That example doesn't even begin to scratch the surface of what you can achieve with WPF Animation and - as you have seen demonstrated in the previous items - how you can include these animations in Windows Forms.
In this part, we will look at a slightly more complex animation. Or at least one that seems complex at first, but a quick analysis reveals that it is really rather simple and easily created by writing the XAML by hand.
In order to see the animation effect, I recommend you download the project attached to this blog item and run it. When you click the Button if there is no text in the TextBox, two animations will run. The first is the resize border one that was covered in the previous blog. The second animation changes the position of each of the colors in the gradient to give the impression of movement.
If you are new to WPF, you perhaps won't be too comfortable with the idea of hand-writing the XAML. You can of course use a tool, such as Expression Blend, to create the XAML for you. A time-limited trial version of Expression Blend is available, so if you decide that the hand-written route isn't for you, then you can certainly use Blend instead. (That said, there is something of a learning curve involved in getting to grips with Blend too - especially if, like me, you have more of a Developer mindset than Designer).
One of the reasons I decided to add this part to the blog was that sometimes you need to start the animation running from some user action. In this case, the user action will be the clicking of a button on a totally unrelated UI - a Windows Form, as it happens (although of course the same approach works fine with an all-WPF application too.)
So, firstly, here is the XAML that goes in the WPF UserControl to create the moving gradient effect:
<Storyboard x:Key="MoveColors" >
<DoubleAnimation By="0.2" Duration="0:0:1.3"
AutoReverse="True"
Storyboard.TargetName="GradBorder"
Storyboard.TargetProperty="BorderBrush.GradientStops[6].Offset"
BeginTime="0:0:0.6" />
<DoubleAnimation By="0.2" Duration="0:0:1.3"
AutoReverse="True"
Storyboard.TargetName="GradBorder"
Storyboard.TargetProperty="BorderBrush.GradientStops[5].Offset"
BeginTime="0:0:0.6" />
<DoubleAnimation By="0.2" Duration="0:0:1.3"
AutoReverse="True"
Storyboard.TargetName="GradBorder"
Storyboard.TargetProperty="BorderBrush.GradientStops[4].Offset"
BeginTime="0:0:0.6" />
<DoubleAnimation By="0.2" Duration="0:0:1.3"
AutoReverse="True"
Storyboard.TargetName="GradBorder"
Storyboard.TargetProperty="BorderBrush.GradientStops[3].Offset"
BeginTime="0:0:0.6" />
<DoubleAnimation By="0.2" Duration="0:0:1.3"
AutoReverse="True"
Storyboard.TargetName="GradBorder"
Storyboard.TargetProperty="BorderBrush.GradientStops[2].Offset"
BeginTime="0:0:0.6" />
<DoubleAnimation By="0.2" Duration="0:0:1.3"
AutoReverse="True"
Storyboard.TargetName="GradBorder"
Storyboard.TargetProperty="BorderBrush.GradientStops[1].Offset"
BeginTime="0:0:0.6" />
<DoubleAnimation By="0.2" Duration="0:0:1.3"
AutoReverse="True"
Storyboard.TargetName="GradBorder"
Storyboard.TargetProperty="BorderBrush.GradientStops[0].Offset"
BeginTime="0:0:0.6" />
</Storyboard>
That may look like a lot of typing, but there's a whole lot of repetition in there, which means you can copy and paste the majority of it, then just make minor tweaks.
<Storyboard x:Key="MoveColors" >
The first line shown above simply creates a new Storyboard instance and assigns it a name, or Key, that we can use to reference it.
The next block creates a DoubleAnimation.
<DoubleAnimation By="0.2" Duration="0:0:1.3"
AutoReverse="True"
Storyboard.TargetName="GradBorder"
Storyboard.TargetProperty="BorderBrush.GradientStops[6].Offset"
BeginTime="0:0:0.6" />
Most of us tend not to think of Types such as Double numeric values when we are thinking about animation. In our mind's eye we are more likely to picture the physical result of such a change - the size of an element or its position, its shape or its color, perhaps. But it is perfectly possible to change the value of a Double Type, taking a set amount of time to make the change, and then having this change be visible to a user by assigning it to a property of an element that takes type Double.
That's exactly what we are doing here - changing the value of the Double that is being used to set the position of a GradientStop in a LinearGradientBrush. Here's a more detailed breakdown of what's going on:
By changes the Double value by the amount stated - in this case by 0.2. In our demonstration animation this moves one of the colors that make up the gradient 0.2 along the gradient's linear scale.
Duration sets the length of time taken to change the value from its starting value to the end of the By value. In this case it is 1.3 seconds.
AutoReverse set to True will ensure that the value returns to its starting value by the end of the Duration. In our gradient example this will cause the color to move 0.2 out and then return the same 0.2 distance back.
Storyboard.TargetName uses the WPF Attached Property syntax to identify which element is the target of the animation.
Storyboard.TargetProperty in a similar way identifies the property of the target element which is to be animated. See the further explanation below about the identification of the property.
BeginTime is an optional pause feature. The animation will only begin after an initial pause of (in this example) 0.6 seconds.
The TargetProperty in each of these DoubleAnimations is the Offset value of a GradientStop. If you look at the XAML which creates the BrightGradient LinearGradientBrush, you will see that it contains seven colors, each of which has its position in the gradient assigned by its Offset value. All we are doing in this animation is shunting each of the colors along by a value of 0.2 and this creates the effect of the color movement.
The particular block of XAML shown above animates the last GradientStop, which has an index of 6 - the index being zero based. When you look at the six DoubleAnimations which follow that one, the only difference is that the Index has changed so that the next GradientStop is targeted. So by copying and pasting the first DoubleAnimation, pasting it six times and then changing the value of the Index, this complex looking animation is shown to be very basic in reality.
All that remains now is to wire up this Storyboard in the code-behind.
Public Sub MoveColors()
Dim SB As Storyboard = CType(FindResource("MoveColors"), Storyboard)
If SB IsNot Nothing Then
SB.Begin()
Else
MessageBox.Show("Can't find storyboard")
End If
End Sub
The FindResource method is very useful in these kind of situations in WPF. I used it in the original example to change the LinearGradientBrush on the Border element and now we can employ it to find the animation. It allows you to dig into the XAML, find the markup you need for a particular task and use it. In this cas, the Resource we are looking for is the Storyboard that has a Key of 'MoveColors' - the one we have just dissected above.
Over in the Windows Forms Form1 code, the Button click has only one additional line. This calls the MoveColors procedure shown above, which in turn runs the animation. The additional line is:
MovingGradientTextBox1.MoveColors()
You can see the remaining unchanged Button Click event code in the sample project attached.