尝试在 Expanded 和 Collapsed 事件期间使用 Behavior 为 Expander 设置动画,它在展开时有效,但在折叠时无效。在花了相当长的时间尝试找出原因(可见性 == 已折叠)后,我无法在折叠时使其动画化。
获取初始内容大小有一种技巧,如果内容发生更改,动画肯定会不正确,但是没有 ContentChanged 类型的事件可以在内容更改的情况下挂钩并获取新大小。
行为:
public class AnimatedExpanderBehavior : Behavior<Expander>
{
public Duration Duration { get; set; }
private Size ContentSize { get; set; }
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Collapsed += AssociatedObject_Collapsed;
AssociatedObject.Expanded += AssociatedObject_Expanded;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Collapsed -= AssociatedObject_Collapsed;
AssociatedObject.Expanded -= AssociatedObject_Expanded;
}
private void AssociatedObject_Collapsed(object sender, RoutedEventArgs e)
{
var expander = sender as Expander;
if (expander != null)
{
var name = expander.Content as FrameworkElement;
if (name != null)
{
// Does not happen, collapses instantly instead
var animation = new DoubleAnimation(name.ActualHeight, 0, Duration);
name.BeginAnimation(FrameworkElement.HeightProperty, animation);
}
}
}
private void AssociatedObject_Expanded(object sender, RoutedEventArgs e)
{
var expander = sender as Expander;
if (expander != null)
{
var name = expander.Content as UIElement;
if (name != null)
{
// Grabbing initial content size
if (ContentSize.Width <= 0 && ContentSize.Height <= 0)
{
name.Measure(new Size(9999, 9999));
ContentSize = name.DesiredSize;
}
var animation = new DoubleAnimation(0, ContentSize.Height, Duration);
name.BeginAnimation(FrameworkElement.HeightProperty, animation);
}
}
}
}
用法 :
<Expander>
<i:Interaction.Behaviors>
<behaviors:AnimatedExpanderBehavior Duration="0:0:0.2" />
</i:Interaction.Behaviors>
<Rectangle Height="100" Fill="Red" />
</Expander>
有趣的是,我一直在研究 Windows UI 是如何做到的,我绝对确定它是双向的,而实际上它只在扩展期间这样做。
折叠时是否有任何限制会阻止实现此类动画?
编辑
新代码,但是当内容更改时它不会调整,而原始扩展器会:
private void AssociatedObject_Expanded(object sender, RoutedEventArgs e)
{
var expander = sender as Expander;
if (expander != null)
{
var name = expander.Content as FrameworkElement;
if (name != null)
{
_expandSite.Visibility = Visibility.Visible;
double height;
if (_firstExpansion)
{
name.Measure(new Size(9999, 9999));
height = name.DesiredSize.Height;
_firstExpansion = false;
}
else
{
height = name.RenderSize.Height;
}
var animation = new DoubleAnimation(0, height, new Duration(TimeSpan.FromSeconds(0.5d)));
name.BeginAnimation(FrameworkElement.HeightProperty, animation);
}
}
}