Общие сведения о Storyboard

В этой теме показано, как использовать объекты Storyboard для организации и применения анимации. Здесь показано, как интерактивно манипулировать объектами Storyboard, а также описан синтаксис косвенного выбора свойств.

Необходимые компоненты

Для понимания этого раздела необходимо ознакомиться с различными типами анимации и их основными возможностями. Общие сведения об анимации см. в разделе Общие сведения об эффектах анимации. Вы также должны знать, как использовать вложенные свойства. Дополнительные сведения о вложенных свойствах см. в разделах Общие сведения о вложенных свойствах.

Что такое раскадровка?

Анимация — не единственный удобный тип временной шкалы. Существуют другие классы временной шкалы, с помощью которых вы сможете создать наборы временных шкал и применить временные шкалы к свойствам. Временные шкалы контейнеров являются производными от класса TimelineGroup и включают ParallelTimeline и Storyboard.

Storyboard соответствует типу временной шкалы контейнера, который предоставляет информацию об определении целей для временных шкал, которые содержит. У Timeline тип временной шкалы контейнера, который предоставляет информацию о целевом назначении для временных шкал, которые содержит. Объекты Storyboard позволяют объединять временные шкалы, которые влияют на различные объекты и свойства, в одно дерево временной шкалы, которое позволит управлять сложным поведением с привязкой ко времени. Например, предположим, что вам необходима кнопка, которая выполняет следующие три действия.

  • Увеличивается и изменяет цвет, когда пользователь выбирает кнопку.

  • Сжимается, а затем увеличивается до исходного размера, когда пользователь нажимает на кнопку.

  • Сжимается и изменяет яркость до 50-процентной прозрачности, если кнопка становится недоступной.

В этом случае у вас есть несколько наборов анимаций, которые применяются к одному объекту и которые требуется воспроизводить в разное время в зависимости от состояния кнопки. С помощью объектов Storyboard можно упорядочить анимации и применить их к одному или нескольким объектам.

Где можно использовать раскадровку?

С помощью Storyboard можно анимировать свойства зависимостей анимируемых классов (дополнительные сведения о том, что делает класс анимируемым, см. в разделе Общие сведения об эффектах анимации). Однако, поскольку раскадровка - это функция уровня платформы, объект должен относиться к NameScope элемента FrameworkElement или FrameworkContentElement.

Например, Storyboard позволяет делать следующее:

  • анимировать кисть SolidColorBrush (элемент, не относящийся к платформе), которая рисует фон кнопки (тип элемента FrameworkElement),

  • анимировать кисть SolidColorBrush (элемент, не относящийся к платформе), который рисует заливку GeometryDrawing (элемент, не относящийся к платформе), отображаемого с помощью Image (FrameworkElement).

  • В коде анимируйте кисть SolidColorBrush, объявленную классом, который также содержит элемент FrameworkElement, если кисть SolidColorBrush зарегистрировала свое имя с элементом FrameworkElement.

Однако с помощью Storyboard невозможно анимировать кисть SolidColorBrush, которая не зарегистрировала свое имя с элементами FrameworkElement и FrameworkContentElement или не использовалась для задания элемента FrameworkElement или FrameworkContentElement.

Применение анимации с помощью раскадровки

Чтобы использовать Storyboard для организации или применения анимации, анимации добавляются как дочерние временные шкалы Storyboard. Класс Storyboard предоставляет присоединенные свойства Storyboard.TargetName и Storyboard.TargetProperty. Эти свойства используются для указания целевого объекта и целевого свойства анимации.

Чтобы применить анимацию к целевым объектам, следует запустить Storyboard с помощью действия или метода триггера. В XAML используется объект BeginStoryboard с EventTrigger, Trigger или DataTrigger. В коде также можно использовать метод Begin.

