Является ли 141 максимальным количеством элементов панели WPF, которые можно анимировать одновременно?

Я разработал несколько анимированных Panel в C #, которые все наследуются от одного базового класса, который выполняет фактическую анимацию для Panel.Children. До недавнего времени все они работали отлично ... но недавно я использовал один с коллекцией, в которой было большое количество элементов, и у меня начались странные визуальные ошибки.

Когда приложение сначала загружает элементы, первое x количество элементов отображается правильно, а затем все остальные отображаются в первой позиции (друг над другом). Если я изменю размер окна или выбираю элемент, они все перестраиваются, чтобы отображаться правильно. (Используя приведенный ниже пример кода, вам придется изменить размер окна, чтобы они сами исправились.)

После большого царапин и отладки голов я обнаружил, что правильные значения все еще попадают в код анимации для каждого элемента, но последние элементы x просто не анимируются. Каждый элемент определенно проходит через код анимации, но последние x элементов остаются в позиции, заданной в анимированном методе Panel.ArrangeOverride.

Чтобы попытаться найти проблему в моем коде, я создал новый UserControl и анимировал Panel класс с минимальным кодом, необходимым для воссоздания проблемы. Сделав это, я был удивлен, что проблема все еще воспроизводима. В моем примере кода было 141 элемент, проблем с отображением не было, но теперь проблема возникает.

Прошу прощения за длинные строки кода, но так много всего нужно отобразить.

AnimatedStackPanel.cs class

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 код

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 для типа данных элемента ... Я уверен, что это связано с анимацией. Если кто-то может увидеть, что я делаю неправильно, или найти решение для этого, я был бы очень признателен, потому что этот сбил меня с толку. Может ли кто-нибудь воспроизвести эту проблему с примером кода? Большое спасибо заранее.

4 голоса | спросил Sheridan 29 Jam1000000amSun, 29 Jan 2012 03:43:24 +040012 2012, 03:43:24

1 ответ


0

Шеридан, я немного поэкспериментировал с твоим примером кода и обнаружил, что, по-видимому, имеет значение , когда ты применяешь 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 еще не были присоединены к элементу управления, пока они уже анимированы.

Кстати, максимальное число было для меня 144 на двух разных системах (двухъядерный и четырехъядерный) под управлением 32-битной Windows 7.

ответил Clemens 30 Jpm1000000pmMon, 30 Jan 2012 14:26:50 +040012 2012, 14:26:50

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132