Moving object animation in X and Y - c#

I have created animation for moving object in X, but how do I add also Y?
TranslateTransform trans = new TranslateTransform();
Pointer.RenderTransform = trans;
DoubleAnimation anim2 = new DoubleAnimation(1, 500, TimeSpan.FromMilliseconds(325));
anim2.EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut };
anim2.Completed += new EventHandler(myanim_Completed);
trans.BeginAnimation(TranslateTransform.XProperty, anim2);

Use StoryBoard and add both animations as child:
Storyboard storyBoard = new Storyboard
{ Duration = new Duration(TimeSpan.FromMilliseconds(325)) };
DoubleAnimation anim2 = new DoubleAnimation(1, 500, TimeSpan.FromMilliseconds(325));
anim2.EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut };
anim2.Completed += new EventHandler(myanim_Completed);
Storyboard.SetTarget(anim2, trans);
Storyboard.SetTargetProperty(anim2, new PropertyPath(TranslateTransform.XProperty));
DoubleAnimation anim1 = new DoubleAnimation(1, 500, TimeSpan.FromMilliseconds(325));
anim1.EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut };
anim1.Completed += new EventHandler(myanim_Completed);
Storyboard.SetTarget(anim1, trans);
Storyboard.SetTargetProperty(anim1, new PropertyPath(TranslateTransform.YProperty));
storyBoard.Children.Add(anim2);
storyBoard.Children.Add(anim1);
storyBoard.Begin();

Figured out an answer:
TranslateTransform trans = new TranslateTransform();
Pointer.RenderTransform = trans;
DoubleAnimation animX = new DoubleAnimation(0, 750, TimeSpan.FromMilliseconds(325));
DoubleAnimation animY = new DoubleAnimation(0, 100, TimeSpan.FromMilliseconds(325));
animX.EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut };
animY.EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut };
animX.Completed += new EventHandler(myanim_Completed);
trans.BeginAnimation(TranslateTransform.XProperty, animX);
trans.BeginAnimation(TranslateTransform.YProperty, animY);

Related

Live Tile like Animation

I'm trying to recreate the slide-up part animation of the notification-queue on Windows 10 live tiles with an image I have ontop of another image. Below I have a "slide-up" storyboard working...but it's not the same.
Is the live tile ani actually growing in height as it slides up over the first?
I can't "see/figure" what it's doing.
public static async Task SlideUp(FrameworkElement element, double duration, int to = 0)
{
var tempTransform = new TranslateTransform();
element.RenderTransform = tempTransform;
var animation = new DoubleAnimation
{
From = element.ActualHeight * 2,
To = to,
Duration = TimeSpan.FromSeconds(duration),
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
};
Storyboard.SetTargetProperty(animation, "Y");
Storyboard.SetTarget(animation, tempTransform);
var sb = new Storyboard();
sb.Duration = animation.Duration;
sb.Children.Add(animation);
await sb.BeginAsync();
}
The flip part of the animations would be nice too.
You could take a look at the DoubleAnimationUsingKeyFrames class:
https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.animation.doubleanimationusingkeyframes.aspx
Update: You can also animate the Height of the image
public static async Task SlideUp(FrameworkElement element, double duration, int to = 0)
{
var trTransform = new TranslateTransform();
element.RenderTransform = trTransform;
double from = element.ActualHeight;
duration *= 1.5;
var animation = new DoubleAnimationUsingKeyFrames();
animation.KeyFrames.Add(new DiscreteDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0,0,0,0)),
Value = from / 2
});
var ks = new KeySpline { ControlPoint1 = new Point(0.0, 0.0), ControlPoint2 = new Point(0.9, 0.1) };
animation.KeyFrames.Add(new SplineDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(duration*1000/2)),
KeySpline = ks,
Value = (from - to) / 3 + to
});
var ks2 = new KeySpline { ControlPoint1 = new Point(0.1, 0.9), ControlPoint2 = new Point(0.2, 1.0) };
animation.KeyFrames.Add(new SplineDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(duration)),
KeySpline = ks2,
Value = to
});
Storyboard.SetTargetProperty(animation, "Y");
Storyboard.SetTarget(animation, trTransform);
var sb = new Storyboard();
sb.Duration = animation.Duration;
sb.Children.Add(animation);
DoubleAnimationUsingKeyFrames resizeHeightAnimation = new DoubleAnimationUsingKeyFrames()
{
EnableDependentAnimation = true
};
resizeHeightAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0)),
Value = 0
});
var heightSpline1 = new KeySpline { ControlPoint1 = new Point(0.0, 0.0), ControlPoint2 = new Point(0.9, 0.1) };
resizeHeightAnimation.KeyFrames.Add(new SplineDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(duration * 1000 / 2)),
KeySpline = heightSpline1,
Value = from / 3
});
var heightSpline2 = new KeySpline { ControlPoint1 = new Point(0.1, 0.9), ControlPoint2 = new Point(0.2, 1.0) };
resizeHeightAnimation.KeyFrames.Add(new SplineDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(duration)),
KeySpline = heightSpline2,
Value = from
});
Storyboard.SetTarget(resizeHeightAnimation, element);
Storyboard.SetTargetProperty(resizeHeightAnimation, "RenderTransform.Height");
sb.Children.Add(resizeHeightAnimation);
sb.Begin();
}
If that looks to laggy for you, you can also try setting the VerticalAlignment of the element to Bottom and remove the position animation part of the method.

