2009-04-26 22 views
5

Tengo algunos Listboxes en mi aplicación vinculados a ObservableCollections, y me gustaría animar un elemento si se elimina.Animar elemento eliminado en Listbox

Ya encontré una pregunta sobre la animación de elementos agregados mediante el uso del evento FrameworkElement.Loaded, pero, por supuesto, eso no funciona de la misma manera con el evento descargado.

¿Hay alguna manera de hacer esto de forma que pueda usarse en una plantilla de datos?

EDITAR: Me he conectado al evento CollectionChanged en mis ItemsSource e intenté aplicar una animación manualmente. Actualmente se ve así:

ListBoxItem item = stack.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem; 
     item.LayoutTransform = new ScaleTransform(1, 1); 

    DoubleAnimation scaleAnimation = new DoubleAnimation(); 
    scaleAnimation.From = 1; 
    scaleAnimation.To = 0; 
    scaleAnimation.Duration = new Duration(new TimeSpan(0, 0, 0, 0, 500)); 
    ScaleTransform transform = (ScaleTransform)item.LayoutTransform; 
    transform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation); 

El problema es que no funciona en absoluto. El ítem simplemente sigue apareciendo. El elemento todavía está allí cuando se llama al método, por lo que no debería estar reproduciendo la animación antes de que desaparezca? ¿O lo estoy haciendo completamente mal?

Respuesta

1

Resultó que incluso si yo estaba planteando un evento antes de eliminarlos, se eliminarían instantáneamente de todos modos. Entonces, como lo estaba usando como una pila observable, trabajé alrededor de esto dejando el elemento eliminado en la colección y eliminándolo más tarde. de esta manera:

public class ObservableStack<T> : ObservableCollection<T> 
{ 
    private T collapsed; 
    public event EventHandler BeforePop; 

    public T Peek() { 
     if (collapsed != null) { 
      Remove(collapsed); 
      collapsed = default(T); 
     } 
     return this.FirstOrDefault(); 
    } 

    public T Pop() { 
     if (collapsed != null) { Remove(collapsed); } 
     T result = (collapsed = this.FirstOrDefault()); 
     if (BeforePop != null && result != null) BeforePop(this, new EventArgs()); 
     return result; 
    } 

    public void Push(T item) { 
     if (collapsed != null) { 
      Remove(collapsed); 
      collapsed = default(T); 
     } 
     Insert(0, item); 
    } 
} 

Puede que no sea la mejor solución, pero hace el trabajo (al menos si sólo lo uso como una pila).

+0

En mi caso tengo 3dparty INotifyCollectionChanged implementado por Obtics y cambiado ocasionalmente por eventos del lado del servidor ... No tengo idea de cómo animar la eliminación de elementos aquí ... Probablemente debería envolverlo por INotifyCollectionChanged personalizado y simplemente retrasar la eliminación del evento personalizado en aumento para animación. Pero esto puede funcionar solo para 1 artículo por evento y por animación. El contrato INotifyCollectionChanged supone que cada instancia cambia su colección inmediatamente por los eventos y, si tengo un retraso, el próximo evento me enviará un índice de elementos, suponiendo que ya mantuve mi colección por índice anterior. –

1

No tengo acceso a una ventana de código en este momento, así que esto está un poco fuera de lugar, pero podría extender el FrameworkElement con un evento de Descarga, luego iniciarlo desde CollectionChanged en un ObservableCollection. Significa usar un ObservableColleciton personalizado y una clase FrameworkElement personalizada pero podría ofrecerle lo que necesita?

+0

Ya hay un evento de descarga. Pero de todos modos es inútil para la animación, ya que este es el último recurso de la existencia del elemento y no hay nada que animar después de que este evento haya ocurrido. –

1

Puede usar Present.Commands Fluent API para cambiar los estados visuales durante la ejecución de un comando. me han publicado un ejemplo de animación añadir y eliminar elementos en un cuadro de lista de usarlo aquí http://adammills.wordpress.com/2011/01/11/mvvm-animation-of-listbox-present-commands/

+0

Esta es la solución para el caso en que el usuario activa este comando ... En mi caso tengo INotifyCollectionChanged implementado por Obtics y cambiado en el lado del servidor ... No tengo idea de cómo animar la eliminación de elementos aquí ... –

2

He resuelto esto añadiendo una propiedad IsRemoved a las partidas consolidadas. Un desencadenador de evento en la plantilla de contenedor ListViewItem se enlaza y reproduce la animación de eliminación cuando este bool cambia a verdadero. Al mismo tiempo, se inicia una tarea con Task.Delay (n) que coincide con la duración de la animación, y hace un seguimiento con la eliminación real de la colección. Tenga en cuenta que esta eliminación debe enviarse al hilo que posee la lista para evitar una excepción de hilo cruzado.

void Remove(MyItem item, IList<MyItem> list) 
{ 
    item.IsRemoved = true; 

    Task.Factory.StartNew(() => 
     { 
      Task.Delay(ANIMATION_LENGTH_MS); 
      Dispatcher.Invoke(new Action(() => list.Remove(item))); 
     }); 
} 
Cuestiones relacionadas