MSDN Magazin > Home > Ausgaben > 2008 > August >  Silverlight: Erstellen von Animationen mit XAML...
Silverlight
Erstellen von Animationen mit XAML und Expression Blend
Lawrence Moroney

Themen in diesem Artikel:
  • Grundlegende und kombinierte Transformationen
  • Verwenden von Auslösern und Ereignissen
  • Lineare und einzelne Keyframeanimation
  • Animation mit Expression Blend
In diesem Artikel werden folgende Technologien verwendet:
Silverlight 2, Expression Blend
Dieser Artikel basiert auf einer Vorabversion von Silverlight 2. Änderungen an allen Informationen in diesem Artikel sind vorbehalten. Dieser Artikel stammt aus dem Buch Introducing Microsoft Silverlight 2, 2nd Edition von Laurence Moroney (Microsoft Press, 2008).
Das Besondere an XAML ist, dass nicht nur Objekte mithilfe einer XML-Syntax deklariert werden können, sondern dass auch Transformationen definiert werden können, um sie auf dieselbe Art zu verwenden. Sie müssen kein Programmierer sein, um Objekte zu drehen, zu verschieben und zu verzerren. Außerdem kann XAML dafür verwendet werden, die Animation des Objekts zu beschreiben, wobei eine Animation als veränderliche Eigenschaften des Objekts über einen Zeitraum definiert ist. Sehen wir uns zunächst Transformationen an. Später werde ich sie zu Zeitachsen hinzufügen, um den Silverlight™-Inhalt zu animieren.

Transformationen
Geht es um Grafiken, definiert eine Transformation, wie Punkte eines Koordinatenbereichs einem anderen zugeordnet werden. Dies wird in der Regel mithilfe einer Transformationsmatrix beschrieben, einem speziellen mathematischen Konstrukt, das eine einfache mathematische Umrechnung von einem System in ein anderes ermöglicht. Silverlight-XAML abstrahiert diese Matrix und unterstützt vier feste Transformationen für Drehung, Skalieren, Verzerren und Translation (Verschiebung). Silverlight-XAML verfügt außerdem über einen zusätzlichen speziellen Transformationstyp, mit dem eine eigene Matrix definiert und implementiert werden kann, um anschließend Transformationen zu kombinieren.
Transformationen werden mithilfe von Transformationseigenschaften angewendet. Es gibt mehrere verschiedene Typen von Transformationseigenschaften, die auf unterschiedliche Objekttypen angewendet werden.
Folglich werden Transformationen durch die Verwendung eines Brush-Typs unterschiedlich definiert. Eine Möglichkeit ist die Verwendung der Brush.Transform-Eigenschaft, wenn sich die Aktion auf den Inhalt des Pinsels auswirken soll (z. B. wenn ein Bild vor der Verwendung in ImageBrush gedreht werden soll). Eine andere Möglichkeit besteht darin, die Brush.RelativeTransform-Eigenschaft zu verwenden, um einen Pinsel mithilfe relativer Werte zu transformieren. (Dies ist z. B. hilfreich, wenn verschiedene Bereiche unterschiedlicher Größe mithilfe desselben Pinsels gezeichnet werden.)
Bei der Verwendung eines Geometry-Typs wird eine einfache Transformation mithilfe der Geometry.Transform-Eigenschaft angewendet. Es ist jedoch zu beachten, dass dieser Typ keine relativen Transformationen unterstützt.
Bei Verwendung eines Benutzeroberflächenelements wird schließlich die Transformation mithilfe der RenderTransform-Eigenschaft festgelegt. Zum Transformieren einer Ellipse wird z. B. Ellipse.RenderTransform verwendet, um die gewünschte Transformation zu definieren.

Drehen mit der RotateTransform-Eigenschaft
RotateTransform ermöglicht das Drehen eines Elements um einen festgelegten Winkel und Mittelpunkt. Der Winkel der Drehung wird mithilfe der Angle-Eigenschaft festgelegt, die die Gradzahl angibt, um die das Element gedreht werden soll. Der nach rechts zeigende horizontale Vektor entspricht 0 Grad, und gedreht wird im Uhrzeigersinn. Das bedeutet, dass der nach unten zeigende vertikale Vektor das Ergebnis einer Drehung um 90 Grad ist.
Der Mittelpunkt der Drehung wird mithilfe der CenterX- und CenterY-Eigenschaften festgelegt, die die Koordinaten des Drehpunkts angeben. Der Standard ist (0,0), wodurch sich der standardmäßige Drehpunkt in der linken oberen Ecke des Containers befindet.
In diesem Beispiel-XAML wird ein TextBlock mithilfe von RenderTransform gedreht, das RotateTransform enthält, welches wiederum eine 45-Grad-Drehung angibt:
<TextBlock Width="320" Height="40" 
  Text="This is the text to rotate" TextWrapping="Wrap"> 
  <TextBlock.RenderTransform> 
    <RotateTransform Angle="45" /> 
  </TextBlock.RenderTransform> 
</TextBlock>
Wie in Abbildung 1 gezeigt, wird der Text um einen Mittelpunkt bei (0,0) in der linken oberen Ecke des Bildschirms gedreht.
Abbildung 1 Verwenden der RotateTransform-Eigenschaft (zum Vergrößern auf das Bild klicken)
Dieses XAML zeigt die Verwendung von CenterX und CenterY zum Drehen um einen anderen Punkt. In diesem Fall findet die Drehung um den Punkt (100,200) statt:
<TextBlock Width="320" Height="40" 
  Text="This is the text to rotate" TextWrapping="Wrap" > 
  <TextBlock.RenderTransform> 
    <RotateTransform Angle="45" CenterX="100" CenterY="200" /> 
  </TextBlock.RenderTransform> 
</TextBlock>

