我在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
後面
在試驗過程中,我發現了一些看起來很奇怪的東西。如果我將Panel.ArrangeOverride
方法中的項目位置更改爲以下內容,則會出現更多意外結果。
child.Arrange(new Rect(endPosition.X, endPosition.Y, childWidth, child.DesiredSize.Height));
不知何故,這改變了實際(動畫)結束位置,即。項目最終被定位。它介紹了某些項目的雙倍間距。如何在開始動畫之前將項目安排在其最終位置,以更改其最終結束位置?我錯過了明顯的東西嗎?另外,如果取消註釋AnimatedStackPanel.AnimatePosition
方法中的註釋行,並註釋掉上面的兩行(即剪切動畫並將項目直接移動到動畫將它們移動到的相同結束位置),則你會看到問題再次消失......無論收集中有多少物品,這都適用。這導致我認爲問題與動畫有關。
我發現的最後一件事是,存在或不使用DataTemplate
s的項目數據類型的問題......我很確定它是動畫相關的。如果任何人都能看到我做錯了什麼,或者找到了解決辦法,我會非常感激,因爲這讓我感到莫名其妙。任何人都可以用示例代碼重現這個問題嗎?提前謝謝了。
額外+1過,據我很擔心!做得好!你究竟如何解決這個問題? – Sheridan 2012-01-30 21:46:12
此外,我想知道最大數量的物品,因爲之前,這個數字對我來說大約是110。 – Sheridan 2012-01-30 21:52:28
報告:64位Windows 8.1雙核上的最大數量爲144 – Vanlalhriata 2015-05-26 10:14:06