2011-11-11 12 views
18

Sono riuscito a scoprire come creare un'animazione WPF: transizione tra due colori.Animazione pennello su pennello

Si chiama ColorAnimation e funziona bene.

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); 

Lo sto usando per animare lo sfondo del mio usercontrol. Lo sfondo dei miei controlli è SolidColorBrush. Recentemente sono passato a LinearGradientBrush. Ora non posso più usare la mia animazione.

Ho bisogno dell'animazione dal pennello al pennello, non dal colore al colore. L'opzione migliore è il tipo di pennello Abstract, che include SolidColor, LinearGradient ecc., Così posso animare ad esempio da SolidColorBrush a LinearGradientBrush. È possibile? Grazie.

risposta

5

È sufficiente utilizzare l'animazione del colore sulle interruzioni del gradiente del pennello sfumato. Ecco un esempio che anima una sfumatura di rettangolo usando uno 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> 
+0

Che funziona bene se so che tipo di pennello aspettarsi. Ma nel mio caso, ci possono essere tinta unita, gradiente lineare o radialgradient a seconda delle impostazioni suer. C'è un modo generale di spazzolare il pennello per l'animazione (indipendentemente dal tipo di pennello)? –

2

È possibile animare il colore del pennello se si dispone di un modello di stile in cui si dà il riempimento pennello un nome, in questo modo:

<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> 

Come preso da MSDN

+0

Funziona solo con i pennelli in tinta unita: non funziona con i pennelli sfumati. – Will

23

altro è possibile, per creare una classe di animazione personalizzata che animi i pennelli. Ho trovato un modo semplice per farlo creando una classe, derivata da AnimationTimeline. Possiamo ignorare alcuni membri nella classe personalizzata, tra le altre cose lo AnimationTimeline.GetCurrentValue method. Restituisce un valore in base all'avanzamento dell'animazione e al valore iniziale e finale.

Il modo più semplice è creare un VisualBrush e dissolvenza incrociata l'inizio- con il valore finale con la proprietà Opacity su un controllo figlio. Il risultato è una classe come la seguente:

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)); 
} 

è possibile utilizzarlo come sempre 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> 

o in codice dietro:

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(); 

E 'anche possibile estendere il BrushAnimation con sovraccarichi del costruttore ecc., quindi sembra un tipo di animazione dato da .NET.

+0

Mi piace l'aspetto di questo - gli darò un giro. – Will

+3

Oh uomo lo hai inchiodato; molto bene. – Will

+0

Grandi cose, grazie! – MoonKnight