Skalieren mit der ScaleTransform-Eigenschaft
Die ScaleTransform-Eigenschaft wird zum Ändern der Größe eines Objekts basierend auf der horizontalen Achse, der vertikalen Achse oder beiden Achsen verwendet. Beim Skalieren eines Objekts muss mindestens eine Achse angegeben werden, um die herum skaliert werden soll, sowie der Wert der Skalierung gegenüber dieser Achse.
Die ScaleX-Eigenschaft wird zum Skalieren des Objekts entlang der horizontalen Achse (x-Achse) verwendet, und ScaleY dient zum Skalieren entlang der vertikalen Achse (y-Achse). Diese werden auf einen double-Wert gesetzt, der den Wert repräsentiert, mit dem die aktuelle Größe des Objekts bezüglich der angegebenen Achse multipliziert wird. Somit strecken Werte größer als 1 das Objekt um dieses Vielfache. Durch Verwendung eines ScaleX-Werts von 2 beispielsweise wird die Größe des Objekts horizontal verdoppelt. Werte zwischen 0 und 1 verkleinern das Objekt. So wird die Größe des Objekts durch die Einstellung 0,5 entlang der festgelegten Dimension halbiert.
Dieses XAML erstellt z. B. ein rotes Rechteck mit einer Breite von 96 Pixeln und einer Höhe von 88 Pixeln:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="112" Canvas.Top="72" />
Abbildung 2 zeigt, wie dieses Objekt nach dem Rendern in Silverlight aussieht.
Abbildung 2 Rendern des Rechtecks (zum Vergrößern auf das Bild klicken)
Um ScaleTransform auf dieses Objekt anzuwenden, wird RenderTransform verwendet und die Transformation als ScaleTransform festgelegt. Hier ist das XAML:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" Canvas.Left="112" Canvas.Top="72"> 
  <Rectangle.RenderTransform> 
    <ScaleTransform ScaleX="2" /> 
  </Rectangle.RenderTransform> 
</Rectangle>
Wenn Sie selbst zu Hause mitcodieren, werden Sie sehen, dass die Größe des Rechtecks mithilfe von ScaleTransform horizontal nach rechts zugenommen hat. Das liegt daran, dass der Mittelpunkt der Skalierung nicht festgelegt wurde. Er kann über die CenterX-Eigenschaft für horizontales Skalieren bzw. die CenterY-Eigenschaft für vertikales Skalieren angegeben werden. Dadurch werden die Koordinaten für den Mittelpunkt der Skalierung festgelegt. Beachten Sie, dass sich diese Koordinate auf die linke obere Ecke des Rechtecks bezieht. Außerdem ist der Koordinatenstandard 0. Das heißt, dass auf der horizontalen Achse nach rechts und auf der vertikalen nach unten skaliert wird.
Wenn die CenterX-Eigenschaft einen positiven Wert erhält (z. B. 50), wird um den X-Punkt 50 Pixel nach rechts von der Seite des Rechtecks skaliert, die sich am weitesten links befindet. Dadurch sieht es so aus, als wäre das Rechteck um eine bestimmte Anzahl von Pixeln nach links verschoben worden gegenüber dem, dessen CenterX nicht geändert wurde (die Anzahl ist abhängig von der Größe des Skalierungsfaktors). Der Grund dafür ist, dass das Strecken in Bezug auf diesem Punkt zentriert ist, wodurch die linke Seite des Rechtecks nach links und die rechte Seite nach rechts geschoben werden. Ähnliche Effekte können erzielt werden, wenn die ScaleY- und ScaleX-Werte auf diese Art festgelegt werden:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="80" Canvas.Top="80"> 
  <Rectangle.RenderTransform> 
    <ScaleTransform ScaleX="2" 
      CenterX="50"/> 
  </Rectangle.RenderTransform> 
</Rectangle>

Verschieben eines Objekts mit der TranslateTransform-Eigenschaft
Eine Translation ist eine Transformation, die ein Objekt auf einer zweidimensionalen Ebene von einer Position zu einer anderen verschiebt. Sie wird durch das Festlegen von Vektoren definiert, die die Verschiebung des Objekts entlang seiner x- und y-Achsen angeben. Diese werden mithilfe der X- und Y-Eigenschaften der Transformation festgelegt. Zum horizontalen Verschieben eines Elements um zwei Einheiten (also nach rechts) wird die X-Eigenschaft auf 2 gesetzt. Zum Verschieben nach links wird ein negativer Wert, z. B. -2, verwendet. Soll ein Objekt vertikal verschoben werden, wird demzufolge die Y-Eigenschaft verwendet. Positive Werte verschieben das Objekt auf dem Bildschirm nach unten, negative nach oben.
Folgendes Beispiel einer Translationstransformation verschiebt die Position des roten Rechtecks, das wir betrachtet haben, indem X- und Y-Werte angegeben werden, die es nach oben und nach links verschieben. Tatsächlich bilden diese Werte einen Vektor, der die Transformation bestimmt:
<Rectangle Fill="#FFFF0404" 
  Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="80" Canvas.Top="80"> 
  <Rectangle.RenderTransform> 
    <TranslateTransform X="-50" Y="-50"/> 
  </Rectangle.RenderTransform> 
</Rectangle>
Die Ergebnisse dieses Vorgangs sind in Abbildung 3 dargestellt. In Bezug auf die festgelegte Position wurde das Rechteck im Vergleich zur Position des Rechtecks in Abbildung 2 nach oben und nach links verschoben.
Abbildung 3 Verwenden der TranslateTransform-Eigenschaft (zum Vergrößern auf das Bild klicken)

Verzerren eines Objekts mit der SkewTransform-Eigenschaft
Das Verzerren eines Objekts bedeutet, dass es auf progressive, einheitliche Weise entlang einer Achse verändert wird. Dadurch wird ein Quadrat oder ein Rechteck in ein Parallelogramm umgewandelt. Dieser visuelle Effekt ist hilfreich bei der Erzeugung der Illusion von Tiefe auf einer zweidimensionalen Fläche.
Eine Verzerrung kann für einen bestimmten Winkel entweder auf der x- oder auf der y-Achse und um einen Mittelpunkt angewendet werden. Diese Möglichkeiten können natürlich so kombiniert werden, dass gleichzeitig für beide Achsen verzerrt wird. Das folgende XAML verzerrt unser Rechteck entlang der x-Achse um 45 Grad:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="80" Canvas.Top="80"> 
     <Rectangle.RenderTransform> 
       <SkewTransform AngleX="45"/> 
     </Rectangle.RenderTransform> 
   </Rectangle>
