Dela via


Översikt över Storyboards

Det här avsnittet visar hur du använder Storyboard objekt för att ordna och använda animeringar. Den beskriver hur du interaktivt manipulerar Storyboard objekt och beskriver syntax för indirekt egenskapsmål.

Förutsättningar

För att förstå det här avsnittet bör du känna till de olika animeringstyperna och deras grundläggande funktioner. En introduktion till animering hittar du i Animation Översikt. Du bör också veta hur du använder bifogade egenskaper. Mer information om bifogade egenskaper finns i översikten över bifogade egenskaper.

Vad är en storyboard

Animeringar är inte den enda användbara typen av tidslinje. Andra tidslinjeklasser finns för att hjälpa dig att organisera grupper av tidslinjer, och tillämpa tidslinjer på egenskaper. Tidslinjer för containrar härleds från klassen TimelineGroup och innehåller ParallelTimeline och Storyboard.

En Storyboard är en typ av containertidslinje som innehåller målinformation för de tidslinjer som den innehåller. En Storyboard kan innehålla alla typer av Timeline, inklusive andra tidslinjer och animeringar för containrar. Storyboard objekt kan du kombinera tidslinjer som påverkar en mängd olika objekt och egenskaper i ett enda tidslinjeträd, vilket gör det enkelt att organisera och kontrollera komplexa tidsbeteenden. Anta till exempel att du vill ha en knapp som gör dessa tre saker.

  • Öka och ändra färg när användaren väljer knappen.

  • Krymp bort och öka sedan tillbaka till den ursprungliga storleken när du klickar.

  • Krymp och blekna till 50 procent opacitet när den inaktiveras.

I det här fallet har du flera uppsättningar animeringar som gäller för samma objekt och som du vill spela upp vid olika tidpunkter, beroende på knappens tillstånd. Storyboard objekt möjliggör att du kan ordna animeringar och tillämpa dem i grupper på ett eller flera objekt.

Var kan du använda en storyboard

En Storyboard kan användas för att animera beroendeegenskaper för animerbara klasser (för mer information om vad som gör en klass animerbar, se animeringsöversikten ). Men eftersom storyboarding är en funktion på ramverksnivå måste objektet vara del av NameScope i en FrameworkElement eller en FrameworkContentElement.

Du kan till exempel använda en Storyboard för att göra följande:

Du kunde dock inte använda en Storyboard för att animera en SolidColorBrush som inte registrerade dess namn med en FrameworkElement eller FrameworkContentElement, eller som inte användes för att ange en egenskap för en FrameworkElement eller FrameworkContentElement.

Hur man använder animeringar med en storyboard

Om du vill använda en Storyboard för att ordna och använda animeringar lägger du till animeringarna som underordnade tidslinjer för Storyboard. Klassen Storyboard tillhandahåller de bifogade egenskaperna Storyboard.TargetName och Storyboard.TargetProperty. Du anger dessa egenskaper för en animering för att ange dess målobjekt och egenskap.

Om du vill tillämpa animeringar på deras mål börjar du Storyboard med hjälp av en utlösaråtgärd eller en metod. I XAML använder du ett BeginStoryboard-objekt med en EventTrigger, Triggereller DataTrigger. I kod kan du också använda metoden Begin.

I följande tabell visas de olika områden där varje Storyboard-börjarteknik stöds: per instans, formatmall, kontrollmall och datamall. "Per instans" refererar till tekniken för att tillämpa en animering eller storyboard direkt på instanser av ett objekt, i stället för i en formatmall, kontrollmall eller datamall.

Storyboard har börjat använda... Per instans Stil Kontrollmall Datamall Exempel
BeginStoryboard och en EventTrigger Ja Ja Ja Ja Animera en egenskap med hjälp av en Storyboard-
BeginStoryboard och en egenskap Trigger Nej Ja Ja Ja utlösa en animering när ett egenskapsvärde ändras
BeginStoryboard och en egenskap MultiTrigger Nej Ja Ja Ja exempel på MultiTrigger-klass
BeginStoryboard och en DataTrigger Nej Ja Ja Ja Så här utlöser du en animering när data ändras
BeginStoryboard och en MultiDataTrigger Nej Ja Ja Ja klassexempel för MultiDataTrigger
Begin metod Ja Nej Nej Nej Animera en egendom med hjälp av en Storyboard

