How would i go about setting a property that doesn't seem to have an animation type associated with it? Specifically, I'd like to change a control's VerticalAlignment whenever an EventTrigger is activated. Here's my current status/failed attempt:
<EventTrigger RoutedEvent="my:MenuHelper.MenuIsReversed">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="VerticalAlignment" Storyboard.TargetName="Bouncy_Bar">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="Top"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
Which yields this exception:
Cannot animate the 'VerticalAlignment' property on a
'System.Windows.Controls.Border' using a
'System.Windows.Media.Animation.ObjectAnimationUsingKeyFrames'. For
details see the inner exception.
Inner exception:
The animation(s) applied to the 'VerticalAlignment' property calculate
a current value of 'Top', which is not a valid value for the property.
I'm not sure if i'm improperly qualifying the VerticalAlignment type or if this is simply the wrong way to go about setting an atypical animation property.
Sorry, for the quick answer of my own question. I found that I wasn't laying out the XAML to specify the target type well enough. Here was the working result:
<EventTrigger RoutedEvent="pill:PillMenuHelper.MenuIsReversed">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Bouncy_Bar" Storyboard.TargetProperty="RenderTransform.Children[1].ScaleY" To="-1" Duration="0:0:.002"/>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="VerticalAlignment" Storyboard.TargetName="Bouncy_Bar">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<VerticalAlignment>Top</VerticalAlignment>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
Related
I have a textblock which should only show 2 lines of the text, while it is unselected. As soon as it gets selected, I want it to expand smoothly.
I started with something like:
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="Second"
Storyboard.TargetProperty="(TextBlock.MaxHeight)"
To="50.0" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
But the issue here is, that I don't know how big the text is.
You should be able to use From='0' instead, which would start the animation with a value of 0 and end with whatever the value of MaxHeight is. However, that raises a different problem, as MaxHeight defaults to infinity, which would make the animation far too fast. Adding an ObjectAnimationUsingKeyframes at the start that sets MaxHeight to ActualHeight might work to resolve this. Something like this:
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyframes
Storyboard.TargetName='Second'
Storyboard.TargetProperty='(TextBlock.MaxHeight)'>
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{Binding TargetName=Second, Path=ActualHeight}" />
</ObjectAnimationUsingKeyframes>
<DoubleAnimation
Storyboard.TargetName="Second"
Storyboard.TargetProperty="(TextBlock.MaxHeight)"
From="0" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
You can use DoubleAnimation to implement this. I have implemented this in a sample application.
<Window.Resources>
<Storyboard x:Key="OnGotFocus">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="textBox" Storyboard.TargetProperty="(FrameworkElement.Height)">
<EasingDoubleKeyFrame KeyTime="0:0:2">
<EasingDoubleKeyFrame.Value>
<System:Double>NaN</System:Double>
</EasingDoubleKeyFrame.Value>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnLostFocus">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="textBox" Storyboard.TargetProperty="(FrameworkElement.Height)">
<EasingDoubleKeyFrame KeyTime="0">
<EasingDoubleKeyFrame.Value>
<System:Double>NaN</System:Double>
</EasingDoubleKeyFrame.Value>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="30" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="UIElement.GotFocus" SourceName="textBox">
<BeginStoryboard Storyboard="{StaticResource OnGotFocus}" />
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.LostFocus" SourceName="textBox">
<BeginStoryboard x:Name="OnLostFocus_BeginStoryboard" Storyboard="{StaticResource OnLostFocus}" />
</EventTrigger>
</Window.Triggers>
Your code for textbox should be :
<TextBox x:Name="textBox"
Height="30"
HorizontalAlignment="Right"
Text="Hello World" />
This will animate the textbox to a specified height as soon as it gets focussed. I have added an animation to collapse it as well when it loses focus.
Hope this helps you.
I have the following XAML for a border trigger that uses a routed event
<Border.Triggers>
<EventTrigger RoutedEvent="MouseLeftButtonUp" EnterActions="">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="0" Duration="0:0:0.4" Storyboard.Target="{Binding ElementName=messageWriterDefinition}" Storyboard.TargetProperty="Height">
<DiscreteObjectKeyFrame >
<DiscreteObjectKeyFrame.Value>
<GridLength>20</GridLength>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
...
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
This trigger fires when the border and containing elements are clicked and animates cause the target to animate open from height of Zero to 200
The trigger works really well but each time the border receives the event the animation runs and the target animates open again (even if already open)
How can one add a condition to the trigger that effectively ignores the animation is the target already has a height greater than Zero?
You may use a DoubleAnimation instead of an ObjectAnimationUsingKeyFrames. By only setting its To property, but not From, the animation starts from the current property value. It requires that you also set an initial value of the Height of the Border:
<Border Height="20" ...>
<Border.Triggers>
<EventTrigger RoutedEvent="MouseLeftButtonUp">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height"
To="200" Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>
I'm making a Windows Phone 8 app and would like to first fade out and then -- and only then -- actually turn a UIElement's Visibility to "Collapsed". However, I can't figure out how to make them happen asynchronously.
I'm using Storyboards and Blend. Here are my storyboards to toggle my little "Popup" StackPanel:
<VisualStateGroup x:Name="PopupStates">
<VisualState x:Name="PopupDisplayed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Popup">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Popup" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PopupHidden">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Popup">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Popup" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
How can I time my storyboard events to happen one-after-another?
You can set the BeginTime property of the second animation to be the duration of the first.
From the MSDN page:
The BeginTime property is useful for creating timelines that play in a sequence: by increasing the BeginTime of successive timelines that share the same parent Storyboard, you can stagger their play times.
The example on that page shows how you use it:
<!-- Animates the rectangle's width. No
BeginTime specified so by default begins
as soon as it's parent (the Storyboard)
begins. -->
<DoubleAnimation
Storyboard.TargetName="MyAnimatedRectangle"
Storyboard.TargetProperty="Width"
To="300" Duration="0:0:1" />
<!-- Animates the rectangle's opacity. A BeginTime
of 3 seconds specified so begins three seconds
after the Storyboard begins (total of 5 seconds)-->
<DoubleAnimation BeginTime="0:0:3"
Storyboard.TargetName="MyAnimatedRectangle"
Storyboard.TargetProperty="Opacity"
To="0" Duration="0:0:1" />
The first animation starts as soon as the Storyboard starts and lasts 1 second. The second animations starts 3 seconds after the Storyboard starts and also lasts 1 second.
So in your example you'd set the duration of the animation that fades the popup to 2 seconds (say):
<DoubleAnimation Duration="0:0:2" To="0"
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="Popup" d:IsOptimized="True"/>
and then set the begin time of the animation that sets the visibility to 2 seconds:
<ObjectAnimationUsingKeyFrames BeginTime="0:0:2"
Storyboard.TargetProperty="(UIElement.Visibility)"
Storyboard.TargetName="Popup">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
I have a set of controls (Button, ToggleButton) I want to have the same style, so I have created a few gradient brushes for normal/disabled/enabled states in my ResourceDictionary, e.g. "ButtonFillBrush", "ButtonFillMouseOverBrush" etc. These are defined as global reusable Brush Resources.
I know it is possible to change individual stops of a gradient in a animation inside a state, for example:
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0" To="#FF041D06" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="path" d:IsOptimized="True"/>
<ColorAnimation Duration="0" To="#FF118519" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="backgroundRectangle" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
Now, I know it is possible in the VisualState Manager to do something like:
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0" To="ButtonFillMouseOverBrush" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush)" Storyboard.TargetName="backgroundRectangle" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
Thanks!
Update: using the answer about the referring with the StaticResource and some more searching: http://wildermuth.com/2008/07/18/Animating_Brushes_with_ObjectAnimationUsingKeyFrames
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="backgroundRectangle"
Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource ButtonFillMouseOverBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
So, it would be nice to have a BrushAnimation or something...
Rogier
You can find more information regarding Resource Dictionaries & the use of them here. However for your color animation question a lot of information regarding Silverlight animations (including color animations) can be found on this link Silverlight Animations Quickstart
i want to be able to change the tooltip on Checked and Unchecked, i tried:
<VisualState x:Name="Checked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="ToolTipService.ToolTip" Storyboard.TargetName="btn">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:String>Button is checked</System:String>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
but it doesnt seem to work, what am i doing wrong?
Once before I also, ran into the same problem. So, I left the VSM away. I made the ToolTip as Resource and applied it for the control. Using the internal state change properties I updated the tooltip value using a converter.
HTH.