VisualStateManager和生成的转换

时间:2011-01-28 12:08:56

标签: wpf animation visualstatemanager transitions vsm

就在我认为我理解VisualStateManager时,有些事证明我错了。

我正在使用WPF 4,我试图简单地将鼠标放大一个项目,并在鼠标离开时缩小它。我想我只需在VisualStateGroup中定义每个州,然后使用VisualTransition指定GeneratedDuration

<Border x:Name="PART_Root" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" RenderTransformOrigin="0.5,0.5">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup Name="CommonStates">
            <VisualStateGroup.Transitions>
                <VisualTransition GeneratedDuration="0:0:1"/>
            </VisualStateGroup.Transitions>

            <VisualState Name="Normal"/>

            <VisualState Name="MouseOver">
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleX" To="1.5" Duration="0"/>
                    <DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleY" To="1.5" Duration="0"/>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <Border.RenderTransform>
        <ScaleTransform x:Name="scaleTransform" ScaleX="1" ScaleY="1"/>
    </Border.RenderTransform>

    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>

由于我有一个VisualTransition并且GeneratedDuration,我期待VSM生成中间动画。也就是说,鼠标悬停在控件上应该会在1秒内将ScaleTransform属性设置为1到1.5。与mousing相同。相反,有1秒的延迟,然后ScaleTransform属性立即捕捉到1.5或回到1.

如果我按如下方式手动指定转换,那么我会得到所需的行为:

<VisualStateGroup.Transitions>
    <VisualTransition From="Normal" To="MouseOver">
        <Storyboard>
            <DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleX" To="1.5" Duration="{StaticResource MouseEnterDuration}"/>
            <DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleY" To="1.5" Duration="{StaticResource MouseEnterDuration}"/>
        </Storyboard>
    </VisualTransition>

    <VisualTransition From="MouseOver" To="Normal">
        <Storyboard>
            <DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleX" To="1" Duration="{StaticResource MouseLeaveDuration}"/>
            <DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleY" To="1" Duration="{StaticResource MouseLeaveDuration}"/>
        </Storyboard>
    </VisualTransition>
</VisualStateGroup.Transitions>

但为什么我要这样做呢?我认为生成转换的重点在于,转换将是生成的。我在这里误解了什么?

更新:根据Rick的回答,Blend会生成 工作的内容。因此,向后工作我确定我确实是直接引用ScaleTransform而不是通过包含它的UIElement。我将我的XAML更改为以下内容并按预期工作:

<Border x:Name="PART_Root" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" RenderTransformOrigin="0.5,0.5">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup Name="CommonStates">
            <VisualStateGroup.Transitions>
                <VisualTransition From="Normal" To="MouseOver" GeneratedDuration="{StaticResource MouseEnterDuration}"/>

                <VisualTransition From="MouseOver" To="Normal" GeneratedDuration="{StaticResource MouseLeaveDuration}"/>
            </VisualStateGroup.Transitions>

            <VisualState Name="Normal"/>

            <VisualState Name="MouseOver">
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)" To="{StaticResource MouseOverScale}" Duration="0"/>
                    <DoubleAnimation Storyboard.TargetName="PART_Root" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" To="{StaticResource MouseOverScale}" Duration="0"/>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <Border.RenderTransform>
        <ScaleTransform/>
    </Border.RenderTransform>

    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>

看起来很荒谬(而且是一个明显的错误),但它确实有效。

由于

1 个答案:

答案 0 :(得分:7)

我不能说我完全理解为什么它不能像我们期望的那样工作,但在这些情况下我们可以使用Expression Blend来执行任务并查看它产生的标记。我已经完成了这个,这是一个基于你的样本的工作示例:

<Grid>
    <Grid.Resources>
        <Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="PART_Root" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" RenderTransformOrigin="0.5,0.5">
                            <Border.RenderTransform>
                                <TransformGroup>
                                    <ScaleTransform/>
                                    <SkewTransform/>
                                    <RotateTransform/>
                                    <TranslateTransform/>
                                </TransformGroup>
                            </Border.RenderTransform>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup Name="CommonStates">
                                    <VisualStateGroup.Transitions>
                                        <VisualTransition GeneratedDuration="0:0:1"/>
                                    </VisualStateGroup.Transitions>
                                    <VisualState Name="Normal"/>
                                    <VisualState x:Name="MouseOver">
                                        <Storyboard>
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="PART_Root">
                                                <EasingDoubleKeyFrame KeyTime="0" Value="2"/>
                                            </DoubleAnimationUsingKeyFrames>
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="PART_Root">
                                                <EasingDoubleKeyFrame KeyTime="0" Value="2"/>
                                            </DoubleAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>
    <Button Content="Button" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Style="{StaticResource ButtonStyle1}"/>
</Grid>

虽然Blend使用更通用的变换组,但我们可以看到的主要区别是故事板将元素和通过该元素的属性路径定位到缩放因子。