Delen via


Tips en trucs voor animatie

Wanneer u met animaties in WPF werkt, zijn er een aantal tips en trucs die ervoor zorgen dat uw animaties beter presteren en u frustraties kunnen besparen.

Algemene problemen

Het animeren van de positie van een schuifbalk of schuifregelaar leidt tot bevriezen.

Als u de positie van een schuifbalk of schuifregelaar animeren met behulp van een animatie met een FillBehavior van HoldEnd (de standaardwaarde), kan de gebruiker de schuifbalk of schuifregelaar niet meer verplaatsen. Dat komt doordat, zelfs als de animatie is beëindigd, de basiswaarde van de doeleigenschap nog steeds wordt overschreven. Als u wilt voorkomen dat de animatie de huidige waarde van de eigenschap overschrijft, verwijdert u deze of geeft u deze een FillBehavior van Stop. Zie voor meer informatie en een voorbeeld Een eigenschap instellen nadat u de animatie hebt aangepast met een Storyboard-.

Het animeren van de uitvoer van een animatie heeft geen effect

U kunt geen animatie toepassen op een object dat de uitvoer van een andere animatie is. Als u bijvoorbeeld een ObjectAnimationUsingKeyFrames gebruikt om de Fill van een Rectangle van een RadialGradientBrush naar een SolidColorBrushte animeren, kunt u geen animatie toepassen op eigenschappen van de RadialGradientBrush of SolidColorBrush.

De waarde van een eigenschap kan niet worden gewijzigd na animatie

In sommige gevallen lijkt het erop dat u de waarde van een eigenschap niet kunt wijzigen nadat deze is geanimeerd, zelfs nadat de animatie is beëindigd. Dat komt doordat, zelfs als de animatie is beëindigd, de basiswaarde van de eigenschap nog steeds wordt overschreven. Als u wilt voorkomen dat de animatie de huidige waarde van de eigenschap overschrijft, verwijdert u deze of geeft u deze een FillBehavior van Stop. Zie voor meer informatie en een voorbeeld Een eigenschap instellen nadat u de animatie hebt aangepast met een Storyboard-.

Het wijzigen van een tijdlijn heeft geen effect

Hoewel de meeste Timeline eigenschappen animatabel zijn en gegevens kunnen zijn gebonden, lijkt het wijzigen van de eigenschapswaarden van een actieve Timeline geen effect te hebben. Dat komt doordat wanneer een Timeline wordt gestart, het timingsysteem een kopie van de Timeline maakt en gebruikt om een Clock object te maken. Het wijzigen van het origineel heeft geen invloed op de kopie van het systeem.

Opdat een Timeline wijzigingen weergeeft, moet de klok opnieuw gegenereerd worden en gebruikt worden om de eerder gemaakte klok te vervangen. Klokken worden niet automatisch opnieuw ingesteld. Hier volgen verschillende manieren om tijdlijnwijzigingen toe te passen:

  • Als de tijdlijn een Storyboardis of tot een Storyboardbehoort, kunt u wijzigingen doorvoeren door het storyboard opnieuw toe te passen met behulp van een BeginStoryboard of de methode Begin. Dit heeft het neveneffect dat de animatie ook opnieuw wordt gestart. In code kunt u de methode Seek gebruiken om het storyboard terug te zetten naar de vorige positie.

  • Als u een animatie rechtstreeks hebt toegepast op een eigenschap met behulp van de methode BeginAnimation, roept u de methode BeginAnimation opnieuw aan en geeft u deze door aan de animatie die is gewijzigd.

  • Als u rechtstreeks op klokniveau werkt, maakt en past u een nieuwe set klokken toe en gebruikt u deze om de vorige set gegenereerde klokken te vervangen.

Zie Animatie- en timingsysteemoverzichtvoor meer informatie over tijdlijnen en klokken.

FillBehavior.Stop werkt niet zoals verwacht

Er zijn momenten waarop het instellen van de eigenschap FillBehavior op Stop geen effect lijkt te hebben, bijvoorbeeld wanneer de ene animatie wordt overgedragen aan een andere animatie omdat deze een HandoffBehavior-instelling van SnapshotAndReplaceheeft.

In het volgende voorbeeld wordt een Canvas, een Rectangle en een TranslateTransformgemaakt. De TranslateTransform wordt geanimeerd om de Rectangle rond de Canvaste verplaatsen.

<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 de voorbeelden in deze sectie worden de voorgaande objecten gebruikt om verschillende gevallen te laten zien waarin de eigenschap FillBehavior zich niet gedraagt zoals verwacht.

FillBehavior="Stop" en HandoffBehavior met meerdere animaties

Soms lijkt het alsof een animatie de FillBehavior eigenschap negeert wanneer deze wordt vervangen door een tweede animatie. In het volgende voorbeeld worden twee Storyboard-objecten gemaakt en gebruikt om dezelfde TranslateTransform te animeren die in het voorgaande voorbeeld wordt weergegeven.

De eerste Storyboard, B1, animeert de eigenschap X van de TranslateTransform van 0 tot 350, waardoor de rechthoek 350 pixels naar rechts verplaatst. Wanneer de animatie het einde van de duur bereikt en stopt met afspelen, wordt de eigenschap X teruggezet naar de oorspronkelijke waarde, 0. Als gevolg hiervan gaat de rechthoek naar rechts 350 pixels en springt vervolgens terug naar de oorspronkelijke positie.

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

