Общие сведения о пользовательской анимации

В этом разделе описано, как и когда расширять систему анимации WPF путем создания пользовательских ключевых кадров и классов анимации или путем использования покадрового обратного вызова для ее обхода.

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

Чтобы понять материал этого раздела, необходимо ознакомиться с различными типами анимации, предоставляемыми WPF. Дополнительные сведения см. в разделах "Общие сведения об анимациях From/To/By", Общие сведения об анимации по ключевым кадрам и Общие сведения об анимация с использованием пути.

Так как классы анимации наследуют от класса Freezable, необходимо ознакомиться с объектами Freezable и способами наследования от класса Freezable. Дополнительные сведения см. в разделе Общие сведения об объектах класса Freezable.

Расширение системы анимации

Существует несколько способов расширения системы анимации WPF, которые зависят от уровня встроенного функционала, который будет использоваться. В механизме анимации WPF имеются три основных точки расширяемости:

  • Создание пользовательского объекта ключевого кадра путем наследования от одного из классов *<Type>*KeyFrame, например DoubleKeyFrame. Этот подход использует основная часть встроенных функциональных возможностей механизма анимации WPF.

  • Создание собственного класса анимации путем наследования от AnimationTimeline или одного из классов *<Type>*AnimationBase.

  • Использование покадрового обратного вызова для создания анимаций на основе отдельных кадров. Такой подход предусматривает полный обход анимации и систему времени.

В следующей таблице описаны некоторые сценарии для расширения системы анимации.

Требуемое действие Используемый подход
Настройка интерполяции между значениями типа, имеющего соответствующий класс *<Type>*AnimationUsingKeyFrames Создайте пользовательский ключевой кадр. Дополнительные сведения см. в разделе Создание пользовательского ключевого кадра.
Настройка не только интерполяции между значениями типа, имеющего соответствующий класс *<Type>*Animation Создайте пользовательский класс анимации, наследующий от класса *<Type>*AnimationBase, соответствующего типу, который требуется анимировать. Дополнительные сведения см. в разделе Создание пользовательского класса анимации.
Анимация типа, не имеющего соответствующей анимации WPF Используйте ObjectAnimationUsingKeyFrames или создайте класс, который наследует от AnimationTimeline. Дополнительные сведения см. в разделе Создание пользовательского класса анимации.
Анимация нескольких объектов со значениями, которые вычисляются для каждого кадра и основаны на последнем наборе взаимодействий объектов Используйте покадровый обратный вызов. Дополнительные сведения см. в разделе Использование покадрового обратного вызова.

Создание пользовательского ключевого кадра

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

  • задает целевое значение с помощью его свойства Value;

  • указывает время, когда должно быть достигнуто это значение, с помощью его свойства KeyTime;

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

Инструкции по реализации

Выполните наследование от абстрактного класса *<Type>*KeyFrame и реализуйте метод InterpolateValueCore. Метод InterpolateValueCore возвращает текущее значение ключевого кадра. Он принимает два параметра: значение предыдущего ключевого кадра и значение хода выполнения в диапазоне от 0 до 1. Значение 0 означает, что ключевой кадр только что запущен, а значение 1 означает, что ключевой кадр только что завершен и должен вернуть значение, заданное его свойством Value.

Так как классы *<Type>*KeyFrame наследуют от класса Freezable, необходимо также переопределить ядро CreateInstanceCore для возврата нового экземпляра вашего класса. Если класс не использует свойства зависимостей для хранения своих данных или требует дополнительной инициализации после создания, может потребоваться переопределить дополнительные методы. Дополнительные сведения см. в разделе Общие сведения об объектах класса Freezable.

После создания пользовательской анимации *<Type>*KeyFrame ее можно использовать с *<Type>*AnimationUsingKeyFrames для данного типа.

Создание пользовательского класса анимации

Создание собственного типа анимации обеспечивает больший уровень контроля над способом анимации объекта. Существуют два рекомендованных способа создания собственного типа анимации: наследование от класса AnimationTimeline или класса *<Type>*AnimationBase. Наследование от классов *<Type>*Animation или *<Type>*AnimationUsingKeyFrames не рекомендуется.

Наследование от класса <Type>AnimationBase

Наследование от класса *<Type>*AnimationBase является самым простым способом для создания типа анимации. Этот подход следует использовать в случае, если требуется создать анимацию для типа, у которого уже есть соответствующий класс *<Type>*AnimationBase.

Инструкции по реализации

