Is this the most straightforward way to handle this functionality? - silverlight

I've created a button which changes its appearance when in different states, the way I do this (as a single example) when the button is being clicked down on:
<vsm:VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.Background).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="Green"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform). (TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0.94"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform). (TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0.94"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
Is there a way I could accomplish this using less code? I Just want the scale and colour to both instantly change to green when pressed, is there a way to do it without using keyframes?
Thanks for any help!

This can be written so:
<ColorAnimation Duration="0" To="Green" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.Background).(SolidColorBrush.Color)" />
<DoubleAnimation Duration="0" To="0.94" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" />
<DoubleAnimation Duration="0" To="0.94" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" />
General animations are easier to understand and to use, and there is very few cases when frame animations can be used isnted of general animations.

Related

WPF Storyboard animation isn't fluid

Here's what I'm trying to do:
Make control1 Visible, make control2 Collapsed, animate opacity from 1 to 0 on control 1 over .8 seconds.
immediately after that is done, do this:
Make control1 Collapsed, make control2 Visible, animate opacity from 0 to 1 on control2 over .8 seconds.
I just can't get it to be fluid and I'm out ideas. here's what I have:
<Storyboard x:Key="sb">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.8000000" Storyboard.TargetName="MainTabControl" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.8000000" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.8000000" Storyboard.TargetName="MainTabControl" Storyboard.TargetProperty="(UIElement.Opacity)">
<LinearDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
<LinearDoubleKeyFrame KeyTime="00:00:00.8000000" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00.8000000" Duration="00:00:00.8000000" Storyboard.TargetName="SearchProjectsView" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Collapsed}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.8000000" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00.8000000" Duration="00:00:00.8000000" Storyboard.TargetName="SearchProjectsView" Storyboard.TargetProperty="(UIElement.Opacity)">
<LinearDoubleKeyFrame KeyTime="00:00:00.0000000" Value="0"/>
<LinearDoubleKeyFrame KeyTime="00:00:00.8000000" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
It isn't clear from your question why you would animate the Opacity and Visbility at the same time, but your problem is that the animation of the Visibility of the second control should start immediately, not after 0.8 seconds.
This should work:
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="MainTabControl" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.8" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="SearchProjectsView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.8" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation
Storyboard.TargetName="MainTabControl" Storyboard.TargetProperty="Opacity"
From="1" To="0" Duration="0:0:0.8"/>
<DoubleAnimation
Storyboard.TargetName="SearchProjectsView" Storyboard.TargetProperty="Opacity"
From="0" To="1" BeginTime="0:0:0.8" Duration="0:0:0.8"/>
</Storyboard>

Animation not firing last part

I have the following code:
<Storyboard x:Key="CounterStoryboard" >
<!-- Panel appear -->
<ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetName="CounterPanel" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<!-- 3-->
<DoubleAnimation
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="CounterLabel3" From="1" To="0" Duration="0:0:1" BeginTime="0:0:0">
</DoubleAnimation>
<!-- 2 -->
<DoubleAnimation
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="CounterLabel2" From="0" To="1" Duration="0:0:0" BeginTime="0:0:1">
</DoubleAnimation>
<DoubleAnimation
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="CounterLabel2" From="1" To="0" Duration="0:0:1" BeginTime="0:0:1">
</DoubleAnimation>
<!-- 1 -->
<DoubleAnimation
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="CounterLabel1" From="0" To="1" Duration="0:0:0" BeginTime="0:0:2">
</DoubleAnimation>
<DoubleAnimation
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="CounterLabel1" From="1" To="0" Duration="0:0:1" BeginTime="0:0:2">
</DoubleAnimation>
<!-- Panel disappear -->
<ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetName="CounterPanel" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:3" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
This acts like a counter, from 3 to 1. Everything works fine, except from the last part. The Panel disappear is not working. It should make the panel invisible, but it's still there...
What I'm doing wrong?
NOTE: I call the storyboard like this:
sb = (Storyboard)FindResource("CounterStoryboard");
sb = sb.Clone();
sb.Completed += sb_Completed;
sb.Begin(this);
Your last animation has a Duration of 0:0:0 yet you set KeyTime to 0:0:3 which is beyond duration time. You can change KeyTime to 0:0:0 and set BeginTime to 0:0:3
<ObjectAnimationUsingKeyFrames Duration="0:0:0" BeginTime="0:0:3" Storyboard.TargetName="CounterPanel" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>