De tweede Storyboard, B2, animeert ook de eigenschap X van hetzelfde TranslateTransform. Omdat alleen de eigenschap To van de animatie in deze Storyboard is ingesteld, gebruikt de animatie de huidige waarde van de eigenschap die deze animeert als beginwaarde.


<!-- 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>

Als u op de tweede knop klikt terwijl de eerste Storyboard wordt afgespeeld, verwacht u mogelijk het volgende gedrag:

  1. Het eerste storyboard eindigt en stuurt de rechthoek terug naar de oorspronkelijke positie, omdat de animatie een FillBehavior van Stopheeft.

  2. Het tweede storyboard krijgt effect en krijgt een animatie van de huidige positie, die nu 0 is, tot 500.

Maar dat is niet wat er gebeurt. In plaats daarvan springt de rechthoek niet terug; het blijft naar rechts gaan. Dat komt doordat de tweede animatie de huidige waarde van de eerste animatie als startwaarde gebruikt en van die waarde naar 500 animeert. Wanneer de tweede animatie de eerste vervangt omdat de SnapshotAndReplaceHandoffBehavior wordt gebruikt, maakt de FillBehavior van de eerste animatie niet uit.

FillBehavior en de voltooide gebeurtenis

In de volgende voorbeelden ziet u een ander scenario waarin de StopFillBehavior geen effect heeft. Nogmaals, in het voorbeeld wordt een Storyboard gebruikt om de eigenschap X van de TranslateTransform van 0 tot 350 te animeren. Dit keer wordt het voorbeeld echter geregistreerd voor de Completed-gebeurtenis.

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

De Completed gebeurtenis-handler start nog een Storyboard die dezelfde eigenschap animeren van de huidige waarde naar 500.

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

Hier volgt de markering die de tweede Storyboard definieert als een resource.

<Page.Resources>
  <Storyboard x:Key="TranslationAnimationStoryboardResource">
    <DoubleAnimation 
      Storyboard.TargetName="MyTranslateTransform"
      Storyboard.TargetProperty="X"
      To="500" Duration="0:0:5" />
  </Storyboard>
</Page.Resources>

Wanneer u de Storyboarduitvoert, kunt u verwachten dat de eigenschap X van de TranslateTransform van 0 tot 350 wordt geanimeerd en vervolgens teruggaat naar 0 nadat deze is voltooid (omdat het een FillBehavior instelling van Stopheeft) en vervolgens animaties van 0 tot 500 heeft. In plaats daarvan beweegt de TranslateTransform van 0 naar 350 en vervolgens naar 500.

Dat komt door de volgorde waarin WPF gebeurtenissen genereert en omdat eigenschapswaarden in de cache worden opgeslagen en niet opnieuw worden berekend, tenzij de eigenschap ongeldig is. De Completed gebeurtenis wordt eerst verwerkt omdat deze is geactiveerd door de hoofdtijdlijn (de eerste Storyboard). Op dit moment retourneert de eigenschap X nog steeds de geanimeerde waarde omdat deze nog niet ongeldig is verklaard. In de tweede Storyboard wordt de waarde in de cache gebruikt als beginwaarde en wordt de animatie gestart.

Prestatie

Animaties blijven actief na het navigeren vanaf een pagina

Wanneer u weg navigeert van een Page met actieve animaties, blijven deze animaties afspelen totdat het Page afval wordt verzameld. Afhankelijk van het navigatiesysteem dat u gebruikt, kan een pagina waar u vandaan navigeert, gedurende onbepaalde tijd in het geheugen blijven, allemaal terwijl resources worden verbruikt met de animaties. Dit is het meest merkbaar wanneer een pagina voortdurend actieve animaties ('ambient') bevat.

Daarom is het een goed idee om de Unloaded gebeurtenis te gebruiken om animaties te verwijderen wanneer u weg navigeert van een pagina.

Er zijn verschillende manieren om een animatie te verwijderen. De volgende technieken kunnen worden gebruikt om animaties te verwijderen die deel uitmaken van een Storyboard.

De volgende techniek kan worden gebruikt, ongeacht hoe de animatie is gestart.

  • Als u animaties uit een specifieke eigenschap wilt verwijderen, gebruikt u de methode BeginAnimation(DependencyProperty, AnimationTimeline). Geef de eigenschap op die wordt geanimeerd als de eerste parameter en null als de tweede. Hiermee worden alle animatieklokken uit de eigenschap verwijderd.

Zie Overzicht van eigenschapsanimatietechniekenvoor meer informatie over de verschillende manieren om eigenschappen te animeren.

Het gebruik van de Compose HandoffBehavior verbruikt systeembronnen

Wanneer u een Storyboard, AnimationTimelineof AnimationClock toepast op een eigenschap met behulp van de ComposeHandoffBehavior, blijven alle eerder gekoppelde Clock objecten systeembronnen gebruiken; het tijdssysteem zal deze klokken niet automatisch verwijderen.

Als u prestatieproblemen wilt voorkomen wanneer u een groot aantal klokken toepast met behulp van Compose, moet u het opstellen van klokken uit de eigenschap animatie verwijderen nadat deze zijn voltooid. Er zijn verschillende manieren om een klok te verwijderen.

Dit is voornamelijk een probleem voor animaties op objecten die een lange levensduur hebben. Wanneer een object wordt verzameld, worden de klokken ook losgekoppeld en afval verzameld.

Zie Overzicht van animatie- en tijdsinstellingensysteem voor meer informatie over klokobjecten.

Zie ook