Выполните наследование от класса *<Type>*Animation и реализуйте метод GetCurrentValueCore. Метод GetCurrentValueCore возвращает текущее значение анимации. Он принимает три параметра: предлагаемое начальное значение, предлагаемое конечное значение и AnimationClock, которое используется для определения хода выполнения анимации.

Так как классы *<Type>*AnimationBase наследуют от класса Freezable, необходимо также переопределить ядро CreateInstanceCore для возврата нового экземпляра вашего класса. Если класс не использует свойства зависимостей для хранения своих данных или требует дополнительной инициализации после создания, может потребоваться переопределить дополнительные методы. Дополнительные сведения см. в разделе Общие сведения об объектах класса Freezable.

Дополнительные сведения см. в документации по методу GetCurrentValueCore для класса *<Type>*AnimationBase по типу, который требуется анимировать. Например, см. раздел Пример пользовательской анимации.

Альтернативные подходы

Если просто требуется изменить способ интерполяции значений анимации, следует рассмотреть возможность наследования от одного из классов *<Type>*KeyFrame. Создаваемый ключевой кадр может использоваться с соответствующим классом *<Type>*AnimationUsingKeyFrames, предоставляемым системой WPF.

Наследование от AnimationTimeline

Наследование от класса AnimationTimeline следует выполнять, если требуется создать анимацию для типа, еще не имеющего соответствующей анимации WPF, или если нужно создать анимацию, которая не является строго типизированной.

Инструкции по реализации

Выполните наследование от класса AnimationTimeline и переопределите следующие члены:

  • CreateInstanceCore — если новый класс является конкретным, необходимо переопределить CreateInstanceCore для возврата нового экземпляра класса.

  • GetCurrentValue — переопределите этот метод для возврата текущего значения анимации. Он принимает три параметра: начальное значение по умолчанию, конечное значение по умолчанию и AnimationClock. AnimationClock используется для получения текущего времени или состояния хода выполнения для анимации. Можно выбрать, какие значения будут использоваться: начальное значение по умолчанию или конечное значение по умолчанию.

  • IsDestinationDefault — переопределите это свойство, чтобы указать, использует ли анимация конечное значение по умолчанию, заданное методом GetCurrentValue.

  • TargetPropertyType — переопределите это свойство, чтобы указать Type выходного значения анимации.

Если класс не использует свойства зависимостей для хранения своих данных или требует дополнительной инициализации после создания, может потребоваться переопределить дополнительные методы. Дополнительные сведения см. в разделе Общие сведения об объектах класса Freezable.

Рекомендуемой концепцией (используемой анимациями WPF) является использование двух уровней наследования:

  1. Создайте абстрактный класс *<Type>*AnimationBase, производный от AnimationTimeline. Этот класс должен переопределять метод TargetPropertyType. Он должен также представить новый абстрактный метод GetCurrentValueCore и переопределить GetCurrentValue так, чтобы он проверял типы параметров начального и конечного значений по умолчанию, а затем вызывал метод GetCurrentValueCore.

  2. Создание другого класса, который наследует от нового класса *<Type>*AnimationBase и переопределяет метод CreateInstanceCore, представленный метод GetCurrentValueCore и свойство IsDestinationDefault.

Альтернативные подходы

Если требуется анимировать тип, не имеющий соответствующей анимации From/To/By или анимации по ключевым кадрам, рассмотрите возможность использования ObjectAnimationUsingKeyFrames. Благодаря своей нестрогой типизации ObjectAnimationUsingKeyFrames может анимировать любой тип значения. Недостатком этого подхода является то, что ObjectAnimationUsingKeyFrames поддерживает только дискретную интерполяцию.

Использование покадрового обратного вызова

Этот подход следует использовать, если требуется полностью обойти систему анимации WPF. Один из сценариев для такого подхода — анимация физики, при которой на каждом шаге анимации требуется пересчитывать новое направление или положение анимированных объектов на основе последнего набора взаимодействий объектов.

Инструкции по реализации

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

Вместо этого нужно зарегистрировать событие Rendering для объекта, содержащего объекты, которые нужно анимировать. Метод обработчика событий вызывается один раз для каждого кадра. Каждый раз, когда WPF выполняет маршалинг сохраненных данных отрисовки в визуальном дереве через дерево композиции, вызывается метод обработчика событий.

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

Чтобы получить время представления текущего кадра, можно привести объект EventArgs, связанный с этим событием, к классу RenderingEventArgs. Этот класс предоставляет свойство RenderingTime, с помощью которого можно получить время отрисовки текущего кадра.

Дополнительные сведения см. на Rendering странице.

См. также