实现“下滑"WPF中的动画 [英] Achieve "slide down" animation in WPF

查看:28
本文介绍了实现“下滑"WPF中的动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为 Expander 控件创建自己的模板.控件展开时,我想让内容慢慢往下滑.

I am attempting to create my own template for an Expander control. When the control is expanded, I want the content to slide down slowly.

在编译时不知道所需的内容高度.

The desired height of the content is not known at compile time.

我认为我们可以将下滑定义为动画:

I thought we could define the slide down as an animation:

<Storyboard x:Key="ExpandContent">

    <DoubleAnimation 
        Storyboard.TargetName="_expanderContent" 
        Storyboard.TargetProperty="Height" 
        From="0.0" 
        To="{Binding ElementName=_expanderContent,Path=DesiredHeight}"
        Duration="0:0:1.0" />
</Storyboard>

但不幸的是没有.我们得到一个错误

But Unfortunately not. We get an error

无法冻结此 Storyboard 时间线树以供跨线程使用.

Cannot freeze this Storyboard timeline tree for use across threads.

在定义动画参数时,我们似乎不能使用绑定.(也在这个问题中进行了讨论.)

It appears that we cannot use binding when defining animation parameters. (Discussed also in this question.)

有人对我如何解决这个问题有任何想法吗?我对使用 LayoutTransform.ScaleY 持谨慎态度,因为那会产生扭曲的图像.

Does anyone have any ideas on how I can approach this? I'm wary of using LayoutTransform.ScaleY, because that would create a distorted image.

这类似于 这个问题,但是这个问题的答案涉及编写代码隐藏,我认为这在控件模板中是不可能的.我想知道是否可以实现基于 XAML 的解决方案.

This is similar to this question, but this question has an answer involved writing code-behind, which I don't think is possible in a control template. I'm wondering if a XAML-based solution is achievable.


值得一提的是,这是我的控件模板的当前状态.


For what it's worth, here is the current state of my control template.

<ControlTemplate x:Key="ExpanderControlTemplate"  TargetType="{x:Type Expander}">
    <ControlTemplate.Resources>
            <!-- Here are the storyboards which don't work -->
            <Storyboard x:Key="ExpandContent">

                <DoubleAnimation 
                    Storyboard.TargetName="_expanderContent" 
                    Storyboard.TargetProperty="Height" 
                    From="0.0" 
                    To="{Binding ElementName=_expanderContent,Path=DesiredHeight}"
                    Duration="0:0:1.0" />
            </Storyboard>
            <Storyboard x:Key="ContractContent">

                <DoubleAnimation 
                    Storyboard.TargetName="_expanderContent" 
                    Storyboard.TargetProperty="Height" 
                    From="{Binding ElementName=_expanderContent,Path=DesiredHeight}"
                    To="0.0"
                    Duration="0:0:1.0" />

            </Storyboard>
        </ControlTemplate.Resources>
    <Grid Name="MainGrid" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Name="ContentRow" Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Border>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <ContentPresenter ContentSource="Header" />
                <ToggleButton Template="{StaticResource ProductButtonExpand}"
                              Grid.Column="1"
                              IsChecked="{Binding Path=IsExpanded,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" 
                              />
                <Rectangle Grid.ColumnSpan="2" Fill="#FFDADADA" Height="1" Margin="8,0,8,2" VerticalAlignment="Bottom"/>

            </Grid>
        </Border>

            <ContentPresenter Grid.Row="1" HorizontalAlignment="Stretch" Name="_expanderContent">

            </ContentPresenter>

    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="IsExpanded" Value="True">
            <Setter TargetName="_expanderContent" Property="Height" Value="{Binding ElementName=_expanderContent,Path=DesiredHeight}" />

                <!-- Here is where I would activate the storyboard if they did work -->
                <Trigger.EnterActions>
                <!--<BeginStoryboard Storyboard="{StaticResource ExpandContent}"/>-->
            </Trigger.EnterActions>
                <Trigger.ExitActions>
                    <!--<BeginStoryboard x:Name="ContractContent_BeginStoryboard" Storyboard="{StaticResource ContractContent}"/>-->
                </Trigger.ExitActions>
        </Trigger>
            <Trigger Property="IsExpanded" Value="False">

                <Setter TargetName="_expanderContent" Property="Height" Value="0" />
            </Trigger>
        </ControlTemplate.Triggers>

</ControlTemplate>

推荐答案

如果你可以使用 InteractionsFluidLayout (Blend 4 SDK) 你很幸运,它对那些花哨的动画非常有用.

If you can use Interactions with FluidLayout (Blend 4 SDK) you are in luck, it's really useful for those fancy animation things.

首先设置内容CP的Height为0:

First set the content CP's Height to 0:

<ContentPresenter Grid.Row="1"
    HorizontalAlignment="Stretch"
    x:Name="_expanderContent"
    Height="0"/>

要对此进行动画处理,只需将 Height 动画化为 VisualState 中的 NaN 表示展开状态(非离散动画)不会让你使用 NaN):

To animate this, the Height just needs to be animated to NaN in the VisualState that represents the expanded state (non-discrete animations would not let you use NaN):

xmlns:is="http://schemas.microsoft.com/expression/2010/interactions"

<Grid x:Name="MainGrid" Background="White">
    <VisualStateManager.CustomVisualStateManager>
        <is:ExtendedVisualStateManager/>
    </VisualStateManager.CustomVisualStateManager>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="ExpansionStates" is:ExtendedVisualStateManager.UseFluidLayout="True">
            <VisualStateGroup.Transitions>
                <VisualTransition GeneratedDuration="0:0:1"/>
            </VisualStateGroup.Transitions>
            <VisualState x:Name="Expanded">
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
                                                   Storyboard.TargetName="_expanderContent">
                        <DiscreteDoubleKeyFrame KeyTime="0" Value="NaN"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
            <VisualState x:Name="Collapsed"/>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <!-- ... --->

这应该是所有必要的,流体布局将从那里为您创建过渡.

That should be all that is necessary, the fluid layout will create the transition for you from there.

如果您有一个很好的代码隐藏解决方案,您甚至可以像这样在字典中使用代码隐藏:

If you have a code-behind solution that would be fine, you can even use code-behind in dictionaries like this:

<!-- TestDictionary.xaml -->
<ResourceDictionary x:Class="Test.TestDictionary"
                    ...>

//TestDictionary.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

namespace Test
{
    partial class TestDictionary : ResourceDictionary
    {
        //Handlers and such here
    }
}

这篇关于实现“下滑"WPF中的动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