I can't get my animation to start and stop, with code behind (c #)
I have tried MyStoryboard.stop() and change duration for the animation and it stops, but only when I change content and go back.
When I start it again my animations run at strange speeds and again only if I change content
when I change content there is a new speed and if I keep doing it, it bugs
Xaml:
<Image Grid.Row="0" MaxHeight="50" Source="..\Images\Propeller.png"
RenderTransformOrigin=".5,.5">
<Image.RenderTransform>
<RotateTransform x:Name="MyAnimation" Angle="0" />
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard x:Name="MyStoryboard">
<DoubleAnimation x:Name="Prope11"
Storyboard.TargetName="MyAnimation"
To="360"
Duration="0:0:0.6"
RepeatBehavior="Forever"
FillBehavior="Stop" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
Code behind:
TimeSpan ts = TimeSpan.FromMilliseconds(600);
MyStoryboard.Stop();
Prope11.Duration = ts;
MyStoryboard.Bigin();
You had not assigned the TargetName Property of the Storyboard to start the animation.
Well, there are two problems in your xaml to make the animation start.
1) Storyboard.TargetName="MyAnimation", Target name must be controls name. In your case, you have provided but you have given or assigned it to RotateTransform, which comes under the Image control, but not the image.
<Image x:Name="ImageControl" Grid.Row="0" MaxHeight="50" Source="C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg"
RenderTransformOrigin=".5,.5" >
and in DoubleAnimation provide TargetName as the Image control's name
Storyboard.TargetName="ImageControl"
2) Another problem is you have not provided the Target Property on which your double animation is dependent.
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
Your stop code didn't work because, it was not started. Adding this below xaml will solve your problem.
Change in the speed is because you have given 600, for 6 Seconds it must be 6000 and not 600.
This is the change i have done. On Mouse Down event I have given to Stop StoryBoard.
<Image.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard x:Name="BeginImageRotateAni" >
<Storyboard x:Name="MyStoryboard">
<DoubleAnimation x:Name="Prope11"
Storyboard.TargetName="ImageControl"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
To="360"
Duration="0:0:6"
RepeatBehavior="Forever"
FillBehavior="Stop"
>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseDown">
<EventTrigger.Actions>
<StopStoryboard BeginStoryboardName="BeginImageRotateAni"/>
</EventTrigger.Actions>
</EventTrigger>
</Image.Triggers>
and subscribed for MouseDownEvent in Constructor
ImageControl.MouseDown += ImageControl_MouseDown;
and write the below code inside the event.
bool IsAnimationstarted = true;
private void ImageControl_MouseDown(object sender, MouseButtonEventArgs e)
{
if (IsAnimationstarted)
{
MyStoryboard.Stop();
IsAnimationstarted = false;
}
else
{
TimeSpan ts = TimeSpan.FromMilliseconds(6000);
Prope11.Duration = ts;
MyStoryboard.Begin();
IsAnimationstarted = true;
}
}
}
Alternate solution:- by creating the animation in the resource and then utilizing it in the codebehind.
<Window.Resources>
<Storyboard x:Name="MyStoryboard" x:Key="Animation1" >
<DoubleAnimation x:Name="Prope11"
Storyboard.TargetName="ImageControl"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
To="360"
Duration="0:0:6"
RepeatBehavior="Forever"
FillBehavior="Stop"
>
</DoubleAnimation>
</Storyboard>
</Window.Resources>
In Code Behind:-
bool IsAnimationstarted = true;
private void ImageControl_MouseDown(object sender, MouseButtonEventArgs e)
{
Storyboard board = (Storyboard)this.FindResource("Animation1");
if (IsAnimationstarted)
{
IsAnimationstarted = false;
board.Begin();
}
else
{
IsAnimationstarted = true;
board.Pause();
}
}
I don't know why are changing the speed or not sure about your intention. What I have done here is when the user clicks on the image control, it will start the animation and pause again clicked and this goes on.
Related
Let's imagine we have an animation that changes a Rectangle's width from 50 to 150 when user moves the cursor over it and back from 150 to 50 when user moves the cursor away. Let the duration of each animation be 1 second.
Everything is OK if user moves the cursor over the rectangle, then waits for 1 second for animation to finish, and then moves the cursor away from the rectangle. Two animations take 2 seconds totally and their speed is exactly what we are expecting to be.
But if user moves the cursor away before the first animation (50 -> 150) is finished, the second animation's duration will be 1 second but the speed of it will be very slow. I mean, the second animation will animate the rectangle's width not from 150 to 50 but from let's say 120 to 50 or from 70 to 50 if you take cursor away very fast. But for the same 1 second!
So what I want to understand is how to make the duration of the "backwards" animation to be dynamic. Dynamic based on at what point the first animation was stopped. Or, if I specify From and To values to 150 and 50, Duration to 1 seconds and rectangle width will be 100 – WPF would calculate by itself that animation is 50% done.
I was testing different ways to use animation like Triggers, EventTrigger in style, and VisualStateGroups but no success.
Here is a XAML sample that shows my problem. If you want to see by yourself what I am talking about, move the cursor over the rectangle, wait for 1-2 seconds (first animation is finished) then move the cursor away. After that, move the cursor over the rectangle for like 0.25 seconds and move it away. You will see that the rectangle's width changes very slowly.
<Rectangle Width="50"
Height="100"
HorizontalAlignment="Left"
Fill="Black">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
To="150"
Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
Also, I would like to explain what calculation I am expecting to see.
So let's imagine another animation that goes from 100 to 1100 and has a duration of 2 seconds. If we stop it at the point of 300, it must start to go back to 100 but not for 2 seconds but for:
((300 - 100) / (1100 - 100)) * 2s = 0.4s
If we stop at 900, duration will be:
((900 - 100) / (1100 - 100)) * 2s = 1.6s
And if we let animation finish normally it will be:
((1100 - 100) / (1100 - 100)) * 2s = 2s
WPF provides the possibility to write custom animations.
You may create one with a MinSpeed property:
public class MinSpeedDoubleAnimation : DoubleAnimation
{
public static readonly DependencyProperty MinSpeedProperty =
DependencyProperty.Register(
nameof(MinSpeed), typeof(double?), typeof(MinSpeedDoubleAnimation));
public double? MinSpeed
{
get { return (double?)GetValue(MinSpeedProperty); }
set { SetValue(MinSpeedProperty, value); }
}
protected override Freezable CreateInstanceCore()
{
return new MinSpeedDoubleAnimation();
}
protected override double GetCurrentValueCore(
double defaultOriginValue, double defaultDestinationValue,
AnimationClock animationClock)
{
var destinationValue = To ?? defaultDestinationValue;
var originValue = From ?? defaultOriginValue;
var duration = Duration != Duration.Automatic ? Duration :
animationClock.NaturalDuration;
var speed = (destinationValue - originValue) / duration.TimeSpan.TotalSeconds;
if (MinSpeed.HasValue && Math.Abs(speed) < MinSpeed)
{
speed = Math.Sign(speed) * MinSpeed.Value;
}
var value = originValue + speed * animationClock.CurrentTime.Value.TotalSeconds;
return speed > 0 ?
Math.Min(destinationValue, value) :
Math.Max(destinationValue, value);
}
}
and use it like this:
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Width"
To="150" Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<local:MinSpeedDoubleAnimation
Storyboard.TargetProperty="Width"
To="50" MinSpeed="100"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
For completeness here is also the most simple code-behind solution without any Triggers and Storyboards:
<Rectangle Width="50" Height="100" HorizontalAlignment="Left" Fill="Black"
MouseEnter="RectangleMouseEnter" MouseLeave="RectangleMouseLeave"/>
with these event handlers:
private void RectangleMouseEnter(object sender, MouseEventArgs e)
{
var element = (FrameworkElement)sender;
var animation = new DoubleAnimation(150, TimeSpan.FromSeconds(1));
element.BeginAnimation(FrameworkElement.WidthProperty, animation);
}
private void RectangleMouseLeave(object sender, MouseEventArgs e)
{
var element = (FrameworkElement)sender;
var duration = (element.ActualWidth - 50) / 100;
var animation = new DoubleAnimation(50, TimeSpan.FromSeconds(duration));
element.BeginAnimation(FrameworkElement.WidthProperty, animation);
}
Unfortunately, Storyboards are compiled code, meaning you can't use binding in the elements to improve their abilities.
I've had to do something similar and the only way I found to achieve it was to access the storyboard property that needed to be dynamic at the time that I needed to touch it, and set the property as needed in code behind.
So it's not ideal to have to touch and trigger from code behind, but hey look at it this way, it's not business logic, it's strictly presentation layer so code behind is typically acceptable practice.
So handle your trigger in code behind, calculate your numbers, update the storyboard properties and then start it. That's probably going to be your best option for now.
I would love to see storyboards become part of the logical tree with dependency properties to dynamically modify values, so maybe request the feature :).
An alternative to a custom animation could be an attached property that is bound to the target element's ActualWidth, which dynamically adjusts the animation's Duration.
The attached property could look like this:
public static class AnimationEx
{
public static readonly DependencyProperty DynamicDurationProperty =
DependencyProperty.RegisterAttached(
"DynamicDuration", typeof(double), typeof(AnimationEx),
new PropertyMetadata(DynamicDurationPropertyChanged));
public static double GetDynamicDuration(DoubleAnimation animation)
{
return (double)animation.GetValue(DynamicDurationProperty);
}
public static void SetDynamicDuration(DoubleAnimation animation, double value)
{
animation.SetValue(DynamicDurationProperty, value);
}
private static void DynamicDurationPropertyChanged(
DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var animation = o as DoubleAnimation;
if (animation != null && animation.To.HasValue)
{
animation.Duration = TimeSpan.FromSeconds(
Math.Abs((double)e.NewValue - animation.To.Value) / 100);
}
}
}
where there might be another attached property for the speed factor, which is hardcoded as 100 above.
The property would be used like this:
<Rectangle.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
To="150" Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="50"
local:AnimationEx.DynamicDuration="{Binding Path=ActualWidth,
RelativeSource={RelativeSource AncestorType=Rectangle}}" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
A possible drawback might be the fact that the Duration is constantly reset when the ActualWidth changes. However, I could not notify any visual effect.
I would like to have an ellipse fill "flash"(turn white instantly and then return to the new color) whenever databound fill color changes. This is what I got so far:
<ctrls:NotifyEllipse Fill="{Binding Cluster.Brush, Converter={StaticResource CloneConverter}}" Width="10" Height="10" >
<ctrls:NotifyEllipse.Style>
<Style TargetType="{x:Type ctrls:NotifyEllipse}">
<Style.Triggers>
<EventTrigger RoutedEvent="ctrls:NotifyEllipse.FillChanged">
<BeginStoryboard>
<Storyboard AutoReverse="True">
<ColorAnimation Storyboard.TargetProperty="(ctrls:NotifyEllipse.Fill).Color" To="White" Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</ctrls:NotifyEllipse.Style>
</ctrls:NotifyEllipse>
where ctrls:NotifyEllipse is UserControl containing only ellipse, with dependency property Fill and routed event FillChanged - similar this answer. The color changed detection part works great, however the flash part(obviously) does not work as I would like to: it first changes fill color to the new color, than slowly turns white and at the end turns back to new color.
As mentioned above, the goal is to "flash" - turn white instantly and then return to new color.
Please note that there is databinding on the Fill so having two animations one instant and other slow is not possible simply because I dont know which color to return to:
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(ctrls:NotifyEllipse.Fill).Color" To="White" Duration="0:0:0" />
<ColorAnimation Storyboard.TargetProperty="(ctrls:NotifyEllipse.Fill).Color" To="???" Duration="0:0:1" />
</Storyboard>
bonus points: Flash to white not instantly but fast and keep original color until the full white was reached and then turn from white to new color slowly, this would be ideal solution but I am afraid it would require a lot of custom animation code. Flash as described above is sufficient.
Just start the ColorAnimation from White:
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Fill.Color"
From="White" Duration="0:0:1" />
</Storyboard>
For completeness, my NotifyEllipse class looks like this:
public class NotifyEllipse : Shape
{
static NotifyEllipse()
{
FillProperty.AddOwner(typeof(NotifyEllipse), new FrameworkPropertyMetadata(
(o, e) =>
{
if (e.NewValue != e.OldValue)
{
((NotifyEllipse)o).RaiseEvent(new RoutedEventArgs(FillChangedEvent));
}
}));
}
public static readonly RoutedEvent FillChangedEvent =
EventManager.RegisterRoutedEvent(
"FillChanged", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(NotifyEllipse));
public event RoutedEventHandler FillChanged
{
add { AddHandler(FillChangedEvent, value); }
remove { RemoveHandler(FillChangedEvent, value); }
}
protected override Geometry DefiningGeometry
{
get { return new EllipseGeometry(new Rect(RenderSize)); }
}
}
I want create a floating animated clickable control like a helium balloon that moves sometimes to right or left too in my WPF application.
The helium balloons likes go up! but also they moves right or left if
we tap on them or by wind.
In advance cases, sometimes they turn to right or left
....................................................................
So i searched the web but i didn't find any usefull sample project or library or styles.
How i can create style and animation in WPF to show an image or
control buoyant or suspended in air.?
Have you any suggestions to implement this idea simply...?
Edit:
What is your suggestion for a random and infinite smooth turns to right and left. for example 51degrees to left then 163degree to right and.... i want keep my balloon in my window and often top of the window.
Edit:
I created an animation base on these answers but more complex by manipulating them and adding multiple parallel animation on balloon image and its container. ;)
Thanks all...
Now my primary result is like this:
You can achieve this with a DoubleAnimation and a RotateTransform like #Ega mentioned. To answer your "random and infinite" turns to right and left, here's how you could do it (it's very basic but does the job).
private async void Button_Click(object sender, RoutedEventArgs e)
{
var rnd = new Random();
var direction = -1;
while (true)
{
var percent = rnd.Next(0, 100);
direction *= -1; // Direction changes every iteration
var rotation = (int)((percent / 100d) * 45 * direction); // Max 45 degree rotation
var duration = (int)(750 * (percent / 100d)); // Max 750ms rotation
var da = new DoubleAnimation
{
To = rotation,
Duration = new Duration(TimeSpan.FromMilliseconds(duration)),
AutoReverse = true // makes the balloon come back to its original position
};
var rt = new RotateTransform();
Balloon.RenderTransform = rt; // Your balloon object
rt.BeginAnimation(RotateTransform.AngleProperty, da);
await Task.Delay(duration * 2); // Waiting for animation to finish, not blocking the UI thread
}
}
edit for .NET 3.5
private void Button_Click(object sender, RoutedEventArgs e)
{
var thread = new Thread(this.AnimateBalloon);
thread.Start();
}
public void AnimateBalloon()
{
var rnd = new Random();
var direction = -1;
while (true)
{
var percent = rnd.Next(0, 100);
direction *= -1; // Direction changes every iteration
var rotation = (int)((percent / 100d) * 45 * direction); // Max 45 degree rotation
var duration = (int)(750 * (percent / 100d)); // Max 750ms rotation
Balloon.Dispatcher.BeginInvoke(
(Action)(() =>
{
var da = new DoubleAnimation
{
To = rotation,
Duration = new Duration(TimeSpan.FromMilliseconds(duration)),
AutoReverse = true // makes the balloon come back to its original position
};
var rt = new RotateTransform();
Balloon.RenderTransform = rt; // Your balloon object
rt.BeginAnimation(RotateTransform.AngleProperty, da);
}));
Thread.Sleep(duration * 2);
}
}
Farseer Physics Engine for C# will allow you to create a real world simulation. You can control gravity, inertia, force and even other physical stuff.
World world = new World(new Vector2(0f, 9.82f));
//We create a body object and make it dynamic (movable)
Body myBody = world.CreateBody();
myBody.BodyType = BodyType.Dynamic;
//We create a circle shape with a radius of 0.5 meters
CircleShape circleShape = new CircleShape(0.5f);
//We fix the body and shape together using a Fixture object
Fixture fixture = myBody.CreateFixture(circleShape);
For this scenario you may need to create a world with less gravity and objects will fly. You can apply force from either side of the object to move it.
in C# DoubleAnimationis a powerful Class Support Animation inside System.Windows.Media.Animation; NameSpace so this class have some Methods and Properties let me to tell you it
DoubleAnimation ANobj = new DoubleAnimation();//make object from DoubleAnimation
ANobj.From=0 //the 0 is point you want to star animation
ANobj.To=270//the end pont of moving
// that values is dependent on your self as you want
ANobj.Duration = new Duration(TimeSpan.FromSeconds(60)); //specify the duration of moving
ANobj.RepeatBehavior = RepeatBehavior.Forever;//RepeatBehavior as you want
also use RotateTransform class to Rotate C# Componets in WPF
RotateTransform RTobj=new RotateTransform();//make object from RotateTransform
RTobj.CenterX = 277;//X point of your Element(Componet)
RTobj.CenterY = 245;//Y point of your Element(Componet)
RTobj.Angle = 360;//angle between
RTobj.BeginAnimation(RotateTransform.AngleProperty,ANobj);
also after doing that configures set this obj to RenderTransform property from your Element like it
yourElementName.RenderTransform=RTobj
if you want read more at MSDN about System.Windows.Media.Animation
May This help You Here,I take polygon and One image to left to right you can set by Your choice :)
<Window x:Class="Animation.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="XAML Animation - Spinning Stars" Height="300" Width="355"
>
<Grid Name="myGrid">
<Canvas Margin="15,18,18,26" MinHeight="50" MinWidth="50" Name="canvas1">
<!-- Invisible element just to host composite transform -->
<Polygon
Name ="mypolygon1"
Stroke="Blue"
StrokeThickness="1.0"
Points="176.5,50 189.2,155.003 286.485,113.5 201.9,177 286.485,240.5
189.2,198.997 176.5,304 163.8,198.997 66.5148,240.5 151.1,177
66.5148,113.5 163.8,155.003">
<Polygon.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="xformRotate" CenterX="176" CenterY="145" />
<TranslateTransform x:Name="xformTranslate" X ="-50" Y="-50" />
<ScaleTransform x:Name ="xformScale" ScaleX=".25" ScaleY=".25" />
</TransformGroup>
</Polygon.RenderTransform>
<Polygon.Fill>
<SolidColorBrush Color="Blue">
<!--<ColorAnimation From="Yellow" To="Blue" Duration="7"
RepeatCount="500" AutoReverse="True"/>-->
</SolidColorBrush>
</Polygon.Fill>
<Polygon.Triggers>
<EventTrigger RoutedEvent="Polygon.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<!-- RotateTransform angle from 0 to 360, repeated -->
<DoubleAnimation Storyboard.TargetName="xformRotate"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:01"
RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="xformTranslate"
Storyboard.TargetProperty="X"
From="1" To="750" Duration="0:0:14"
AutoReverse ="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Polygon.Triggers>
</Polygon>
<Polygon
Name ="mypolygon2"
Stroke="Red"
StrokeThickness="1.0"
Points="176.5,50 189.2,155.003 286.485,113.5 201.9,177 286.485,240.5
189.2,198.997 176.5,304 163.8,198.997 66.5148,240.5 151.1,177
66.5148,113.5 163.8,155.003">
<Polygon.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="xformRotateIt" CenterX="176" CenterY="145" />
<ScaleTransform ScaleX=".25" ScaleY=".25" />
<TranslateTransform x:Name="xformTranslateIt" X="0" Y="100" />
</TransformGroup>
</Polygon.RenderTransform>
<Polygon.Fill>
<SolidColorBrush x:Name ="mybrush" Color="Red" />
</Polygon.Fill>
<Polygon.Triggers>
<EventTrigger RoutedEvent="Polygon.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard x:Name="myStoryBoard" Completed="OnCompletedAnimation">
<!-- RotateTransform angle from 0 to 360, repeated -->
<DoubleAnimation Storyboard.TargetName="xformRotateIt"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:01"
RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="xformTranslateIt"
Storyboard.TargetProperty="X"
From="1" To="100" Duration="0:0:14"
AutoReverse ="True" RepeatBehavior="Forever" />
<ColorAnimation Storyboard.TargetName="mybrush" Storyboard.TargetProperty="Color" From="Red" To="Blue" Duration="0:0:7"
RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Polygon.Triggers>
</Polygon>
<Image Margin="75,61,0,119" Name="image1" Source="Images\KENNY.bmp" HorizontalAlignment="Left" Width="72">
<Image.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="KennyRotateIt" CenterX="50" CenterY="50" Angle="45" />
<ScaleTransform x:Name="KennyScaleIt" ScaleX=".75" ScaleY=".75" />
<TranslateTransform x:Name="KennyTranslateIt" X="0" Y="100" />
</TransformGroup>
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Image.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard x:Name="myStoryBoard1" Completed="OnCompletedAnimation">
<!-- RotateTransform angle from 0 to 360, repeated -->
<DoubleAnimation Storyboard.TargetName="KennyRotateIt"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:01"
RepeatBehavior="Forever" />
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="KennyTranslateIt"
Storyboard.TargetProperty="X"
Duration="0:0:10" AutoReverse="True" RepeatBehavior="Forever">
<!-- These KeyTime properties are specified as TimeSpan values
which are in the form of "hours:minutes:seconds". -->
<LinearDoubleKeyFrame Value="10" KeyTime="0:0:3" />
<LinearDoubleKeyFrame Value="100" KeyTime="0:0:5" />
<LinearDoubleKeyFrame Value="200" KeyTime="0:0:10" />
</DoubleAnimationUsingKeyFrames>
<!-- DoubleAnimation Storyboard.TargetName="KennyTranslateIt"
Storyboard.TargetProperty="X"
From="-50" To="100" Duration="0:0:14"
AutoReverse ="True" RepeatBehavior="Forever" / -->
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Image.Triggers>
</Image>
</Canvas>
</Grid>
</Window>
Here is one I did in high school. Probably very outdated now but just for interest sake.
//the animation thread
System.Threading.Thread thr;
thr = new System.Threading.Thread(annimate);
thr.Start();
the animation method
void annimate()
{
try
{
double angleToAnimateTo = 20;
double CurrentAngle = 0;
bool increment = false;
while (IsAnimating)
{
if (increment)
CurrentAngle++;
else
CurrentAngle--;
if (CurrentAngle == angleToAnimateTo )
increment = false;
if (CurrentAngle == (angleToAnimateTo * -1))
increment = true;
this.Dispatcher.Invoke((Action)(() =>
{
this.imgBallon.RenderTransform = new RotateTransform(CurrentAngle);
}));
System.Threading.Thread.Sleep(100);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
imgBalloon is a simple image in wpf. Here is the xaml..
<Image x:Name="imgBallon"
Source="/img/balloon_blue.png" Width="50"> </Image>
I have a background image in my wpf application, I want to achieve a effect of the background image continuous move. The following code can achieve a simple effect, but when the time of the end of the picture moves over again, I want to make this picture the effect of the movement has been the phenomenon does not come to a halt.
void StartBackgroudMove()
{
Storyboard sb = new Storyboard();
DoubleAnimation TranslateXExtendAnimation = new DoubleAnimation() { From = 0, To = -100, Duration = TimeSpan.FromMilliseconds(2500) };
Storyboard.SetTarget(TranslateXExtendAnimation, BackgroundImage);
Storyboard.SetTargetProperty(TranslateXExtendAnimation, new PropertyPath("(FrameworkElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"));
sb.Children.Add(TranslateXExtendAnimation);
sb.FillBehavior = FillBehavior.Stop;
sb.Completed += (s, args) =>
{
this.StartBackgroudMove();
};
sb.Begin();
}
You may use an ImageBrush with TileMode set to Tile and animate its Viewport property:
<Grid>
<Grid.Background>
<ImageBrush ImageSource="C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"
Stretch="Fill" TileMode="Tile"
ViewportUnits="Absolute" Viewport="0,0,1024,768"/>
</Grid.Background>
<Grid.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<RectAnimation Storyboard.TargetProperty="Background.Viewport"
To="-1024,0,1024,768" Duration="0:0:10"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
The following alternative solution places two adjacent images in a Canvas and animates the Canvas' RenderTransform property.
<Grid>
<Canvas>
<Canvas.RenderTransform>
<TranslateTransform x:Name="translation"/>
</Canvas.RenderTransform>
<Image Stretch="None"
Source="C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"/>
<Image Canvas.Left="1024" Stretch="None"
Source="C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"/>
</Canvas>
<Grid.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="X"
Storyboard.TargetName="translation"
To="-1024" Duration="0:0:10"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
You can set the Storyboard.RepeatBehavior to RepeatBehavior.Forever
Example:
void StartBackgroudMove()
{
Storyboard sb = new Storyboard();
DoubleAnimation TranslateXExtendAnimation = new DoubleAnimation() { From = 0, To = -100, Duration = TimeSpan.FromMilliseconds(2500) };
Storyboard.SetTarget(TranslateXExtendAnimation, BackgroundImage);
Storyboard.SetTargetProperty(TranslateXExtendAnimation, new PropertyPath("(FrameworkElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"));
sb.Children.Add(TranslateXExtendAnimation);
sb.FillBehavior = FillBehavior.Stop;
sb.RepeatBehavior = RepeatBehavior.Forever;
sb.Begin();
}
I am using two storyboards to move balls(image) left and right directions, on tap event of left button I want to move balls in left direction and on tap event of right button , balls should move in right direction. It's working correctly on taping left and right button, but on loading application storyboards begins automatically and balls move one step without tapping buttons. How do I restrict storyboard to begin automatically?
This is my first storyboard to move balls 40 pixels in left direction:
<EventTrigger>
<BeginStoryboard>
<Storyboard x:Name="ballstoryleft">
<DoubleAnimation Storyboard.TargetName="balltrans" Storyboard.TargetProperty="TranslateX"
Duration="0:0:0.5" By="-40" FillBehavior="HoldEnd">
<DoubleAnimation.EasingFunction>
<ElasticEase Oscillations="0" Springiness="1" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
This is my second storyboard to move balls 40 pixels in right direction:
<EventTrigger>
<BeginStoryboard>
<Storyboard x:Name="ballstoryright">
<DoubleAnimation Storyboard.TargetName="balltrans" Storyboard.TargetProperty="TranslateX"
Duration="0:0:0.5" By="40" FillBehavior="HoldEnd">
<DoubleAnimation.EasingFunction>
<ElasticEase Oscillations="0" Springiness="1" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
I have written this code in code behind:
private void imgleft_Tapped(object sender, TappedRoutedEventArgs e)
{
ballstoryleft.Begin();
}
private void imgright_Tapped(object sender, TappedRoutedEventArgs e)
{
ballstoryright.Begin();
}
Where did you put your Storyboards? I see they are inside EventTriggers. They might be the ones triggering the storyboards when the application loads.
You should just put both Storyboards in a Resources collection:
<Page.Resources>
<Storyboard x:Name="ballstoryleft">
<DoubleAnimation Storyboard.TargetName="balltrans" Storyboard.TargetProperty="TranslateX"
Duration="0:0:0.5" By="-40" FillBehavior="HoldEnd">
<DoubleAnimation.EasingFunction>
<ElasticEase Oscillations="0" Springiness="1" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Name="ballstoryright">
<DoubleAnimation Storyboard.TargetName="balltrans" Storyboard.TargetProperty="TranslateX"
Duration="0:0:0.5" By="40" FillBehavior="HoldEnd">
<DoubleAnimation.EasingFunction>
<ElasticEase Oscillations="0" Springiness="1" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</Page.Resources>
Now there should be no reason for them to trigger automatically while your code which triggers them on tap should still work just like it does now.
You can define whole story board from code behind also
Try this example:
void OnButtonClick(object sender, RoutedEventArgs args)
{
DoubleAnimation anima = new DoubleAnimation
{
EnableDependentAnimation = true,
To = 96,
Duration = new Duration(new TimeSpan(0, 0, 1)),
AutoReverse = true,
RepeatBehavior = new RepeatBehavior(3) };
Storyboard.SetTarget(anima, sender as Button);
Storyboard.SetTargetProperty(anima, "FontSize");
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(anima);
storyboard.Begin();
}