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?
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.)