I'm running into a really weird issue with Silverlight 3. I've defined an extension method to create a storyboard around a given DoubleAnimation and play that animation. I know the default duration for storyboards in Silverlight is 1s, but I would like to change that for my animations. However, when I set a different duration, instead of altering the animation to move from start to finish in the allotted time, the animation will just play for the duration I specified and then stop. For example, if I'm moving something from 0,0 to 0,10 and set the duration to .3s, the item will only move to 0.3. I can't imagine this is by design. Any ideas what is going on here?
Here's the code I'm using. ConfigureStoryboard is where the storyboard is created around the animation. I've removed some code regarding the easing function to make it more readable.
public static void BeginAnimation(
this Transform transform,
DependencyProperty property,
DoubleAnimation animation,
EasingFunction function
)
{
var storyboard = new Storyboard();
ConfigureStoryboard(animation, storyboard, function);
Storyboard.SetTarget(storyboard, transform);
Storyboard.SetTargetProperty(
storyboard,
new PropertyPath(property));
storyboard.Begin();
}
private static void ConfigureStoryboard(DoubleAnimation animation, Storyboard storyboard, EasingFunction function)
{
DoubleAnimation myAnimation = new DoubleAnimation();
storyboard.Duration = animation.Duration;
myAnimation.From = animation.From;
myAnimation.To = animation.To;
storyboard.Children.Add(myAnimation);
}
private static void ConfigureStoryboard(DoubleAnimation animation, Storyboard storyboard, EasingFunction function)
{
DoubleAnimation myAnimation = new DoubleAnimation();
myAnimation.Duration = animation.Duration;
myAnimation.From = animation.From;
myAnimation.To = animation.To;
storyboard.Children.Add(myAnimation);
}
Animation needs to have a duration else it get the default, and since the storyboard will only run for 0.3s, only a third of your animation will run before stopping.
Related
I am trying to do a basic animation using the DoubleAnimation class in WPF. On a button click the rectangle spins. The cs code is
DoubleAnimation da = new DoubleAnimation();
da.From = 0; // start from 0 to 360, full circle
da.To = 360;
da.Duration = new Duration(TimeSpan.FromSeconds(0.5));
da.RepeatBehavior = RepeatBehavior.Forever;
RotateTransform rt = new RotateTransform();
rectangle1.RenderTransform = rt;
rt.BeginAnimation(RotateTransform.AngleProperty, da);
What i am trying to do is to update the da.Duration = new Duration(TimeSpan.FromSeconds(0.5)) value with the slider value.
Tried with slider value binding, but not able to get this correctly.
Changing the Duration is not enough. How fast the animation is controlled by the inner AnimationClock. This clock is initialized just once after you call BeginAnimation(). So you have to update the inner AnimationClock by using ApplyAnimationClock() method.
Also note that you should also set the From property to the currently animated value, so that when changing the Slider's Value, the Angle will be animated smoothly (without restarting from 0):
//The ValueChanged handler for your Slider
private void slider_ValueChanged(object sender,
RoutedPropertyChangedEventArgs e){
da.Duration = new Duration(TimeSpan.FromMilliseconds(yourSlider.Value));
da.From = rt.Angle;
rt.ApplyAnimationClock(RotateTransform.AngleProperty, da.CreateClock());
}
Note that I suppose the slider's Value corresponds to the number of milliseconds, so the Maximum value of the Slider should be large enough (about several thousands) if you don't want your Rectangle to be rotated super fast. Also all the variables you declared should be able to access inside the ValueChanged handler.
One more important note is you should use By property here instead of To, like this:
da.By = 360;
That way you can just update the From without caring about the To (it is always 360 degrees rotated).
I want to apply a continuous FadeIn/FadeOut animation to a specific Canvas in my WPF.
I'm able to do the FadeOut part but then the FadeIn part executes immediately after that and ruins the animation.
I also want all of this to be in a smooth loop without interfering with my normal operations.
Look at it as an animated background.
What's the best method to do this? Should I use While? or should I use Timer? ...
var duration = new Duration(TimeSpan.FromMilliseconds(1000));
var fadeOut = new DoubleAnimation(0.0, duration);
var fadeIn = new DoubleAnimation(1.0, duration);
MyCanvas.BeginAnimation(OpacityProperty, fadeOut);
MyCanvas.BeginAnimation(OpacityProperty, fadeIn);
You can set the AutoReverse and RepeatBehavior properties of a single DoubleAnimation to get a continous effect:
var fadeInOutAnimation = new DoubleAnimation
{
From = 0,
To = 1,
Duration = TimeSpan.FromSeconds(1),
AutoReverse = true,
RepeatBehavior = RepeatBehavior.Forever,
};
MyCanvas.BeginAnimation(OpacityProperty, fadeInOutAnimation);
In your approach you would have to set the BeginTime property of the second animation to the Duration of the first one.
I have my custom 3D model class (Model) which contains Visual3D element and a Storyboard (sb) to hold animations related to that model. I'm trying to rotate the Visual3D element using the Storyboard but unfortunately it's not working.
Here is the code snippet
public void AnimationRotate(Model model, double duration, double startTime, RepeatBehavior behaviour)
{
//Rotate transform 3D
RotateTransform3D rotateTransform = new RotateTransform3D();
//assign transform to the model
model.Visual3D.Transform = Transform3DHelper.CombineTransform(model.Visual3D.Transform, rotateTransform);
//define the rotation axis
AxisAngleRotation3D rotateAxis = new AxisAngleRotation3D(new Vector3D(0, 0, 1), 180);
//create 3D rotation animation
Rotation3DAnimation rotateAnimation = new Rotation3DAnimation(rotateAxis, TimeSpan.FromSeconds(0.5));
//rotation behaviour
rotateAnimation.RepeatBehavior = behaviour;
//start animation from time
rotateAnimation.BeginTime = TimeSpan.FromSeconds(startTime);
//begin animation - THIS WORKS FINE
// rotateTransform.BeginAnimation(RotateTransform3D.RotationProperty, rotateAnimation);
Storyboard.SetTargetProperty(rotateAnimation, new PropertyPath(RotateTransform3D.RotationProperty));
Storyboard.SetTarget(rotateAnimation, rotateTransform);
//add animation to the storyboard of the model
model.sb.Children.Add(rotateAnimation);
//BUT THIS APPROACH IS NOT WOKRING
model.sb.Begin();
}
The problem is described in this answer.
Instead of using Storyboard.SetTarget you need to register a name for the transform and call Storyboard.SetTargetName. Furthermore you must call Storyboard.Begin(FrameworkElement) and pass a FrameworkElement with the appropriate name scope as parameter (this here).
RegisterName("RotateTransform", rotateTransform);
Storyboard.SetTargetName(rotateAnimation, "RotateTransform");
...
model.sb.Begin(this);
Also I guess you need to clear the Storyboard's Children somewhere, or create a new Storyboard whenever the animation is started.
I have a method that enables me to animate objects that have to do with a DoubleAnimation:
public void animDouble(DependencyObject target, DependencyProperty property, double to, TimeSpan duration, double? from = null, TimeSpan? beginTime = null, IEasingFunction e = null)
{
DoubleAnimation animation = new DoubleAnimation();
animation.To = to;
if (beginTime == null)
beginTime = TimeSpan.FromSeconds(0);
if (from != null)
animation.From = from;
animation.BeginTime = beginTime;
animation.Duration = duration;
if (e != null)
animation.EasingFunction = e;
//start animating
Storyboard.SetTarget(animation, target); // what object will be animated?
Storyboard.SetTargetProperty(animation, new PropertyPath(property)); // what property will be animated
Storyboard sb = new Storyboard();
sb.Children.Add(animation);
sb.Begin();
}
so if I have a boarder called br1 for example and I want to animate it's height I will call the method as:
animDouble(br1, FrameworkElement.HeightProperty, 150, TimeSpan.FromSeconds(5));
if I want to animate it's width I will do:
animDouble(br1, FrameworkElement.WidthProperty, 150, TimeSpan.FromSeconds(5));
I could also animate it's visibility with the same method.
for some reason I am not able to animate its x property in order to translate it along the x axis or y-axis. When I call the method as:
a.animDouble(br1, TranslateTransform.XProperty, 150, TimeSpan.FromSeconds(5));
the boarder does not animates. I don't get any errors aether.
Somehow i would have expected an error, well, anyway, the Border owns no such property, if you want to move your control you need to set the RenderTransform or LayoutTransform of the border to a TranslateTransform, then you can pass the transform itself into the method as target.
(The whole storyboard is awfully redundant as you only have one animation, you can just call BeginAnimation on the target itself)
It had to do with registering the name. I found a link in here
I don't know what the method registerName does but I guess I needed it. from the page I managed to get the basic animations. I where not able to animate two things at once SOMETIMES. if you are interested in seeing the method take a look tat this question. I think it is a prety nice class that will enable to create animations with code. copy the namespace to visual studio and copy the first example that I posted so that you can see how it works.
I have something this:
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, shrinkAnimation);
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, shrinkAnimation);
MyDialog.Show();
The animations run correctly in parallel (x and y shrink together), but because BeginAnimation is an asynchronous call, the Show() method gets executed while the animation is still running (suppose shrinkAnimation runs for 1 second).
How can I wait for animations to complete before calling Show()?
Thanks!
You can use a Storyboard, which has a completed event, instead of that BeginAnimation method. Here's an example, setting opacity, but it's the same concept:
DoubleAnimation animation = new DoubleAnimation(0.0, new Duration(TimeSpan.FromSeconds(1.0)));
Storyboard board = new Storyboard();
board.Children.Add(animation);
Storyboard.SetTarget(animation, MyButton);
Storyboard.SetTargetProperty(animation, new PropertyPath("(Opacity)"));
board.Completed += delegate
{
MessageBox.Show("DONE!");
};
board.Begin();