I följande exempel används en Storyboard för att animera Width hos ett Rectangle-element och Color hos en SolidColorBrush som används för att måla Rectangle.

<!-- This example shows how to animate with a storyboard.-->
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.Samples.Animation.StoryboardsExample" 
  WindowTitle="Storyboards Example">
  <StackPanel Margin="20">
    
    <Rectangle Name="MyRectangle"
      Width="100"
      Height="100">
      <Rectangle.Fill>
        <SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
      </Rectangle.Fill>
      <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseEnter">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation 
                Storyboard.TargetName="MyRectangle"
                Storyboard.TargetProperty="Width"
                From="100" To="200" Duration="0:0:1" />
              
              <ColorAnimation 
                Storyboard.TargetName="MySolidColorBrush"
                Storyboard.TargetProperty="Color"
                From="Blue" To="Red" Duration="0:0:1" />  
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Rectangle.Triggers>
    </Rectangle> 
  </StackPanel>
</Page>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Data;
using System.Windows.Shapes;
using System.Windows.Input;

namespace Microsoft.Samples.Animation
{
    public class StoryboardsExample : Page
    {
        public StoryboardsExample()
        {
            this.WindowTitle = "Storyboards Example";
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(20);

            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "MyRectangle";

            // Create a name scope for the page.
            NameScope.SetNameScope(this, new NameScope());

            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Blue);
            this.RegisterName("MySolidColorBrush", mySolidColorBrush);
            myRectangle.Fill = mySolidColorBrush;

            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 100;
            myDoubleAnimation.To = 200;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation,
                new PropertyPath(Rectangle.WidthProperty));

            ColorAnimation myColorAnimation = new ColorAnimation();
            myColorAnimation.From = Colors.Blue;
            myColorAnimation.To = Colors.Red;
            myColorAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTargetName(myColorAnimation, "MySolidColorBrush");
            Storyboard.SetTargetProperty(myColorAnimation,
                new PropertyPath(SolidColorBrush.ColorProperty));
            Storyboard myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            myStoryboard.Children.Add(myColorAnimation);

            myRectangle.MouseEnter += delegate(object sender, MouseEventArgs e)
            {
                myStoryboard.Begin(this);
            };

            myStackPanel.Children.Add(myRectangle);
            this.Content = myStackPanel;
        }
    }
}

I följande avsnitt beskrivs de bifogade egenskaperna för TargetName och TargetProperty i detalj.

Rikta in sig på ramverkselement, ramverksinnehållselement och freezables

I föregående avsnitt nämndes att för att en animering ska kunna hitta målet måste den känna till målets namn och egenskapen för att animera. Att ange egenskapen att animera är enkelt: ange helt enkelt TargetProperty med namnet på egenskapen som ska animeras. Du anger namnet på det objekt vars egenskap du vill animera genom att ange egenskapen Storyboard.TargetName för animeringen.

Försiktighet

Du kan använda egenskapen Target för att binda direkt till ett objekt som ett alternativ till TargetName, men den kan inte serialiseras. Det finns ingen garanti för att Target-objektet kan refereras korrekt i XAML.

För att egenskapen TargetName ska fungera måste målobjektet ha ett namn. Att tilldela ett namn till en FrameworkElement eller en FrameworkContentElement i XAML skiljer sig från att tilldela ett namn till ett Freezable objekt.

Ramverkselement är de klasser som ärver från klassen FrameworkElement. Exempel på ramverkselement är Window, DockPanel, Buttonoch Rectangle. I stort sett alla fönster, paneler och kontroller är element. Ramverksinnehållselement är de klasser som ärver från klassen FrameworkContentElement. Exempel på ramverksinnehållselement är FlowDocument och Paragraph. Om du inte är säker på om en typ är ett ramverkselement eller ett ramverksinnehållselement kontrollerar du om den har en namnegenskap. Om det gör det är det förmodligen ett ramverkselement eller ett ramverksinnehållselement. För att vara säker, kontrollera avsnittet Arvshierarki på dess typ-sida.

Om du vill aktivera mål för ett ramverkselement eller ett ramverksinnehållselement i XAML anger du dess egenskap Name. I kod måste du också använda metoden RegisterName för att registrera elementets namn med elementet som du har skapat en NameScopeför.

Följande exempel, som tas från föregående exempel, tilldelar namnet MyRectangle en Rectangle, en typ av FrameworkElement.

<Rectangle Name="MyRectangle"
  Width="100"
  Height="100">
