DataTrigger.EnterActions.BeginStoryboard not Beginning

Целью этого XAML является анимация ListBox.

  1. Выбранный ListBoxItem - Zoomed X2
  2. NotSelected ListBoxItem - увеличенный X.5
  3. Когда ничего не выбрано, они 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>
Другие вопросы по тегам