gpt4 book ai didi

c# - 141 是可以同时设置动画的 WPF 面板项的最大数量吗?

转载 作者:太空狗 更新时间:2023-10-30 01:24:31 26 4
gpt4 key购买 nike

我用 C# 设计了几个动画 Panel,它们都继承自一个基类,该基类在 Panel.Children 上执行实际动画。直到最近,它们都运行良好……但最近,我在使用一个包含大量项目的集合时,我开始遇到一些奇怪的视觉错误。

当应用程序首次加载项目时,前 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 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 代码隐藏

public partial class AnimatedListBox : UserControl
{
public AnimatedListBox()
{
InitializeComponent();
Data = new ObservableCollection<int>();
// change this 150 below to anything less than 142 and the problem disappears!!
for (int count = 1; count <= 150; count++) Data.Add(count);
DataContext = this;
}

public static DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(ObservableCollection<int>), typeof(AnimatedListBox));

public ObservableCollection<int> Data
{
get { return (ObservableCollection<int>)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
}

在实验过程中,我发现了一些看起来很奇怪的东西。如果我将 Panel.ArrangeOverride 方法中项目的位置更改为以下内容,则会出现更多意想不到的结果。

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

不知何故,这改变了实际(动画)的结束位置,即。项目最终被定位的地方。它引入了某种双倍间距的项目。在开始动画之前将项目安排在其结束位置如何改变其最终结束位置?我是否遗漏了一些明显的东西?

此外,如果您取消注释 AnimatedStackPanel.AnimatePosition 方法中的注释行并注释掉上面的两行(即剪切动画并将项目直接移动到与动画会将它们移动到)然后你会看到问题再次消失......无论集合中有多少项目,这都适用。这就是让我认为问题与动画相关的原因。

我发现的最后一件事是无论是否使用 DataTemplate 作为项目数据类型都存在问题...我很确定它与动画相关。如果有人能看到我做错了什么,或者找到解决方案,我将非常感激,因为这个让我感到困惑。谁能用示例代码重现这个问题?非常感谢。

最佳答案

Sheridan,我稍微研究了一下您的代码示例,发现何时您应用 RenderTransform 显然很重要。我没有在 AnimatePosition 中分配它,即在 ArrangeOverride 的第一次运行期间,而是将代码移动到 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 尚未附加到控件,但已经设置了动画。

顺便说一句,我在运行 32 位 Windows 7 的两个不同系统(双核和四核)上的最大数量是 144。

关于c# - 141 是可以同时设置动画的 WPF 面板项的最大数量吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9049610/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com