Rectangle myRectangle = new Rectangle();
myRectangle.Name = "MyRectangle";

// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope());

this.RegisterName(myRectangle.Name, myRectangle);

När det har ett namn kan du animera en egenskap för det elementet.

<DoubleAnimation 
  Storyboard.TargetName="MyRectangle"
  Storyboard.TargetProperty="Width"
  From="100" To="200" Duration="0:0:1" />
Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
Storyboard.SetTargetProperty(myDoubleAnimation,
    new PropertyPath(Rectangle.WidthProperty));

Freezable typer är de klasser som ärver från klassen Freezable. Exempel på Freezable är SolidColorBrush, RotateTransformoch GradientStop.

För att möjliggöra riktning av en Freezable med en animering i XAML använder du x:Name Directive för att tilldela den ett namn. I kod använder du metoden RegisterName för att registrera dess namn med elementet som du har skapat en NameScopeför .

I följande exempel tilldelas ett namn till ett Freezable objekt.

<SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Blue);
this.RegisterName("MySolidColorBrush", mySolidColorBrush);

Objektet kan sedan riktas mot en animering.

<ColorAnimation 
  Storyboard.TargetName="MySolidColorBrush"
  Storyboard.TargetProperty="Color"
  From="Blue" To="Red" Duration="0:0:1" />  
Storyboard.SetTargetName(myColorAnimation, "MySolidColorBrush");
Storyboard.SetTargetProperty(myColorAnimation,
    new PropertyPath(SolidColorBrush.ColorProperty));

Storyboard objekt använder namnområden för att lösa egenskapen TargetName. Mer information om WPF-namnomfattningar finns i WPF XAML Namescopes. Om egenskapen TargetName utelämnas riktas animeringen mot det element som den definieras för, eller, när det gäller formatmallar, det formaterade elementet.

Ibland kan ett namn inte tilldelas till ett Freezable objekt. Om till exempel en Freezable deklareras som en resurs eller används för att ange ett egenskapsvärde i ett format kan det inte ges ett namn. Eftersom det inte har något namn kan det inte riktas direkt , men det kan riktas indirekt. I följande avsnitt beskrivs hur du använder indirekt inriktning.

Indirekt målinriktning

Det finns tillfällen då en Freezable inte kan riktas direkt mot en animering, till exempel när Freezable deklareras som en resurs eller används för att ange ett egenskapsvärde i ett format. I dessa fall kan du, även om du inte kan rikta in dig på det direkt, fortfarande animera Freezable-objektet. I stället för att ange egenskapen TargetName med namnet på Freezableger du den namnet på det element som Freezable "tillhör". Till exempel tillhör en SolidColorBrush som används för att ange Fill för ett rektangelelement den rektangeln. Om du vill animera penseln ställer du in animeringens TargetProperty med en kedja av egenskaper som börjar vid egenskapen hos ramverkselementet eller systemets innehållselement där Freezable användes för att ange och slutar med egenskapen Freezable som ska animeras.

<ColorAnimation 
  Storyboard.TargetName="Rectangle01"
  Storyboard.TargetProperty="Fill.Color"
  From="Blue" To="AliceBlue" Duration="0:0:1" />
DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath);

Observera att om Freezable är fryst kommer en klon att göras och klonen kommer att animeras. När detta händer fortsätter det ursprungliga objektets egenskap HasAnimatedProperties att returnera falseeftersom det ursprungliga objektet inte är animerat. Mer information om kloning finns i översikten över frysbara objekt .

Observera också att när du använder indirekt målinriktning av egenskaper är det möjligt att rikta in sig på objekt som inte finns. Du kan till exempel anta att Background för en viss knapp har angetts med en SolidColorBrush och försöker animera dess färg, när i själva verket en LinearGradientBrush användes för att ange knappens Bakgrund. I dessa fall utlöses inget undantag. animeringen kan inte ha en synlig effekt eftersom LinearGradientBrush inte reagerar på ändringar i egenskapen Color.

Syntaxen för indirekt riktning av egenskaper beskrivs mer detaljerat i följande avsnitt.

Indirekt rikta in sig på en egenskap hos ett Freezable-objekt i XAML

Om du vill rikta in dig på en egenskap för en freezable i XAML använder du följande syntax.

Egenskapssyntax
ElementPropertyName.FreezablePropertyName

Var