Das Ergebnis ist in Abbildung 4 dargestellt.
Abbildung 4 Verzerren des Rechtecks mit SkewTransform (zum Vergrößern auf das Bild klicken)
Durch Verzerren werden dreidimensionale Effekte in Grafiken simuliert. SkewTransform kann z. B. auf drei benachbarte Rechtecke angewendet werden, von denen zwei auf der x-Achse und eines auf der y-Achse verzerrt werden, um die Illusion einer dreidimensionalen Perspektive zu erzeugen (siehe Abbildung 5).
Abbildung 5 Simulieren von Perspektive mit drei verzerrten Rechtecken (zum Vergrößern auf das Bild klicken)

Definieren von Transformationen mit MatrixTransform
Alle Transformationen werden im Grunde durch Multiplizieren des Koordinatenbereichs des Objekts mit einer Transformationsmatrix durchgeführt. Alle Transformationen, die ich bisher beschrieben habe, sind bekannte und definierte Transformationen. Matrixmathematik und die Implementierung von Transformationen übersteigen den Umfang dieses Artikels, aber um der syntaktischen Vollständigkeit willen werde ich darlegen, wie sie in Silverlight-XAML implementiert werden.
Beachten Sie, dass die in MatrixTransform verwendete Matrix eine affine Matrix ist, das heißt, dass die unterste Reihe der Matrix immer auf (0 0 1) gesetzt ist und nur die ersten beiden Spalten festgelegt werden. Diese werden mit der Matrix-Eigenschaft der Transformation durch eine Zeichenfolge festgelegt, die die ersten beiden Reihen durch Leerzeichen getrennter Werte enthält:
<Rectangle Fill="#FFFF0404" 
     Stroke="#FF000000" 
     Width="96" Height="88" 
     Canvas.Left="80" Canvas.Top="80"> 
     <Rectangle.RenderTransform> 
       <MatrixTransform Matrix="1 0 1 2 0 1"/> 
     </Rectangle.RenderTransform> 
   </Rectangle>
Durch die Transformation mithilfe dieser Matrix wird ein kombiniertes gestrecktes und verzerrtes Rechteck gerendert.

Kombinieren von Transformationen
Wie am vorherigen Beispiel gezeigt, kann eine komplexe Transformation mithilfe einer affinen Transformationsmatrix erstellt und mithilfe des MatrixTransform-Typs festgelegt werden. Sollten Sie jedoch kein Experte in Matrixmathematik sein, gibt es ein anderes Verfahren für die Verwendung von Transformationen zu deren Kombination mittels des TransformGroup-Elements. Dadurch können mehrere Transformationen einfach festgelegt werden, und der kombinierte Effekt jeder Transformation wird auf das Objekt angewendet. Hier ist ein Beispiel:
<Rectangle Fill="#FFFF0404" Stroke="#FF000000" 
  Width="96" Height="88" 
  Canvas.Left="80" Canvas.Top="80"> 
  <Rectangle.RenderTransform> 
    <TransformGroup> 
      <ScaleTransform ScaleX="1.2" ScaleY="1.2" /> 
      <SkewTransform AngleX="30" /> 
      <RotateTransform Angle="45" /> 
    </TransformGroup> 
  </Rectangle.RenderTransform> 
</Rectangle>
Dieses Beispiel kombiniert ScaleTransform, das die Größe der Form entlang beider Achsen um 20 Prozent erhöht, mit einer Verzerrung um 30 Grad entlang der x-Achse und einer Drehung um 45 Grad.

Animation bedeutet wörtlich „beleben“. Das heißt, mit Animationen können Sie Ihren Objekten Leben einhauchen, indem Sie Attribute wie z. B. Farbe, Größe, Deckkraft und andere Eigenschaften über einen bestimmten Zeitraum als Reaktion auf Benutzeraktionen ändern.
In XAML wird ein Element durch Ändern einer oder mehrerer Eigenschaften über einen Zeitraum animiert. Diese Zeit wird mithilfe einer Zeitachse definiert. Um z. B. ein Element in 5 Sekunden über den Bildschirm zu verschieben, wird eine Zeitachse von fünf Minuten festgelegt, die die Canvas.Left-Eigenschaft von 0 bis zur Breite des Bildschirms animiert. In den folgenden Abschnitten erörtere ich jeden verfügbaren Animationstyp sowie den Unterschied bei der Animation dieser Eigenschaften mithilfe von Keyframes.
Bevor Sie sich die verschiedenen Animationstypen ansehen, sollten Sie wissen, dass es ein Framework für Animationen mit Auslösern, Ereignisauslösern und Storyboards gibt. Zunächst werde ich jedoch diese Grundkonzepte beleuchten und anschließend die unterschiedlichen Animationstypen detaillierter vorstellen.

Verwenden von Auslösern und Ereignisauslösern
In Silverlight finden Animationen als Reaktion auf ein Ereignis statt, das mithilfe eines Auslösers definiert wurde. Momentan wird in Silverlight-XAML nur ein Auslöser unterstützt, der Ereignisauslöser (EventTrigger). Jede Benutzeroberflächeneigenschaft verfügt über eine Auslösersammlung, die zum Definieren eines oder mehrerer Auslöser verwendet wird (das heißt, eines oder mehrerer Ereignisauslöser).
Daher muss beim Hinzufügen einer Animation zu einem Element zunächst seine Auslösersammlung definiert werden. Anschließend muss der erstellten Sammlung mindestens ein Ereignisauslöser hinzugefügt werden. Wenn Sie z. B. ein Rechteck animieren, sieht der erste Schritt – das Festlegen der Auslösersammlung – folgendermaßen aus:
<Rectangle x:Name="rect" Fill="Red" 
  Canvas.Top="100" Canvas.Left="100" 
  Width="100" Height="100"> 
  <Rectangle.Triggers> 
  </Rectangle.Triggers> 
