VisualStateManager and generated transitions

When I think I understand VisualStateManager , something proves that I'm wrong.

I am using WPF 4 and I am trying to simply enlarge an element with the mouse and compress it when leaving the mouse. I decided that I would just define each state in a VisualStateGroup , and then specify VisualTransition with 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> 

Since I have catch-all VisualTransition with GeneratedDuration , I expected VSM to generate intermediate animations. That is, the mouse over the control should animate the properties of the ScaleTransform from 1 to 1.5 for 1 second. The same with washing. Instead, there is a delay of 1 second, and then the ScaleTransform properties instantly snap to 1.5 or vice versa to 1.

If I manually specify the transitions as follows, I get the desired behavior:

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

But why should I do this? I thought that the whole point of the generated transitions was that the transition, as you know, will be generated. What i don't understand here?

UPDATE . According to the answers, Rika Blend generates what works. So, working backwards, I decided that it was really a fact that I only refer to ScaleTransform , and not through the UIElement that contains it. I changed my XAML to the following and it works as expected:

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

Seems funny (and an obvious mistake), but it works.

thanks

+8
animation wpf transitions visualstatemanager
source share
1 answer

I can’t say that I fully understand why it doesn’t work the way we expected, but in these situations we can use Expression Blend to complete the task and see what markup it produces. I did this and here is a working example based on your example:

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

Although Blend uses a more general group of transformations, the main difference that we see is that the storyboard is aimed at the element and the path of the properties through this element to the scaling factors.

+6
source share

All Articles