В следующей таблице показано, где поддерживается каждый из методов запуска Storyboard: применение к конкретным экземплярам, в стилях, в шаблонах элементов управления и в шаблонах данных. Применение к конкретным экземплярам подразумевает применение анимации или раскадровки непосредственно к экземплярам объектов, а не в стилях, шаблонах элементов управления или шаблонах данных.

Раскадровка запускается с помощью метода... Применение к конкретным экземплярам Стиль Шаблон элемента управления Шаблон данных Пример
BeginStoryboard и EventTrigger Да Да Да Да Анимация свойства с помощью раскадровки
BeginStoryboard и свойство Trigger No Да Да Да Запуск анимации при изменении значения свойства
BeginStoryboard и свойство MultiTrigger No Да Да Да Пример класса MultiTrigger
BeginStoryboard и DataTrigger No Да Да Да Практическое руководство. Запуск анимации при изменении данных
BeginStoryboard и MultiDataTrigger No Да Да Да Пример класса MultiDataTrigger
BeginМетод Да Нет Нет No Анимация свойства с помощью раскадровки

В следующем примере Storyboard используется для анимации свойства Width элемента Rectangle и свойства Color кисти SolidColorBrush, используемой для рисования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;
        }
    }
}

В следующих разделах более подробно описаны вложенные свойства TargetName и TargetProperty.

Элементы целевой платформы, элементы содержимого платформы и объекты Freezable

В предыдущем разделе упоминалось, что для поиска целевого объекта анимации необходимо знать имя целевого объекта и анимируемое свойство. Указать свойства, которое нужно анимировать, очень просто: просто установите TargetProperty с именем свойства, которое нужно анимировать. Чтобы указать имя объекта, свойство которого требуется анимировать, для анимации задается свойство Storyboard.TargetName.

Внимание

Хотя свойство Target можно использовать для привязки непосредственно к объекту в качестве альтернативы TargetName, оно не сериализуется. Нет гарантии, что объект Target может быть правильно указан в XAML.

Чтобы свойство TargetName работало, у целевого объекта должно быть имя. Присвоение имени элементу FrameworkElement или FrameworkContentElement в XAML отличается от присвоения имени объекту Freezable.

Элементы платформы — это классы, которые наследуют от класса FrameworkElement. Примеры элементов платформы: Window,DockPanel, Button и Rectangle. По существу все окна, панели и элементы управления являются элементами. Элементы содержимого платформы — это классы, которые наследуют от класса FrameworkContentElement. Примеры элементов содержимого платформы: FlowDocument и Paragraph. Если вы не уверены, что этот элемент является элементом платформы или элементом содержимого платформы, проверьте, есть ли у этого элемента свойство Name. Если есть, скорее всего, это элемент платформы или элемент содержимого платформы. Чтобы убедиться в этом, обратитесь к разделу "Иерархия наследования" на странице типа элемента.

Чтобы включить определение целей для элемента платформы или элемента содержимого платформы в XAML, необходимо задать его свойство Name. В коде также необходимо использовать метод RegisterName для регистрации имени элемента с элементом, для которого создано свойство NameScope.

В следующем примере, взятом из предыдущего, присваивает имя MyRectangle для Rectangle и тип 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);

После того как элемент получил имя, вы можете анимировать свойство этого элемента.

<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 — это классы, которые наследуют от класса Freezable. Примеры Freezable: SolidColorBrush, RotateTransform и GradientStop.

Чтобы включить определение целей Freezable с помощью анимации в XAML, для назначения имени используется директива x:Name. В коде используется метод RegisterName для регистрации имени с элементом, для которого создано свойство NameScope.

В следующем примере объекту Freezable присваивается имя.

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

Затем этот объект можно выбрать в качестве целевого с помощью анимации.

<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 используют диапазоны имен для разрешения свойства TargetName. Дополнительные сведения об областях видимости имен WPF см. в разделе Области видимости имен XAML в WPF. Если свойство TargetName не указано, целевым объектом для анимации становится тот объект, для которого она определена, или (для стилей) элемент, к которому применен стиль.