</Rectangle>
Danach muss ein Ereignisauslöser definiert werden, der dieser Sammlung hinzugefügt wird. Bei diesem Ereignisauslöser wird die RoutedEvent-Eigenschaft verwendet, um festzulegen, als Reaktion auf welches Ereignis die Animation ausgeführt wird. Beachten Sie, dass RoutedEvent nur das Loaded-Ereignis unterstützt.
Zum Implementieren einer Animation, die beim Laden des Rechecks gestartet wird, müsste der Ereignisauslöser folgendermaßen angegeben werden:
<EventTrigger RoutedEvent="Rectangle.Loaded"> 
</EventTrigger>
Der XAML-Ausschnitt zu Ausführen dieser Animation sieht folgendermaßen aus:
<Rectangle x:Name="rect" Fill="Red" Canvas.Top="100" 
  Canvas.Left="100" Width="100" Height="100"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>
Als Nächstes wird die zu verwendende Animation definiert. Animationen sind in Storyboards enthalten.

Verwenden von BeginStoryboard und Storyboard
BeginStoryboard ist eine Auslöseraktion, die ein Storyboard-Objekt enthält. Storyboard-Objekte enthalten die Animationsdefinitionen. Beim Definieren einer Animation werden diese Objekte einfach in die EventTrigger-Definition eingebettet. Der folgende Code zeigt, wie dies mithilfe meines Rechteckbeispiels erreicht werden kann:
<Rectangle x:Name="rect" Fill="Red" 
  Canvas.Top="100" Canvas.Left="100" 
  Width="100" Height="100"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>

Definieren der Animationsparameter
Nachdem das Framework für die Animation eingerichtet wurde, kann die Animation festgelegt werden, die durchgeführt werden soll. Ganz einfach gesagt, definiert die Animation das Ändern einer Eigenschaft über einen Zeitraum. Es können drei verschiedene Eigenschaftstypen animiert werden. Jeder dieser Eigenschaftstypen wird von einem Wert, der im Attribut „From“ angegeben ist (oder dem aktuellen Wert, falls er nicht festgelegt ist), entweder zu einem Wert animiert, der im Attribut „To“ angegeben ist, oder um einen Wert, der im Attribut „By“ angegeben ist.
Double-Typen – Diese werden mithilfe von DoubleAnimation oder DoubleAnimationUsingKeyFrames animiert. Diese Methode wird zum Animieren von Eigenschaften mit double-Werten verwendet, z. B. für Dimensionen wie Canvas.Left oder visuelle Attribute wie Opacity (Deckkraft).
Point-Typen – Diese werden mithilfe eines PointAnimiation- oder PointAnimationUsingKeyFrames-Typs animiert. Diese spezielle Methode wird zum Animieren von Eigenschaften verwendet, die einen Point-Wert enthalten, wie z. B. Liniensegmente oder Kurven, die mithilfe von Punkten definiert werden.
Color-Typen – Diese werden mithilfe eines ColorAnimation- oder ColorAnimationUsingKeyFrames-Typs animiert. Diese Methode wird zum Animieren von Eigenschaften verwendet, die einen Farbwert enthalten, z. B. der Hintergrund oder Strich eines Elements.

Anpassen der Animation
Um zu definieren, auf welches Objekt die Animation angewendet werden soll, wird für diese Animationentypen die Storyboard.TargetName-Eigenschaft verwendet. Sie muss den Namen des jeweiligen Objekts erhalten, der mit der x:Name-Eigenschaft festgelegt wird. Zusätzlich wird mithilfe von Storyboard.TargetProperty die Eigenschaft angegeben, die animiert wird. Beachten Sie, dass eine komplexe oder angefügte Eigenschaft (wie z. B. Canvas.Left) in Klammern angegeben wird. Um z. B. eine Double-Animation festzulegen, die auf Canvas.Left des Rechtecks namens „rect“ abzielt, sieht das XAML folgendermaßen aus:
<DoubleAnimation Storyboard.TargetName="rect" 
  Storyboard.TargetProperty="(Canvas.Left)" />

Festlegen von Animationseigenschaften
Um zu definieren, wie lange der Übergang der jeweiligen Eigenschaften von einem Wert zu einem anderen dauert, wird die Duration-Eigenschaft verwendet. Beachten Sie, dass diese im Format HH:MM:SS angegeben wird, wobei eine Zeitspanne für die Animation von fünf Sekunden als 00:00:05, abgekürzt als 0:0:5, angegeben wird.
<DoubleAnimation Storyboard.TargetName="rect" 
  Storyboard.TargetProperty="(Canvas.Left)" Duration="0:0:5" />
Soll die Animation nicht sofort beginnen, kann mithilfe der BeginTime-Eigenschaft und derselben Syntax eine Verzögerung eingefügt werden:
<DoubleAnimation Storyboard.TargetName="rect" 
  Storyboard.TargetProperty="(Canvas.Left)" BeginTime="0:0:5" />
Das Verhalten der Animation kann durch Multiplizieren der Dauer mit einem Geschwindigkeitsverhältnis angepasst werden. Dies geschieht mit der SpeedRatio-Eigenschaft. Im vorherigen Beispiel wurde die Dauer auf 5 Sekunden festgelegt. Das Geschwindigkeitsverhältnis kann so geändert werden, dass die Animation 10 Sekunden dauert. Dafür wird SpeedRatio auf 2 gesetzt. Alternativ kann die Animation auf 1 Sekunde beschleunigt werden, indem SpeedRatio auf 0.2 gesetzt wird.
<DoubleAnimation Storyboard.TargetName="rect" 
  Storyboard.TargetProperty="(Canvas.Left)" 
  SpeedRatio="2" Duration="0:0:5" />
