因为在Silverlight中没有ThicknessAnimation,所以为Margin添加动画有点麻烦:
1. 使用ObjectAnimationUsingKeyFrames来做,这个就是通过计算要显示的每一帧内容来设置动画,可能看起来不是那么平滑,如果需要平滑的话,那样就需要写代码来动态生成动画效果,看起来会平滑很多。
使用XAML来进行描述就是这样:
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="150"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Storyboard x:Name="sb">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Margin"
Storyboard.TargetName="bdTest">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
<DiscreteObjectKeyFrame.Value>
<Thickness>3,7,5,9</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.6">
<DiscreteObjectKeyFrame.Value>
<Thickness>4,8,6,10</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.7">
<DiscreteObjectKeyFrame.Value>
<Thickness>40,80,60,100</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
<Border x:Name="bdTest" Grid.Row="0" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" Background="Red" />
<Button Content="Button" HorizontalAlignment="Left" Grid.Row="1" VerticalAlignment="Top" Width="75" Click="Button_Click_1" />
</Grid>
2. 另一种方式请参见 Code Project:
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 ThicknessAnimation
{
public class ThicknessWrapper : FrameworkElement
{
public FrameworkElement Target
{
get
{
return (FrameworkElement)GetValue(TargetProperty);
}
set
{
SetValue(TargetProperty, value);
}
}
// Using a DependencyProperty as the backing store for Target. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TargetProperty =
DependencyProperty.Register("Target", typeof(FrameworkElement), typeof(ThicknessWrapper), new PropertyMetadata(null, OnTargetChanged));
static void OnTargetChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
ThicknessWrapper sender = (ThicknessWrapper)source;
sender.UpdateMargin();
}
public String PropertyName
{
get
{
return (String)GetValue(PropertyNameProperty);
}
set
{
SetValue(PropertyNameProperty, value);
}
}
// Using a DependencyProperty as the backing store for PropertyName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PropertyNameProperty =
DependencyProperty.Register("PropertyName", typeof(String), typeof(ThicknessWrapper), new PropertyMetadata("Margin"));
public Side Side
{
get
{
return (Side)GetValue(SideProperty);
}
set
{
SetValue(SideProperty, value);
}
}
// Using a DependencyProperty as the backing store for Side. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SideProperty =
DependencyProperty.Register("Side", typeof(Side), typeof(ThicknessWrapper), new PropertyMetadata(Side.Left, OnSideChanged));
static void OnSideChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
ThicknessWrapper sender = (ThicknessWrapper)source;
sender.UpdateMargin();
}
public double Value
{
get
{
return (double)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
}
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(ThicknessWrapper), new PropertyMetadata(0.0, OnValueChanged));
static void OnValueChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
ThicknessWrapper sender = (ThicknessWrapper)source;
sender.UpdateMargin();
}
static void OnPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
ThicknessWrapper sender = (ThicknessWrapper)source;
sender.UpdateMargin();
}
private void UpdateMargin()
{
if(Target != null)
{
var thicknessProperty = Target.GetType().GetProperty(PropertyName);
var currentThickness = (Thickness)thicknessProperty.GetValue(Target, null);
var nextThickness = new Thickness(
CalculateThickness(Side.Left, currentThickness.Left),
CalculateThickness(Side.Top, currentThickness.Top),
CalculateThickness(Side.Right, currentThickness.Right),
CalculateThickness(Side.Bottom, currentThickness.Bottom)
);
thicknessProperty.SetValue(Target, nextThickness, null);
}
}
private double CalculateThickness(ThicknessAnimation.Side sideToCalculate, double currentValue)
{
return (Side & sideToCalculate) == sideToCalculate ? Value : currentValue;
}
}
[Flags]
public enum Side
{
Left = 1,
Top = 2,
Right = 4,
Bottom = 8,
All = 15
}
}
<Grid x:Name="LayoutRoot" Background="White">
<Grid.Resources>
<Storyboard x:Key="animation">
<!--<DoubleAnimation Storyboard.TargetName="rectTopMargin" Storyboard.TargetProperty="Value" From="0" To="100" Duration="00:00:1"></DoubleAnimation>-->
<DoubleAnimation Storyboard.TargetName="rectStrokeThickness" Storyboard.TargetProperty="Value" From="0" To="20" Duration="00:00:1"></DoubleAnimation>
</Storyboard>
</Grid.Resources>
<local:ThicknessWrapper x:Name="rectTopMargin" Target="{Binding ElementName=rect}" Side="Top" PropertyName="Margin"></local:ThicknessWrapper>
<local:ThicknessWrapper x:Name="rectStrokeThickness" Target="{Binding ElementName=rect}" Side="Left, Right" PropertyName="BorderThickness"></local:ThicknessWrapper>
<StackPanel>
<Button Content="Click to animate" Click="Button_Click"></Button>
<Border x:Name="rect" HorizontalAlignment="Left" BorderBrush="Black" VerticalAlignment="Top" Background="Green" Height="50" Width="50"></Border>
</StackPanel>
</Grid>