2009-09-23 3 views
7

Sto animando un ridimensionamento del bordo in Silverlight, ma ho anche bisogno di rimuovere gradualmente il margine attorno ad esso (attualmente 50). La miscela non sembra generare un'interpolazione per il cambio di margine: salta semplicemente da 50 a 0 in una volta sola. C'è un modo per ottenere questo?Modifica del margine di animazione in Silverlight

risposta

8

Il problema è che un margine è in realtà di tipo "System.Windows.Thickness" che NON è un oggetto di dipendenza, quindi Left, Top, Right e Bottom non sono proprietà dipendenti e quindi non può essere animato utilizzando DoubleAnimation (che consente il tweening).

Ciò che viene utilizzato per animare il margine è un oggetto ObjectAnimation che non interpola. Questo è il motivo per cui vedi il margine saltare dalla sua posizione originale alla sua nuova posizione. Come un altro esempio comune, lo stesso accade quando si tenta di animare la proprietà Visibility tra Visible e Collapsed.

È necessario eseguire un'animazione basata su timer per animare margine o implementare il proprio tipo di animazione per gli oggetti spessore.

0

Here is an updated version che permette di animare dal di dentro XAML

using System; 
using System.Net; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Ink; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 

namespace NiceCards.Animations 
{ 
    public class ThicknessAnimationX 
    { 
     public static readonly DependencyProperty ElementProperty = DependencyProperty.RegisterAttached("Element", typeof(DependencyObject), typeof(DoubleAnimation), new PropertyMetadata(new PropertyChangedCallback(OnElementPropertyChanged))); 

     // The time along the animation from 0-1 
     public static DependencyProperty TimeProperty = DependencyProperty.RegisterAttached("Time", typeof(double), typeof(DoubleAnimation), new PropertyMetadata(OnTimeChanged)); 

     // The object being animated 
     public static DependencyProperty TargetProperty = DependencyProperty.RegisterAttached("Target", typeof(DependencyObject), typeof(ThicknessAnimationX), null); 
     public static DependencyProperty TargetPropertyProperty = DependencyProperty.RegisterAttached("TargetProperty", typeof(DependencyProperty), typeof(DependencyObject), null); 

     public static readonly DependencyProperty FromProperty = DependencyProperty.RegisterAttached("From", typeof(Thickness), typeof(DoubleAnimation), null); 
     public static readonly DependencyProperty ToProperty = DependencyProperty.RegisterAttached("To", typeof(Thickness), typeof(DoubleAnimation), null); 

     public static void SetElement(DependencyObject o, DependencyObject value) 
     { 
      o.SetValue(ElementProperty, value); 
     } 

     public static DependencyObject GetElement(DependencyObject o) 
     { 
      return (DependencyObject)o.GetValue(ElementProperty); 
     } 

     private static void OnElementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      if (e.NewValue != null) 
      { 
       DoubleAnimation doubleAnimation = (DoubleAnimation)d; 

       doubleAnimation.SetValue(TargetProperty, e.NewValue); 
       doubleAnimation.From = 0; 
       doubleAnimation.To = 1; 
       doubleAnimation.SetValue(TargetPropertyProperty, FrameworkElement.MarginProperty); 
       Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(ThicknessAnimationX.Time)")); 
       Storyboard.SetTarget(doubleAnimation, doubleAnimation); 
      } 
     } 


     private static void OnTimeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
     { 
      DoubleAnimation animation = (DoubleAnimation)sender; 
      double time = GetTime(animation); 
      Thickness from = (Thickness)sender.GetValue(FromProperty); 
      Thickness to = (Thickness)sender.GetValue(ToProperty); 
      DependencyProperty targetProperty = (DependencyProperty)sender.GetValue(TargetPropertyProperty); 
      DependencyObject target = (DependencyObject)sender.GetValue(TargetProperty); 
      target.SetValue(targetProperty, new Thickness((to.Left - from.Left) * time + from.Left, 
                  (to.Top - from.Top) * time + from.Top, 
                  (to.Right - from.Right) * time + from.Right, 
                  (to.Bottom - from.Bottom) * time + from.Bottom)); 
     } 

     public static double GetTime(DoubleAnimation animation) 
     { 
      return (double)animation.GetValue(TimeProperty); 
     } 

     public static void SetTime(DoubleAnimation animation, double value) 
     { 
      animation.SetValue(TimeProperty, value); 
     } 

     public static Thickness GetFrom(DoubleAnimation animation) 
     { 
      return (Thickness)animation.GetValue(FromProperty); 
     } 

     public static void SetFrom(DoubleAnimation animation, Thickness value) 
     { 
      animation.SetValue(FromProperty, value); 
     } 

     public static Thickness GetTo(DoubleAnimation animation) 
     { 
      return (Thickness)animation.GetValue(ToProperty); 
     } 

     public static void SetTo(DoubleAnimation animation, Thickness value) 
     { 
      animation.SetValue(ToProperty, value); 
     } 
    } 
} 

E poi si può fare questo in XAML

<VisualStateManager.VisualStateGroups> 
    <VisualStateGroup x:Name="Positions"> 
     <VisualStateGroup.Transitions> 
      <VisualTransition GeneratedDuration="0:0:0.2"/> 
     </VisualStateGroup.Transitions> 
     <VisualState x:Name="Left">      
      <Storyboard> 
       <DoubleAnimation Duration="0:0:0.3" NiceCards:ThicknessAnimationX.To="0,0,0,0" NiceCards:ThicknessAnimationX.Element="{Binding ElementName=rectangle1}" Storyboard.TargetName="rectangle1" Storyboard.TargetProperty="Opacity"/> 
      </Storyboard>      
     </VisualState> 
     <VisualState x:Name="Right">      
      <Storyboard> 
       <DoubleAnimation Duration="0:0:0.3" NiceCards:ThicknessAnimationX.To="0,200,0,0" NiceCards:ThicknessAnimationX.Element="{Binding ElementName=rectangle1}" Storyboard.TargetName="rectangle1" Storyboard.TargetProperty="Opacity"/> 
      </Storyboard>      
     </VisualState> 
    </VisualStateGroup> 
</VisualStateManager.VisualStateGroups> 
<Rectangle Height="100" HorizontalAlignment="Left" Margin="23,25,0,0" x:Name="rectangle1" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="200" Fill="#FF1BAA00"/> 

Nota che se non si imposta una proprietà Target su DoubleAnimation in XAML, non sarà possibile visualizzare il controllo/la pagina in Blend. Per risolvere questo problema, basta aggiungere una proprietà target fasulla (nel codice sopra ho aggiunto la proprietà opacity che è un valore doppio), e sarà comunque sovrascritta in fase di esecuzione

+0

Ho provato a utilizzare questo in XAML come per il tuo esempio e sto ricevendo un flusso di errori in SL5. Ho aggiunto una dichiarazione 'xmlns: someName', ma sembra che XAML non sappia cosa sia una proprietà' someName: ThicknessAnimationX'. – Shaamaan