Följande kod visar hur du animerar Color för en SolidColorBrush som används för att ange Fill för ett rektangelelement.

<Rectangle
  Name="Rectangle01"
  Height="100"
  Width="100"
  Fill="{StaticResource MySolidColorBrushResource}">
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <ColorAnimation 
            Storyboard.TargetName="Rectangle01"
            Storyboard.TargetProperty="Fill.Color"
            From="Blue" To="AliceBlue" Duration="0:0:1" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

Ibland måste du sikta på en frysbar som finns i en samling eller matris.

Om du vill rikta in en fryst objekt som finns i en samling använder du följande sökvägssyntax.

Sökvägssyntax
ElementPropertyName.Children[CollectionIndex].FreezablePropertyName

Där CollectionIndex är indexet för objektet i dess matris eller samling.

Anta till exempel att en rektangel har en TransformGroup resurs som tillämpas på dess egenskap RenderTransform och att du vill animera en av de transformeringar som den innehåller.

<TransformGroup x:Key="MyTransformGroupResource"
  x:Shared="False">
  <ScaleTransform />
  <RotateTransform />
</TransformGroup>

Följande kod visar hur du animerar egenskapen Angle för RotateTransform som visas i föregående exempel.

<Rectangle
  Name="Rectangle02"
  Height="100"
  Width="100"
  Fill="Blue"
  RenderTransform="{StaticResource MyTransformGroupResource}">
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.MouseEnter">
      <BeginStoryboard>
        <Storyboard>
          <DoubleAnimation 
            Storyboard.TargetName="Rectangle02"
            Storyboard.TargetProperty="RenderTransform.Children[1].Angle"
            From="0" To="360" Duration="0:0:1" />
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>  

Indirekt rikta in sig på en egenskap hos ett frysbart objekt i kod

I kod skapar du ett PropertyPath objekt. När du skapar PropertyPathanger du en Path och PathParameters.

Om du vill skapa PathParametersskapar du en matris av typen DependencyProperty som innehåller en lista över fält för beroendeegenskapsidentifierare. Det första identifierarfältet är för egenskapen för FrameworkElement eller FrameworkContentElement som Freezable används för att ange. Nästa identifierarfält representerar egenskapen hos Freezable som ska riktas mot. Se det som en kedja av egenskaper som ansluter Freezable till FrameworkElement-objektet.

Följande är ett exempel på en beroendeegenskapskedja som är inriktad på Color för en SolidColorBrush som används för att ange Fill för ett rektangelelement.

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};

Du måste också ange en Path. En Path är en String som talar om för Path hur PathParametersska tolkas. Den använder följande syntax.

Syntax för egenskapssökväg
( OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

Var

  • OwnerPropertyArrayIndex är indexet för den DependencyProperty matris som innehåller identifieraren för FrameworkElement-objektets egenskap som Freezable används för att ange, och

  • FreezablePropertyArrayIndex är indexet för den DependencyProperty matris som innehåller identifieraren av egenskapen som ska riktas mot målet.

I följande exempel visas Path som skulle följa med PathParameters som definierats i föregående exempel.

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";

I följande exempel kombineras koden i föregående exempel för att animera Color av en SolidColorBrush som används för att ställa in Fill för en rektangelformad komponent.


// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope());

Rectangle rectangle01 = new Rectangle();
rectangle01.Name = "Rectangle01";
this.RegisterName(rectangle01.Name, rectangle01);
rectangle01.Width = 100;
rectangle01.Height = 100;
rectangle01.Fill =
    (SolidColorBrush)this.Resources["MySolidColorBrushResource"];

ColorAnimation myColorAnimation = new ColorAnimation();
myColorAnimation.From = Colors.Blue;
myColorAnimation.To = Colors.AliceBlue;
myColorAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTargetName(myColorAnimation, rectangle01.Name);

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath);

Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myColorAnimation);
BeginStoryboard myBeginStoryboard = new BeginStoryboard();
myBeginStoryboard.Storyboard = myStoryboard;
EventTrigger myMouseEnterTrigger = new EventTrigger();
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent;
myMouseEnterTrigger.Actions.Add(myBeginStoryboard);
rectangle01.Triggers.Add(myMouseEnterTrigger);

Ibland måste du rikta mot ett objekt som kan frysas och som finns i en samling eller en array. Anta till exempel att en rektangel har en TransformGroup resurs som tillämpas på dess egenskap RenderTransform och att du vill animera en av de transformeringar som den innehåller.

