Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate Insertions to ItemsControl

Tags:

animation

wpf

I'm finding WPF inscrutable at times. Given the following XAML how would one add triggers to animate (slide down, fade in) new items added to the ObservableCollection Timeline. I've seen various examples for list boxes but nothing for items control.

<Grid>
    <ScrollViewer>
        <ItemsControl Name="TimelineItem"
                      ItemsSource="{Binding Timeline}"
                      Style="{StaticResource TimelineStyle}"
                      ItemContainerStyle="{StaticResource TweetItemStyle}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid VerticalAlignment="Top"
                          HorizontalAlignment="Left">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Style="{StaticResource TweetImageColumnStyle}" />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <Rectangle Grid.Column="0"
                                   Style="{StaticResource TweetImageStyle}">
                            <Rectangle.Fill>
                                <ImageBrush ImageSource="{Binding ProfileImageUrl}" />
                            </Rectangle.Fill>
                        </Rectangle>
                        <StackPanel Grid.Column="1">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <TextBlock Grid.Column="0"
                                           Style="{StaticResource TweetNameStyle}"
                                           Text="{Binding Name}" />
                                <TextBlock Grid.Column="1"
                                           Style="{StaticResource TweetTimeStyle}"
                                           Text="{Binding TimeAgo}" />
                            </Grid>
                            <Controls:TextBlockMarkup Grid.Row="1"
                                                      Grid.Column="1"
                                                      Markup="{Binding MarkupText}"
                                                      Style="{StaticResource TweetStyle}" />
                        </StackPanel>
                        <Separator Grid.Row="2"
                                   Grid.ColumnSpan="2"
                                   Style="{StaticResource TweetSeparatorTop}" />
                        <Separator Grid.Row="3"
                                   Grid.ColumnSpan="2"
                                   Style="{StaticResource TweetSeparatorBottom}" />
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>
</Grid>
like image 762
Mike Ward Avatar asked Sep 29 '12 16:09

Mike Ward


1 Answers

It's been a while since I've animated WPF, but this should work by setting a DataTrigger in the DataTemplate of the ItemsControl for the Loaded Event.

A couple of notes:

  1. Add the following xaml to the DataTemplate of the ItemsControl
  2. Name the <Grid> inside the DataTemplate: "MyGrid"
  3. Add a RenderTransformOriginproperty to the MyGrid to set the Y origin at the top:
    • <Grid x:Name="MyGrid" RenderTransformOrigin="0.5,0">
  4. Be sure to include the Grid.RenderTransform attached property to your grid (see sample below)

Xaml

<DataTemplate.Resources>
    <Storyboard x:Key="ItemAnimation" AutoReverse="False">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyGrid" Storyboard.TargetProperty="(UIElement.Opacity)">
            <EasingDoubleKeyFrame KeyTime="0" Value="0" />
            <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyGrid" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
            <EasingDoubleKeyFrame KeyTime="0" Value="0" />
            <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</DataTemplate.Resources>

<DataTemplate.Triggers>
    <EventTrigger RoutedEvent="FrameworkElement.Loaded">
        <BeginStoryboard Storyboard="{StaticResource ItemAnimation}" />
    </EventTrigger>
</DataTemplate.Triggers>

Add the RenderTransform groups to your Grid

<!-- Include in the Grid -->
<Grid.RenderTransform>
    <TransformGroup>
        <ScaleTransform/>
    </TransformGroup>
</Grid.RenderTransform>

This should get you close enough so that you can customize it yourself. FWIW: I used Blend to build out the animation by editing the style of the ItemTemplate of the Timeline object.

One last note: The animation will occur when the window loads the ItemsControl for the first time, for each item in the original collection. And will occur for an individual item when it is added to the collection. This behavior is a bit wonky, so you could remove the explicit binding of the trigger in the xaml and bind the trigger in the code-behind after the ItemsControl or Window loads.

EDIT

  1. I've updated the example so that it should work with your XAML now.
  2. Added another animation to slide (sort of) the new item. Actually, it's growing from a size of 0% to 100%, starting from the top of the Y axis.
  3. Revised note #3 from above to include a RenderTransformOrigin property.
  4. Added note #4 to include the Grid.RenderTransform attached property.
like image 121
Metro Smurf Avatar answered Sep 28 '22 07:09

Metro Smurf