2009-09-23 27 views
7

Animuję zmianę rozmiaru obramowania w Silverlight, ale muszę również stopniowo usuwać margines wokół niego (obecnie 50). Mieszanka nie wydaje się generować animacji dla zmiany marginesu - po prostu przeskakuje od 50 do 0 za jednym razem. Czy istnieje sposób, aby to osiągnąć?Animate Margin Change w Silverlight

Odpowiedz

8

Problem polega na tym, że margines jest naprawdę typu "System.Windows.Thickness", który NIE jest obiektem zależności, w związku z czym lewy, górny, prawy i dolny NIE są zależne od właściwości, dlatego nie można ich animować za pomocą DoubleAnimation (które pozwala na animowanie).

Do animacji marży służy animacja obiektów, która nie zawiera animacji. Dlatego widzisz skok marginesu z pierwotnej lokalizacji do nowej lokalizacji. Innym typowym przykładem jest to samo, gdy próbujesz animować właściwość Visibility między Visible i Collapsed.

Musisz albo wykonać animację opartą na timerze, aby animować margines, albo zaimplementować własny typ animacji dla obiektów grubości.

0

Here is an updated version który pozwala animować od wewnątrz 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); 
     } 
    } 
} 

a następnie można to zrobić w 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"/> 

pamiętać, że jeśli nie ustawiasz właściwości Target na DoubleAnimation w XAML, nie będziesz w stanie wyświetlić kontrolki/strony w Blend. Aby to naprawić, po prostu dodaj fałszywą właściwość target (w powyższym kodzie dodałem właściwość nieprzezroczystości, która jest wartością podwójną), i to będzie i przesłonięte w czasie wykonywania.

+0

Próbowałem użyć tego w XAML, jak na twoje przykład i otrzymuję strumień błędów w SL5. Dodałem deklarację 'xmlns: someName', ale wygląda na to, że XAML nie wie, jaka jest własność' someName: ThicknessAnimationX'. – Shaamaan