Иногда имя не может быть присвоено объекту Freezable. Например, если объект Freezable объявлен как ресурс или используется для установки свойства в стиле, то имя ему назначить нельзя. Так как у объекта нет имени, к нему нельзя обратиться напрямую, но можно обратиться косвенно. В следующих разделах описано, как обращаться к целевым объектам косвенно.

Косвенное обращение

Иногда объект Freezable нельзя выбрать в качестве целевого объекта для анимации, например если объект Freezable объявлен в качестве ресурса или используется для установки значения свойства в стиле. В этих случаях объект Freezable можно анимировать, хотя обратиться к нему напрямую нельзя. Вместо задания свойстваTargetName с именем Freezable присвойте ему имя элемента, которому «принадлежит» объект Freezable. Например, кисть SolidColorBrush, используемая для задания свойства Fill элемента прямоугольника, относится к данному прямоугольнику. Чтобы анимировать кисть, в свойство анимации TargetProperty записывается цепочка свойств, которая начинается со свойства элемента платформы или элемента содержимого платформы, для установки которого использовался объект Freezable, и заканчивается анимируемым свойством Freezable.

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

Обратите внимание, что если объект Freezable зафиксирован, то создается клон, которые будет анимирован. Когда это происходит, свойство HasAnimatedProperties исходного объекта продолжает возвращать false, так как исходный объект фактически не анимируется. Дополнительные сведения о клонировании см. в статье Общие сведения об объектах класса Freezable.

Обратите внимание, что при косвенном обращении к целевым объектам можно обращаться к объектам, которых не существует. Например, можно предположить, что Background определенной кнопки был установлен с помощью кисти SolidColorBrush и попытаться анимировать ее цвет, когда на самом деле для установки фона кнопки была использована кисть LinearGradientBrush. В этих случаях исключение не возникает; у анимации нет видимого эффекта, потому что LinearGradientBrush не реагирует на изменения свойства Color.

В следующих разделах более подробно описан синтаксис косвенного обращения к целевым объектам.

Косвенное обращение к свойству объекта Freezable в XAML

Чтобы обратиться к свойству объекта Freezable в XAML, используйте следующий синтаксис.

Синтаксис свойства
ElementPropertyName.FreezablePropertyName

Где

  • ElementPropertyName — это свойство элемента FrameworkElement, для задания которого используется объект Freezable, и

  • FreezablePropertyName — анимируемое свойство Freezable.

В следующем коде показано, как анимировать свойство Color кисти SolidColorBrush, используемой для задания свойства Fill элемента прямоугольника.

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

Иногда требуется обратиться к объекту Freezable, который содержится в коллекции или массиве.

Чтобы обратиться к объекту Freezable, который содержится в коллекции, используйте следующий синтаксис пути.

Синтаксис Path
ElementPropertyName.Children[CollectionIndex].FreezablePropertyName

Здесь CollectionIndex — индекс объекта в массиве или коллекции.

Например, предположим, что у прямоугольника есть ресурс TransformGroup, примененный к его свойству RenderTransform, и требуется анимировать одно из содержащихся в нем преобразований.

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

Следующий код показывает, как анимировать свойство Angle преобразования RotateTransform, показанного в предыдущем примере.

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

Косвенное обращение к свойству объекта Freezable в коде

В коде создается объект PropertyPath. При создании PropertyPath укажите Path и PathParameters.

Для создания PathParameters создается массив типа DependencyProperty со списком полей идентификаторов свойств зависимостей. Первое поле идентификатора предназначено для свойства элемента FrameworkElement или FrameworkContentElement, для установки которого используется объект Freezable. Следующее поле идентификатора представляет свойство объекта Freezable для целевого объекта. Думайте об этом как о цепочке свойств, которая соединяет объект Freezable с элементом FrameworkElement.

Ниже приведен пример цепочки свойств зависимости, которая направлена на свойство Color кисти SolidColorBrush, используемой для установки свойства Fill элемента прямоугольника.

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

