DataTrigger.EnterActions.BeginStoryboard not Beginning - PullRequest
3 голосов
/ 27 августа 2011

Цель этого XAML - анимировать ListBox.

  1. Выбранный ListBoxItem Zoomed X2
  2. NotSelected ListBoxItem Zoomed 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 Ответ

2 голосов
/ 27 августа 2011

Я не уверен в лучшем обходном пути, но проблема в том, что триггерам все равно нужно будет «отменить» свои анимированные значения, когда триггер больше не действует. Так что в вашем случае первый триггер может быть применен, но он эффективно удаляется с помощью 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>
...