2012-01-28 13 views
4

我在C#中設計了幾個動畫Panel,它們都從一個基類中繼承,它們在Panel.Children上執行實際的動畫。直到最近,他們都完美地工作......但最近,我用了一個集合中有大量項目的集合,我開始出現一些奇怪的視覺錯誤。141是可以同時動畫的WPF面板項目的最大數量?

當應用程序第一次加載項目時,前x個項目正確顯示,然後剩餘部分全部顯示在第一個位置(彼此頂部)。如果我調整窗口大小或選擇一個項目,它們都會重新排列以正確顯示。 (使用下面的示例代碼,您將不得不調整窗口大小,以查看它們是否正確)

經過很多頭部劃傷和調試,我發現正確的值仍然通過動畫代碼對於每個項目,但最後的x項目根本不是動畫。每個項目都必須通過動畫代碼,但最後的x個項目保留在動畫Panel.ArrangeOverride方法中設置的位置。

爲了嘗試找到我的代碼中的問題,我創建了一個新的UserControl和動畫Panel類,並重新創建問題所需的最小代碼。這樣做後,我很驚訝這個問題仍然可以重現。在我的示例代碼中有141個項目,沒有顯示問題,但隨着問題出現。

請原諒冗長的代碼行,但有太多要顯示。

AnimatedStackPanel.cs類

public class AnimatedStackPanel : Panel 
{ 
    protected override Size MeasureOverride(Size availableSize) 
    { 
     double x = 0, y = 0; 
     foreach (UIElement child in Children) 
     { 
      child.Measure(availableSize); 
      x = Math.Max(x, availableSize.Width == double.PositiveInfinity ? child.DesiredSize.Width : availableSize.Width); 
      y += child.DesiredSize.Height; 
     } 
     return new Size(availableSize.Width == double.PositiveInfinity ? x : availableSize.Width, availableSize.Height == double.PositiveInfinity ? y : availableSize.Height); 
    } 

    protected override Size ArrangeOverride(Size finalSize) 
    { 
     if (this.Children == null || this.Children.Count == 0) return finalSize; 
     Size previousChildSize = new Size(); 
     Point endPosition = new Point(0, 0); 
     foreach (UIElement child in Children) 
     { 
      endPosition.Y += previousChildSize.Height; 
      double childWidth = finalSize.Width; 
      child.Arrange(new Rect(0, 0, childWidth, child.DesiredSize.Height)); 
      Point startPosition = new Point(endPosition.X, endPosition.Y + finalSize.Height); 
      AnimatePosition(child, startPosition, endPosition, new TimeSpan(0, 0, 1)); 
      previousChildSize = child.DesiredSize; 
     } 
     return finalSize; 
    } 

    private void AnimatePosition(UIElement child, Point startPosition, Point endPosition, TimeSpan animationDuration) 
    { 
     DoubleAnimation xAnimation = new DoubleAnimation(startPosition.X, endPosition.X, animationDuration); 
     DoubleAnimation yAnimation = new DoubleAnimation(startPosition.Y, endPosition.Y, animationDuration); 
     TransformGroup transformGroup = child.RenderTransform as TransformGroup; 
     if (transformGroup == null) 
     { 
      TranslateTransform translatationTransform = new TranslateTransform(); 
      transformGroup = new TransformGroup(); 
      transformGroup.Children.Add(translatationTransform); 
      child.RenderTransform = transformGroup; 
      child.RenderTransformOrigin = new Point(0, 0); 
     } 
     TranslateTransform translateTransform = (TranslateTransform)transformGroup.Children[0]; 
     translateTransform.BeginAnimation(TranslateTransform.XProperty, xAnimation, HandoffBehavior.Compose); 
     translateTransform.BeginAnimation(TranslateTransform.YProperty, yAnimation, HandoffBehavior.Compose); 
     //child.Arrange(new Rect(endPosition.X, endPosition.Y, child.DesiredSize.Width, child.DesiredSize.Height)); 
    } 
} 

