开发者

TranslateTransform moving elements more than expected

I'm pretty new to WPF (and completely new to animations), so I would imagine there's just something that I'm missing here. I'm in the process of creating a new layout Panel that lays the controls out in a particular way; the details aren't (or shouldn't be) especially important here. What I'd like to do is animate the movement of the elements that I'm managing when I call Arrange on them.

In general, what I do is keep track of the last Rect that I used to Arrange each child element. When ArrangeOverride is called...

  • If animation is enabled and there is a previous bounding Rect for the element, I Arrange it to the X and Y of that bounding rect with the new Width and Height, then use two DoubleAnimations (one for X and one for Y) to animate it to the X and Y of the new bounds
  • If animation is disabled or there is no existing bounding Rect for the element, I just Arrange it to the new bounds

When I disable animation, everything renders correctly (which is a good thing). When I enable animation, the elements render in the incorrect locations. If I resize the container, they generally animate themselves back into the correct spot.

Edit for clarification

In general, the error appears to be directly related to the coordinates of the bounds of the control. In other words, if the control is farther to the right to begin with, then the TranslateTransform appears to offset it more than a control that is not as far to the right. The same goes for up/down. Again, resizing seems to correct the problem (in fact, the controls animate themselves into the correct spot, which is frustratingly neat), but only if the entire set of controls is visible in the new size.

This is an abbreviated version of the class:

public class MyPanel : Panel
{
    private Dictionary<UIElement, Rect> lastBounds = new Dictionary<UIElement, Rect>();

    protected override Size MeasureOverride(Size availableSize)
    {
        // do all of my measurements here and delete anything from lastBounds that
        // isn't on the panel any more. This works fine
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach(UIElement child in Children)
        {
            Rect newBounds = // get the previously calculated new bounds;

            TransformGroup group= child.RenderTransform as TransformGroup;

            if (group == null)
            {
                group = new TransformGroup();

                group.Children.Add(new TranslateTransform());

                child.RenderTransform = group;
            }

            Rect lastBounds;

            if (!this.lastBounds.TryGetValue(child, out lastBounds)) 
                lastBounds = Rect.Empty;

            if (!lastBounds.IsEmpty && EnableAnimation)
            {
                Rect tempBounds = new Rect(lastBounds.X, lastBounds.Y, newBounds.Width, newBounds.Height);

                child.Arrange(tempBounds);

                int animationDuration = 300;

                DoubleAnimation xAnim = new Double开发者_StackOverflowAnimation(newBounds.X - lastBounds.X, TimeSpan.FromMilliseconds(animationDuration));
                DoubleAnimation yAnim = new DoubleAnimation(newBounds.Y - lastBounds.Y, TimeSpan.FromMilliseconds(animationDuration));

                xAnim.AccelerationRatio = yAnim.AccelerationRatio = 0.2;
                xAnim.DecelerationRatio = yAnim.DecelerationRatio = 0.7;

                TranslateTransform translate = group.Children[0] as TranslateTransform;

                translate.BeginAnimation(TranslateTransform.XProperty, xAnim);
                translate.BeginAnimation(TranslateTransform.YProperty, yAnim);
            }
            else
            {
                child.Arrange(newBounds);
            }
        }
    }
}


You appear to be arranging the children to their old location, then applying a render transform to get them to appear in their new location. This may be an issue because the layout engine might have a problem with you giving it a location that is now outside the parent layout container. You may have better luck always arranging to the new bounds (within the parent element), then applying the render translate animation to move it back to where it really is:

child.Arrange(newBounds);

int animationDuration = 300;

DoubleAnimation xAnim = new DoubleAnimation(lastBounds.X - newBounds.X, 0, TimeSpan.FromMilliseconds(animationDuration));
DoubleAnimation yAnim = new DoubleAnimation(lastBounds.Y - newBounds.Y, 0, TimeSpan.FromMilliseconds(animationDuration));
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