Silverlight: use GradientBrush resource for state animation - silverlight

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

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.

Change the Visibility and then change the Opacity of a Silverlight/WPF UIElement

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>

Silverlight, VisualStateManager gotostate doesn't work with datatemplates

I have a button with name "PART_closeButton" inside ContentPresenter. I am defining some visual states for my button.
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0" To="1"
Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PART_closeButton" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Normal">
<Storyboard>
<DoubleAnimation Duration="0" To="0.7" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PARTcloseButton" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
So everything is working for me. When I mouse over on button it becomes semitransparent.
But if I load some datatemplate for contentpresenter which also contains button with that same name, visual states does not react anymore. (mouseOver event is handled for that button also and it fires).
goToState is not working.
I know that actual button object is changing, VisualState is connected with button with TargetName. So new button have the same name, why statemanager is not working ?

Set VerticalAlignment in an EventTrigger

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>

Silverlight: VisualState Animation Being Overridden Somehow

I've got a rather complicated custom control that would boggle your mind if I showed you all of the code. ;) In general it's a panel displaying multiple controls. You can think of it as a custom list box. (Please don't tell me to use a listbox, I've been there and it doesn't meet my needs completely).
So, I set some animations in a VisualStateManager. Here's what happens:
When I hover over one of my child controls, I expect the MouseOver state to fire. It does.
When I select one of my child controls I expect the Selected state to fire and it does.
When I select a different child control, the Selected state fires as well
When I go back to my first child control I selected, and select it, the Selected state is shown to fire (by debug statements in my code) but the MouseOver animation is displayed.
Is there some issue with animations able to be overridden somehow or a problem between the MouseOver and Selected states I'm not aware of?
Here's my VSM markup:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.150000" Storyboard.TargetName="Backdrop" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="0" Value="DarkGray"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.150000" Storyboard.TargetName="Backdrop" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="0" Value="Yellow"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectedStates">
<VisualState x:Name="Unselected">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="0" Duration="1" Storyboard.TargetName="Backdrop" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="0" Value="Purple"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Selected">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="0" Duration="1" Storyboard.TargetName="Backdrop" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="0" Value="Green"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
And here's my GoToState() logic:
private void GoToState(bool useTransitions)
{
TestingVariables("Inside GoToState");
if (_isSelected)
{
System.Diagnostics.Debug.WriteLine(_thumbnail.ShortFileName + " firing Selected VSM");
VisualStateManager.GoToState(this, "Selected", useTransitions);
}
else if (_wasSelected)
{
_wasSelected = false;
System.Diagnostics.Debug.WriteLine(_thumbnail.ShortFileName + " firing Unselected");
VisualStateManager.GoToState(this, "Unselected", useTransitions);
}
else if (_isMouseOver)
{
System.Diagnostics.Debug.WriteLine(_thumbnail.ShortFileName + " firing MouseOver VSM");
VisualStateManager.GoToState(this, "MouseOver", useTransitions);
}
else
{
System.Diagnostics.Debug.WriteLine(_thumbnail.ShortFileName + " firing Normal VSM");
VisualStateManager.GoToState(this, "Normal", useTransitions);
}
}
So, I can see which VisualStateManger.GoToState() method is fired and the call to TestingVariables() is just a method I use to write out the conditional flags I'm using to determine which visual state to fire.
Thanks in advance.
See answer to this question: Custom styled listbox - how can I keep the style for a selected item?

Resources