Rimuovere storyboard ma mantenere il valore d'animazione?
-
18-09-2019 - |
Domanda
Come posso rimuovere uno storyboard in XAML (vale a dire l'azione RemoveStoryboard in un DataTrigger), ma mantenere il valore che è stato animato. Simile al Animatable.BeginAnimation :
Se BeginTime dell'animazione è nullo, qualsiasi animazione correnti verranno rimossi e si terrà il valore corrente della proprietà.
Soluzione
uso primario di RemoveStoryboard è quello di rimuovere i valori animati e impostare di nuovo al loro stato di non-animato. Nella maggior parte dei casi si può semplicemente passare la chiamata a PauseStoryboard o StopStoryboard invece, a seconda del caso specifico. L'unica eccezione è quando si ha bisogno per liberare risorse detenute dalla storyboard o utilizzarlo per altri scopi.
Se davvero si vuole rimuovere la storyboard e mantenere i valori di proprietà, è necessario impostare i valori animati direttamente sulle proprietà. Questo può essere fatto impostando ogni valore al valore d'animazione, qualcosa di simile a questo:
void CopyAnimatedValuesToLocalValues(DependencyObject obj)
{
// Recurse down tree
for(int i=0; i<VisualTreeHelper.GetChildrenCount(obj); i++)
CopyAnimatedValuesToLocalValues(VisualTreeHelper.GetChild(obj, i));
var enumerator = obj.GetLocalValueEnumerator();
while(enumerator.MoveNext())
{
var prop = enumerator.Current.Property;
var value = enumerator.Current.Value as Freezable;
// Recurse into eg. brushes that may be set by storyboard, as long as they aren't frozen
if(value!=null && !value.IsFrozen)
CopyAnimatedValuesToLocalValues(value);
// *** This is the key bit of code ***
if(DependencyPropertyHelper.GetValueSource(obj, prop).IsAnimated)
obj.SetValue(prop, obj.GetValue(prop));
}
}
Chiama questo diritto prima di rimuovere lo storyboard per copiare i valori animati.
Modifica Un commento è stato fatto che questo codice potrebbe essere inutile perché chiamando BeginAnimation con BeginTime = null ottiene un effetto simile.
Se è vero che BeginAnimation con BeginTime = null rende sembra come se i valori sono stati copiati in locale, una chiamata più tardi per RemoveStoryboard farà sì che i valori per ritornare. Questo perché BeginAnimation con BeginTime = null fa sì che l'animazione prima di tenere i suoi valori in attesa dell'inizio della nuova animazione, ma non fa nulla per influenzare i valori locali.
Il codice sopra effettivamente sovrascrive valori locali, quindi tutte le animazioni può essere rimosso e gli oggetti avranno ancora i nuovi valori. Quindi, se si vuole veramente chiamare RemoveStoryboard e ancora mantenere i vostri valori, è necessario il codice che ho scritto sopra o qualcosa di simile.
Altri suggerimenti
Ho avuto un problema simile quando si utilizza AnimationTimeline
. La soluzione più semplice si è rivelato essere catturare l'evento Completed
in codice dietro e prima di chiamare BeginAnimation
con il parametro null
per rimuovere l'animazione, ottenere il valore corrente della proprietà e l'uso che per impostarlo.
Questo diventa l'ultimo valore d'animazione, e lo imposta.
void OnCompleted( object sender, EventArgs args )
{
// Required to copy latest animated value to local value.
o.SomeValue = o.SomeValue;
o.BeginAnimation( SomeClass.SomeValueProperty, null );
}