Reputation: 2262
When a button is pressed the state transitions are as follows:
Normal -> MouseOver -> Normal -> Pressed -> Normal -> MouseOver
The problem I have is that the MouseOver
and the Pressed
state have a lot in common visually and the transition to normal between these messes up the animation. As a more practical example I have a button that by default has a black border and it has a green border in the MouseOver
and Pressed
state. When I press it it first changes from green to black and then to green, which is not desirable. Is there any way to either skip the Normal
state in this situation or make it look bad?
This is the template of the button:
<Button Command="{Binding PlayScene}" Width="220">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border"
BorderThickness="3"
Margin="2 0"
BorderBrush="{DynamicResource ButtonBorderBrush}"
RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Border.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.2"/>
<VisualTransition GeneratedDuration="0:0:0.2" To="Pressed">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
<VisualTransition GeneratedDuration="0:0:0.1" To="MouseOver"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush)" Storyboard.TargetName="border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource HighlightBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(Brush.RelativeTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="border">
<EasingDoubleKeyFrame KeyTime="0" Value="1.1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(Brush.RelativeTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="border">
<EasingDoubleKeyFrame KeyTime="0" Value="1.1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="border">
<EasingDoubleKeyFrame KeyTime="0" Value="0.95"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="border">
<EasingDoubleKeyFrame KeyTime="0" Value="0.95"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush)" Storyboard.TargetName="border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource HighlightDarkBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border.Background>
<ImageBrush ImageSource="{Binding Image}" Stretch="UniformToFill">
<ImageBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform CenterY="0.5" CenterX="0.5"/>
<TranslateTransform/>
</TransformGroup>
</ImageBrush.RelativeTransform>
</ImageBrush>
</Border.Background>
<ContentPresenter x:Name="contentPresenter" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
Upvotes: 3
Views: 196
Reputation: 1962
The Visual State Transitions are run prior to the entering the actual state. Since you have not set a brush in the transitions, they are defaulting back to the base value (in this case ButtonBorderBrush). I'm not entirely sure of your desired outcome, but my example assumes you want to immediately change color from HighlightBrush (in the MouseOver state) to HighlightDarkBrush (in the Pressed state), obviously if a fade from one color to another is desired the storyboard animation animation can be changed to implement that.
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.2"/>
<VisualTransition GeneratedDuration="0:0:0.2" To="Pressed">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush)" Storyboard.TargetName="border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource HighlightDarkBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition GeneratedDuration="0:0:0.1" To="MouseOver"/>
Essentially you need to add the Storyboard to both the Pressed state and to=Pressed transition. If you only add it to the transition, the color will revert back once it enters the State.
Also note, that while it may look as if the transitioning sequence is
MouseOver -> Normal-> Pressed
that is in fact not the case. You can see this for yourself if you gave the Normal state some value (currently it is using the base values) like this:
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush)" Storyboard.TargetName="border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TestBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
If (for example) TestBrush is a red brush, the border will only be red in when the mouse is not over. In between states, it will be black (ButtonBorderBrush)
Upvotes: 3