7

I want to create user control based on ListBox (ListView) with such animation: the items in listbox do not loads all at once, they have to load step-by-step (item-by-item, first then second, then third, etc.) with some timeout between them.

How can I do that?

H.B.
  • 166,899
  • 29
  • 327
  • 400
JaneKate
  • 71
  • 1
  • 3

1 Answers1

10

You could use a Blend SDK behavior for this:

<ListBox ItemsSource="{Binding Collection, Source={StaticResource SampleData}}">
    <i:Interaction.Behaviors>
        <b:FadeAnimateItemsBehavior Tick="0:0:0.05">
            <b:FadeAnimateItemsBehavior.Animation>
                <DoubleAnimation From="0" To="1" Duration="0:0:0.3"/>
            </b:FadeAnimateItemsBehavior.Animation>
        </b:FadeAnimateItemsBehavior>
    </i:Interaction.Behaviors>
</ListBox>
class FadeAnimateItemsBehavior : Behavior<ListBox>
{
    public DoubleAnimation Animation { get; set; }
    public TimeSpan Tick { get; set; }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
    }

    void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e)
    {
        IEnumerable<ListBoxItem> items;
        if (AssociatedObject.ItemsSource == null)
        {
            items = AssociatedObject.Items.Cast<ListBoxItem>();
        }
        else
        {
            var itemsSource = AssociatedObject.ItemsSource;
            if (itemsSource is INotifyCollectionChanged)
            {
                var collection = itemsSource as INotifyCollectionChanged;
                collection.CollectionChanged += (s, cce) =>
                    {
                        if (cce.Action == NotifyCollectionChangedAction.Add)
                        {
                            var itemContainer = AssociatedObject.ItemContainerGenerator.ContainerFromItem(cce.NewItems[0]) as ListBoxItem;
                            itemContainer.BeginAnimation(ListBoxItem.OpacityProperty, Animation);
                        }
                    };

            }
            ListBoxItem[] itemsSub = new ListBoxItem[AssociatedObject.Items.Count];
            for (int i = 0; i < itemsSub.Length; i++)
            {
                itemsSub[i] = AssociatedObject.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
            }
            items = itemsSub;
        }
        foreach (var item in items)
        {
            item.Opacity = 0;
        }
        var enumerator = items.GetEnumerator();
        if (enumerator.MoveNext())
        {
            DispatcherTimer timer = new DispatcherTimer() { Interval = Tick };
            timer.Tick += (s, timerE) =>
            {
                var item = enumerator.Current;
                item.BeginAnimation(ListBoxItem.OpacityProperty, Animation);
                if (!enumerator.MoveNext())
                {
                    timer.Stop();
                }
            };
            timer.Start();
        }
    }
}

Tick specifies the time between when items are started to fade in. Animation is the animation applied to the Opacity for the fade in, it can be set in Xaml to be very costomizable (e.g. easing functions and fade time).

Edit: Added new item fade in (only works if ItemsSource is used and implements INotifyCollectionChanged)

(Use code snippets like this with caution, if at all. This code is mainly for demonstration purposes and giving a general idea of how this can be approached. This could probably also be done using Blend 4's native FluidMoveBehaviors if availabe.)

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • Thanks for such qualified answer! At last, how could I animate items without Opacity property, but with Visibility property. I tried so much but can't do that. – JaneKate May 16 '11 at 12:43
  • You can animate Visibility using a [`ObjectAnimationUsingKeyFrames`](http://msdn.microsoft.com/en-us/library/system.windows.media.animation.objectanimationusingkeyframes%28v=vs.95%29.aspx), in [this answer](http://stackoverflow.com/questions/5587374/animating-wpf-datagrid-row-details/5588022#5588022) you can see an example. – H.B. May 16 '11 at 12:47
  • Thanks! It was so tried to find answer becouse such animation (or behavior) has not special name (accordion? - may be the best!). – JaneKate May 16 '11 at 12:51
  • Glad it helped. If this answers your question you could accept it by clicking the checkmark outline on the left of my answer. – H.B. May 16 '11 at 12:55
  • How would I use this for a canvas full of shapes? – George R Feb 02 '12 at 12:14
  • @GeorgeR: You use an `ItemsControl` and set its `ItemsPanel` to a `Canvas`, then you can bind the `ItemsSource` and apply such a behavior to it (behavior target type needs to be changed), – H.B. Feb 02 '12 at 13:51