Вот готовый к использованию пример, основанный на StackPanel (не стесняйтесь заменить его на GroupBox).
Для тех, у кого есть «InvalidOperationException: невозможно заморозить это дерево временной шкалы раскадровки для использования между потоками», это исключение возникает, когда привязка определена внутри раскадровки, которая сама определена внутри ControlTemplate или Style. В некотором смысле замороженная анимация — это анимация, в которой все значения статичны (скажем, предварительно рассчитаны).
Просто чтобы почувствовать проблему, представьте, что в StackPanel добавляются или удаляются некоторые элементы управления во время анимации, теоретически для успешного выполнения этой анимации механизм анимации должен учитывать эти изменения (через привязки), но, к сожалению, WPF на самом деле этого не делает. поддержите это дело.
Чтобы вернуться к приведенному ниже решению, обратите внимание, что я использую привязки вне какого-либо ControlTemplate или Style. В этом случае параметры анимации вычисляются при запуске событий, но после воспроизведения они не обновляются при изменении связанных свойств.
Следовательно, это решение (если не другие) страдает от 2 неблокирующих проблем:
- В конце анимации размер StackPanel может быть неправильным, если содержимое StackPanel изменяется во время анимации.
- При быстром щелчке несколько раз по флажку продолжительность анимации всегда будет одинаковой независимо от оставшегося пространства для свертывания или расширения.
<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