c# - Pincel a pincel animación
wpf animation (3)
Me las arreglé para descubrir cómo hacer una animación WPF - transición entre dos colores.
Se llama ColorAnimation y funciona bien.
ColorAnimation animation = new ColorAnimation
{
From = Colors.DarkGreen,
To = Colors.Transparent,
Duration = new Duration(TimeSpan.FromSeconds(1.5)),
AutoReverse = false
};
animation.Completed += new EventHandler(animation_Completed);
SolidColorBrush brush = new SolidColorBrush(Colors.Transparent);
animation.AccelerationRatio = 0.5;
Background = brush;
brush.BeginAnimation(SolidColorBrush.ColorProperty, animation);
Estoy usando esto para animar el fondo de mi control de usuario. El fondo de mis controles es SolidColorBrush
. Recientemente he cambiado a LinearGradientBrush
. Ahora ya no puedo usar mi animación.
Necesito animación de pincel a pincel, no de color a color. Y la mejor opción es el tipo de pincel abstracto, que incluye SolidColor, LinearGradient, etc., por lo que puedo animar, por ejemplo, de SolidColorBrush
a LinearGradientBrush
. ¿Es eso posible? Gracias.
Otra forma posible es crear una clase de animación personalizada que anime pinceles. Encontré una forma sencilla de hacerlo creando una clase, derivada de AnimationTimeline
. Podemos anular algunos miembros en la clase personalizada, entre otras cosas, el método AnimationTimeline.GetCurrentValue
. Devuelve un valor que depende del progreso de la animación y del valor inicial y final.
La forma más sencilla es crear un VisualBrush
y VisualBrush
con el valor final con la propiedad Opacity
en un control secundario. El resultado es una clase como la siguiente:
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));
}
Puedes usarlo como siempre en 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>
o en el código detrás de:
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();
También es posible extender el BrushAnimation
con sobrecargas del constructor, etc., para que parezca un tipo de animación dado en .NET.
Puede animar el color del pincel si tiene un estilo de plantilla en el que le asigna un nombre al pincel de relleno, así:
<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>
Según lo tomado de MSDN
Solo necesita utilizar la animación de color en las paradas de degradado del pincel de degradado. Aquí hay un ejemplo que anima un degradado de rectángulo usando un guión gráfico.
<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>