Animating the transition from Pressed to Normal button state - wpf

My Pressed state is lowering the opacity of the Button content.
I would like to animate the transition back from Pressed to Normal, so that it takes 3 seconds to happen. I tried defining a VisualTransition but it doesn't work. Pressing my button immediately goes back to Normal, I don't see the opacity gradually coming back from 0.5 to 1.
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition From="Pressed"
To="Normal"
GeneratedDuration="0:0:3" />
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="ContentContainer">
<DiscreteObjectKeyFrame KeyTime="0"
Value="0.5" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
I would like to know what I'm doing wrong.

Is it not working on phone or within dev environment using mouse?
If the latter, have you tried changing your VisualTransition to Pressed->MouseOver? With mouse it isn't possible to go from pressed->normal because mouse will still be the over.
Apart from that possibility, everything looks ok at first glance.
(A useful resource I've found is http://samples.msdn.microsoft.com/Silverlight/SampleBrowser/index.htm#/?sref=CustomTemplateSamples&id=4, which although for SilverLight should still be useful for WPF)

Related

wpf usercontrol states, modifying height

I am a little bit confused of states and animations in WPF.
I would like to make a usercontrol. This usercontrol will contains (inside the main grid) 2 another grid. One of them would be HEADER and second one will be CONTENT. If user click on header, content will expand, otherwise will be collapsed. And i would like to animation that expanding (Slide down the content from the header).
Basicaly i would like to do that by states (for future purpose). Problem is, if i add the states and i am using the slide efect with transformation, the content of this grid (CONTENT GRID) is transformed as well. So i would like to use the states with modifying just the height of the element. If u modify only the element, no animation appear and it just change its height at once.
The hierarchy looks like:
--- wrapper grid
------ header grid
--------- content of header
------ content grid
--------- content of content grid (like buttons, labels, etc)
The visualstates looks like:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Expanded"/>
<VisualState x:Name="Collapsed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="grid">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<x:Double>0</x:Double>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Any advice to see the expanding and collapsing the grid with modifying height by states?
With animation only it works perfect, but its better for me to do it with states, how i said, for future purpose.
Maybe i found a answer. For now it works but i am trying to understanding that changes.
code of visualstates in here:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Expanded">
<Storyboard>
<DoubleAnimation EnableDependentAnimation="True" Storyboard.TargetName="grid" Storyboard.TargetProperty="(FrameworkElement.Height)" From="0" To="366" Duration="0:0:0.600" />
</Storyboard>
</VisualState>
<VisualState x:Name="Collapsed">
<Storyboard>
<DoubleAnimation EnableDependentAnimation="True" Storyboard.TargetName="grid" Storyboard.TargetProperty="(FrameworkElement.Height)" From="366" To="0" Duration="0:0:0.600" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
The important line is:
<DoubleAnimation EnableDependentAnimation="True" Storyboard.TargetName="grid" Storyboard.TargetProperty="(FrameworkElement.Height)" From="366" To="0" Duration="0:0:0.600" />
I found its needed to have EnableDependantAnimation true.
Now it works as a charm, but i do not like that FROM TO set. But its possibly the best i can do in here.

VSM CommonStates for Button work differently for touch and mouse

I have a very simple visual state manager for Button which animates the color of a border and zooms the image content of a button to the Pressed state. This works when pressed with the mouse, but when using a touch screen the Pressed state is only reached after the finger is smudged over the button (some dragging occurs over the face of the button).
I looked at all the CommonStates for Button, but there is no Touched state. Anything I'm overlooking?
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.05" />
<VisualTransition GeneratedDuration="0:0:0.1" To="Pressed" />
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="ButtonBorder" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#A9CC3D"/>
<DoubleAnimation Storyboard.TargetName="GrayBorder" Storyboard.TargetProperty="(Border.Background).(ImageBrush.RelativeTransform).(ScaleTransform.ScaleX)" To="1.1"/>
<DoubleAnimation Storyboard.TargetName="GrayBorder" Storyboard.TargetProperty="(Border.Background).(ImageBrush.RelativeTransform).(ScaleTransform.ScaleY)" To="1.1"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
The odd thing is that before we had it working using ControlTemplate.Triggers.
The problem is that by default Windows maps touch hold to right click. Check the following Stackoverflow discussion on how to disable this behavior on a control/window level.
Disable a right click (press and hold) in WPF application.

Binding and VisualStateManager do not work together

I have VisualStateManager to control when the State occurs, the control is enabled:
Here is the property of the state (string):
states:StateManager.VisualStateProperty="{Binding SomeProp}"
Here the VisualStateManager:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualState x:Name="MyName">
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.IsEnabled)" Storyboard.TargetName="MyTextBox">
<DiscreteBooleanKeyFrame KeyTime="0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="HerName">
<Storyboard>
...
</Storyboard>
</VisualState>
<VisualState x:Name="This">
<Storyboard>
...
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Here my text box:
<TextBox Name="MyTextBox" />
My question is: What happens when I add the TextBox the following line:
IsEnable= {Binding isProp}// isProp = bool
The way I see it, it eliminates the IsEnable of the TextBox and not refers to him, only to State.
Is this true? And is there a way they both work?
In your case, the Animation will take precedence over the binding, but only as long as the Animation's timeline is running. That is, when the visual state is "MyName", the animation will control the IsEnabled property; otherwise, the binding will.
You may be interested in this list of Dependency Property Value Precedence. The binding counts as a "Local value" and is of lower precedence than the animation.

Why is the ColorAnimation for Checked state not persisting color after the MouseOver state is triggered?

I encountered an issue with a ControlTemplate for ToggleButton I created.
When the button is Checked, a ColorAnimation is triggered and the control's background changes color. However, if the user enters the MouseOver state, another animation is triggered that affects the button's background as well.
When the mouse is no longer in the MouseOver state, the control does not return to the color it should be while it is in the Checked state. I'm not sure why this does not persist when the MouseOver state is triggered.
The VisualStateManager portion of my ControlTemplate looks sorta like this:
<VisualStateManger.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"></VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundBorder"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="Gold" Duration="0:0:0.3" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CheckedStates">
<VisualState x:Name="Checked">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundBorder"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="PaleGoldenrod" Duration="0:0:0.3" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
My workaround for the issue I was having involved creating a Grid that enclosed the Border.
For the CommonStates I made animation changes to the Border.Background and for the CheckedStates I made animation changes to the Grid.Background.
It achieves the visual effect I was looking for.

How to test VisualStateManager states?

How do I check the current states of a control? VisualStateManager allows me to set it from the control itself, but I can't see any way of reading it back?
If you have one group, or wants to find the state in a specific group you can do something like :
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Group1">
<VisualState x:Name="State1">
<Storyboard>
</Storyboard>
</VisualState>
<VisualState x:Name="State2">
<Storyboard>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
and in your code you can do something like :
var state = Group1.CurrentState;
Console.WriteLine(state.Name);

Resources