我正在尝试为Expander
控件创建自己的模板。当控件扩展时,我希望内容缓慢滑下。
在编译时不知道内容的所需高度。
我认为我们可以将幻灯片定义为动画:
<Storyboard x:Key="ExpandContent">
<DoubleAnimation
Storyboard.TargetName="_expanderContent"
Storyboard.TargetProperty="Height"
From="0.0"
To="{Binding ElementName=_expanderContent,Path=DesiredHeight}"
Duration="0:0:1.0" />
</Storyboard>
但不幸的是没有。我们收到错误
无法冻结此Storyboard时间轴树以供跨线程使用。
在定义动画参数时似乎无法使用绑定。 (也在this question讨论。)
有没有人对如何处理此问题有任何想法?我担心使用LayoutTransform.ScaleY
,因为这会产生扭曲的图像。
这与this question类似,但这个问题有一个答案,包括编写代码隐藏,我认为在控件模板中是不可能的。 我想知道基于XAML的解决方案是否可以实现。
<小时/> 对于它的价值,这是我的控制模板的当前状态。
<ControlTemplate x:Key="ExpanderControlTemplate" TargetType="{x:Type Expander}">
<ControlTemplate.Resources>
<!-- Here are the storyboards which don't work -->
<Storyboard x:Key="ExpandContent">
<DoubleAnimation
Storyboard.TargetName="_expanderContent"
Storyboard.TargetProperty="Height"
From="0.0"
To="{Binding ElementName=_expanderContent,Path=DesiredHeight}"
Duration="0:0:1.0" />
</Storyboard>
<Storyboard x:Key="ContractContent">
<DoubleAnimation
Storyboard.TargetName="_expanderContent"
Storyboard.TargetProperty="Height"
From="{Binding ElementName=_expanderContent,Path=DesiredHeight}"
To="0.0"
Duration="0:0:1.0" />
</Storyboard>
</ControlTemplate.Resources>
<Grid Name="MainGrid" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Name="ContentRow" Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter ContentSource="Header" />
<ToggleButton Template="{StaticResource ProductButtonExpand}"
Grid.Column="1"
IsChecked="{Binding Path=IsExpanded,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
/>
<Rectangle Grid.ColumnSpan="2" Fill="#FFDADADA" Height="1" Margin="8,0,8,2" VerticalAlignment="Bottom"/>
</Grid>
</Border>
<ContentPresenter Grid.Row="1" HorizontalAlignment="Stretch" Name="_expanderContent">
</ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="_expanderContent" Property="Height" Value="{Binding ElementName=_expanderContent,Path=DesiredHeight}" />
<!-- Here is where I would activate the storyboard if they did work -->
<Trigger.EnterActions>
<!--<BeginStoryboard Storyboard="{StaticResource ExpandContent}"/>-->
</Trigger.EnterActions>
<Trigger.ExitActions>
<!--<BeginStoryboard x:Name="ContractContent_BeginStoryboard" Storyboard="{StaticResource ContractContent}"/>-->
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsExpanded" Value="False">
<Setter TargetName="_expanderContent" Property="Height" Value="0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
答案 0 :(得分:5)
如果你可以Interactions
使用FluidLayout
(Blend 4 SDK),那么你很幸运,这对于那些奇特的动画事物非常有用。
首先将内容CP的高度设置为0:
<ContentPresenter Grid.Row="1"
HorizontalAlignment="Stretch"
x:Name="_expanderContent"
Height="0"/>
要为此设置动画,Height
只需要动画显示NaN
代表展开状态的VisualState
(非离散动画不允许您使用NaN
}):
xmlns:is="http://schemas.microsoft.com/expression/2010/interactions"
<Grid x:Name="MainGrid" Background="White">
<VisualStateManager.CustomVisualStateManager>
<is:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ExpansionStates" is:ExtendedVisualStateManager.UseFluidLayout="True">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Expanded">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="_expanderContent">
<DiscreteDoubleKeyFrame KeyTime="0" Value="NaN"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Collapsed"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<!-- ... --->
这应该是所有必要的,流体布局将为您创造过渡。
如果你有一个很好的代码隐藏解决方案,你甚至可以在这样的词典中使用代码隐藏:
<!-- TestDictionary.xaml -->
<ResourceDictionary x:Class="Test.TestDictionary"
...>
//TestDictionary.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Test
{
partial class TestDictionary : ResourceDictionary
{
//Handlers and such here
}
}
答案 1 :(得分:5)
这是一个古老的问题,但今天我遇到了这个问题,所以我想发布我的解决方案是值得的:
我必须设置网格行的高度属性(向上和向下滑动)的动画,但需要动态绑定,以便该行再次滑动到与之前相同的位置。
我发现这个答案非常有用(在毫无结果地与XAML作战之后): http://go4answers.webhost4life.com/Question/found-solution-work-protected-override-190845.aspx
有时在代码隐藏中做事情更简单:
Storyboard sb = new Storyboard();
var animation = new GridLengthAnimation
{
Duration = new Duration(500.Milliseconds()),
From = this.myGridRow.Height,
To = new GridLength(IsGridRowVisible ? GridRowPreviousHeight : 0, GridUnitType.Pixel)
};
// Set the target of the animation
Storyboard.SetTarget(animation, this.myGridRow);
Storyboard.SetTargetProperty(animation, new PropertyPath("Height"));
// Kick the animation off
sb.Children.Add(animation);
sb.Begin();
GridLengthAnimation类可以在这里找到: http://social.msdn.microsoft.com/forums/en-US/wpf/thread/da47a4b8-4d39-4d6e-a570-7dbe51a842e4/
答案 2 :(得分:1)
有一个即用型和仅限XAML的解决方案on CodeProject:
样式:
<local:MultiplyConverter x:Key="MultiplyConverter" />
<Style TargetType="Expander" x:Key="VerticalSlidingEmptyExpander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<ScrollViewer x:Name="ExpanderContentScrollView"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Top"
>
<ScrollViewer.Tag>
<system:Double>0.0</system:Double>
</ScrollViewer.Tag>
<ScrollViewer.Height>
<MultiBinding Converter="{StaticResource MultiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</ScrollViewer.Height>
<ContentPresenter x:Name="ExpanderContent" ContentSource="Content"/>
</ScrollViewer>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ExpanderContentScrollView"
Storyboard.TargetProperty="Tag"
To="1"
Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ExpanderContentScrollView"
Storyboard.TargetProperty="Tag"
To="0"
Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Expander" x:Key="HorizontalSlidingEmptyExpander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<ScrollViewer x:Name="ExpanderContentScrollView"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
HorizontalContentAlignment="Left"
VerticalContentAlignment="Stretch"
>
<ScrollViewer.Tag>
<system:Double>0.0</system:Double>
</ScrollViewer.Tag>
<ScrollViewer.Width>
<MultiBinding Converter="{StaticResource MultiplyConverter}">
<Binding Path="ActualWidth" ElementName="ExpanderContent"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</ScrollViewer.Width>
<ContentPresenter x:Name="ExpanderContent" ContentSource="Content"/>
</ScrollViewer>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ExpanderContentScrollView"
Storyboard.TargetProperty="Tag"
To="1"
Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ExpanderContentScrollView"
Storyboard.TargetProperty="Tag"
To="0"
Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
MultiplyConverter:
public class MultiplyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, CultureInfo culture)
{
double result = 1.0;
for (int i = 0; i < values.Length; i++)
{
if (values[i] is double)
result *= (double)values[i];
}
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
throw new Exception("Not implemented");
}
}
我将Style复制为水平和垂直版本并省略了ToggleButtons,但您可以轻松地从原始帖子中获取。