2009-04-26 11 views
5

Ho alcune liste nella mia app associate a ObservableCollections e vorrei animare un oggetto se è stato rimosso.Animazione di elementi rimossi nella casella di riepilogo

Ho già trovato una domanda sull'animazione di elementi aggiunti utilizzando l'evento FrameworkElement.Loaded, ma ovviamente non funziona allo stesso modo con l'evento Unloaded.

C'è un modo per farlo in un modo che può essere utilizzato in un datatemplate?

EDIT: mi sono collegato all'evento CollectionChanged nella mia ItemsSource e ho provato ad applicare manualmente un'animazione. Attualmente appare così:

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); 

Il problema è che non funziona affatto. L'oggetto si apre ancora. L'oggetto è ancora lì quando viene chiamato il metodo, quindi non dovrebbe giocare l'animazione prima che scompaia? O sto sbagliando completamente?

risposta

1

Si è scoperto che anche se stavo sollevando un evento prima di rimuoverli, sarebbero comunque rimossi immediatamente. Così, mentre lo stavo usando come pila osservabile, ho lavorato su questo lasciando l'elemento rimosso nella raccolta e rimuovendolo in seguito. così:

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); 
    } 
} 

Potrebbe non essere la soluzione migliore, ma fa il lavoro (almeno se lo uso solo come una pila).

+0

Nel mio caso ho 3dparty INotifyCollectionChanged implementato da Obtics e cambiato di tanto in tanto da eventi lato server ... Non ho idea di come animare la rimozione degli oggetti qui ... Probabilmente dovrei avvolgerlo con l'INotifyCollectionChanged personalizzato e ritardare la rimozione dell'evento personalizzato in aumento per animazione. Ma questo può funzionare solo per 1 elemento per evento e per animazione. Il contratto INotifyCollectionChanged presuppone che ogni istanza modifichi immediatamente la propria raccolta in base agli eventi e, se ho un ritardo, il prossimo evento mi invierà l'indice degli elementi presumendo che abbia già mantenuto la mia raccolta per indice precedente. –

1

Al momento non ho accesso a una finestra di codice, quindi è un po 'esagerato, ma è possibile estendere FrameworkElement con un evento di scarico, quindi avviarlo da CollectionChanged in ObservableCollection. Significa utilizzare una ObservableColleciton personalizzata e una classe di FrameworkElement personalizzata ma potrebbe offrirti ciò che ti serve?

+0

Ci sono già eventi di scarico. Ma in ogni caso è inutile per l'animazione, dal momento che questa è l'ultima risorsa dell'esistenza degli elementi e non c'è nulla da animare dopo questo evento. –

1

È possibile utilizzare Present.Commands API Fluent per modificare gli stati visivi durante l'esecuzione di un comando. Ho inviato un esempio di animazione aggiunta e la rimozione di elementi in una casella di riepilogo utilizzando qui http://adammills.wordpress.com/2011/01/11/mvvm-animation-of-listbox-present-commands/

+0

Questa è la soluzione per il caso in cui l'utente attiva questo comando ... Nel mio caso ho INotifyCollectionChanged implementato da Obtics e cambiato sul lato server ... Non ho idea di come animare la rimozione degli oggetti qui ... –

2

Ho risolto questo con l'aggiunta di una proprietà IsRemoved agli elementi legati. Un trigger di evento nel modello di contenitore ListViewItem viene quindi associato che riproduce l'animazione di rimozione quando questo bool diventa true. Contemporaneamente, viene avviato un task con Task.Delay (n) che corrisponde alla durata dell'animazione e viene seguito con la rimozione effettiva dalla raccolta. Si noti che questa rimozione deve essere inviata al thread proprietario dell'elenco per evitare un'eccezione cross-thread.

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))); 
     }); 
}