2009-10-15 28 views
1

我对WPF很陌生(并且对动画完全不熟悉),所以我会想象这里只是我在这里失踪的东西。我正在创建一个新布局Panel,它以特定方式放置控件;这里的细节不是(或不应该)特别重要。我想要做的就是动画化我管理的元素的移动,当我对它们调用Arrange时。TranslateTransform移动元素超出预期

一般情况下,我所做的是跟踪最后Rect,我曾用Arrange每个子元素。当ArrangeOverride叫...

  • 如果动画已启用,并且有前一个边界Rect的元素,我把它Arrange与新宽度和高度的边界矩形的X和Y,然后使用两个DoubleAnimation s(一个用于X和一个用于Y)将其设置为新边界的X和Y
  • 如果动画被禁用或者没有现有的边界Rect作为元素,我只需Arrange它到新的边界

当我禁用动画时,一切正确渲染(这是一件好事)。当我启用动画时,元素会在不正确的位置呈现。如果我调整容器的大小,他们通常会将自己重新设置回正确的位置。

编辑澄清

一般来说,出现错误时,直接关系到控制的边界的坐标。换句话说,如果控件距离开始的距离更远,那么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); 
      } 
     } 
    } 
} 

回答

3

你似乎是安排孩子们自己的老位置,然后应用渲染转换,让他们出现在他们的新位置。这可能是一个问题,因为布局引擎可能在给它一个位于父布局容器外的位置时出现问题。您可能有更好的运气总是安排到新的边界(父元素内),然后应用渲染转换动画,其移动回它真的是:​​

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

我不知道怎么会工作。 ..不会把它移回*它*的位置? – 2009-10-19 23:33:40

+0

不,它将儿童的实际位置放置到其新的真实位置(按布局条件)。应用的动画是渲染变换以显示它在那里滑动。如果它从0,0移到10,10,它将被安排到10,10,然后开始从-10,-10回到0,0的渲染变换。当应用到新的位置时,这意味着它看起来应该从0,0移动到10,10。 – RandomEngy 2009-10-20 15:39:59

+0

啊,这很有道理。这照顾了这个问题,谢谢! – 2009-10-20 17:05:58