DataTrigger.EnterActions.BeginStoryboard not Beginning
Целью этого XAML является анимация ListBox.
- Выбранный ListBoxItem - Zoomed X2
- NotSelected ListBoxItem - увеличенный X.5
- Когда ничего не выбрано, они Zoomed X1
Тем не менее, эти раскадровки не работают, как ожидалось.
(просто скопируйте все это в Kaxaml или в свой любимый редактор XAML).
Здесь есть что-то очевидное?
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:Array Type="{x:Type sys:String}" x:Key="MyData">
<sys:String>One</sys:String>
<sys:String>Two</sys:String>
<sys:String>Three</sys:String>
<sys:String>Four</sys:String>
<sys:String>Five</sys:String>
<sys:String>Six</sys:String>
<sys:String>Seven</sys:String>
<sys:String>Eight</sys:String>
</x:Array>
</Page.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource MyData}}" Name="ListBoxA">
<ListBox.ItemTemplate>
<DataTemplate>
<DataTemplate.Triggers>
<!-- selected (Grow) -->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="True" Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
<Condition Value="1" Binding="{Binding Path=SelectedItems.Count, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Name="BeginStoryboardSelected">
<Storyboard>
<ParallelTimeline>
<DoubleAnimation To="2" DecelerationRatio="0.5" Duration="00:00:00.500" Storyboard.TargetName="MyTransform" Storyboard.TargetProperty="ScaleX" />
<DoubleAnimation To="2" DecelerationRatio="0.5" Duration="00:00:00.500" Storyboard.TargetName="MyTransform" Storyboard.TargetProperty="ScaleY" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
<!-- none selected -->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="False" Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
<Condition Value="0" Binding="{Binding Path=SelectedItems.Count, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Name="BeginStoryboardNoneSelected">
<Storyboard>
<ParallelTimeline>
<DoubleAnimation To="1" DecelerationRatio="0.5" Duration="00:00:00.500" Storyboard.TargetName="MyTransform" Storyboard.TargetProperty="ScaleX" />
<DoubleAnimation To="1" DecelerationRatio="0.5" Duration="00:00:00.500" Storyboard.TargetName="MyTransform" Storyboard.TargetProperty="ScaleY" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
<!-- shrink -->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="False" Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
<Condition Value="1" Binding="{Binding Path=SelectedItems.Count, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Name="BeginStoryboardNotSelected">
<Storyboard>
<ParallelTimeline>
<DoubleAnimation To=".5" DecelerationRatio="0.5" Duration="00:00:00.500" Storyboard.TargetName="MyTransform" Storyboard.TargetProperty="ScaleX" />
<DoubleAnimation To=".5" DecelerationRatio="0.5" Duration="00:00:00.500" Storyboard.TargetName="MyTransform" Storyboard.TargetProperty="ScaleY" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
</DataTemplate.Triggers>
<!-- debug content -->
<UniformGrid Columns="3">
<TextBlock Text="{Binding Path=SelectedItems.Count, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}, StringFormat={} SelectedItems.Count is {0}}" Margin="0,0,10,0" Foreground="Gray" />
<TextBlock Text="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, StringFormat={} ListBoxItem.IsSelected is {0}}" Margin="0,0,10,0" Foreground="Gray" />
<TextBlock Text="{Binding .}">
<TextBlock.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="1" x:Name="MyTransform"/>
</TextBlock.LayoutTransform>
</TextBlock>
</UniformGrid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Page>
1 ответ
Я не уверен в лучшем обходном пути, но проблема в том, что триггерам все еще нужно будет "отменить" свои анимированные значения, когда триггер больше не действует. Так что в вашем случае первый триггер может быть применен, но он эффективно удаляется с помощью ExitAction последнего триггера.
Поскольку вы не указываете ExitAction, он, вероятно, просто выполняет BeginAnimation(..., null)
очистить анимацию EnterAction. Вы можете проверить это, переупорядочив триггеры, и вы увидите, что последний всегда действует.
Подобный вопрос можно найти здесь. Но, кажется, даже с этим, это не работает, как ожидалось.
Я бы, наверное, пошел с пользовательским элементом управления, который обрабатывает анимацию масштабирования для вас. Что-то вроде:
public class AnimatedZoomDecorator : Decorator {
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register("ZoomLevel",
typeof(double), typeof(AnimatedZoomDecorator), new FrameworkPropertyMetadata(1.0, OnZoomLevelPropertyValueChanged));
public double ZoomLevel {
get { return (double)this.GetValue(ZoomLevelProperty); }
set { this.SetValue(ZoomLevelProperty, value); }
}
private static void OnZoomLevelPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
AnimatedZoomDecorator control = d as AnimatedZoomDecorator;
if (control != null) {
ScaleTransform scaleTransform = control.LayoutTransform as ScaleTransform;
if (scaleTransform == null)
control.LayoutTransform = scaleTransform = new ScaleTransform();
DoubleAnimation animation = new DoubleAnimation() {
To = control.ZoomLevel,
DecelerationRatio = 0.5,
Duration = new Duration(TimeSpan .FromMilliseconds(500)),
};
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, animation);
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, animation);
}
}
}
Который затем можно использовать так:
<DataTemplate>
<local:AnimatedZoomDecorator x:Name="zoom">
<TextBlock Text="{Binding .}" />
</local:AnimatedZoomDecorator>
<DataTemplate.Triggers>
<!-- shrink -->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="False"
Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
<Condition Value="1"
Binding="{Binding Path=SelectedItems.Count, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}" />
</MultiDataTrigger.Conditions>
<Setter TargetName="zoom" Property="ZoomLevel" Value="0.5" />
</MultiDataTrigger>
<!-- selected (Grow) -->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="True"
Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
<Condition Value="1"
Binding="{Binding Path=SelectedItems.Count, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}" />
</MultiDataTrigger.Conditions>
<Setter TargetName="zoom" Property="ZoomLevel" Value="2" />
</MultiDataTrigger>
</DataTemplate.Triggers>
</DataTemplate>