LinearGradientBrushAnimation






4.78/5 (8投票s)
创建和使用 LinearGradientBrushAnimation。
引言
LinearGradientBrushAnimation
类似于 System.Windows.Media.Automation
中的 ColorAnimation
,但它适用于 LinearGradientBrush
。



背景
我想重新设计按钮类,并计划在鼠标光标悬停在其上方时动画化背景。为此,我需要动画化背景画笔。我找到了 ColorAnimation
的示例,但我使用的是 LinearGradientBrush
作为背景画笔。我在网上找到了一些通过代码实现的方法,但我的计划是将此功能直接添加到 XAML 中。
LinearGradientBrushAnimationBase
首先,我使用 Reflector 工具查看,并从 AnimationTimeline
类派生了 LinearGradientBrushAnimationBase
类。我将所有 Color
类型更改为 LinearGradientBrush
类型。之后,它看起来像这样
public abstract class LinearGradientBrushAnimationBase : AnimationTimeline
{
protected LinearGradientBrushAnimationBase()
{
}
public new LinearGradientBrushAnimationBase Clone()
{
return (LinearGradientBrushAnimationBase)base.Clone();
}
public sealed override object GetCurrentValue(object defaultOriginValue,
object defaultDestinationValue, AnimationClock animationClock)
{
if (defaultOriginValue == null)
{
throw new ArgumentNullException("defaultOriginValue");
}
if (defaultDestinationValue == null)
{
throw new ArgumentNullException("defaultDestinationValue");
}
return this.GetCurrentValue((LinearGradientBrush)defaultOriginValue,
(LinearGradientBrush)defaultDestinationValue, animationClock);
}
public LinearGradientBrush GetCurrentValue(LinearGradientBrush
defaultOriginValue, LinearGradientBrush defaultDestinationValue,
AnimationClock animationClock)
{
base.ReadPreamble();
if (animationClock == null)
{
throw new ArgumentNullException("animationClock");
}
if (animationClock.CurrentState == ClockState.Stopped)
{
return defaultDestinationValue;
}
return this.GetCurrentValueCore(defaultOriginValue,
defaultDestinationValue, animationClock);
}
protected abstract LinearGradientBrush GetCurrentValueCore(LinearGradientBrush
defaultOriginValue, LinearGradientBrush defaultDestinationValue,
AnimationClock animationClock);
// Properties
public override Type TargetPropertyType
{
get { return typeof(LinearGradientBrush); }
}
}
LinearGradientBrushAnimation
下一步是添加一个从基类派生的 LinearGradiantBrushAnimation
类。完整的类如下所示
public class LinearGradientBrushAnimation : LinearGradientBrushAnimationBase
{
public static readonly DependencyProperty FromProperty;
public static readonly DependencyProperty ToProperty;
// Methods
static LinearGradientBrushAnimation()
{
Type propertyType = typeof(LinearGradientBrush);
Type ownerType = typeof(LinearGradientBrushAnimation);
PropertyChangedCallback propertyChangedCallback =
new PropertyChangedCallback(
LinearGradientBrushAnimation.AnimationFunction_Changed);
ValidateValueCallback validateValueCallback =
new ValidateValueCallback(LinearGradientBrushAnimation.ValidateValues);
FromProperty = DependencyProperty.Register("From", propertyType,
ownerType, new PropertyMetadata(null, propertyChangedCallback),
validateValueCallback);
ToProperty = DependencyProperty.Register("To", propertyType,
ownerType, new PropertyMetadata(null, propertyChangedCallback),
validateValueCallback);
}
private static bool ValidateValues(object value)
{
return true;
}
private static void AnimationFunction_Changed(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
LinearGradientBrushAnimation animation = (LinearGradientBrushAnimation)d;
//animation.PropertyChanged(e.Property);
}
public LinearGradientBrushAnimation()
{
}
public LinearGradientBrushAnimation(LinearGradientBrush fromValue,
LinearGradientBrush toValue, Duration duration)
: this()
{
this.From = fromValue;
this.To = toValue;
base.Duration = duration;
}
protected override LinearGradientBrush GetCurrentValueCore(LinearGradientBrush
defaultOriginValue, LinearGradientBrush defaultDestinationValue,
AnimationClock animationClock)
{
// check for length of from and to
if (From.GradientStops.Count != To.GradientStops.Count)
return From;
if (animationClock.CurrentProgress == null)
return From;
LinearGradientBrush brush = new LinearGradientBrush();
brush.StartPoint = From.StartPoint + ((To.StartPoint - From.StartPoint) *
(double)animationClock.CurrentProgress);
brush.EndPoint = From.EndPoint + ((To.EndPoint - From.EndPoint) *
(double)animationClock.CurrentProgress);
// calc gradientstops
for (int cnt = 0; cnt < From.GradientStops.Count; cnt++)
{
GradientStop stop1 = From.GradientStops[cnt];
GradientStop stop2 = To.GradientStops[cnt];
// calc color
Color color1 = stop1.Color;
Color color2 = stop2.Color;
Color newColor = Color.Subtract(color2, color1);
newColor = Color.Multiply(newColor,
(float)animationClock.CurrentProgress);
newColor = Color.Add(newColor, color1);
// calc offset
double offset1 = (double)stop1.Offset;
double offset2 = (double)stop2.Offset;
double offset = offset1 + ((offset2 - offset1) *
(double)animationClock.CurrentProgress);
brush.GradientStops.Add(new GradientStop(newColor, offset));
}
return brush;
}
protected override Freezable CreateInstanceCore()
{
return new LinearGradientBrushAnimation();
}
// Properties
public LinearGradientBrush From
{
get { return (LinearGradientBrush)base.GetValue(FromProperty); }
set { base.SetValue(FromProperty, value); }
}
public LinearGradientBrush To
{
get { return (LinearGradientBrush)base.GetValue(ToProperty); }
set { base.SetValue(ToProperty, value); }
}
}
这个类中最重要的函数是 GetCurrentValueCore()
。该函数根据 animationClock.CurrentProgress
值返回动画画笔。该值是动画中的位置,是一个介于 0.0 和 1.0 之间的双精度浮点数。如你所见,我不仅动画化了 Color
值。LinearGradientBrush
的所有其他属性(StartPoint
、EndPoint
、Offset
)也都被动画化了。
Using the Code
现在是时候测试新类了。在这个示例中,我在 XAML 中创建一个新的标签,并添加两个触发器。第一个是用于 MouseEnter
,第二个是用于 MouseLeave
事件。From
和 To
属性是要动画化的 LinearGradiantBrush
。duration
是动画持续的时间,在本示例中为 0.3 秒。如你所见,LinearGradiantBrushAnimation
像 ColorAnimation
一样直接在 XAML 中工作,并且非常易于使用。你可以将 LinearGradiantBrush
直接放入代码中,或者放入 ResourceDictionary
中,如示例所示。
<Label Content="Label 1" Margin="8"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Height="121" Width="131"
Background="{StaticResource ButtonNormalBackground1}"
Foreground="White">
<Label.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard>
<Storyboard>
<res:LinearGradiantBrushAnimation
Storyboard.TargetProperty="Background"
Duration="00:00:0.3"
AutoReverse="False"
From="{StaticResource ButtonNormalBackground1}"
To="{StaticResource ButtonNormalBackgroundHover1}" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard>
<Storyboard>
<res:LinearGradiantBrushAnimation
Storyboard.TargetProperty="Background"
Duration="00:00:0.3"
AutoReverse="False"
From="{StaticResource ButtonNormalBackgroundHover1}"
To="{StaticResource ButtonNormalBackground1}" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Label.Triggers>
</Label>
在完整的示例中,有四个带有不同动画的 Label
。
历史
- 2010年3月14日:初始发布