Animation mit Silverlight bietet die Möglichkeit, die vorgenommenen Änderungen als Teil der Animation zu speichern. Wird z. B. ein double-Wert von 0 bis 500 über einen bestimmten Zeitrahmen verschoben, veranlasst AutoReverse, dass sich die Animation von 500 zurück auf 0 verschiebt.
Wenn die Dauer der Animation wie zuvor auf 5 Sekunden und AutoReverse auf „true“ gesetzt ist, dauert die gesamte Animation 10 Sekunden. Es folgt ein Beispiel von XAML mit der AutoReverse-Eigenschaft:
<DoubleAnimation Storyboard.TargetName="rect"    
  Storyboard.TargetProperty="(Canvas.Left)" 
  AutoReverse="True" 
  Duration="0:0:5" />

Festlegen der RepeatBehavior-Eigenschaft
Wenn die Animation beendet ist, kann eine Reihe von Optionen angewendet werden, um das Verhalten zu steuern. Diese werden mithilfe der RepeatBehavior-Eigenschaft festgelegt. Diese Eigenschaft kann drei verschiedene Werttypen annehmen:
  • Eine Zeit, die in Sekunden angegeben wird. Die Zeitachse wartet für diese Zeit und startet die Animation anschließend erneut.
  • Für eine konstante Wiederholung wird das Wiederholungsverhalten auf „Forever“ gesetzt.
  • Eine bestimmte Anzahl von Wiederholungen wird durch angeben einer Zahl gefolgt von x festgelegt. Soll die Animation z. B. drei Mal laufen, geben Sie den Wert „3x“ an.
Abbildung 6 zeigt das vollständige XAML für das animierte Rechteck, um es entlang der x-Achse von 100 nach 500 und wieder zurück auf 100 zu verschieben und dieses Verhalten drei Mal zu wiederholen:
<Rectangle x:Name="rect" Fill="Red" 
  Canvas.Top="100" Canvas.Left="100" 
  Width="100" Height="100"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <DoubleAnimation RepeatBehavior="3x"               
            Storyboard.TargetName="rect" 
            Storyboard.TargetProperty="(Canvas.Left)" 
            To="500" Duration="0:0:5" 
            AutoReverse="True" /> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>
Nun soll jeder dieser Animationstypen genauer betrachtet werden. Zuerst untersuche ich die Attribute, die zum Animieren jedes einzelnen Typs erforderlich sind, und anschließend werde ich darauf eingehen, wie der zugehörige Keyframetyp der Animation in das Bild passt.

Animieren eines Werts mit DoubleAnimation
Mithilfe des DoubleAnimation-Objekts kann angegeben werden, wie sich ein double-Wert in Bezug auf eine bestimmte Zeitachse ändert. Die Animation wird als lineare Interpolation zwischen den Eigenschaftswerten mit der Zeit berechnet.
Beim Animieren eines double-Werts wird der Wert zu Beginn der Animation mithilfe des Werts „From“ angegeben und dann entweder in den Wert „To“ geändert, der ein absolutes Ziel angibt, oder in den Wert „By“, der ein relatives Ziel angibt. Wird z. B. die Canvas.Left-Eigenschaft eines Objekts von 100 (nahe der linken Seite des Bildschirms) zu 500 verschoben, können „From“ auf 100 und „To“ auf 500 bzw. „By“ auf 400 gesetzt werden. Werden beide Eigenschaften angegeben, erhält „To“ Vorrang und „By“ wird ignoriert. Befindet sich das Rechteck bereits an der gewünschten From-Position, muss diese Eigenschaft nicht festgelegt werden.
Das vorherige XAML-Beispiel hat dieses Verhalten gezeigt. Das Rechteck befindet sich bei einem Canvas.Left-Wert von 100, und DoubleAnimation gibt den To-Wert als 500 an. Somit wird der Wert durch die Animation von 100 bis 500 verschoben, wodurch sich das Rechteck über den Bildschirm nach rechts verschiebt.

Animieren einer Farbe mit ColorAnimation
ColorAnimation funktioniert auf ähnliche Weise wie DoubleAnimation. Es dient zum Festlegen der Veränderung des Farbwerts eines Elements über eine bestimmte Zeit. Die Animation wird dann als lineare Interpolation zwischen den Farbwerten während der festgelegten Zeit berechnet.
Beim Animieren einer Farbe wird der Wert zu Beginn der Animation mithilfe der From-Eigenschaft angegeben. Ist diese nicht angegeben, wird die aktuelle Farbe verwendet. Die gewünschte Endfarbe wird mithilfe des To-Attributs angegeben. Es kann auch ein By-Attribut angegeben werden, das die Endfarbe angibt, die das Ergebnis des Hinzufügens des Werts der From-Farbe (oder der Startfarbe) zur By-Farbe ist.
Beim Animieren einer farbbasierten Eigenschaft werden die Inhalte der Eigenschaft nicht direkt animiert, da der Inhalt der Eigenschaft normalerweise ein Pinsel und keine Farbe ist. Soll also die Füllfarbe eines Rechtecks animiert werden, verwenden Sie nicht die Fill-Eigenschaft des Rechtecks als Ziel. Stattdessen geben Sie an, dass die Color-Eigenschaft von SolidBrush animiert werden soll, das zum Durchführen der Füllung verwendet wird.
Abbildung 7 zeigt ein Beispiel für das Animieren der Farbe eines Rechtecks, das Ändern der Farbe von Schwarz in Weiß über einen Zeitraum von fünf Sekunden mithilfe einer Farbanimation. Wie aus dem Code ersichtlich ist, legt dieser XAML-Ausschnitt die Color-Eigenschaft von SolidColorBrush fest, das die Form als Zieleigenschaft füllt. Beachten Sie, dass es sich hierbei um die typische XAML-Syntax handelt, die für komplexe Eigenschaften wie dieses Szenario verwendet wird.
<Rectangle x:Name="rect" Canvas.Top="100" 
  Canvas.Left="100" Width="100" 
  Height="100" Fill="Black"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <ColorAnimation Storyboard.TargetName="rect" 
            Storyboard.TargetProperty= 
            "(Shape.Fill).(SolidColorBrush.Color)" 
            To="#00000000" Duration="0:0:5" /> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>

