El fundido de entrada es fácil, pero para el fundido de salida los elementos deberán permanecer en la lista fuente hasta que se complete la animación (como usted dijo).
Si todavía queremos poder usar la fuente ObservableCollection
normalmente (Agregar/Quitar etc.) entonces tendríamos que crear una colección espejo que esté constantemente sincronizada con la colección fuente con un retraso para eliminar hasta la animación esta completado. Esto se puede hacer con el evento CollectionChanged
.
Aquí hay una implementación que hice de esto, usando un comportamiento adjunto. Se puede usar para ItemsControl
, ListBox
, DataGrid
o cualquier otra cosa que se derive de ItemsControl
.
En lugar de Encuadernar ItemsSource
, enlazar la propiedad adjunta ItemsSourceBehavior.ItemsSource
. Creará un espejo ObservableCollection
usando Reflection, use el espejo como ItemsSource
y maneje las animaciones FadeIn/FadeOut
.
Tenga en cuenta que no he probado esto exhaustivamente y que podría haber errores y varias mejoras que se pueden hacer, pero funcionó muy bien en mis escenarios.
Uso Muestra
<ListBox behaviors:ItemsSourceBehavior.ItemsSource="{Binding MyCollection}">
<behaviors:ItemsSourceBehavior.FadeInAnimation>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0.0"
To="1.0"
Duration="0:0:3"/>
</Storyboard>
</behaviors:ItemsSourceBehavior.FadeInAnimation>
<behaviors:ItemsSourceBehavior.FadeOutAnimation>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="0.0"
Duration="0:0:1"/>
</Storyboard>
</behaviors:ItemsSourceBehavior.FadeOutAnimation>
<!--...-->
</ListBox>
ItemsSourceBehavior
public class ItemsSourceBehavior
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.RegisterAttached("ItemsSource",
typeof(IList),
typeof(ItemsSourceBehavior),
new UIPropertyMetadata(null, ItemsSourcePropertyChanged));
public static void SetItemsSource(DependencyObject element, IList value)
{
element.SetValue(ItemsSourceProperty, value);
}
public static IList GetItemsSource(DependencyObject element)
{
return (IList)element.GetValue(ItemsSourceProperty);
}
private static void ItemsSourcePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
ItemsControl itemsControl = source as ItemsControl;
IList itemsSource = e.NewValue as IList;
if (itemsControl == null)
{
return;
}
if (itemsSource == null)
{
itemsControl.ItemsSource = null;
return;
}
Type itemsSourceType = itemsSource.GetType();
Type listType = typeof(ObservableCollection<>).MakeGenericType(itemsSourceType.GetGenericArguments()[0]);
IList mirrorItemsSource = (IList)Activator.CreateInstance(listType);
itemsControl.SetBinding(ItemsControl.ItemsSourceProperty, new Binding{ Source = mirrorItemsSource });
foreach (object item in itemsSource)
{
mirrorItemsSource.Add(item);
}
FadeInContainers(itemsControl, itemsSource);
(itemsSource as INotifyCollectionChanged).CollectionChanged +=
(object sender, NotifyCollectionChangedEventArgs ne) =>
{
if (ne.Action == NotifyCollectionChangedAction.Add)
{
foreach (object newItem in ne.NewItems)
{
mirrorItemsSource.Add(newItem);
}
FadeInContainers(itemsControl, ne.NewItems);
}
else if (ne.Action == NotifyCollectionChangedAction.Remove)
{
foreach (object oldItem in ne.OldItems)
{
UIElement container = itemsControl.ItemContainerGenerator.ContainerFromItem(oldItem) as UIElement;
Storyboard fadeOutAnimation = GetFadeOutAnimation(itemsControl);
if (container != null && fadeOutAnimation != null)
{
Storyboard.SetTarget(fadeOutAnimation, container);
EventHandler onAnimationCompleted = null;
onAnimationCompleted = ((sender2, e2) =>
{
fadeOutAnimation.Completed -= onAnimationCompleted;
mirrorItemsSource.Remove(oldItem);
});
fadeOutAnimation.Completed += onAnimationCompleted;
fadeOutAnimation.Begin();
}
else
{
mirrorItemsSource.Remove(oldItem);
}
}
}
};
}
private static void FadeInContainers(ItemsControl itemsControl, IList newItems)
{
EventHandler statusChanged = null;
statusChanged = new EventHandler(delegate
{
if (itemsControl.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
itemsControl.ItemContainerGenerator.StatusChanged -= statusChanged;
foreach (object newItem in newItems)
{
UIElement container = itemsControl.ItemContainerGenerator.ContainerFromItem(newItem) as UIElement;
Storyboard fadeInAnimation = GetFadeInAnimation(itemsControl);
if (container != null && fadeInAnimation != null)
{
Storyboard.SetTarget(fadeInAnimation, container);
fadeInAnimation.Begin();
}
}
}
});
itemsControl.ItemContainerGenerator.StatusChanged += statusChanged;
}
public static readonly DependencyProperty FadeInAnimationProperty =
DependencyProperty.RegisterAttached("FadeInAnimation",
typeof(Storyboard),
typeof(ItemsSourceBehavior),
new UIPropertyMetadata(null));
public static void SetFadeInAnimation(DependencyObject element, Storyboard value)
{
element.SetValue(FadeInAnimationProperty, value);
}
public static Storyboard GetFadeInAnimation(DependencyObject element)
{
return (Storyboard)element.GetValue(FadeInAnimationProperty);
}
public static readonly DependencyProperty FadeOutAnimationProperty =
DependencyProperty.RegisterAttached("FadeOutAnimation",
typeof(Storyboard),
typeof(ItemsSourceBehavior),
new UIPropertyMetadata(null));
public static void SetFadeOutAnimation(DependencyObject element, Storyboard value)
{
element.SetValue(FadeOutAnimationProperty, value);
}
public static Storyboard GetFadeOutAnimation(DependencyObject element)
{
return (Storyboard)element.GetValue(FadeOutAnimationProperty);
}
}
tengo solución que funcione para añadir elementos ... yo también estoy buscando la eliminación de elementos cosa ... – Bathineni