尝试在展开和折叠事件期间使用行为为扩展器设置动画,它在扩展时有效,但在折叠时无效。花了很长时间才弄清楚原因(Visibility == Collapsed)我崩溃时无法使它成为动画。
在抓取初始内容大小方面存在一些黑客攻击,如果内容发生变化,动画肯定是不正确的,但是在内容发生变化的情况下,没有任何类型的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);
}
}
}
答案 0 :(得分:3)
此处的问题是Expander.ControlTemplate
只有ContentPresenter
Visibility
Collapsed
IsExpanded
false
ContentPresenter
p>
因此,即使您的动画实际运行,您也永远不会看到它,因为它的父级是不可见的。这个ExpandSite
被称为private UIElement _expandSite;
protected override void OnAttached() {
base.OnAttached();
AssociatedObject.Collapsed += AssociatedObject_Collapsed;
AssociatedObject.Expanded += AssociatedObject_Expanded;
AssociatedObject.Loaded += (sender, args) => {
_expandSite = AssociatedObject.Template.FindName("ExpandSite", AssociatedObject) as UIElement;
if (_expandSite == null)
throw new InvalidOperationException();
};
}
...
private void AssociatedObject_Collapsed(object sender, RoutedEventArgs e) {
var expander = sender as Expander;
if (expander == null)
return;
var name = expander.Content as FrameworkElement;
if (name == null)
return;
_expandSite.Visibility = Visibility.Visible;
var animation = new DoubleAnimation(name.ActualHeight, 0, Duration);
animation.Completed += (o, args) => {
_expandSite.Visibility = Visibility.Collapsed;
name.BeginAnimation(FrameworkElement.HeightProperty, null);
};
name.BeginAnimation(FrameworkElement.HeightProperty, animation);
}
private void AssociatedObject_Expanded(object sender, RoutedEventArgs e) {
var expander = sender as Expander;
if (expander == null)
return;
var name = expander.Content as FrameworkElement;
if (name == null)
return;
if (name.DesiredSize.Width <= 0 && name.DesiredSize.Height <= 0)
name.Measure(new Size(9999, 9999));
_expandSite.Visibility = Visibility.Visible;
var animation = new DoubleAnimation(0, name.DesiredSize.Height, Duration);
animation.Completed += (o, args) => name.BeginAnimation(FrameworkElement.HeightProperty, null);
name.BeginAnimation(FrameworkElement.HeightProperty, animation);
}
(来自默认模板),我们可以通过类似
_expandSite.Visibility = Visibility.Visible;
我们在扩展动画之前设置Visibility
的原因是我们在行为中设置ExpandSite
Trigger.Setter
时的优先级,它优先于Style
默认Visibility
被忽略。因此,我们在两种情况下都要管理Behavior<...>
。
您确实拥有整个流程的替代方案。请勿使用Style
,而只是为Expander
提供自定义Trigger.Enter/ExitActions
,并在ControlTemplate
中相应指定Visibility
以设置ExpandSite
动画Content
和Visibility
。
<强>更新强>
示例下载:Link
重新调整大小的问题也存在于您的原始代码中。它与我发布的答案无关,因为我们添加的是切换ExpandSite
的{{1}}。该问题是由于动画冻结了Height
的{{1}}属性,因此除非通过以下动画,否则不会允许任何未来的更改。
这个^^样本也应该有解决方法。