【问题标题】:Animate Margin Change in SilverlightSilverlight 中的动画边距变化
【发布时间】:2010-11-30 18:41:17
【问题描述】:

我在 Silverlight 中为边框调整大小设置动画,但我还需要逐渐移除它周围的边距(目前为 50)。 Blend 似乎不会为边距变化生成补间 - 它只是一次从 50 跳到 0。有没有办法做到这一点?

【问题讨论】:

    标签: silverlight animation storyboard blend


    【解决方案1】:

    问题是 Margin 实际上是“System.Windows.Thickness”类型,它不是依赖对象,因此 Left、Top、Right 和 Bottom 不是依赖属性,因此不能使用 DoubleAnimation 进行动画处理(它允许补间)。

    用于为 Margin 设置动画的是不补间的 ObjectAnimation。这就是为什么您会看到边距从其原始位置跳到新位置的原因。作为另一个常见示例,当您尝试在 Visible 和 Collapsed 之间为 Visibility 属性设置动画时,也会发生同样的情况。

    您需要执行基于计时器的动画以便为边距设置动画,或者为厚度对象实现您自己的动画类型。

    【讨论】:

      【解决方案2】:

      【讨论】:

        【解决方案3】:

        Here is an updated version 允许您在 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);
                }
            }   
        }
        

        然后您可以在 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"/>
        

        请注意,如果您没有在 XAML 中将 Target 属性设置为 DoubleAnimation,您将无法在 Blend 中显示控件/页面。要解决这个问题,只需添加一个假目标属性(在上面的代码中,我添加了一个双精度值的 opacity 属性),无论如何它都会在运行时被覆盖

        【讨论】:

        • 我已尝试按照您的示例在 XAML 中使用它,但在 SL5 中出现了一系列错误。我添加了 xmlns:someName 声明,但 XAML 似乎不知道 someName:ThicknessAnimationX 属性是什么。
        猜你喜欢
        • 2011-09-24
        • 1970-01-01
        • 1970-01-01
        • 2014-03-22
        • 2011-05-29
        • 2011-11-09
        • 2010-12-02
        • 2013-06-06
        • 2017-12-19
        相关资源
        最近更新 更多