<TransformGroup x:Key="MyTransformGroupResource"
  x:Shared="False">
  <ScaleTransform />
  <RotateTransform />
</TransformGroup>  

Om du vill rikta in dig på en Freezable som finns i en samling använder du följande sökvägssyntax.

Sökvägssyntax
( OwnerPropertyArrayIndex).(CollectionChildrenPropertyArrayIndex)[CollectionIndex].(FreezablePropertyArrayIndex)

Där CollectionIndex är indexet för objektet i dess matris eller samling.

Om du vill rikta egenskapen Angle för RotateTransform, den andra transformen i TransformGroupanvänder du följande Path och PathParameters.

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {
            Rectangle.RenderTransformProperty,
            TransformGroup.ChildrenProperty,
            RotateTransform.AngleProperty
        };
string thePath = "(0).(1)[1].(2)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath);

I följande exempel visas den fullständiga koden för att animera Angle för en RotateTransform som finns i en TransformGroup.

Rectangle rectangle02 = new Rectangle();
rectangle02.Name = "Rectangle02";
this.RegisterName(rectangle02.Name, rectangle02);
rectangle02.Width = 100;
rectangle02.Height = 100;
rectangle02.Fill = Brushes.Blue;
rectangle02.RenderTransform =
    (TransformGroup)this.Resources["MyTransformGroupResource"];

DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 0;
myDoubleAnimation.To = 360;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
Storyboard.SetTargetName(myDoubleAnimation, rectangle02.Name);

DependencyProperty[] propertyChain =
    new DependencyProperty[]
        {
            Rectangle.RenderTransformProperty,
            TransformGroup.ChildrenProperty,
            RotateTransform.AngleProperty
        };
string thePath = "(0).(1)[1].(2)";
PropertyPath myPropertyPath = new PropertyPath(thePath, propertyChain);
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath);

Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myDoubleAnimation);
BeginStoryboard myBeginStoryboard = new BeginStoryboard();
myBeginStoryboard.Storyboard = myStoryboard;
EventTrigger myMouseEnterTrigger = new EventTrigger();
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent;
myMouseEnterTrigger.Actions.Add(myBeginStoryboard);
rectangle02.Triggers.Add(myMouseEnterTrigger);

Indirekt målstyrning med en frysbart objekt som startpunkt

I föregående avsnitt beskrivs hur en Freezable kan målinriktas indirekt genom att börja med en FrameworkElement eller FrameworkContentElement och skapa en egenskapskedja till en underordnad egenskap av typen Freezable. Du kan också använda en Freezable som utgångspunkt och indirekt rikta in dig på en av dess Freezable underegenskaper. En ytterligare begränsning gäller när du använder en Freezable som utgångspunkt för indirekt inriktning: start-Freezable och varje Freezable mellan den och den indirekt riktade underegenskapen får inte frysas.

Interaktiv kontroll av en storyboard i XAML

Om du vill starta en storyboard i XAML (Extensible Application Markup Language) använder du en BeginStoryboard utlösaråtgärd. BeginStoryboard distribuerar animeringarna till de objekt och egenskaper som de animerar och startar storyboarden. (Mer information om den här processen finns i Översikt över animerings- och tidsschemasystem.) Om du ger BeginStoryboard ett namn genom att ange dess egenskap Name gör du den till en kontrollbar storyboard. Du kan sedan interaktivt styra storyboarden när den har startats. Följande är en lista över kontrollerbara storyboard-åtgärder som du använder med händelseutlösare för att styra en storyboard.

I följande exempel används kontrollerbara storyboard-åtgärder för att interaktivt styra en storyboard.

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.SDK.Animation.ControllableStoryboardExample"
  WindowTitle="Fading Rectangle Example">
  <StackPanel Margin="10">

    <Rectangle
      Name="MyRectangle"
      Width="100" 
      Height="100"
      Fill="Blue">
    </Rectangle>

    <Button Name="BeginButton">Begin</Button>
    <Button Name="PauseButton">Pause</Button>
    <Button Name="ResumeButton">Resume</Button>
    <Button Name="SkipToFillButton">Skip To Fill</Button>
    <Button Name="StopButton">Stop</Button>

    <StackPanel.Triggers>
      <EventTrigger RoutedEvent="Button.Click" SourceName="BeginButton">
        <BeginStoryboard Name="MyBeginStoryboard">
          <Storyboard>
            <DoubleAnimation
              Storyboard.TargetName="MyRectangle" 
              Storyboard.TargetProperty="(Rectangle.Opacity)"
              From="1.0" To="0.0" Duration="0:0:5" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="PauseButton">
        <PauseStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="ResumeButton">
        <ResumeStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="SkipToFillButton">
        <SkipStoryboardToFill BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
      <EventTrigger RoutedEvent="Button.Click" SourceName="StopButton">
        <StopStoryboard BeginStoryboardName="MyBeginStoryboard" />
      </EventTrigger>
    </StackPanel.Triggers>
  </StackPanel>