Making a user control pulse

What I'm trying to do is make my control "pulse" (as in enlarge a bit, then shrink a bit, then back to its normal size). The following code does exactly what I want, but it just seems like there should be a simpler way. It has to be done in code behind because this is an abstract class that most of our controls derive from. I don't have much experience with animation controls and story boards.
So specifically my question is, is there a simpler way to get the desired results than the following method (while still being done in the code-behind)?
public void Pulse()
{
var storyboard = new Storyboard
{
FillBehavior = FillBehavior.Stop,
RepeatBehavior = new RepeatBehavior(2)
};
double timeIncrement = .15;
double changePercent = 20;
var firstTime = TimeSpan.FromSeconds(timeIncrement);
var secondTime = TimeSpan.FromSeconds(timeIncrement * 3);
var thirdTime = TimeSpan.FromSeconds(timeIncrement * 4);
var scale = new ScaleTransform(1.0, 1.0);
RenderTransformOrigin = new Point(.5, .5);
RenderTransform = scale;
//enlarge
{
DoubleAnimation growX = new DoubleAnimation
{
Duration = firstTime,
To = 1 + changePercent
};
storyboard.Children.Add(growX);
Storyboard.SetTargetProperty(growX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation growY = new DoubleAnimation
{
Duration = firstTime,
To = 1 + changePercent
};
storyboard.Children.Add(growY);
Storyboard.SetTargetProperty(growY, new PropertyPath("RenderTransform.ScaleY"));
}
//shrink
{
DoubleAnimation shrinkX = new DoubleAnimation
{
Duration = secondTime,
To = 1 - changePercent
};
storyboard.Children.Add(shrinkX);
Storyboard.SetTargetProperty(shrinkX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation shrinkY = new DoubleAnimation
{
Duration = secondTime,
To = 1 - changePercent
};
storyboard.Children.Add(shrinkY);
Storyboard.SetTargetProperty(shrinkY, new PropertyPath("RenderTransform.ScaleY"));
}
//back to normal
{
DoubleAnimation normX = new DoubleAnimation
{
Duration = thirdTime,
To = 1
};
storyboard.Children.Add(normX);
Storyboard.SetTargetProperty(normX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation normY = new DoubleAnimation
{
Duration = thirdTime,
To = 1
};
storyboard.Children.Add(normY);
Storyboard.SetTargetProperty(normY, new PropertyPath("RenderTransform.ScaleY"));
}
BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace, false);
}
You could perhaps simplify things a little by moving your grow/shrink logic into its own method. This reduces duplication and provides a potentially more reusable code kibble.
public void Pulse()
{
var storyboard = new Storyboard
{
FillBehavior = FillBehavior.Stop,
RepeatBehavior = new RepeatBehavior(2)
};
double timeIncrement = .15;
double growPercent = 20;
double shrinkPercent = -20;
var firstTime = TimeSpan.FromSeconds(timeIncrement);
var secondTime = TimeSpan.FromSeconds(timeIncrement * 3);
var thirdTime = TimeSpan.FromSeconds(timeIncrement * 4);
var scale = new ScaleTransform(1.0, 1.0);
RenderTransformOrigin = new Point(.5, .5);
RenderTransform = scale;
storyboard = AddSizeChange(firstTime, growPercent, storyboard);
storyboard = AddSizeChange(secondTime, shrinkPercent, storyboard);
storyboard = AddSizeChange(thirdTime, growPercent, storyboard);
BeginStoryboard(storyboard, HandoffBehavior.SnapshotAndReplace, false);
}
public Storyboard AddSizeChange(TimeSpan animTime, double changePercent, Storyboard storyboard)
{
DoubleAnimation growX = new DoubleAnimation
{
Duration = animTime,
To = 1 + changePercent
};
storyboard.Children.Add(growX);
Storyboard.SetTargetProperty(growX, new PropertyPath("RenderTransform.ScaleX"));
DoubleAnimation growY = new DoubleAnimation
{
Duration = animTime,
To = 1 + changePercent
};
storyboard.Children.Add(growY);
Storyboard.SetTargetProperty(growY, new PropertyPath("RenderTransform.ScaleY"));
return storyboard;
}
That's a fine way of doing it, WPF does not provide methods or events to automatically pulse. Yours is simple and as you've created it, you know how to modify it as you wish.

Translate Transform and rotation in WPF

the translate works fine, but there is no rotation, can you please help me?
TranslateTransform trans = new TranslateTransform();
Pointer.RenderTransform = trans;
DoubleAnimation animX = new DoubleAnimation(fromX, toX, TimeSpan.FromMilliseconds(325));
DoubleAnimation animY = new DoubleAnimation(fromY, toY, TimeSpan.FromMilliseconds(325));
DoubleAnimation rotateBy = new DoubleAnimation(0, 90, TimeSpan.FromMilliseconds(325));
animX.EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut };
animY.EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut };
animX.Completed += new EventHandler(myanim_Completed);
trans.BeginAnimation(TranslateTransform.XProperty, animX);
trans.BeginAnimation(TranslateTransform.YProperty, animY);
trans.BeginAnimation(RotateTransform.AngleProperty, rotateBy);
TranslateTransform doesn't have an Angle property. You should use a TransformGroup:
var group = new TransformGroup();
var trans = new TranslateTransform();
group.Children.Add(trans);
var rotate = new RotateTransform();
group.Children.Add(rotate);
Pointer.RenderTransform = group;
// the rest of the code is fine; only the last line needs fixing:
rotate.BeginAnimation(RotateTransform.AngleProperty, rotateBy);
You should also look into using Storyboard to group your animations.

