I am trying to make use of interactivity and interactions libraries in wpf app. I need it to work on a grid, and it works well, but now I need this stuff in multiple grids and I cant find a way of reusing it. Here is the xaml
<Grid>
<i:Interaction.Behaviors>
<ei:DataStateBehavior Binding="{Binding KeepAlive}"
FalseState="InactiveState"
TrueState="ActiveState"
Value="false" />
</i:Interaction.Behaviors>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="ActiveState" />
<VisualState x:Name="InactiveState">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="ActiveContainer"
Storyboard.TargetProperty="(Control.IsEnabled)">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<system:Boolean>False</system:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="InactiveContainer"
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border>
<Grid>
Content comes here, Texboxes, labels when active or inactive etc.
</Grid>
</Border>
</Grid>
It works great, but how can I refactor the above code so I can reuse the exact same behaviour on multiple grids?
Thank you
A few approach immediately come up: style or resource. But Blend behavior cannot work when declared in resources. You can use attached property. See:
How to add a Blend Behavior in a Style Setter
I created generic behaviour, from which you could simply inherit and add to your style
see my answer below
https://stackoverflow.com/a/31292989/4711853
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>
Using Visual state manager, How to change the Data for a Path. i have changed it by ObjectAnimationUsingKeyFrames in Silverlight but the same cant be used in WPF. Below i got an error that cant find the Target property "Data"..
Any Idea on this?
<Storyboard BeginTime="0">
<ObjectAnimationUsingKeyFrames BeginTime="0"
Duration="1"
Storyboard.TargetName="path"
Storyboard.TargetProperty="Data">
<DiscreteObjectKeyFrame KeyTime="0" Value="M2.1299944,9.9798575L55.945994,9.9798575 35.197562,34.081179 35.197562,62.672859 23.428433,55.942383 23.428433,33.52121z M1.3001332,0L56.635813,0C57.355887,0,57.935946,0.5891428,57.935946,1.3080959L57.935946,2.8258877C57.935946,3.5448422,57.355887,4.133985,56.635813,4.133985L1.3001332,4.133985C0.58005941,4.133985,-2.3841858E-07,3.5448422,0,2.8258877L0,1.3080959C-2.3841858E-07,0.5891428,0.58005941,0,1.3001332,0z" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
You would have to write it this way:
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="path"
Storyboard.TargetProperty="Data">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Geometry>M2.1299944,9.9798575L55.945994,9.9798575 35.197562,34.081179 35.197562,62.672859 23.428433,55.942383 23.428433,33.52121z M1.3001332,0L56.635813,0C57.355887,0,57.935946,0.5891428,57.935946,1.3080959L57.935946,2.8258877C57.935946,3.5448422,57.355887,4.133985,56.635813,4.133985L1.3001332,4.133985C0.58005941,4.133985,-2.3841858E-07,3.5448422,0,2.8258877L0,1.3080959C-2.3841858E-07,0.5891428,0.58005941,0,1.3001332,0z</Geometry>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
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>
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