Animieren eines Punkts mit PointAnimation
Um einen Wert zu ändern, der als Punkt über einen Zeitraum definiert ist, wird der PointAnimation-Typ verwendet. Die Animation wird dann als lineare Interpolation zwischen den Werten während der festgelegten Zeit berechnet.
Auf diese Weise wird ähnlich wie bei den Color- und Double-Animationen der Startwert mithilfe von „From“ und das Ziel entweder als relative Richtung (mithilfe von „By“) oder als absoluter Punkt (mithilfe von „To“) angegeben. Abbildung 8 zeigt ein Beispiel einer möglichen Animation des Endpunkts einer Bezierkurve. In diesem Fall ist die Bezierkurve mit einem Startpunkt bei (100,100), einem Endpunkt bei (300,100) und einem Steuerungspunkt bei (200,0) definiert. Es wird eine Animation eingerichtet, die nach dem Laden des Pfads ausgelöst wird, und sie animiert den Endpunkt der Kurve (Point2) von (300,100) zu (300,600) über eine Zeitdauer von fünf Sekunden.
<Path Stroke="Black" > 
  <Path.Data> 
    <PathGeometry> 
      <PathFigure StartPoint="100,100"> 
        <QuadraticBezierSegment x:Name="seg" 
          Point1="200,0" Point2="300,100"  /> 
      </PathFigure> 
    </PathGeometry> 
  </Path.Data> 
  <Path.Triggers> 
    <EventTrigger RoutedEvent="Path.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <PointAnimation Storyboard.TargetName="seg" 
            Storyboard.TargetProperty="Point2" 
            From="300,100" To="300,600" Duration="0:0:5" /> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Path.Triggers> 
</Path>

Verwenden von Keyframes
Die drei Animationentypen, die hier vorgestellt wurden – ColorAnimation, DoubleAnimation und PointAnimation – funktionieren alle durch Ändern einer definierten Eigenschaft über einen Zeitraum mithilfe einer linearen Interpolation. Verschieben Sie z. B. einen double-Wert von 100 zu 500 über fünf Sekunden, wird er jede Sekunde um 80 erhöht.
Für jeden dieser drei Animationstypen kann dieser Übergang mit einem Satz von Meilensteinen namens „Keyframes“ definiert werden. Um das lineare Verhalten der Animation von der Starteigenschaft zur Endeigenschaft zu ändern, werden einfach eines oder mehrere Keyframes eingefügt. Danach wird der Stil der Animation definiert, der zwischen diesen verschiedenen Punkten gewünscht ist.
Keyframes werden mithilfe von Schlüsselzeiten definiert. Dabei handelt es sich um Zeiten, die relativ zur Startzeit der Animation festgelegt werden. Außerdem geben sie die Endzeit des Keyframes an. Wird z. B. eine Animation über neun Sekunden mit drei im gleichmäßigen Abstand angeordneten Keyframes benötigt, kann festgelegt werden, dass der erste Keyframe bei 0:0:3 endet, der zweite bei 0:0:6 und der dritte bei 0:0:9. Beachten Sie, dass die Dauer der Schlüsselzeit nicht angegeben werden muss, stattdessen wird die Endzeit jedes Keyframes festgelegt.
Ein weiteres Beispiel ist eine Double-Animation, die den halben Bereich von 100 bis 500 abdecken soll. In der ersten Hälfte soll sich die Animation sehr schnell verschieben und in der zweiten Hälfte sehr langsam. Insgesamt ist ein Gesamtübergang von sechs Sekunden erforderlich. Da 350 der Mittelpunkt zwischen 100 und 500 ist, wird der Beginn eines Keyframes bei 350 definiert. Die Zeitdauer wischen dem Startpunkt und dem Mittelpunkt wird mithilfe eines Keyframes von 0:0:1 auf eine Sekunde festgelegt. Anschließend wird mithilfe eines zweiten Keyframes von 0:0:6 eine Zeitdauer von fünf Sekunden zwischen dem Mittelpunkt und dem Endpunkt festgelegt. Jetzt ist das Objekt so definiert, dass es vom Startpunkt zum Mittelpunkt eilt und den Rest der Strecke schleicht.
Im vorherigen Beispiel sind beide animierten Segmente linear interpoliert. Für zusätzliche Flexibilität stehen zwei weitere Keyframetypen zur Verfügung: ein einzelner Keyframe, der den Wert zwischen den beiden Werten sofort überspringt, sowie ein Splinekeyframe, der den Wert zwischen dem ersten Punkt und dem Endpunkt mithilfe einer quadratischen Kurve zum Definieren der Interpolation verschiebt. (In den folgenden Abschnitten werde ich zeigen, wie eine Animation mithilfe von Keyframes für den Double-Typ definiert wird. Beachten Sie, dass die gleichen Prinzipien für die Animationstypen „Point“ und „Color“ gelten.)
Zum Festlegen von Keyframes wird auf die Animation das UsingKeyFrames-Postfix angewendet. Das heißt, um Double-Animationen zu definieren und Keyframes zu verwenden, wird DoubleAnimationUsingKeyFrames verwendet, in dem das Ziel und die Eigenschaft (wie bei Verwendung von DoubleAnimation) festgelegt werden. DoubleAnimationUsingKeyFrames enthält die Keyframedefinitionen. (Wie bereits erwähnt, triff dies auch auf PointAnimationUsingKeyFrames oder ColorAnimationUsingKeyFrames zu.)

