2011-11-11 7 views
18

Pude averiguar cómo hacer una animación WPF: transición entre dos colores.Brush to Brush Animation

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 usercontrol. Mi fondo de controles es SolidColorBrush. Recientemente cambié al LinearGradientBrush. Ahora puedo usar mi animación no más.

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, desde SolidColorBrush hasta LinearGradientBrush. ¿Es eso posible? Gracias.

Respuesta

5

Solo necesita usar la animación de color en las paradas de gradiente 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> 
+0

Eso funciona bien si sé qué tipo de cepillo esperar. Pero en mi caso, puede haber color sólido, gradiente lineal o gradiente radial dependiendo de la configuración de los sensores. ¿Hay una forma general de cepillar la animación (independientemente del tipo de pincel)? –

2

Puede animar el color del pincel si usted tiene un estilo de plantilla en la que le da el relleno cepillar un nombre, 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> 

Como tomada de MSDN

+0

Esto solo funciona para las escobillas de color sólido; esto no funciona con las escobillas de gradiente. – Will

23

Otro La forma posible es crear una clase de animación personalizada que anima los pinceles. Encontré una manera simple de hacerlo creando una clase, derivada de AnimationTimeline. Podemos anular algunos miembros en la clase personalizada, entre otras cosas, el AnimationTimeline.GetCurrentValue method. Devuelve un valor que depende del progreso de la animación y del valor inicial y final.

La manera más simple es crear un VisualBrush y realizar un fundido cruzado 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)); 
} 

Usted puede 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:

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 de constructor, etc., por lo que parece un tipo de animación dado por .NET.

+0

Me gusta el aspecto de esto, lo voy a dar un giro. – Will

+3

Oh hombre, lo clavaste; bien hecho. – Will

+0

¡Cosas geniales, gracias! – MoonKnight