VisualStateManager doesn't skip 'non-generated' transitions

The VisualState tools in Blend / WPF / Silverlight are great but I think we can all agree that that are trés buggy on occasion. Here is an example and I would like some clarification / a workaround / fix.
Consider a bunch of visual states defined like this:
<VisualState x:Name="Hidden">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Revealed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Now create a series of trigger to kick switch to these states but select to ignore transition.
The transitions still play. It seems that the visual state manager sees storyboard with more than one contiguous keyframe and plays the whole thing rather than skipping-to-fill when transitions are not used.
The effect I am going for is a 2 stage hide/reveal where the content is faded out and then shrunk. Unfortunately, this means that the state 'transition' will always be played, regardless of my decision to ignore transitions.
Am I being stupid or is this a bug? Is there a workaround?
EDIT - is it better in this case to use an acute easing function to "delay" a transition?
The Storyboard declared inside a VisualState is the Storyboard that plays while the VSM is in that state.
The transitions you're talking about ignoring are Storyboards that play while transitioning from VisualState to VisualState. These are specified separately in a VisualStateGroup.Transitions section.
So, something like:
<VisualStateGroup x:Name="Something">
<VisualState x:Name="Hidden">
<VisualState x:Name="Revealed">
<VisualStateGroup.Transitions>
<VisualTransition From="Hidden" To="Revealed">
<Storyboard>
...
<Storyboard>
</VisualTransition>
<VisualTransition From="Revealed" To="Hidden">
<Storyboard>
...
<Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
</VisualStateGroup>
And fill in the appropriate animations inside the Storyboards.
After this, when you pass in false to the useTransitions parameter of the VisualStateManager's GoToState or GoToElementState methods, you won't see the transitions.

How to use one animation for several controls in Silverlight

Im just studing silverlight(in C#) and i got a problem.
I have 14 rectangles and their width/Height are set to "Auto". I want to creat animation on MouseEnter/MouseLeave. Animation will be just changing the width/Height. I did it using Expression Blend for Silverlight 5, and everything is ok but it made HUGE code. Can i make some resourse animation for all rectangles ?
This is the XAML code made by Blend, and i have 14 such blocks
<Storyboard x:Name="BigTableOne_MouseEnter">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="Table1">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1.04"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="Table1">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1.04"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="BigTableOne_MouseLeave">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="Table1">
<EasingDoubleKeyFrame KeyTime="0" Value="1.04"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="Table1">
<EasingDoubleKeyFrame KeyTime="0" Value="1.04"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
All your storyboards have same content besides "Storyboard.TargetName" property.So you can just delete this property and set it at runtime dynamically.
You can find more detail here.

Is it possible to animate a LinearGradientBrush in WPF?

Is it possible to animate the StartPoint or EndPoint of a LinearGradientBrush? If so, what is the type of the Storyboard object used to animate the Points, as when I try the following I get "0,1" is not a valid value for Double, and I do realize I shouldn't be using the DoubleAnimationUsingKeyFrames type.
Current Code:
<UserControl.Triggers>
<EventTrigger RoutedEvent="UserControl.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="Path1"
Storyboard.TargetProperty="(Path.Stroke).(LinearGradientBrush.StartPoint)">
<SplineDoubleKeyFrame KeyTime="00:00:0" Value="0,1"/>
<SplineDoubleKeyFrame KeyTime="00:00:2" Value=".5,.5"/>
<SplineDoubleKeyFrame KeyTime="00:00:4" Value="1,0"/>
<SplineDoubleKeyFrame KeyTime="00:00:6" Value=".5,.5"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="Path1"
Storyboard.TargetProperty="(Path.Stroke).(LinearGradientBrush.EndPoint)">
<SplineDoubleKeyFrame KeyTime="00:00:0" Value="1,0"/>
<SplineDoubleKeyFrame KeyTime="00:00:2" Value=".5,.5"/>
<SplineDoubleKeyFrame KeyTime="00:00:4" Value="0,1"/>
<SplineDoubleKeyFrame KeyTime="00:00:6" Value=".5,.5"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</UserControl.Triggers>
Yes. Just use "PointAnimationUsingKeyFrames" and "SplinePointKeyFrame" in your example above. It should work.

Resources