wpf - DataTrigger.EnterActions.BeginStoryboard 未开始

标签 wpf storyboard datatrigger multidatatrigger

此 XAML 的目的是为列表框设置动画。

  1. 选定的 ListBoxItem 已缩放 X2
  2. NotSelected ListBoxItem 缩放了 X.5
  3. 当没有选择任何东西时,它们是放大 X1

但是,这些 Storyboard 并未按预期运行。

(只需将整个内容复制到 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>

最佳答案

我不确定最佳解决方法,但问题是当触发器不再有效时,触发器仍需要“取消应用”它们的动画值。因此,在您的情况下,可能会应用第一个触发器,但它会被最后一个触发器的 ExitAction 有效地删除。

由于您没有指定 ExitAction,它可能只是执行 BeginAnimation(..., null) 来清除 EnterAction 的动画。您可以通过重新排序触发器来验证这一点,您会看到最后一个始终生效。

可以找到类似的问题here .但即使如此,它似乎也没有按预期工作。

我可能会选择一个自定义控件来为您处理缩放动画。像这样的东西:

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>

关于wpf - DataTrigger.EnterActions.BeginStoryboard 未开始,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7211463/

相关文章:

c# - MediaElement 支持哪些格式?

wpf - INotifyPropertyChanged 和 DependencyProperty 有什么关系?

c# - WPF 如何设置 CollectionViewSource 的最大结果量

iphone - Xcode 4.5 Storyboard 'Exit'

iOS Storyboard 呈现 Segues "relationship, embed, push, modal, custom"类型

wpf - 将 DataTrigger 绑定(bind)到复选框的 IsChecked 属性

wpf - 数据触发器未触发

WPF - ContentControl 内容作为 DrawingVisual

xcode - 数据检测和可编辑(这些属性互斥)

wpf - TextBlock 样式触发器