Также необходимо указать Path. Path имеет тип String, что предписывает Path то, как интерпретировать его параметры PathParameters. Для этого используется следующий синтаксис.

Синтаксис пути к свойству
(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex)

Где

  • OwnerPropertyArrayIndex — это индекс массива DependencyProperty с идентификатором свойства элемента FrameworkElement, для задания которого используется объект Freezable, и

  • FreezablePropertyArrayIndex — индекс массива DependencyProperty с идентификатором целевого свойства.

Следующий пример показывает Path, который будет сопровождать параметры PathParameters, определенные в предыдущем примере.

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

Следующий пример объединяет код из предыдущих примеров, чтобы анимировать свойство Color кисти SolidColorBrush, использованной для установки Fill элемента прямоугольника.


// 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);

Иногда требуется обратиться к объекту Freezable, который содержится в коллекции или массиве. Например, предположим, что у прямоугольника есть ресурс TransformGroup, примененный к его свойству RenderTransform, и требуется анимировать одно из содержащихся в нем преобразований.

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

Чтобы обратиться к объекту Freezable, который содержится в коллекции, используйте следующий синтаксис пути.

Синтаксис Path
(OwnerPropertyArrayIndex).(CollectionChildrenPropertyArrayIndex)[CollectionIndex].(FreezablePropertyArrayIndex)

Здесь CollectionIndex — индекс объекта в массиве или коллекции.

Чтобы нацелить свойство Angle преобразования RotateTransform, второе преобразование в TransformGroup, следует использовать объекты Path и 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);

В следующем примере показан полный код для анимации свойства Angle преобразования RotateTransform, содержащегося внутри 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);

Косвенное обращение с использованием объекта Freezable в качестве начальной точки

В предыдущих разделах описывалось, как косвенно нацелиться на объект Freezable, начав с элемента FrameworkElement или FrameworkContentElement и создав цепочку свойств до подсвойства Freezable. Объект Freezable также можно использовать в качестве отправной точки и косвенно нацелиться на одно из его подсвойств Freezable. При использовании Freezable в качестве начальной точки для косвенного обращения действует одно дополнительное ограничение: начальный объект Freezable, все промежуточные объекты Freezable и объект, к которому производится косвенное обращение, не должны фиксироваться.

Интерактивное управление раскадровкой в XAML

Чтобы запустить раскадровку на языке Extensible Application Markup Language (XAML), используйте действие триггера BeginStoryboard. BeginStoryboard распределяет анимации между анимируемыми объектами и свойствами, а затем запускает раскадровку. (Дополнительные сведения об этом процессе см. в разделеОбзор системы анимации и времени.) Если указать BeginStoryboardName его свойство, сделайте его управляемым раскадровкой. Вы можете затем интерактивно управлять раскадровкой после ее запуска. Ниже приведен список действий для управляемой раскадровки, которые используются совместно с триггерами событий для управления раскадровкой.

  • PauseStoryboard: приостанавливает раскадровку.

  • ResumeStoryboard: возобновляет приостановленную раскадровку.

  • SetStoryboardSpeedRatio: изменяет скорость раскадровки.

  • SkipStoryboardToFill: переводит раскадровку в конец ее периода заполнения, если он задан.

  • StopStoryboard: останавливает раскадровку.

  • RemoveStoryboard: удаляет раскадровку.

В следующем примере показано использование действий для интерактивного управления раскадровкой.

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

Интерактивное управление раскадровкой с помощью кода

В предыдущих примерах было показано, как анимировать свойства с помощью действий триггера. В коде также можно управлять раскадровкой, используя интерактивные методы класса Storyboard. Чтобы сделать раскадровку Storyboard интерактивной в коде, необходимо использовать соответствующую перегрузку метода Begin раскадровки и указать значение true, чтобы сделать его управляемым. Дополнительные сведения см. на Begin(FrameworkElement, Boolean) странице.

