DataTrigger.EnterActions.BeginStoryboard 未开始

发布于 2024-12-02 04:26:20 字数 6282 浏览 0 评论 0原文

此 XAML 的目的是为 ListBox 制作动画。

  1. 选定的 ListBoxItem 缩放 X2
  2. 未选定的 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>

The purpose of this XAML is to animate a ListBox.

  1. The Selected ListBoxItem is Zoomed X2
  2. The NotSelected ListBoxItem is Zoomed X.5
  3. When nothing is selected, they are Zoomed X1

However, these Storyboards are not acting as expected.

(just copy this whole thing into Kaxaml, or your fav. XAML editor)

Is there something obvious here?

<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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凑诗 2024-12-09 04:26:20

我不确定最好的解决方法,但问题是当触发器不再有效时,触发器仍然需要“取消应用”其动画值。因此,在您的情况下,可能会应用第一个触发器,但它会被最后一个触发器的 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>

I'm not sure of the best workaround, but the problem is the triggers will still need to "unapply" their animated values when the trigger is no longer valid. So in your case, the first trigger may be applied, but it is effectively removed by the ExitAction of the last trigger.

Since you don't specify an ExitAction, it probably just performs a BeginAnimation(..., null) to clear the EnterAction's animation. You can verify this by reordering the triggers, and you will see the last one always takes effect.

A similar question can be found here. But it seems even with that, it does not work as expected.

I'd probably go with a custom control that handles the zoom animation for you. Something like:

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);
        }
    }

}

Which could then be used like this:

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文