I am trying to add a initial animation when items are added to a list box.
For this I'm using Layoutstates, generated by blend inside the itemcontainerstyle:
<VisualStateGroup x:Name="LayoutStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.2"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="AfterLoaded"/>
<VisualState x:Name="BeforeLoaded">
<Storyboard>
<DoubleAnimation Duration="0" To="35" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="BeforeUnloaded">
<Storyboard>
<DoubleAnimation Duration="0" To="0.85" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
<DoubleAnimation Duration="0" To="0.85" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
my listbox looks like this:
<ListBox Grid.Row="1" ItemsSource="{Binding Days}" x:Name="Days"
HorizontalAlignment="Stretch"
SelectedItem="{Binding CurrentDay, Mode=TwoWay}"
ItemTemplate="{StaticResource TimeRecordByDayItemTemplate}"
ItemsPanel="{StaticResource ByMonthDaysItemsPanelTemplate}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemContainerStyle="{StaticResource DayListBoxItemStyle}" />
I just don't get any animation even though i was just following the channel9 tutorials step by step!
This is the first problem with my state manager, I am also encountering problems with datatriggers, that should go to a state when certain conditions are met, where some do work and some do not, but all of my bindings are correct!
Also all the animations do work in Expression Blend preview.
I can't make out the problem, I've had this so often with silverlight and animations copied from the simplest samples not working in the own environment (look here at channel 9)...
Thanks for you help!
Sounds like you need to add the items one by one once everything is loaded. Seems like a simple solution would be this in your view model:
public class MyViewModel
{
private string[] _items;
private ObservableCollection<string> _itemCollection;
public MyViewModel()
{
// meets requirement of loading items in constructor
_items = { "Johnny", "Thommy", "Jay", "Wommy" };
}
public ObservableCollection<string> Items
{
get
{
if (_itemCollection == null)
{
_itemCollection = new ObservableCollection<string>();
Dispatcher.Invoke(() => LoadItems());
}
return _itemCollection;
}
}
private void LoadItems()
{
foreach (var item in _items)
{
ItemCollection.Add(item);
}
}
}
Basically when the ListBox sets up the binding you queue up the adding of the items to the collection. This should have the items loaded at the right time so that they trigger your animations.
Related
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.
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 ?
I am trying to animate a control so that it's visibility is set to visible then animating the opacity from 0 to 1
However nothing happens, then after 1 second the control is show with an opacity of 1... I cannot see what i am doing wrong
This is the code i have tried
<Grid x:Name="layout_root" Margin="10">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Filtering">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1">
<VisualTransition.GeneratedEasingFunction>
<ElasticEase EasingMode="EaseInOut"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Disabled"/>
<VisualState x:Name="Enabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Duration="0:0:0" Storyboard.TargetName="filter_control" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="filter_control" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox x:Name="filter_control" Margin="0,0,0,10" Text="Filtering" Visibility="Collapsed" Opacity="0"/>
<ListView Grid.Row="1" ItemsSource="{Binding Posts}">
<ListView.View>
<GridView>
<GridViewColumn Width="100" Header="Date" DisplayMemberBinding="{Binding Date, StringFormat={}{0:dd/MM/yyyy}}"/>
<GridViewColumn Width="100" Header="Text" DisplayMemberBinding="{Binding Text}"/>
<GridViewColumn Width="100" Header="Value" DisplayMemberBinding="{Binding Value, StringFormat=F2}"/>
</GridView>
</ListView.View>
</ListView>
<Button Grid.Row="1" Content="v" FontFamily="Marlett" FontSize="14" VerticalAlignment="Top" HorizontalAlignment="Left" Click="ShowFilterClick"/>
</Grid>
As to the question of what you're doing wrong or why you see the behavior that you see: the storyboard for the Enabled state is the storyboard that the VSM uses while the VSGroup is in that state. You specify a transition storyboard for the group, though, and the VSM applies that when transitioning between states. So, when you put the VSGroup into the Enabled state, the VSM first plays the transition storyboard then uses the steady-state storyboard that you specify for the Enabled state. The transition storyboard is 1 sec, and that's why you're seeing the 1 sec delay and then the pop.
Something like the following is probably what you want. Note that the transition storyboard does the action/animation that you want, and the state storyboards just state the final values at which the animated properties should be held. Also, I apply the easing function to the double animation rather than to the entire VisualTransition -- it doesn't make sense to try to interpolate Visibility with an easing function.
<VisualStateGroup x:Name="Filtering">
<VisualStateGroup.Transitions>
<VisualTransition From="Disabled" To="Enabled" GeneratedDuration="0:0:1">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetName="filter_control" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0:0:1" Storyboard.TargetName="filter_control" Storyboard.TargetProperty="(UIElement.Opacity)" To="1">
<DoubleAnimation.EasingFunction>
<ElasticEase EasingMode="EaseInOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualTransition>
<!-- you could also have a transition from Enabled to Disabled -->
</VisualStateGroup.Transitions>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetName="filter_control" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0:0:0" Storyboard.TargetName="filter_control" Storyboard.TargetProperty="(UIElement.Opacity)" To="0"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Enabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetName="filter_control" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0:0:0" Storyboard.TargetName="filter_control" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
The Visibility enum is not an inherently animatable property. Generally only numeric properties are truly animatable, since WPF can fill in the spaces between keyframes. For example, it knows that an opacity halfway between the value of 0 and 1 is 0.5. It knows every possible value based on the current time.
If you animate from Visibility.Collapsed to Visibility.Visible over 1 second, it has no idea what to do at the 0.5 second mark or any other point in between. It only knows you're changing an enum from 1 value to another. If your transition time is 1 second, it waits till that second is up and then changes the value, so you never get to see the opacity animation happening.
You can try using FluidLayout. You enable it like so:
<VisualStateGroup x:Name="Filtering" ei:ExtendedVisualStateManager.UseFluidLayout="True">
You can also enable it using a toggle in the Blend UI.
FluidLayout animates layout changes for you. Collapsing or expanding an element affects the layout, so it can automatically animate those layout changes.
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'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?