Ниже приведен список методов для управления раскадровкой Storyboard после ее запуска:

Преимущество использования этих методов заключается в том, что не нужно создавать объекты Trigger или TriggerAction; просто нужна ссылка на управляемую раскадровку Storyboard, которой требуется манипулировать.

Примечание.

Все интерактивные действия, выполняемые с объектом Clock, а значит и с объектом Storyboard, будут происходить на следующем тике временного механизма, который начнется незадолго до следующего рендеринга. Например, если для перехода к следующей точке анимации используется метод Seek, то значение свойства не изменится сразу же. Оно изменится только при следующем такте таймера.

В следующем примере показано, как применять анимации и управлять ими с помощью интерактивных методов класса 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

Анимация с использованием стилей

Объекты Storyboard можно использовать для определения анимаций в стиле Style. Анимация с помощью раскадровки Storyboard со стилем Style аналогична использованию Storyboard в других местах, за следующими тремя исключениями:

  • TargetName не указывается. Раскадровка Storyboard всегда нацелена на элемент, к которому применяется Style. Чтобы обратиться к объектам Freezable, необходимо использовать косвенное обращение. Дополнительные сведения о косвенном обращении см. в разделе Косвенное обращение.

  • Невозможно указать SourceName для EventTrigger или Trigger.

  • Динамические ссылки на ресурсы или выражения привязки к данным нельзя использовать для установки Storyboard или значений свойств анимации. Это потому, что все внутри Style должно быть потокобезопасным, а система управления временем должна Freeze объекты Storyboard, чтобы сделать их потокобезопасными. Раскадровку Storyboard нельзя зафиксировать, если она или ее дочерние временные шкалы содержат динамические ссылки на ресурсы или выражения привязки данных. Дополнительные сведения о фиксации и других функциях Freezable см. в статье Общие сведения об объектах класса Freezable.

  • В XAML нельзя объявить обработчики событий для Storyboard или событий анимации.

Пример определения раскадровки с использованием стиля см. в разделе Анимация с использованием стилей.

Анимация в ControlTemplate

Объекты Storyboard можно использовать для определения анимаций в стиле ControlTemplate. Анимация с помощью раскадровки Storyboard со стилем ControlTemplate аналогична использованию Storyboard в других местах, за следующими двумя исключениями:

  • Объект TargetName может ссылаться только на дочерние объекты шаблона ControlTemplate. Если свойство TargetName не указано, анимация нацеливается на элемент, к которому применяется ControlTemplate.

  • Свойство SourceName триггера EventTrigger или Trigger может ссылаться только на дочерние объекты шаблона ControlTemplate.

  • Динамические ссылки на ресурсы или выражения привязки к данным нельзя использовать для установки Storyboard или значений свойств анимации. Это потому, что все внутри ControlTemplate должно быть потокобезопасным, а система управления временем должна Freeze объекты Storyboard, чтобы сделать их потокобезопасными. Раскадровку Storyboard нельзя зафиксировать, если она или ее дочерние временные шкалы содержат динамические ссылки на ресурсы или выражения привязки данных. Дополнительные сведения о фиксации и других функциях Freezable см. в статье Общие сведения об объектах класса Freezable.

  • В XAML нельзя объявить обработчики событий для Storyboard или событий анимации.

Пример определения раскадровки в ControlTemplate см. в примере Анимация в ControlTemplate.

Анимация при изменении значения свойства

В стилях и шаблонах элементов можно использовать объекты триггеров для запуска раскадровки при изменении свойства. Примеры см. в статьях Запуск анимации при изменении значения свойства и Анимация в ControlTemplate.

Анимация, примененная объектами свойства Trigger, ведет себя более сложным образом, чем анимация EventTrigger или анимация, которая запускается с использованием методов Storyboard. Она сменяет анимацию, определенную другими объектами Trigger, но объединяется с EventTrigger и анимацией, запускаемой методом.

См. также