Verwenden linearer Keyframes
Die Standardmethode für Animation zwischen zwei Eigenschaftswerten ist lineare Interpolation, in der der Betrag über einen Zeitraum gleichmäßig aufgeteilt wird. Außerdem können lineare Schritte zwischen Frames mithilfe des LinearKeyFrame-Typs definiert werden, wobei lineare Interpolation weiterhin verwendet wird, jedoch zwischen Keyframes, sodass ein Beschleunigungs-/Verlangsamungseffekt erzielt wird.
Sehen Sie sich den Code an, der im ersten Teil von Abbildung 9 gezeigt wird. Hier wird DoubleAnimationUsingKeyFrames verwendet, das zwei Keyframes definiert. Einer definiert eine lineare Interpolation zwischen 0 und 300 für Canvas.Left-Änderungen über eine Sekunde, und der andere definiert eine lineare Interpolation zwischen 300 und 600 für Canvas.Left-Änderungen über acht Sekunden. Dadurch verschiebt sich das Rechteck schnell bis zum Mittelpunkt und dann langsam für den Rest des Wegs. Ähnliche Prinzipien gelten für LinearPointKeyFrame und LinearColorKeyFrame.
Lineare Interpolation
<Rectangle Fill="#FFFF0000" Stroke="#FF000000" 
  Width="40" Height="40" 
  Canvas.Top="40" x:Name="rect"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="rect" 
            Storyboard.TargetProperty="(Canvas.Left)" > 
            <LinearDoubleKeyFrame KeyTime="0:0:1" Value="300" /> 
            <LinearDoubleKeyFrame KeyTime="0:0:9" Value="600" /> 
          </DoubleAnimationUsingKeyFrames> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>
Einzelne Keyframes
<Rectangle Fill="#FFFF0000" Stroke="#FF000000" 
  Width="40" Height="40" 
  Canvas.Top="40" x:Name="rect"> 
  <Rectangle.Triggers> 
    <EventTrigger RoutedEvent="Rectangle.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="rect" 
            Storyboard.TargetProperty="(Canvas.Left)" > 
            <DiscreteDoubleKeyFrame KeyTime="0:0:1" Value="300" /> 
            <DiscreteDoubleKeyFrame KeyTime="0:0:9" Value="600" /> 
          </DoubleAnimationUsingKeyFrames> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Rectangle.Triggers> 
</Rectangle>

Verwenden einzelner Keyframes
Soll die Eigenschaft ohne lineare Interpolation von einem Wert in einen anderen geändert werden, können Sie einen einzelnen Keyframe verwenden. Dadurch springt das Objekt bei der festgelegten Keyframezeit zu dem Wert.
Der zweite Teil von Abbildung 9 zeigt das gleiche Beispiel wie zuvor. Hier wird jedoch ein einzelner Keyframe verwendet. Eine Sekunde nach Start der Animation springt das Rechteck die halbe Strecke über den Bildschirm. Neun Sekunden nach Start der Animation springt es auf die rechte Seite des Bildschirms. Beachten Sie, dass ähnliche Prinzipien für DiscretePointKeyFrame und DiscreteColorKeyFrame gelten.

Verwenden von Splinekeyframes
Zum Ändern der Eigenschaft von einem Wert in einen anderen mithilfe eines gebogenen Werts, der zu einer Beschleunigung oder Verlangsamung führt, dient ein Splinekeyframe. Zunächst wird eine quadratische Bezierkurve definiert, und anschließend wird die Geschwindigkeit der Eigenschaft für die Verschiebung von einem Wert zum anderen mittels Parallelprojektion dieser Kurve bestimmt.
Da dies möglicherweise schwer vorstellbar ist, denken Sie an folgendes Szenario: Die Sonne steht im Zenit, und Sie schießen einen Fußball über das Feld. Sie betrachten den Schatten des Balls. Während er in die Luft steigt, scheint sich die Verschiebung des Schattens zu beschleunigen. Mit Erreichen des Scheitelpunkts verlangsamt sich der Schatten. Während der Ball fällt, beschleunigt sich die Geschwindigkeit des Schattens erneut, bis der Ball auf den Boden fällt.
Stellen Sie sich vor, dass Ihre Animation in diesem Fall der Schatten des Balls und der Spline die Kurve des Fußballs ist. Sie definieren die Flugbahn des Fußballs, einen Spline, mithilfe eines KeySpline. Der KeySpline definiert Steuerungspunkte für eine quadratische Bezierkurve. Sie ist normalisiert, sodass der erste Punkt der Kurve bei 0 und der zweite bei 1 liegt. Für eine Parabel, der die Flugbahn des Fußballs folgt, enthält der KeySpline zwei durch Komma getrennte normalisierte Werte.
Zum Definieren einer Kurve wie beim Flug eines Fußballs können Sie den Spline mithilfe eines KeySpline wie z. B. „0.3,0 0.6,1“ festlegen. Das definiert den ersten Punkt der Kurve bei (0.3,0) und den zweiten bei (0.6,1). Dadurch beschleunigt die Animation bis etwa zu einem Drittel des Gesamtverschiebung des Fußballs schnell. Anschließend verschiebt sie sich mit gleichmäßiger Geschwindigkeit bis etwa zwei Drittel der Flugbahn des Balls erreicht sind. Dann verlangsamt sich die Animation für den Rest des Fußballflugs, da sie den Fall des Balls auf die Erde simuliert.
Abbildung 10 zeigt ein Beispiel für die Verwendung eines KeySpline zum Definieren des Spline für diese Simulation mithilfe von DoubleAnimationUsingKeyFrames. Dieses Beispiel animiert die Ellipse so, dass sie sich ähnlich dem Schatten eines Fußballs über den Bildschirm verschiebt, als würde der Betrachter über dem Fußball stehen und nach unten Richtung Erde sehen, während der Ball durch die Luft fliegt.
<Ellipse Fill="a#FF444444" Stroke="#FF444444" 
  Width="40" Height="40" 
  Canvas.Top="40" x:Name="ball"> 
  <Ellipse.Triggers> 
    <EventTrigger RoutedEvent="Ellipse.Loaded"> 
      <BeginStoryboard> 
        <Storyboard> 
          <DoubleAnimationUsingKeyFrames 
            Storyboard.TargetName="ball" 
            Storyboard.TargetProperty="(Canvas.Left)" > 
            <SplineDoubleKeyFrame KeyTime="0:0:5" 
              KeySpline="0.3,0 0.6,1" Value="600" /> 
          </DoubleAnimationUsingKeyFrames> 
        </Storyboard> 
      </BeginStoryboard> 
    </EventTrigger> 
  </Ellipse.Triggers> 