</Page>

Interaktiv kontroll av en storyboard med hjälp av kod

Föregående exempel har visat hur du animerar med utlösaråtgärder. I kod kan du också styra en storyboard med hjälp av interaktiva metoder i klassen Storyboard. För att en Storyboard ska göras interaktiv i kod måste du använda lämplig överlagring av storyboardens Begin-metod och ange true för att göra den kontrollerbar. Mer information finns på sidan Begin(FrameworkElement, Boolean).

I följande lista visas de metoder som kan användas för att manipulera en Storyboard när den har startats:

Fördelen med att använda dessa metoder är att du inte behöver skapa Trigger eller TriggerAction objekt. du behöver bara en referens till den kontrollerbara Storyboard du vill ändra.

Anmärkning

Alla interaktiva åtgärder som tas på en Clock, och därmed även på en Storyboard, sker vid nästa tick i tidsstyrmotorn, vilket inträffar strax före nästa återgivning. Om du till exempel använder metoden Seek för att hoppa till en annan punkt i en animering ändras egenskapsvärdet inte omedelbart, snarare ändras värdet vid nästa tick i tidsmotorn.

I följande exempel visas hur du använder och styr animeringar med hjälp av interaktiva metoder i klassen Storyboard.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace SDKSample
{

    public class ControllableStoryboardExample : Page
    {
        private Storyboard myStoryboard;

        public ControllableStoryboardExample()
        {

            // Create a name scope for the page.

            NameScope.SetNameScope(this, new NameScope());

            this.WindowTitle = "Controllable Storyboard Example";
            StackPanel myStackPanel = new StackPanel();
            myStackPanel.Margin = new Thickness(10);

            // Create a rectangle.
            Rectangle myRectangle = new Rectangle();
            myRectangle.Name = "myRectangle";

            // Assign the rectangle a name by
            // registering it with the page, so that
            // it can be targeted by storyboard
            // animations.
            this.RegisterName(myRectangle.Name, myRectangle);
            myRectangle.Width = 100;
            myRectangle.Height = 100;
            myRectangle.Fill = Brushes.Blue;
            myStackPanel.Children.Add(myRectangle);

            //
            // Create an animation and a storyboard to animate the
            // rectangle.
            //
            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = 1.0;
            myDoubleAnimation.To = 0.0;
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(5000));
            myDoubleAnimation.AutoReverse = true;

            // Create the storyboard.
            myStoryboard = new Storyboard();
            myStoryboard.Children.Add(myDoubleAnimation);
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
            Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Rectangle.OpacityProperty));

            //
            // Create some buttons to control the storyboard
            // and a panel to contain them.
            //
            StackPanel buttonPanel = new StackPanel();
            buttonPanel.Orientation = Orientation.Horizontal;
            Button beginButton = new Button();
            beginButton.Content = "Begin";
            beginButton.Click += new RoutedEventHandler(beginButton_Clicked);
            buttonPanel.Children.Add(beginButton);
            Button pauseButton = new Button();
            pauseButton.Content = "Pause";
            pauseButton.Click += new RoutedEventHandler(pauseButton_Clicked);
            buttonPanel.Children.Add(pauseButton);
            Button resumeButton = new Button();
            resumeButton.Content = "Resume";
            resumeButton.Click += new RoutedEventHandler(resumeButton_Clicked);
            buttonPanel.Children.Add(resumeButton);
            Button skipToFillButton = new Button();
            skipToFillButton.Content = "Skip to Fill";
            skipToFillButton.Click += new RoutedEventHandler(skipToFillButton_Clicked);
            buttonPanel.Children.Add(skipToFillButton);
            Button setSpeedRatioButton = new Button();
            setSpeedRatioButton.Content = "Triple Speed";
            setSpeedRatioButton.Click += new RoutedEventHandler(setSpeedRatioButton_Clicked);
            buttonPanel.Children.Add(setSpeedRatioButton);
            Button stopButton = new Button();
            stopButton.Content = "Stop";
            stopButton.Click += new RoutedEventHandler(stopButton_Clicked);
            buttonPanel.Children.Add(stopButton);
            myStackPanel.Children.Add(buttonPanel);
            this.Content = myStackPanel;
        }

        // Begins the storyboard.
        private void beginButton_Clicked(object sender, RoutedEventArgs args)
        {
            // Specifying "true" as the second Begin parameter
            // makes this storyboard controllable.
            myStoryboard.Begin(this, true);
        }

        // Pauses the storyboard.
        private void pauseButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Pause(this);
        }

        // Resumes the storyboard.
        private void resumeButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Resume(this);
        }

        // Advances the storyboard to its fill period.
        private void skipToFillButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.SkipToFill(this);
        }

        // Updates the storyboard's speed.
        private void setSpeedRatioButton_Clicked(object sender, RoutedEventArgs args)
        {
            // Makes the storyboard progress three times as fast as normal.
            myStoryboard.SetSpeedRatio(this, 3);
        }

        // Stops the storyboard.
        private void stopButton_Clicked(object sender, RoutedEventArgs args)
        {
            myStoryboard.Stop(this);
        }
    }
}

Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Shapes
Imports System.Windows.Media
Imports System.Windows.Media.Animation

Namespace SDKSample

    Public Class ControllableStoryboardExample
        Inherits Page
        Private myStoryboard As Storyboard

        Public Sub New()

            ' Create a name scope for the page.

            NameScope.SetNameScope(Me, New NameScope())

            Me.WindowTitle = "Controllable Storyboard Example"
            Dim myStackPanel As New StackPanel()
            myStackPanel.Margin = New Thickness(10)

            ' Create a rectangle.
            Dim myRectangle As New Rectangle()
            myRectangle.Name = "myRectangle"

            ' Assign the rectangle a name by 
            ' registering it with the page, so that
            ' it can be targeted by storyboard
            ' animations.
            Me.RegisterName(myRectangle.Name, myRectangle)
            myRectangle.Width = 100
            myRectangle.Height = 100
            myRectangle.Fill = Brushes.Blue
            myStackPanel.Children.Add(myRectangle)

            '
            ' Create an animation and a storyboard to animate the
            ' rectangle.
            '
            Dim myDoubleAnimation As New DoubleAnimation()
            myDoubleAnimation.From = 1.0
            myDoubleAnimation.To = 0.0
            myDoubleAnimation.Duration = New Duration(TimeSpan.FromMilliseconds(5000))
            myDoubleAnimation.AutoReverse = True

            ' Create the storyboard.
            myStoryboard = New Storyboard()
            myStoryboard.Children.Add(myDoubleAnimation)
            Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name)
            Storyboard.SetTargetProperty(myDoubleAnimation, New PropertyPath(Rectangle.OpacityProperty))

            '
            ' Create some buttons to control the storyboard
            ' and a panel to contain them.
            '
            Dim buttonPanel As New StackPanel()
            buttonPanel.Orientation = Orientation.Horizontal
            Dim beginButton As New Button()
            beginButton.Content = "Begin"
            AddHandler beginButton.Click, AddressOf beginButton_Clicked
            buttonPanel.Children.Add(beginButton)
            Dim pauseButton As New Button()
            pauseButton.Content = "Pause"
            AddHandler pauseButton.Click, AddressOf pauseButton_Clicked
            buttonPanel.Children.Add(pauseButton)
            Dim resumeButton As New Button()
            resumeButton.Content = "Resume"
            AddHandler resumeButton.Click, AddressOf resumeButton_Clicked
            buttonPanel.Children.Add(resumeButton)
            Dim skipToFillButton As New Button()
            skipToFillButton.Content = "Skip to Fill"
            AddHandler skipToFillButton.Click, AddressOf skipToFillButton_Clicked
            buttonPanel.Children.Add(skipToFillButton)
            Dim setSpeedRatioButton As New Button()
            setSpeedRatioButton.Content = "Triple Speed"
            AddHandler setSpeedRatioButton.Click, AddressOf setSpeedRatioButton_Clicked
            buttonPanel.Children.Add(setSpeedRatioButton)
            Dim stopButton As New Button()
            stopButton.Content = "Stop"
            AddHandler stopButton.Click, AddressOf stopButton_Clicked
            buttonPanel.Children.Add(stopButton)
            myStackPanel.Children.Add(buttonPanel)
            Me.Content = myStackPanel


        End Sub

        ' Begins the storyboard.
        Private Sub beginButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            ' Specifying "true" as the second Begin parameter
            ' makes this storyboard controllable.
            myStoryboard.Begin(Me, True)

        End Sub

        ' Pauses the storyboard.
        Private Sub pauseButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Pause(Me)

        End Sub

        ' Resumes the storyboard.
        Private Sub resumeButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Resume(Me)

        End Sub

        ' Advances the storyboard to its fill period.
        Private Sub skipToFillButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.SkipToFill(Me)

        End Sub

        ' Updates the storyboard's speed.
        Private Sub setSpeedRatioButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            ' Makes the storyboard progress three times as fast as normal.
            myStoryboard.SetSpeedRatio(Me, 3)

        End Sub

        ' Stops the storyboard.
        Private Sub stopButton_Clicked(ByVal sender As Object, ByVal args As RoutedEventArgs)
            myStoryboard.Stop(Me)

        End Sub

    End Class

End Namespace

Animera i en stil

Du kan använda objekt Storyboard för att definiera animeringar i en Style. Att animera med en Storyboard i en Style liknar att använda en Storyboard någon annanstans, med följande tre undantag:

  • Du anger inte en TargetName; Storyboard alltid riktar in sig på det element som Style tillämpas på. Om du vill rikta in dig på Freezable objekt måste du använda indirekt inriktning. Mer information om indirekt inriktning finns i avsnittet Indirect Targeting .

  • Du kan inte ange en SourceName för en EventTrigger eller en Trigger.

  • Du kan inte använda dynamiska resursreferenser eller databindningsuttryck för att ange egenskapsvärden för Storyboard eller animering. Det beror på att allt i en Style måste vara trådsäkert, och tidssystemet måste FreezeStoryboard objekt för att göra dem trådsäkra. En Storyboard kan inte frysas om den eller dess underordnade tidslinjer innehåller dynamiska resursreferenser eller databindningsuttryck. Mer information om frysning och andra funktioner Freezable finns i översikten över frysbara objekt .

  • I XAML kan du inte deklarera händelsehanterare för Storyboard- eller animeringshändelser.

Ett exempel som visar hur du definierar en storyboard i ett format finns i Animera i ett format exempel.

Animera i ett ControlTemplate

Du kan använda objekt Storyboard för att definiera animeringar i en ControlTemplate. Att animera med en Storyboard i en ControlTemplate liknar att använda en Storyboard någon annanstans, med följande två undantag:

  • TargetName kan bara referera till underordnade objekt i ControlTemplate. Om TargetName inte anges riktar animeringen in sig på det element som ControlTemplate tillämpas på.

  • SourceName för en EventTrigger eller en Trigger kan bara referera till underordnade objekt till ControlTemplate.

  • Du kan inte använda dynamiska resursreferenser eller databindningsuttryck för att ange egenskapsvärden för Storyboard eller animering. Det beror på att allt i en ControlTemplate måste vara trådsäkert, och tidssystemet måste FreezeStoryboard objekt för att göra dem trådsäkra. En Storyboard kan inte frysas om den eller dess underordnade tidslinjer innehåller dynamiska resursreferenser eller databindningsuttryck. Mer information om frysning och andra Freezable funktioner finns i översikten över friserbara objekt.

  • I XAML kan du inte deklarera händelsehanterare för Storyboard- eller animeringshändelser.

Ett exempel som visar hur du definierar en storyboard i en ControlTemplatefinns i Animera i ett ControlTemplate- exempel.

Animera när ett egenskapsvärde ändras

I format och kontrollmallar kan du använda Utlösarobjekt för att starta en storyboard när en egenskap ändras. Exempel finns i Utlösa en animering när ett egenskapsvärde ändras och Animering i en kontrollmall.

Animeringar som tillämpas på objekt med egenskap Trigger beter sig på ett mer komplext sätt än de animeringar som EventTrigger skapar eller som startas med Storyboard-metoder. De "överlämnar" med animeringar som definierats av andra Trigger-objekt, men kombineras med EventTrigger och metodutlösta animeringar.

Se även