我正在创建一个模板控件。我们的想法是创建一个扩展控件。它将具有Header和Details属性,每个属性对应ContentPresenter
。用户将能够点击标题,详细信息部分将以动画展开。当用户再次点击标题时,“详细信息”部分将使用另一个动画缩回。
我正在使用Visual States和VisualTransitions
来实现这一目标。这是我的代码。
[TemplatePart(Name ="Header", Type=typeof(ContentPresenter))]
[TemplatePart(Name = "Details", Type = typeof(ContentPresenter))]
[TemplateVisualState(GroupName ="ExpandStates",Name ="Expanded")]
[TemplateVisualState(GroupName = "ExpandStates", Name = "Compact")]
public sealed class ExpandingItem : Control
{
private ContentPresenter header;
private bool isExpanded;
public ExpandingItem()
{
this.DefaultStyleKey = typeof(ExpandingItem);
}
public FrameworkElement Header
{
get { return (FrameworkElement)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(FrameworkElement), typeof(ExpandingItem), new PropertyMetadata(default(FrameworkElement)));
public FrameworkElement Details
{
get { return (FrameworkElement)GetValue(DetailsProperty); }
set { SetValue(DetailsProperty, value); }
}
// Using a DependencyProperty as the backing store for Details. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DetailsProperty =
DependencyProperty.Register("Details", typeof(FrameworkElement), typeof(ExpandingItem), new PropertyMetadata(default(FrameworkElement)));
protected override void OnApplyTemplate()
{
if (header != null)
{
header.Tapped -= HeaderTapped;
}
base.OnApplyTemplate();
header = (ContentPresenter)GetTemplateChild("Header");
header.Tapped += HeaderTapped;
}
private void HeaderTapped(object sender, TappedRoutedEventArgs e)
{
if (isExpanded)
{
Retract();
OnStateChanged(new ExpandItemEventArgs(false));
}
else
{
Expand();
OnStateChanged(new ExpandItemEventArgs(true));
}
isExpanded = !isExpanded;
}
public void Expand()
{
VisualStateManager.GoToState(this, "Expanded", true);
}
public void Retract()
{
VisualStateManager.GoToState(this, "Compact", true);
}
public EventHandler<ExpandItemEventArgs> StateChanged;
private void OnStateChanged(ExpandItemEventArgs e)
{
// Make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler<ExpandItemEventArgs> handler = StateChanged;
// Event will be null if there are no subscribers
if (handler != null)
{
handler(this, e);
}
}
}
和模板
<Style TargetType="controls:ExpandingItem" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ExpandingItem">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ExpandStates">
<VisualStateGroup.Transitions>
<VisualTransition From="Compact" To="Expanded">
<VisualTransition.Storyboard>
<Storyboard>
<FadeInThemeAnimation
TargetName="Details"/>
</Storyboard>
</VisualTransition.Storyboard>
</VisualTransition>
<VisualTransition From="Expanded" To="Compact">
<VisualTransition.Storyboard>
<Storyboard>
<FadeOutThemeAnimation
TargetName="Details"/>
</Storyboard>
</VisualTransition.Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Compact"/>
<VisualState x:Name="Expanded">
<VisualState.Setters>
<Setter Target="Details.Visibility" Value="Visible"/>
</VisualState.Setters>
<Storyboard>
<FadeInThemeAnimation
TargetName="Details"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter
x:Name="Header"
Grid.Row="0"
Content="{TemplateBinding Header}"/>
<ContentPresenter
x:Name="Details"
Grid.Row="1"
Content="{TemplateBinding Details}"
Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我正在使用fadein / fadeout动画,因为它是一个简单的动画,但理想情况下我想使用像splitopen / splitclose动画这样的东西。
问题在于即使状态之间的转换正常发生。动画永远不会发生。你能帮我找出问题吗?
编辑:以下是ExpandItemEventArgs
public class ExpandItemEventArgs : EventArgs
{
private readonly bool isExpanded;
public ExpandItemEventArgs(bool isExpanded)
{
this.isExpanded = isExpanded;
}
public bool IsExpanded => isExpanded;
}
答案 0 :(得分:0)
问题在于即使状态之间的转换正常发生。动画永远不会发生。你能帮我找出问题吗?
这是因为您的VisualTransition From="Compact" To="Expanded"
,首先您没有让您的控件进入名为VisualState
的{{1}}。当你Compact
时,由于你没有为<VisualTransition From="Expanded" To="Compact">
设置Visibility
属性,它会删除最后Details
并直接返回到折叠状态,动画将不会显示。
在这里我修改了你的代码,为了使淡入淡出的动画更明显,我也改变了动画:
VisualState
我修改后面的代码:
<Style TargetType="local:ExpandingItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ExpandingItem">
<Grid Name="RootGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ExpandStates">
<VisualStateGroup.Transitions>
<VisualTransition To="Expanded" GeneratedDuration="0:0:3">
<Storyboard x:Name="FadeIn">
<DoubleAnimation From="0.1" To="1" Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="Details" Duration="0:0:3">
<DoubleAnimation.EasingFunction>
<CubicEase />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualTransition>
<VisualTransition From="Expanded" To="Compact" GeneratedDuration="0:0:2.5">
<VisualTransition.Storyboard>
<Storyboard x:Name="FadeOut">
<DoubleAnimation From="1" To="0.1" Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="Details" Duration="0:0:3">
<DoubleAnimation.EasingFunction>
<CubicEase />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualTransition.Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Target="Details.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Compact">
<VisualState.Setters>
<Setter Target="Details.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Expanded">
<VisualState.Setters>
<Setter Target="Details.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter
x:Name="Header"
Grid.Row="0"
Content="{TemplateBinding Header}" />
<ContentPresenter
x:Name="Details"
Grid.Row="1"
Content="{TemplateBinding Details}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
渲染图片: