Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Beim Arbeiten mit Animationen in WPF gibt es eine Reihe von Tipps und Tricks, mit denen Ihre Animationen besser ausgeführt werden können und Sie Frust sparen können.
Allgemeine Probleme
Das Animieren der Position einer Bildlaufleiste oder eines Schiebereglers friert sie ein.
Wenn Sie die Position einer Bildlaufleiste oder eines Schiebereglers mithilfe einer Animation animieren, die einen FillBehavior von HoldEnd (Standardwert) aufweist, kann der Benutzer die Bildlaufleiste oder den Schieberegler nicht mehr verschieben. Das liegt daran, dass die Animation zwar beendet wurde, aber dennoch den Basiswert der Zieleigenschaft überschreibt. Um zu verhindern, dass die Animation den aktuellen Wert der Eigenschaft überschreibt, entfernen Sie sie, oder setzen Sie einen FillBehavior auf Stop. Weitere Informationen und ein Beispiel finden Sie unter Festlegen einer Eigenschaft nach dem Animieren mit einem Storyboard.
Das Animieren der Ausgabe einer Animation hat keinen Effekt
Sie können ein Objekt nicht animieren, das die Ausgabe einer anderen Animation ist. Wenn Sie z. B. ein ObjectAnimationUsingKeyFrames verwenden, um die Fill eines Rectangle von einer RadialGradientBrush zu einer SolidColorBrush zu animieren, können Sie keine Eigenschaften des RadialGradientBrush oder SolidColorBrush animieren.
Der Wert einer Eigenschaft kann nach dem Animieren nicht geändert werden.
In einigen Fällen kann es vorkommen, dass Sie den Wert einer Eigenschaft nach dem Animieren nicht mehr ändern können, auch nachdem die Animation beendet wurde. Das liegt daran, dass die Animation zwar beendet wurde, aber dennoch den Basiswert der Eigenschaft außer Kraft setzt. Um zu verhindern, dass die Animation den aktuellen Wert der Eigenschaft überschreibt, entfernen Sie sie, oder setzen Sie einen FillBehavior auf Stop. Weitere Informationen und ein Beispiel finden Sie unter Festlegen einer Eigenschaft nach dem Animieren mit einem Storyboard.
Das Ändern einer Zeitachse hat keine Auswirkung
Obwohl die meisten Timeline Eigenschaften animierbar sind und datengebunden sein können, scheint das Ändern der Eigenschaftswerte eines Aktiven Timeline keine Auswirkung zu haben. Das liegt daran, dass das Timing-System beim Start eines Timeline eine Kopie des Timeline erstellt und sie dann verwendet, um ein Clock Objekt zu erzeugen. Das Ändern des Originals hat keine Auswirkungen auf die Kopie des Systems.
Damit Änderungen widerspiegelt werden können, muss seine Uhr neu generiert und verwendet werden, um die vorher erstellte Uhr zu ersetzen. Uhren werden nicht automatisch für Sie regeneriert. Im Folgenden finden Sie verschiedene Möglichkeiten zum Anwenden von Zeitachsenänderungen:
Wenn die Zeitachse zu einer StoryboardZeitachse gehört, können Sie diese Änderungen vornehmen, indem Sie das Storyboard mithilfe einer BeginStoryboard oder der Begin Methode erneut anwenden. Dies hat den Nebeneffekt, die Animation auch neu zu starten. Im Code können Sie die Seek Methode verwenden, um das Storyboard zurück zur vorherigen Position zu wechseln.
Wenn Sie eine Animation mithilfe der BeginAnimation Methode direkt auf eine Eigenschaft angewendet haben, rufen Sie die BeginAnimation Methode erneut auf, und übergeben Sie sie an die Animation, die geändert wurde.
Wenn Sie direkt auf der Taktebene arbeiten, erstellen Sie einen neuen Satz an Takten und wenden Sie ihn an, um den vorherigen Satz der generierten Takte zu ersetzen.
Weitere Informationen zu Zeitachsen und Uhren finden Sie unter Animation und Timing System Overview.
FillBehavior.Stop funktioniert nicht wie erwartet
Es gibt Zeiten, in denen das Festlegen der FillBehavior-Eigenschaft Stop keinen Effekt hat, z. B. wenn eine Animation an eine andere übergeht, da sie eine HandoffBehavior-Einstellung von SnapshotAndReplace hat.
Im folgenden Beispiel wird ein Canvas, ein Rectangle und ein TranslateTransform erstellt. Das TranslateTransform wird animiert, um das Rectangle um das Canvas zu bewegen.
<Canvas Width="600" Height="200">
<Rectangle
Canvas.Top="50" Canvas.Left="0"
Width="50" Height="50" Fill="Red">
<Rectangle.RenderTransform>
<TranslateTransform
x:Name="MyTranslateTransform"
X="0" Y="0" />
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
In den Beispielen in diesem Abschnitt werden die vorherigen Objekte verwendet, um mehrere Fälle zu veranschaulichen, in denen sich die FillBehavior Eigenschaft nicht wie erwartet verhält.
FillBehavior="Stop" und HandoffBehavior mit mehreren Animationen
Manchmal scheint es so, als ob eine Animation ihre FillBehavior Eigenschaft ignoriert, wenn sie durch eine zweite Animation ersetzt wird. Nehmen Sie das folgende Beispiel, bei dem zwei Storyboard Objekte erstellt und verwendet werden, um dasselbe TranslateTransform wie im vorherigen Beispiel zu animieren.
Der erste StoryboardB1 animiert die X-Eigenschaft von TranslateTransform von 0 bis 350, wodurch das Rechteck um 350 Pixel nach rechts verschoben wird. Wenn die Animation das Ende der Dauer erreicht und die Wiedergabe beendet, wird die X Eigenschaft auf den ursprünglichen Wert 0 zurückgesetzt. Infolgedessen bewegt sich das Rechteck um 350 Pixel nach rechts und kehrt dann an seine ursprüngliche Position zurück.
<Button Content="Start Storyboard B1">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard x:Name="B1">
<DoubleAnimation
Storyboard.TargetName="MyTranslateTransform"
Storyboard.TargetProperty="X"
From="0" To="350" Duration="0:0:5"
FillBehavior="Stop"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
Der zweite Storyboard, B2, animiert auch die X-Eigenschaft desselben TranslateTransform. Da nur die To-Eigenschaft der Animation in diesem Storyboard festgelegt ist, verwendet die Animation den aktuellen Wert der Eigenschaft, die sie animiert, als Startwert.
<!-- Animates the same object and property as the preceding
Storyboard. -->
<Button Content="Start Storyboard B2">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard x:Name="B2">
<DoubleAnimation
Storyboard.TargetName="MyTranslateTransform"
Storyboard.TargetProperty="X"
To="500" Duration="0:0:5"
FillBehavior="Stop" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
Wenn Sie auf die zweite Schaltfläche klicken, während die erste Storyboard abgespielt wird, erwarten Sie möglicherweise folgendes Verhalten:
Das erste Storyboard endet und sendet das Rechteck an seine ursprüngliche Position zurück, da die Animation eine FillBehavior von Stop.
Das zweite Storyboard wird wirksam und wird von der aktuellen Position aus, die derzeit bei 0 liegt, bis zur Position 500 animiert.
Aber das passiert nicht. Stattdessen springt das Rechteck nicht zurück; sie bewegt sich weiter nach rechts. Das liegt daran, dass die zweite Animation den aktuellen Wert der ersten Animation als Startwert verwendet und von diesem Wert auf 500 animiert wird. Wenn die zweite Animation die erste ersetzt, weil SnapshotAndReplaceHandoffBehavior verwendet wird, spielt die FillBehavior der ersten Animation keine Rolle.
FillBehavior und das Completed-Ereignis
Die nächsten Beispiele veranschaulichen ein weiteres Szenario, in dem das StopFillBehavior scheinbar keine Wirkung zeigt. Auch hier wird im Beispiel ein Storyboard verwendet, um die X Eigenschaft von TranslateTransform von 0 bis 350 zu animieren. Dieses Mal registriert sich das Beispiel jedoch für das Completed Ereignis.
<Button Content="Start Storyboard C">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard Completed="StoryboardC_Completed">
<DoubleAnimation
Storyboard.TargetName="MyTranslateTransform"
Storyboard.TargetProperty="X"
From="0" To="350" Duration="0:0:5"
FillBehavior="Stop" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
Der Completed Ereignishandler startet einen anderen Storyboard, der dieselbe Eigenschaft von ihrem aktuellen Wert auf 500 animiert.
private void StoryboardC_Completed(object sender, EventArgs e)
{
Storyboard translationAnimationStoryboard =
(Storyboard)this.Resources["TranslationAnimationStoryboardResource"];
translationAnimationStoryboard.Begin(this);
}
Private Sub StoryboardC_Completed(ByVal sender As Object, ByVal e As EventArgs)
Dim translationAnimationStoryboard As Storyboard = CType(Me.Resources("TranslationAnimationStoryboardResource"), Storyboard)
translationAnimationStoryboard.Begin(Me)
End Sub
Im Folgenden sehen Sie das Markup, das die zweite Storyboard als Ressource definiert.
<Page.Resources>
<Storyboard x:Key="TranslationAnimationStoryboardResource">
<DoubleAnimation
Storyboard.TargetName="MyTranslateTransform"
Storyboard.TargetProperty="X"
To="500" Duration="0:0:5" />
</Storyboard>
</Page.Resources>
Wenn Sie die Storyboard starten, könnten Sie erwarten, dass die X Eigenschaft des TranslateTransform von 0 bis 350 animiert wird, dann nach Abschluss auf 0 zurückgesetzt wird (weil es eine FillBehavior-Einstellung von Stop hat) und anschließend von 0 bis 500 animiert wird. Stattdessen wird TranslateTransform von 0 bis 350 und dann auf 500 animiert.
Das liegt an der Reihenfolge, in der WPF Ereignisse auslöst und Eigenschaftswerte zwischengespeichert werden und nicht neu berechnet werden, außer wenn die Eigenschaft invalidiert ist. Das Completed Ereignis wird zuerst verarbeitet, da es durch die Stammzeitachse (die erste Storyboard) ausgelöst wurde. Zu diesem Zeitpunkt gibt die X Eigenschaft ihren animierten Wert weiterhin zurück, da sie noch nicht ungültig wurde. Der zweite Storyboard verwendet den zwischengespeicherten Wert als Startwert und beginnt mit der Animierung.
Leistung
Animationen laufen nach dem Verlassen einer Seite weiter
Wenn Sie von einem Page mit laufenden Animationen weg navigieren, werden diese Animationen weiterhin abgespielt, bis der Page durch die Speicherbereinigung entfernt wird. Je nach verwendetem Navigationssystem bleibt eine Seite, von der Sie weg navigieren, möglicherweise für eine unbegrenzte Zeit im Arbeitsspeicher, während Ressourcen mit ihren Animationen verbraucht werden. Dies ist am deutlichsten, wenn eine Seite ständig laufende Animationen ("ambient") enthält.
Aus diesem Grund empfiehlt es sich, mithilfe des Unloaded Ereignisses Animationen zu entfernen, wenn Sie von einer Seite weg navigieren.
Es gibt verschiedene Möglichkeiten zum Entfernen einer Animation. Die folgenden Techniken können verwendet werden, um Animationen zu entfernen, die zu einem Storyboard gehören.
Zum Entfernen eines Storyboard, das mit einem Ereignistrigger gestartet wurde, siehe How to: Remove a Storyboard.
Informationen zum Entfernen eines StoryboardCodes finden Sie unter der Remove Methode.
Die nächste Technik kann unabhängig davon verwendet werden, wie die Animation gestartet wurde.
- Verwenden Sie die BeginAnimation(DependencyProperty, AnimationTimeline) Methode, um Animationen aus einer bestimmten Eigenschaft zu entfernen. Geben Sie die zu animierende Eigenschaft als ersten Parameter an und
nullals zweiten. Dadurch werden alle Animationsuhren aus der Eigenschaft entfernt.
Weitere Informationen zu den verschiedenen Methoden zum Animieren von Eigenschaften finden Sie unter Property Animation Techniques Overview.
Verwendung von Compose HandoffBehavior verbraucht Systemressourcen
Wenn Sie ein Storyboard, AnimationTimeline oder AnimationClock auf eine Eigenschaft mithilfe von ComposeHandoffBehavior anwenden, werden alle Clock-Objekte, die zuvor dieser Eigenschaft zugeordnet waren, weiterhin Systemressourcen verbrauchen; Das Zeitsystem entfernt diese Uhren nicht automatisch.
Um Leistungsprobleme zu vermeiden, wenn Sie eine große Anzahl von Zeitgebern mit Compose verwenden, sollten Sie zusammengesetzte Zeitgeber aus der animierten Eigenschaft entfernen, nachdem diese abgeschlossen sind. Es gibt mehrere Möglichkeiten, eine Uhr zu entfernen.
Wenn Sie alle Uhren aus einer Eigenschaft entfernen möchten, verwenden Sie die ApplyAnimationClock(DependencyProperty, AnimationClock)-Methode oder die BeginAnimation(DependencyProperty, AnimationTimeline)-Methode des animierten Objekts. Geben Sie die zu animierende Eigenschaft als ersten Parameter an und
nullals zweiten. Dadurch werden alle Animationsuhren aus der Eigenschaft entfernt.Verwenden Sie zum Entfernen einer bestimmten AnimationClock aus einer Liste von Uhren die Controller-Eigenschaft der AnimationClock, um eine ClockController abzurufen, und rufen Sie dann die Remove-Methode der ClockController auf. Dies erfolgt typischerweise im Completed Ereignishandler für einen Zeitgeber. Beachten Sie, dass nur Stammuhren durch ein ClockController gesteuert werden können; die Controller Eigenschaft einer untergeordneten Uhr gibt
nullzurück. Beachten Sie auch, dass das Completed Ereignis nicht aufgerufen wird, wenn die effektive Dauer der Uhrzeit unendlich ist. In diesem Fall muss der Benutzer bestimmen, wann er anruft Remove.
Dies ist in erster Linie ein Problem bei Animationen für Objekte, die eine lange Lebensdauer aufweisen. Wenn ein Objekt gesammelt wird, werden seine Uhren ebenfalls getrennt und gesammelt.
Weitere Informationen zu Uhrobjekten finden Sie unter Animation und Timing System Overview.
Siehe auch
.NET Desktop feedback