Animating the height and width of an object in C#

I am trying to get these ellipses to grow but I cannot figure out how to start the animation. This is my first attempt at WPF animation and I don't quite understand how it all works.
private void drawEllipseAnimation(double x, double y)
{
StackPanel myPanel = new StackPanel();
myPanel.Margin = new Thickness(10);
Ellipse e = new Ellipse();
e.Fill = Brushes.Yellow;
e.Stroke = Brushes.Black;
e.Height = 0;
e.Width = 0;
e.Opacity = .8;
canvas2.Children.Add(e);
Canvas.SetLeft(e, x);
Canvas.SetTop(e, y);
DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 0;
myDoubleAnimation.To = 10;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
myStoryboard = new Storyboard();
myStoryboard.Children.Add(myDoubleAnimation);
Storyboard.SetTargetName(myDoubleAnimation, e.Name);
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Ellipse.HeightProperty));
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Ellipse.WidthProperty));
}
You don't need a Storyboard here. Just do
e.BeginAnimation(Ellipse.WidthProperty, myDoubleAnimation);
e.BeginAnimation(Ellipse.HeightProperty, myDoubleAnimation);
If you really need to do it with a Storyboard, you will have to add separate animations, one per animated property, to the Storyboard. And you have to call SetTarget instead of SetTargetName when you don't apply a name. Finally you'll need to start the Storyboard by calling Begin:
DoubleAnimation widthAnimation = new DoubleAnimation
{
From = 0,
To = 10,
Duration = TimeSpan.FromSeconds(5)
};
DoubleAnimation heightAnimation = new DoubleAnimation
{
From = 0,
To = 10,
Duration = TimeSpan.FromSeconds(5)
};
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(Ellipse.WidthProperty));
Storyboard.SetTarget(widthAnimation, e);
Storyboard.SetTargetProperty(heightAnimation, new PropertyPath(Ellipse.HeightProperty));
Storyboard.SetTarget(heightAnimation, e);
Storyboard s = new Storyboard();
s.Children.Add(widthAnimation);
s.Children.Add(heightAnimation);
s.Begin();

Microsoft Surface: When is Storyboard#completed called?

