Анимировать высоту группового поля от 0 до авто

У меня есть групповые ящики, действующие как расширители в моем приложении. Когда мне нужно свернуть групповой ящик, я устанавливаю его высоту равной 0. когда мне нужно его расширить, я устанавливаю его высоту, равную auto (double.Nan), можно ли сделать это с помощью раскадровки. Откуда я мог знать высоту авто заранее. Комбинация выражений не позволяет мне анимировать авто.

введите здесь описание изображения


person Tono Nam    schedule 02.07.2011    source источник


Ответы (3)


Вы можете использовать ScaleTransform для этого

<GroupBox Header="GroupBox">
    <GroupBox.RenderTransform>
        <ScaleTransform ScaleY="1"/>
    </GroupBox.RenderTransform>
</GroupBox>

При сворачивании группового поля установите для ScaleTransform.ScaleX значение 0. При расширении установите значение 1.

person Rikker Serg    schedule 14.07.2011
comment
Мне действительно нужно анимировать с определенной высоты на авто. Поэтому перед запуском анимации я создам цикл, который проверит, в каком масштабе я получу приблизительную высоту 50 (попробуйте с 0,01, затем 0,02 и т. д., пока она не будет близка), и привяжу эту переменную к моей раскадровке. Спасибо, Риккер. - person Tono Nam; 16.07.2011
comment
Тьфу, масштабное преобразование сжимает изображение, выглядит не очень хорошо. Я предпочитаю анимировать высоту (и поля, если они есть). - person Chris Bordeman; 29.10.2018

Поскольку я ненавижу трансформацию масштаба, потому что считаю ее уродливой, я искал другое решение.

Что ж, я знаю, что это старый пост и существует множество обходных путей, но мой довольно прост, и я не читал его нигде, даже если кто-то точно его нашел.
Вместо анимации высоты от X до Auto (что невозможно), вы можете сделать высоту равной Auto и анимировать свойство MaxHeight:

<MyControl x:Name="ctrlAutoHeight" Height="Auto">
    <MyControl.Triggers>
        <EventTrigger RoutedEvent="myRoutedEvent">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation 
                        Storyboard.TargetName="ctrlAutoHeight" 
                        Storyboard.TargetProperty="MaxHeight"
                        From="0.0" 
                        To="{Binding ElementName=ParentControl, Path=ActualHeight}"
                        Duration="0:0:1" 
                        AutoReverse="False"
                        />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </MyControl.Triggers>
</MyControl>
person lunair    schedule 10.04.2013
comment
Я еще не пробовал, но не понимаю, как это не сработает. Довольно умный. - person Kilazur; 26.01.2015
comment
Теперь я знаю: я не знаю точного условия, но я получаю InvalidOperationException, когда пытаюсь привязать To к MaxHeight моего окна или к его сетке. - person Kilazur; 26.01.2015
comment
Я также получил исключение: InvalidOperationException: невозможно заморозить это дерево временной шкалы раскадровки для использования в потоках. Это из-за использования привязки внутри - person Pavel Griza; 29.05.2017
comment
Это решение великолепно! - person Skintkingle; 01.10.2018
comment
Обратите внимание, что вам также может понадобиться анимировать поля, если они есть у элемента, с помощью ThicknessAnimation. - person Chris Bordeman; 29.10.2018
comment
Почему так много людей сказали: нельзя использовать binding в анимации? Почему вы можете это сделать? stackoverflow.com/a/154227/3907561 - person Joke Huang; 31.03.2021

Вот готовый к использованию пример, основанный на StackPanel (не стесняйтесь заменить его на GroupBox).

Для тех, у кого есть «InvalidOperationException: невозможно заморозить это дерево временной шкалы раскадровки для использования между потоками», это исключение возникает, когда привязка определена внутри раскадровки, которая сама определена внутри ControlTemplate или Style. В некотором смысле замороженная анимация — это анимация, в которой все значения статичны (скажем, предварительно рассчитаны).

Просто чтобы почувствовать проблему, представьте, что в StackPanel добавляются или удаляются некоторые элементы управления во время анимации, теоретически для успешного выполнения этой анимации механизм анимации должен учитывать эти изменения (через привязки), но, к сожалению, WPF на самом деле этого не делает. поддержите это дело.

Чтобы вернуться к приведенному ниже решению, обратите внимание, что я использую привязки вне какого-либо ControlTemplate или Style. В этом случае параметры анимации вычисляются при запуске событий, но после воспроизведения они не обновляются при изменении связанных свойств.

Следовательно, это решение (если не другие) страдает от 2 неблокирующих проблем:

  1. В конце анимации размер StackPanel может быть неправильным, если содержимое StackPanel изменяется во время анимации.
  2. При быстром щелчке несколько раз по флажку продолжительность анимации всегда будет одинаковой независимо от оставшегося пространства для свертывания или расширения.
<StackPanel>

    <!-- CheckBox used for triggering the StackPanel animation -->
    <CheckBox Content="Expand/Collapse">
        <CheckBox.Triggers>
            <EventTrigger RoutedEvent="CheckBox.Checked">
                <!-- Expand animation -->
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="StackPanel" 
                                         Storyboard.TargetProperty="Height"
                                         From="{Binding ElementName=StackPanel, Path=Height}" 
                                         To="{Binding ElementName=ContentSize, Path=DesiredSize.Height}"
                                         Duration="0:0:1" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <EventTrigger RoutedEvent="CheckBox.Unchecked">
                <!-- Collapse animation -->
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="StackPanel" 
                                         Storyboard.TargetProperty="Height"
                                         From="{Binding ElementName=StackPanel, Path=Height}" 
                                         To="0"
                                         Duration="0:0:1" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </CheckBox.Triggers>
    </CheckBox>

    <!-- The animated StackPanel -->
    <StackPanel x:Name="StackPanel" Height="0">
        <!-- The border below acts as a probe to get the expected StackPanel container size -->
        <Border x:Name="ContentSize">
            <TextBlock>Some Content</TextBlock>
        </Border>
    </StackPanel>
</StackPanel>

До сих пор кажется, что идеального и простого решения этой проблемы не существует...

person Kino101    schedule 13.03.2021