</Ellipse>

Animation und Expression Blend
Animationen können in Expression Blend™ grafisch definiert werden. Dadurch wird das XAML zum Durchführen der Animation generiert, und die verschiedenen Animationstypen werden automatisch bereitgestellt.
Wählen Sie bei Verwendung von Expression Blend im Menü „Fenster“ den Animationsarbeitsbereich aus. Dieser bietet Ihnen die Tools zum grafischen Erstellen von Zeitachsen, und wenn Sie die Eigenschaften, die geändert werden sollen, mithilfe des visuellen Editors bearbeiten, wird der XAML-Code für die Animation generiert.
Am unteren Rand des Bildschirms sehen Sie die Ansicht „Objekte und Zeitachsen“. Damit können Sie eine Zeitachse und anschließend visuell Keyframes hinzufügen. Klicken Sie zum Hinzufügen einer neuen Zeitachse in der Ansicht „Objekte und Zeitachsen“ auf die Schaltfläche „+“.
Wenn Sie auf die Schaltfläche „+“ klicken, wird das Dialogfeld „Storyboard erstellen“ angezeigt, und Sie werden aufgefordert, einen Namen für das zu erstellende Storyboard einzugeben. In diesem Fall habe ich den Standardnamen von „Storyboard1“ in „Timeline1“ geändert und das Kontrollkästchen „Create as Resource“ (Als Ressource erstellen) deaktiviert.
Mit Expression Blend kann eine Animation auf der Canvas-Ebene oder als Ressource erstellt werden. Im ersteren Fall werden Animationen als Reaktion auf Auslöser auf dem Canvas ausgeführt. Im Folgenden sehen Sie eine Beispiel des XAML, das mit Blend über das Dialogfeld „Storyboard erstellen“ erstellt wurde, wobei der Benutzer festgelegt hat, dass die Animation nicht als Ressource erstellt werden soll:
<Canvas.Triggers> 
  <EventTrigger RoutedEvent="Canvas.Loaded"> 
    <BeginStoryboard> 
      <Storyboard x:Name="Timeline1"/> 
    </BeginStoryboard> 
  </EventTrigger> 
</Canvas.Triggers>
Beachten Sie, dass beim Aktivieren des Kontrollkästchens „Create as Resource“ das Storyboard in <Canvas.Resources> erstellt wird und von Javascript ausgeführt wird.
Die Ansicht „Objekte und Zeitachsen“ zeigt die soeben erstellte Zeitachse an. Sie sehen die Zeitachse am unteren Rand von Abbildung 11. Die vertikale Linie bei Zeit 0, die in der Zeitachse zu sehen ist, kennzeichnet die aktuelle Zeit. (In Expression Blend ist diese Linie gelb.) Zum Hinzufügen eines Keyframes wird diese Zeile einfach zu der Zeit gezogen, bei der ein Keyframe gewünscht ist. Klicken Sie anschließend auf die Schaltfläche „Keyframe aufzeichnen“. Diese Schaltfläche befindet sich direkt über der Zeitachse links von 0:00:000.
Abbildung 11 Animationsarbeitsbereich von Expression Blend (zum Vergrößern auf das Bild klicken)
Ziehen Sie die Linie zur Vier-Sekunden-Markierung, und fügen Sie einen Keyframe hinzu. Der Keyframe wird als kleines ovales Symbol auf der Zeitachse hinzugefügt. Nachdem sich die Zeitachse auf dem Vier-Sekunden-Frame befindet und ein Keyframe hinzugefügt wurde, können Sie die Farbe des Rechtecks, den Ort, die Deckkraft oder die Form bearbeiten. Die korrekten Transformationen, die für die Animation erforderlich sind, werden von Blend berechnet. Wenn Sie den Zeitachsenindikator verschieben, wird eine Vorschau der Animation angezeigt, und Sie sehen, wie sie sich zu einer bestimmten Zeit verhält.

In diesem Artikel habe ich erläutert, wie Transformationen und Animationen in Silverlight-XAML definiert werden. Ich habe Ihnen die verschiedenen Transformationstypen zum Drehen, Skalieren oder Verzerren eines Objekts sowie Freiformtransformationen mithilfe einer affinen Matrix, die auf eine Form angewendet wird, vorgestellt. Es wurde ein Überblick über Animationen geboten, und es wurde gezeigt, wie eine Animation basierend auf einem XAML-Auslöser ausgeführt wird. Sie haben gesehen, wie Animationen Eigenschaftswerte über einen Zeitraum ändern, und wir haben die XAML-Typen betrachtet, die die Animation von double-, point- und color-Werten unterstützen. Anschließend habe ich erläutert, wie Keyframes für eine genauere Steuerung der Animationen verwendet werden. Abschließend habe ich den Animationsdesigner von Expression Blend vorgestellt, um Ihnen zu zeigen, wie einfach Animationen mithilfe von Expression Blend visuell erzeugt werden können.

Laurence Moroney ist bei Microsoft als leitender Technologieexperte mit dem Schwerpunkt Silverlight tätig. Er ist Autor zahlreicher Bücher über Themen aus der Datenverarbeitung, einschließlich Silverlight, AJAX, Interoperabilität und Sicherheit. Sie finden seinen Blog unter blogs.msdn.com/webnext.
Page view tracker