C# TranslateTransform移动元素超出预期

C# TranslateTransform移动元素超出预期,c#,.net,wpf,animation,C#,.net,Wpf,Animation,我对WPF非常陌生(对动画也完全陌生),所以我可以想象我在这里遗漏了一些东西。我正在创建一个新的布局面板,它以特定的方式布置控件;这里的细节并不(或不应该)特别重要。我想做的是,当我调用Arrange时,为我正在管理的元素的移动设置动画 通常,我所做的是跟踪我用来排列每个子元素的最后一个Rect。调用ArrangeOverride时 如果启用了动画,并且元素有以前的边界Rect,我将以新的宽度和高度将其排列到该边界矩形的X和Y,然后使用两个DoubleAnimations(一个用于X,一个用于

我对WPF非常陌生(对动画也完全陌生),所以我可以想象我在这里遗漏了一些东西。我正在创建一个新的布局
面板
,它以特定的方式布置控件;这里的细节并不(或不应该)特别重要。我想做的是,当我调用
Arrange
时,为我正在管理的元素的移动设置动画

通常,我所做的是跟踪我用来排列每个子元素的最后一个
Rect
。调用
ArrangeOverride

  • 如果启用了动画,并且元素有以前的边界
    Rect
    ,我将
    以新的宽度和高度将其排列到该边界矩形的X和Y,然后使用两个
    DoubleAnimation
    s(一个用于X,一个用于Y)将其动画化到新边界的X和Y
  • 如果动画被禁用,或者元素没有现有的边界
    Rect
    ,我只是
    将其排列到新边界
当我禁用动画时,所有内容都正确渲染(这是一件好事)。启用动画时,元素在错误的位置渲染。如果我调整容器的大小,它们通常会将自己的动画设置回正确的位置

编辑以进行澄清

通常,错误似乎与控件边界的坐标直接相关。换句话说,如果控件开始时更靠右,则
TranslateTransform
会比不靠右的控件偏移更多。上行/下行也是如此。同样,调整大小似乎可以纠正问题(事实上,控件将自身动画化到正确的位置,这是令人沮丧的整洁),但前提是整个控件集以新的大小可见

这是该类的缩写版本:

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 DoubleAnimation(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);
            }
        }
    }
}
公共类MyPanel:Panel
{
private Dictionary lastBounds=新字典();
受保护的覆盖尺寸测量覆盖(尺寸可用尺寸)
{
//在这里做我所有的测量,并从中删除任何内容
//已经不在面板上了。这个很好用
}
受保护的替代尺寸排列替代(尺寸最终化)
{
foreach(UIElement子元素中的子元素)
{
Rect newBounds=//获取以前计算的新边界;
TransformGroup group=child.RenderTransform作为TransformGroup;
如果(组==null)
{
组=新组();
group.Children.Add(新的TranslateTransform());
child.RenderTransform=组;
}
矩形边界;
如果(!this.lastBounds.TryGetValue(子级,超出lastBounds))
lastBounds=Rect.Empty;
如果(!lastbunds.IsEmpty&&EnableAnimation)
{
Rect tempBounds=new Rect(lastBounds.X,lastBounds.Y,newBounds.Width,newBounds.Height);
安排(临时边界);
int animationDuration=300;
DoubleAnimation xAnim=新的DoubleAnimation(newBounds.X-lastBounds.X,TimeSpan.fromMillistics(animationDuration));
DoubleAnimation yAnim=新的DoubleAnimation(newBounds.Y-lastBounds.Y,TimeSpan.fromMillistics(animationDuration));
xAnim.AccelerationRatio=yAnim.AccelerationRatio=0.2;
xAnim.减速比=yAnim.减速比=0.7;
TranslateTransform translate=group.Children[0]作为TranslateTransform;
translate.BeginAnimation(TranslateTransform.XProperty,xAnim);
translate.BeginAnimation(TranslateTransform.YProperty,yAnim);
}
其他的
{
儿童。安排(新生儿);
}
}
}
}

您似乎正在将子对象安排到其旧位置,然后应用渲染变换以使其出现在新位置。这可能是一个问题,因为您为布局引擎指定的位置现在位于父布局容器之外时,布局引擎可能有问题。您可能会更幸运地始终安排到新边界(在父元素内),然后应用“渲染平移”动画将其移回实际位置:

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,0移动到10,10,它将被安排到10,10,然后开始渲染变换,从-10,-10返回到0,0。当应用到它的新位置时,这意味着它似乎在从0,0移动到10,10。