Reputation: 4255
I created a custom Panel
in wpf where the children need to be animated after the rendering. The animation I want for each child is to translate (move) using a bezier curve.
I followed Microsoft's example and created the AddAnimation
method where I am adding the Path
where I want every item of the panel to be animated.
Unfortunatelly I get the bellow exception:
Cannot animate the 'X' property on a 'System.Windows.Media.TranslateTransform' using a 'System.Windows.Media.Animation.DoubleAnimationUsingPath'
But how am I supposed to animate the X property without a DoubleAnimationUsingPath
?
Here is that method:
private void AddAnimation(FrameworkElement child, Point childLocation)
{
var middlePoint = GetMiddlePoint();
var finalPoint = GetFinalPoint();
var animatedTranslateTransform = new TranslateTransform();
child.RenderTransform = animatedTranslateTransform;
child.RenderTransformOrigin = new Point(0.5, 0.5);
// Create the animation path.
PathGeometry animationPath = new PathGeometry();
PathFigure pFigure = new PathFigure();
pFigure.StartPoint = childLocation;
PolyBezierSegment pBezierSegment = new PolyBezierSegment();
pBezierSegment.Points.Add(middlePoint);
pBezierSegment.Points.Add(finalPoint);
pFigure.Segments.Add(pBezierSegment);
animationPath.Figures.Add(pFigure);
// Freeze the PathGeometry for performance benefits.
animationPath.Freeze();
// Create a DoubleAnimationUsingPath to move the
// rectangle horizontally along the path by animating
// its TranslateTransform.
DoubleAnimationUsingPath translateXAnimation =
new DoubleAnimationUsingPath();
translateXAnimation.PathGeometry = animationPath;
translateXAnimation.Duration = TimeSpan.FromSeconds(5);
// Set the Source property to X. This makes
// the animation generate horizontal offset values from
// the path information.
translateXAnimation.Source = PathAnimationSource.X;
// Set the animation to target the X property
Storyboard.SetTarget(translateXAnimation, child);
Storyboard.SetTargetProperty(translateXAnimation,
new PropertyPath("(FrameworkElement.RenderTransform).(TranslateTransform.X)"));
// Create a DoubleAnimationUsingPath to move the
// rectangle vertically along the path by animating
// its TranslateTransform.
DoubleAnimationUsingPath translateYAnimation =
new DoubleAnimationUsingPath();
translateYAnimation.PathGeometry = animationPath;
translateYAnimation.Duration = TimeSpan.FromSeconds(5);
// Set the Source property to Y. This makes
// the animation generate vertical offset values from
// the path information.
translateYAnimation.Source = PathAnimationSource.Y;
// Set the animation to target the Y property
// of the TranslateTransform named "AnimatedTranslateTransform".
Storyboard.SetTarget(translateYAnimation, child);
Storyboard.SetTargetProperty(translateYAnimation,
new PropertyPath("(FrameworkElement.RenderTransform).(TranslateTransform.Y)"));
// Create a Storyboard to contain and apply the animations.
Storyboard pathAnimationStoryboard = new Storyboard();
pathAnimationStoryboard.RepeatBehavior = RepeatBehavior.Forever;
pathAnimationStoryboard.Children.Add(translateXAnimation);
pathAnimationStoryboard.Children.Add(translateYAnimation);
// Start the animations when the rectangle is loaded.
child.Loaded += (sender, args) =>
{
Debug.WriteLine($"Child {child} loaded.");
pathAnimationStoryboard.Begin(child);
};
}
Upvotes: 0
Views: 472
Reputation: 128147
Take a look at the InnerException
property of the AnimationException.
The cause of the exception is that two points are not enough for a PolyBezierSegment
, because it needs two control points and an end point, hence three points per curve.
Use a PolyQuadraticBezierSegment
instead:
var pBezierSegment = new PolyQuadraticBezierSegment();
pBezierSegment.Points.Add(middlePoint);
pBezierSegment.Points.Add(finalPoint);
Or just a QuadraticBezierSegment
:
var bezierSegment = new QuadraticBezierSegment();
bezierSegment.Point1 = middlePoint;
bezierSegment.Point2 = finalPoint;
The code seems also far too complicated for what it is supposed to do. You may replace the Storyboard with two DoubleAnimationUsingPath
children with a single MatrixAnimationUsingPath
that animates the Matrix
property of a MatrixTransform
:
var animation = new MatrixAnimationUsingPath
{
PathGeometry = animationPath,
Duration = TimeSpan.FromSeconds(5)
};
var transform = new MatrixTransform();
child.RenderTransform = transform;
child.Loaded += (s, e) =>
transform.BeginAnimation(MatrixTransform.MatrixProperty, animation);
Upvotes: 2