Я создаю шаблонный элемент управления. Идея состоит в том, чтобы создать расширенный контроль. Он будет иметь свойство заголовка и детали, каждое из которых соответствует ContentPresenter
. Пользователь сможет нажать на заголовок, а раздел «Подробности» будет расширяться с помощью анимации. Когда пользователь снова закроет заголовок, раздел «Подробности» вернется с другой анимацией.Не удается получить VisualStateGroup.Transitions для работы в шаблоном управлении
Я использую визуальные состояния и 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/затухания анимации, как это простой анимации, но в идеале я хотел бы использовать что-то вроде splitopen/splitclose анимации.
Проблема в том, что даже если переход между состояниями происходит нормально. Анимация никогда не возникает. Можете ли вы помочь мне определить проблему?
Edit: Вот код для ExpandItemEventArgs
public class ExpandItemEventArgs : EventArgs
{
private readonly bool isExpanded;
public ExpandItemEventArgs(bool isExpanded)
{
this.isExpanded = isExpanded;
}
public bool IsExpanded => isExpanded;
}
Как ваш 'ExpandItemEv entArgs'? Можете ли вы опубликовать этот код? –
@ GraceFeng-MSFT Я добавил ExpandItemEventArgs. Однако я не думаю, что они могут повлиять на визуальные состояния. – Corcus