样式动画:
<Window.Resources>
<Style x:Key="GrowButtonStyle">
<Style.Triggers>
<Trigger Property="Button.IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
To="250" Duration="0:0:5"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Button Padding="10" Name="cmdGrow" Height="40" Width="160" Style="{StaticResource GrowButtonStyle}"
HorizontalAlignment="Center" VerticalAlignment="Center">
Click and Make Me Grow
</Button>
动画控制:
<Window.Triggers>
<EventTrigger SourceName="cmdStart" RoutedEvent="Button.Click">
<BeginStoryboard Name="fadeStoryboardBegin">
<!-- The SpeedRatio binding makes sure the initial speed matches the slider.
The Slider's event handling code makes sure the speed is updated when
the slider is moved. -->
<Storyboard Name="fadeStoryboard" CurrentTimeInvalidated="storyboard_CurrentTimeInvalidated"
SpeedRatio="{Binding ElementName=sldSpeed,Path=Value}">
<DoubleAnimation
Storyboard.TargetName="imgDay"
Storyboard.TargetProperty="Opacity"
From="1" To="0" Duration="0:0:10" ></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger SourceName="cmdPause" RoutedEvent="Button.Click">
<PauseStoryboard BeginStoryboardName="fadeStoryboardBegin"></PauseStoryboard>
</EventTrigger>
<EventTrigger SourceName="cmdResume" RoutedEvent="Button.Click">
<ResumeStoryboard BeginStoryboardName="fadeStoryboardBegin"></ResumeStoryboard>
</EventTrigger>
<EventTrigger SourceName="cmdStop" RoutedEvent="Button.Click">
<StopStoryboard BeginStoryboardName="fadeStoryboardBegin"></StopStoryboard>
</EventTrigger>
<EventTrigger SourceName="cmdMiddle" RoutedEvent="Button.Click">
<SeekStoryboard BeginStoryboardName="fadeStoryboardBegin"
Offset="0:0:5"></SeekStoryboard>
</EventTrigger>
</Window.Triggers>
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Padding" Value="5"></Setter>
<Setter Property="Margin" Value="1"></Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid>
<Image Source="night.jpg"></Image>
<Image Source="day.jpg" Name="imgDay"></Image>
</Grid>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
<Button Name="cmdStart">Start</Button>
<Button Name="cmdPause">Pause</Button>
<Button Name="cmdResume">Resume</Button>
<Button Name="cmdStop">Stop</Button>
<Button Name="cmdMiddle">Move To Middle</Button>
</StackPanel>
<TextBlock Grid.Row="2" Name="lblTime" HorizontalAlignment="Center">[[ stopped ]]</TextBlock>
<Grid Grid.Row="3" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock>Speed:</TextBlock>
<Slider Grid.Column="1" Name="sldSpeed"
Minimum="0" Maximum="3" Value="1" TickPlacement="BottomRight" TickFrequency="0.1"
ValueChanged="sldSpeed_ValueChanged"></Slider>
</Grid>
<ProgressBar Grid.Row="4" Margin="0,5,0,0" Height="10" Name="progressBar" Minimum="0" Maximum="1"></ProgressBar>
</Grid>
private void storyboard_CurrentTimeInvalidated(object sender, EventArgs e)
{
// Sender is the clock that was created for this storyboard.
Clock storyboardClock = (Clock)sender;
if (storyboardClock.CurrentProgress == null)
{
lblTime.Text = "[[ stopped ]]";
progressBar.Value = 0;
}
else
{
lblTime.Text = storyboardClock.CurrentTime.ToString();
progressBar.Value = (double)storyboardClock.CurrentProgress;
}
}
private void sldSpeed_ValueChanged(object sender, RoutedEventArgs e)
{
fadeStoryboard.SetSpeedRatio(this, sldSpeed.Value);
}
动画缓存:
<Window.Resources>
<local:ArithmeticConverter x:Key="converter"></local:ArithmeticConverter>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="rect" AutoReverse="True" RepeatBehavior="Forever"
To="{Binding ElementName=window,Path=Width,Converter={StaticResource converter},ConverterParameter=-100}"
Duration="0:0:15"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Canvas Name="canvas">
<Path Name="pathBackground" Stroke="DarkRed" StrokeThickness="1" ></Path>
<Rectangle Name="rect" Canvas.Left="10" Canvas.Top="100" Fill="Blue" Width="75" Height="75">
</Rectangle>
</Canvas>
<CheckBox Grid.Row="2" x:Name="chkCache" Content="Enable Caching"
IsChecked="False" Click="chkCache_Click"></CheckBox>
</Grid>
public CachingTest()
{
InitializeComponent();
PathGeometry pathGeometry = new PathGeometry();
PathFigure pathFigure = new PathFigure();
pathFigure.StartPoint = new Point(0,0);
PathSegmentCollection pathSegmentCollection = new PathSegmentCollection();
int maxHeight = (int)this.Height;
int maxWidth = (int)this.Width;
Random rand = new Random();
for (int i = 0; i < 500; i++)
{
LineSegment newSegment = new LineSegment();
newSegment.Point = new Point(rand.Next(0, maxWidth), rand.Next(0, maxHeight));
pathSegmentCollection.Add(newSegment);
}
pathFigure.Segments = pathSegmentCollection;
pathGeometry.Figures.Add(pathFigure);
pathBackground.Data = pathGeometry;
}
private void chkCache_Click(object sender, RoutedEventArgs e)
{
if (chkCache.IsChecked == true)
{
BitmapCache bitmapCache = new BitmapCache();
pathBackground.CacheMode = new BitmapCache();
}
else
{
pathBackground.CacheMode = null;
}
}
public class ArithmeticConverter : IValueConverter
{
private const string ArithmeticParseExpression = "([+\\-*/]{1,1})\\s{0,}(\\-?[\\d\\.]+)";
private Regex arithmeticRegex = new Regex(ArithmeticParseExpression);
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double && parameter != null)
{
string param = parameter.ToString();
if (param.Length > 0)
{
Match match = arithmeticRegex.Match(param);
if (match != null && match.Groups.Count == 3)
{
string operation = match.Groups[1].Value.Trim();
string numericValue = match.Groups[2].Value;
double number = 0;
if (double.TryParse(numericValue, out number)) // this should always succeed or our regex is broken
{
double valueAsDouble = (double)value;
double returnValue = 0;
switch (operation)
{
case "+":
returnValue = valueAsDouble + number;
break;
case "-":
returnValue = valueAsDouble - number;
break;
case "*":
returnValue = valueAsDouble * number;
break;
case "/":
returnValue = valueAsDouble / number;
break;
}
return returnValue;
}
}
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard x:Name="storyboard">
<DoubleAnimation Storyboard.TargetName="rotateTransform"
Storyboard.TargetProperty="Angle"
To="360" Duration="0:0:2" RepeatBehavior="Forever"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleX" AutoReverse="True"
To="20" Duration="0:0:1.8" RepeatBehavior="Forever"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleY" AutoReverse="True"
To="20" Duration="0:0:1.8" RepeatBehavior="Forever"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Canvas>
<Image x:Name="img" Source="phone_booth.jpg" Stretch="None" CacheMode="BitmapCache">
<Image.RenderTransform>
<RotateTransform x:Name="rotateTransform" CenterX="300" CenterY="100"></RotateTransform>
</Image.RenderTransform>
</Image>
<Button x:Name="cmd" Content="I GROW and SHRINK." Canvas.Top="70" Canvas.Left="10" >
<Button.CacheMode>
<BitmapCache RenderAtScale="5"></BitmapCache>
</Button.CacheMode>
<Button.RenderTransform>
<ScaleTransform x:Name="scaleTransform"></ScaleTransform>
</Button.RenderTransform>
</Button>
</Canvas>
<CheckBox Grid.Row="2" x:Name="chkCache" Content="Enable Caching"
IsChecked="True" Click="chkCache_Click"></CheckBox>
</Grid>
private void chkCache_Click(object sender, RoutedEventArgs e)
{
if (chkCache.IsChecked == true)
{
BitmapCache bitmapCache = new BitmapCache();
bitmapCache.RenderAtScale = 5;
cmd.CacheMode = bitmapCache;
img.CacheMode = new BitmapCache();
}
else
{
cmd.CacheMode = null;
img.CacheMode = null;
}
}
代码动画:
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Button Padding="10" Name="cmdGrow" Click="cmdGrow_Click" Height="40" Width="160"
HorizontalAlignment="Center" VerticalAlignment="Center">
Click and Make Me Grow
</Button>
<Button Grid.Row="1" Padding="10" Name="cmdShrink" Click="cmdShrink_Click"
HorizontalAlignment="Center" VerticalAlignment="Center">
Shrink It Back
</Button>
<Button Grid.Row="2" Padding="10" Name="cmdGrowIncrementally" Click="cmdGrowIncrementally_Click"
HorizontalAlignment="Center" VerticalAlignment="Center" Width="240">
Click and Make Me Grow (Incrementally)
</Button>
private void cmdGrow_Click(object sender, RoutedEventArgs e)
{
DoubleAnimation widthAnimation = new DoubleAnimation();
widthAnimation.To = this.Width - 30;
widthAnimation.Duration = TimeSpan.FromSeconds(5);
widthAnimation.Completed += animation_Completed;
DoubleAnimation heightAnimation = new DoubleAnimation();
heightAnimation.To = (this.Height - 50)/3;
heightAnimation.Duration = TimeSpan.FromSeconds(5);
cmdGrow.BeginAnimation(Button.WidthProperty, widthAnimation);
cmdGrow.BeginAnimation(Button.HeightProperty, heightAnimation);
}
private void animation_Completed(object sender, EventArgs e)
{
//double currentWidth = cmdGrow.Width;
//cmdGrow.BeginAnimation(Button.WidthProperty, null);
//cmdGrow.Width = currentWidth;
//MessageBox.Show("Completed!");
}
private void cmdShrink_Click(object sender, RoutedEventArgs e)
{
DoubleAnimation widthAnimation = new DoubleAnimation();
widthAnimation.Duration = TimeSpan.FromSeconds(5);
DoubleAnimation heightAnimation = new DoubleAnimation();
heightAnimation.Duration = TimeSpan.FromSeconds(5);
cmdGrow.BeginAnimation(Button.WidthProperty, widthAnimation);
cmdGrow.BeginAnimation(Button.HeightProperty, heightAnimation);
}
private void cmdGrowIncrementally_Click(object sender, RoutedEventArgs e)
{
DoubleAnimation widthAnimation = new DoubleAnimation();
widthAnimation.By = 10;
widthAnimation.Duration = TimeSpan.FromSeconds(0.5);
cmdGrowIncrementally.BeginAnimation(Button.WidthProperty, widthAnimation);
}
自定义缓动动画:
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Canvas.Left)"
To="500" Duration="0:0:10">
</DoubleAnimation>
<DoubleAnimation
Storyboard.TargetName="ellipse2" Storyboard.TargetProperty="(Canvas.Left)"
To="500" Duration="0:0:10">
<DoubleAnimation.EasingFunction>
<local:RandomJitterEase EasingMode="EaseIn" Jitter="1000"></local:RandomJitterEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Canvas Margin="10">
<Ellipse Name="ellipse1" Canvas.Left="0" Fill="Red" Width="20" Height="20"></Ellipse>
<Ellipse Name="ellipse2" Canvas.Top="100" Canvas.Left="0" Fill="Red" Width="20" Height="20"></Ellipse>
</Canvas>
public class RandomJitterEase : EasingFunctionBase
{
// Store a random number generator.
private Random rand = new Random();
protected override double EaseInCore(double normalizedTime)
{
//To see the values add code like this:
//System.Diagnostics.Debug.WriteLine(...);
// Make sure there's no jitter in the final value.
if (normalizedTime == 1) return 1;
// Offset the value by a random amount.
return Math.Abs(normalizedTime - (double)rand.Next(0,10)/(2010 - Jitter));
}
public int Jitter
{
get { return (int)GetValue(JitterProperty); }
set { SetValue(JitterProperty, value); }
}
public static readonly DependencyProperty JitterProperty =
DependencyProperty.Register("Jitter", typeof(int), typeof(RandomJitterEase),
new UIPropertyMetadata(1000), new ValidateValueCallback(ValidateJitter));
private static bool ValidateJitter(object value)
{
int jitterValue = (int)value;
return ((jitterValue <= 2000) && (jitterValue >= 0));
}
// This required override simply provides a live instance of your easing function.
protected override Freezable CreateInstanceCore()
{
return new RandomJitterEase();
}
}
缓动动画:
<Grid Background="White">
<Button x:Name="cmdGrow" Width="300" Height="60" Content="This button grows">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width"
To="400" Duration="0:0:1.5">
<DoubleAnimation.EasingFunction>
<ElasticEase EasingMode="EaseOut" Oscillations="10"></ElasticEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="cmdGrow" Storyboard.TargetProperty="Width"
Duration="0:0:3">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
帧速率:
<Window.Resources>
<BeginStoryboard x:Key="beginStoryboard">
<Storyboard Timeline.DesiredFrameRate="{Binding ElementName=txtFrameRate,Path=Text}">
<DoubleAnimation Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Canvas.Left)"
From="0" To="300" Duration="0:0:5">
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Canvas.Top)"
From="300" To="0" AutoReverse="True" Duration="0:0:2.5"
DecelerationRatio="1">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<StaticResource ResourceKey="beginStoryboard"></StaticResource>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid Background="LightGoldenrodYellow" >
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Border Background="White" BorderBrush="DarkGray" BorderThickness="3" Width="300" Height="300" HorizontalAlignment="Center" VerticalAlignment="Center">
<Canvas ClipToBounds="True">
<Ellipse Name="ellipse" Fill="Red" Width="10" Height="10"></Ellipse>
</Canvas>
</Border>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Margin="10">
<TextBlock VerticalAlignment="Center" xml:space="preserve">Desired Frame Rate: </TextBlock>
<TextBox Grid.Column="2" Width="50" Name="txtFrameRate">60</TextBox>
</StackPanel>
<Button Grid.Row="2" HorizontalAlignment="Center" Padding="3" Margin="3">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<StaticResource ResourceKey="beginStoryboard"></StaticResource>
</EventTrigger>
</Button.Triggers>
<Button.Content>
Repeat
</Button.Content>
</Button>
</Grid>
图片擦除:
<Grid>
<Image Source="night.jpg"></Image>
<Image Source="day.jpg" Name="imgDay">
<Image.OpacityMask>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Offset="0" Color="Transparent" x:Name="transparentStop" />
<GradientStop Offset="0" Color="Black" x:Name="visibleStop" />
</LinearGradientBrush>
</Image.OpacityMask>
</Image>
</Grid>
<Button Name="cmdStart" Grid.Row="1" Padding="5" Margin="5">
Start
<Button.Triggers>
<EventTrigger SourceName="cmdStart" RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="transparentStop"
Storyboard.TargetProperty="Offset" BeginTime="0:0:0.2"
From="0" To="1" Duration="0:0:1" ></DoubleAnimation>
<DoubleAnimation
Storyboard.TargetName="visibleStop"
Storyboard.TargetProperty="Offset"
From="0" To="1.2" Duration="0:0:1.2" ></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
Xaml动画:
<Window.Resources>
<local:ArithmeticConverter x:Key="converter"></local:ArithmeticConverter>
</Window.Resources>
<Button Padding="10" Name="cmdGrow" Height="40" Width="160"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
To="{Binding ElementName=window,Path=Width,Converter={StaticResource converter},ConverterParameter=-30}"
Duration="0:0:5"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="Height"
To="{Binding ElementName=window,Path=Height,Converter={StaticResource converter},ConverterParameter=-50}"
Duration="0:0:5"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
<Button.Content>
Click and Make Me Grow
</Button.Content>
</Button>