AnimatedListBox.xaml UserControl

<UserControl x:Class="WpfTest.Views.AnimatedListBox" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:Controls="clr-namespace:WpfTest.Views.Controls"> 
    <UserControl.Resources> 
     <ItemsPanelTemplate x:Key="AnimatedStackPanel"> 
      <Controls:AnimatedStackPanel /> 
     </ItemsPanelTemplate> 
    </UserControl.Resources> 
    <Grid> 
     <ListBox ItemsSource="{Binding Data}" ItemsPanel="{StaticResource AnimatedStackPanel}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" /> 
    </Grid> 
</UserControl> 

AnimatedListBox.xaml.cs UserControl後面

代碼10

在試驗過程中,我發現了一些看起來很奇怪的東西。如果我將Panel.ArrangeOverride方法中的項目位置更改爲以下內容,則會出現更多意外結果。

child.Arrange(new Rect(endPosition.X, endPosition.Y, childWidth, child.DesiredSize.Height)); 

不知何故,這改變了實際(動畫)結束位置,即。項目最終被定位。它介紹了某些項目的雙倍間距。如何在開始動畫之前將項目安排在其最終位置,以更改其最終結束位置?我錯過了明顯的東西嗎?另外,如果取消註釋AnimatedStackPanel.AnimatePosition方法中的註釋行,並註釋掉上面的兩行(即剪切動畫並將項目直接移動到動畫將它們移動到的相同結束位置),則你會看到問題再次消失......無論收集中有多少物品,這都適用。這導致我認爲問題與動畫有關。

我發現的最後一件事是,存在或不使用DataTemplate s的項目數據類型的問題......我很確定它是動畫相關的。如果任何人都能看到我做錯了什麼,或者找到了解決辦法,我會非常感激,因爲這讓我感到莫名其妙。任何人都可以用示例代碼重現這個問題嗎?提前謝謝了。

回答

4

謝里登,我玩了一下你的代碼示例,我發現它顯然很重要當你應用RenderTransform時。相反ArrangeOverride的第一次運行過程中AnimatePosition,即分配給它的,我感動的代碼MeasureOverride

protected override Size MeasureOverride(Size availableSize) 
{ 
    double x = 0, y = 0; 
    foreach (UIElement child in Children) 
    { 
     TransformGroup transformGroup = child.RenderTransform as TransformGroup; 
     if (transformGroup == null) 
     { 
      TranslateTransform translatationTransform = new TranslateTransform(); 
      transformGroup = new TransformGroup(); 
      transformGroup.Children.Add(translatationTransform); 
      child.RenderTransform = transformGroup; 
      child.RenderTransformOrigin = new Point(0, 0); 
     } 

     child.Measure(availableSize); 
     x = Math.Max(x, availableSize.Width == double.PositiveInfinity ? child.DesiredSize.Width : availableSize.Width); 
     y += child.DesiredSize.Height; 
    } 
    return new Size(
     availableSize.Width == double.PositiveInfinity ? x : availableSize.Width, 
     availableSize.Height == double.PositiveInfinity ? y : availableSize.Height); 
} 

現在動畫像預期的那樣甚至ArrangeOverride的第一次調用。看起來像最後幾個RenderTransforms還沒有附加到控件,而已經是動畫。

順便說一句,最大數量是144,我在兩個不同的系統(雙核和四核處理器)上運行32位Windows 7

+0

額外+1過,據我很擔心!做得好!你究竟如何解決這個問題? – Sheridan 2012-01-30 21:46:12

+0

此外,我想知道最大數量的物品,因爲之前,這個數字對我來說大約是110。 – Sheridan 2012-01-30 21:52:28

+0

報告:64位Windows 8.1雙核上的最大數量爲144 – Vanlalhriata 2015-05-26 10:14:06

相關問題