I have the following code:
private void Package_ContactDown(object sender, ContactEventArgs e)
{
ScatterViewItem svi = new ScatterViewItem();
svi.Orientation = 0;
removeShadow(svi);
svi.IsActive = true;
PackageView view = new PackageView(sourceFile, this);
view.setScatterViewItem(svi);
svi.Width = 1024;
svi.Height = 768;
svi.Center = new Point(512, 384);
Viewbox box = new Viewbox();
box.Name = "box";
box.Child = view;
this.RegisterName(box.Name, box);
Viewbox boxSmall = new Viewbox();
boxSmall.Name = "boxSmall";
this.RegisterName(boxSmall.Name, boxSmall);
TextBlock txt = new TextBlock();
txt.Foreground = Brushes.White;
txt.Text = "Package of class";
boxSmall.Child = txt;
boxSmall.Opacity = 0;
boxSmall.IsHitTestVisible = false;
Rectangle border = new Rectangle();
border.Name = "border";
this.RegisterName(border.Name, border);
border.Fill = Brushes.Transparent;
border.Stroke = Brushes.White;
border.StrokeThickness = 2;
border.Opacity = 0;
Grid g = new Grid();
g.Background = this.FindResource("WindowBackground") as ImageBrush;
g.Children.Add(box);
g.Children.Add(boxSmall);
g.Children.Add(border);
svi.Content = g;
window.IconDisplay.Items.Add(svi);
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0.0;
animation.To = 1.0;
animation.Duration = new Duration(TimeSpan.FromSeconds(3));
animation.AutoReverse = false;
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
Storyboard.SetTargetName(animation, boxSmall.Name);
Storyboard.SetTargetProperty(animation, new PropertyPath(Viewbox.OpacityProperty));
DoubleAnimation animation2 = new DoubleAnimation();
animation2.From = 1.0;
animation2.To = 0.0;
animation2.Duration = new Duration(TimeSpan.FromSeconds(3));
animation2.AutoReverse = false;
Storyboard storyboard2 = new Storyboard();
storyboard2.Children.Add(animation2);
Storyboard.SetTargetName(animation2, box.Name);
Storyboard.SetTargetProperty(animation2, new PropertyPath(Viewbox.OpacityProperty));
DoubleAnimation animation3 = new DoubleAnimation();
animation3.From = 0.0;
animation3.To = 1.0;
animation3.Duration = new Duration(TimeSpan.FromSeconds(3));
animation3.AutoReverse = false;
Storyboard storyboard3 = new Storyboard();
storyboard3.Children.Add(animation3);
Storyboard.SetTargetName(animation3, border.Name);
Storyboard.SetTargetProperty(animation3, new PropertyPath(Rectangle.OpacityProperty));
svi.SizeChanged += delegate(object s, SizeChangedEventArgs args)
{
if (args.NewSize.Width < 150 && args.NewSize.Height < 150 && !isSmall)
{
svi.CanScale = false;
storyboard.Begin(this);
storyboard2.Begin(this);
storyboard3.Begin(this);
storyboard3.Completed += delegate(object sender2, EventArgs args2)
{
Console.WriteLine("Storyboard completed");
svi.CanScale = true;
};
isSmall = true;
}
if (args.NewSize.Width > 150 && args.NewSize.Height > 150 && isSmall)
{
isSmall = false;
}
};
}
And I noticed that the Storyboard#completed Event is never triggered. Why? And an additional question... Is there any way to reverse all these 3 animations? If I want to display the animations the other way round?
The completed event will not fire the first time around because it is not set before you call the begin method. Set the completed handler then call the begin and you should see the handler get called.
Is there a reason that you have three storyboards? Storyboards can contain multiple animations and you could just put all the animations into one storyboard. This would simplify reversing the storyboard.
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0.0;
animation.To = 1.0;
animation.Duration = new Duration(TimeSpan.FromSeconds(3));
animation.AutoReverse = false;
DoubleAnimation animation2 = new DoubleAnimation();
animation2.From = 1.0;
animation2.To = 0.0;
animation2.Duration = new Duration(TimeSpan.FromSeconds(3));
animation2.AutoReverse = false;
DoubleAnimation animation3 = new DoubleAnimation();
animation3.From = 0.0;
animation3.To = 1.0;
animation3.Duration = new Duration(TimeSpan.FromSeconds(3));
animation3.AutoReverse = false;
Storyboard storyboard = new Storyboard();
storyboard.AutoReverse = true;
storyboard.Children.Add(animation);
Storyboard.SetTargetName(animation, boxSmall.Name);
Storyboard.SetTargetProperty(animation, new PropertyPath(Viewbox.OpacityProperty));
storyboard.Children.Add(animation2);
Storyboard.SetTargetName(animation2, box.Name);
Storyboard.SetTargetProperty(animation2, new PropertyPath(Viewbox.OpacityProperty));
storyboard.Children.Add(animation3);
Storyboard.SetTargetName(animation3, border.Name);
Storyboard.SetTargetProperty(animation3, new PropertyPath(Rectangle.OpacityProperty));
svi.SizeChanged += delegate(object s, SizeChangedEventArgs args)
{
if (args.NewSize.Width < 150 && args.NewSize.Height < 150 && !isSmall)
{
svi.CanScale = false;
storyboard.Completed += (o, s) =>
{
Console.WriteLine("Storyboard completed");
svi.CanScale = true;
};
storyboard.Begin(this);
isSmall = true;
}
if (args.NewSize.Width > 150 && args.NewSize.Height > 150 && isSmall)
{
isSmall = false;
}
};

Categories

Resources