Storyboard 개요
이 항목에서는 Storyboard 개체를 사용하여 애니메이션을 구성 및 적용하는 방법을 보여 줍니다. Storyboard 개체를 대화형으로 조작하는 방법을 설명하고 간접 속성 대상 지정 구문에 대해 설명합니다.
사전 요구 사항
이 항목을 이해하려면 여러 다른 애니메이션 형식 및 해당 기본 기능에 익숙해야 합니다. 애니메이션에 대한 소개는 애니메이션 개요를 참조하십시오. 또한 연결된 속성을 사용하는 방법을 알아야 합니다. 연결된 속성에 대한 자세한 내용은 연결된 속성 개요를 참조하십시오.
Storyboard란?
애니메이션이 사용 가능한 유일한 Timeline의 형식은 아닙니다. Timeline 집합을 구성하고 Timeline을 속성에 적용하는 데 도움이 되도록 다른 Timeline 클래스가 제공됩니다. 컨테이너 Timeline은 TimelineGroup 클래스에서 파생되고 ParallelTimeline 및 Storyboard를 포함합니다.
Storyboard는 포함된 Timeline에 대한 대상 정보를 제공하는 컨테이너 Timeline 형식입니다. Storyboard는 다른 컨테이너 Timeline 및 애니메이션을 비롯한 모든 형식의 Timeline을 포함할 수 있습니다. Storyboard 개체를 사용하면 다양한 개체 및 속성에 영향을 주는 Timeline을 단일 Timeline 트리에 결합할 수 있으며 이를 통해 복잡한 타이밍 동작을 쉽게 구성 및 제어할 수 있습니다. 예를 들어 다음 세 가지 작업을 수행하는 단추가 필요하다고 가정해 봅니다.
사용자가 단추를 선택하면 커지고 색이 변경됩니다.
클릭하면 축소되어 원래 크기로 돌아갑니다.
사용하지 않도록 설정하면 축소되고 50% 불투명하게 흐려집니다.
이 경우 동일한 개체에 적용되는 여러 애니메이션 집합이 있으며 단추의 상태에 따라 이러한 애니메이션 집합을 다른 시점에 재생해야 합니다. Storyboard 개체를 사용하면 애니메이션을 구성하여 하나 이상의 개체에 그룹으로 적용할 수 있습니다.
Storyboard를 사용할 수 있는 위치
Storyboard를 사용하여 애니메이션 가능한 클래스의 종속성 속성에 애니메이션 효과를 줄 수 있습니다. 클래스를 애니메이션 가능하게 만드는 방법에 대한 자세한 내용은 애니메이션 개요를 참조하십시오. 그러나 스토리보드 작성이 프레임워크 수준 기능이므로 개체는 FrameworkElement 또는 FrameworkContentElement의 NameScope에 속해야 합니다.
예를 들어 Storyboard를 사용하여 다음을 수행할 수 있습니다.
단추(FrameworkElement 형식)의 배경을 그리는 SolidColorBrush(비프레임워크 요소)에 애니메이션 효과를 줍니다.
Image(FrameworkElement)를 사용하여 표시되는 GeometryDrawing(비프레임워크 요소)의 채우기를 그리는 SolidColorBrush(비프레임워크 요소)에 애니메이션 효과를 줍니다.
코드에서 SolidColorBrush가 이름을 FrameworkElement에 등록한 경우 또한 해당 FrameworkElement를 포함하는 클래스에 의해 선언된 SolidColorBrush에 애니메이션 효과를 줍니다.
그러나 해당 이름을 FrameworkElement 또는 FrameworkContentElement에 등록하지 않았거나 FrameworkElement 또는 FrameworkContentElement의 속성을 설정하는 데 사용되지 않은 SolidColorBrush에는 Storyboard를 사용하여 애니메이션 효과를 줄 수 없습니다.
Storyboard와 함께 애니메이션을 적용하는 방법
Storyboard를 사용하여 애니메이션을 구성 및 적용하려면 애니메이션을 Storyboard의 자식 Timeline으로 추가합니다. Storyboard 클래스에서는 Storyboard.TargetName 및 Storyboard.TargetProperty 연결 속성을 제공합니다. 애니메이션에서 이러한 속성을 설정하여 대상 개체 및 속성을 지정합니다.
애니메이션을 대상에 적용하려면 트리거 동작 또는 메서드를 사용하여 Storyboard를 시작합니다. XAML에서 BeginStoryboard 개체를 EventTrigger, Trigger 또는 DataTrigger와 함께 사용합니다. 코드에서는 Begin 메서드를 사용할 수도 있습니다.
다음 표에서는 각 Storyboard 시작 기술이 지원되는 여러 다른 위치(인스턴스별, 스타일, 컨트롤 템플릿 및 데이터 템플릿)를 보여 줍니다. 이때 인스턴스별"은 애니메이션이나 Storyboard를 스타일, 컨트롤 템플릿 또는 데이터 템플릿에 적용하지 않고 개체의 인스턴스에 직접 적용하는 기술을 말합니다.
다음을 사용하여 Storyboard 시작 |
인스턴스별 |
스타일 |
컨트롤 템플릿 |
데이터 템플릿 |
예제 |
---|---|---|---|---|---|
예 |
예 |
예 |
예 |
||
BeginStoryboard 및 속성 Trigger |
아니요 |
예 |
예 |
예 |
|
아니요 |
예 |
예 |
예 |
||
Begin 메서드 |
예 |
아니요 |
아니요 |
아니요 |
다음 예제에서는 Storyboard를 사용하여 Rectangle 요소의 Width 및 해당 Rectangle을 그리는 데 사용되는 SolidColorBrush의 Color에 애니메이션 효과를 줍니다.
<!-- This example shows how to animate with a storyboard.-->
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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>
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Data
Imports System.Windows.Shapes
Imports System.Windows.Input
Namespace Microsoft.Samples.Animation
Public Class StoryboardsExample
Inherits Page
Public Sub New()
Me.WindowTitle = "Storyboards Example"
Dim myStackPanel As New StackPanel()
myStackPanel.Margin = New Thickness(20)
Dim myRectangle As New Rectangle()
myRectangle.Name = "MyRectangle"
' Create a name scope for the page.
NameScope.SetNameScope(Me, New NameScope())
Me.RegisterName(myRectangle.Name, myRectangle)
myRectangle.Width = 100
myRectangle.Height = 100
Dim mySolidColorBrush As New SolidColorBrush(Colors.Blue)
Me.RegisterName("MySolidColorBrush", mySolidColorBrush)
myRectangle.Fill = mySolidColorBrush
Dim myDoubleAnimation As 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))
Dim myColorAnimation As 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))
Dim myStoryboard As New Storyboard()
myStoryboard.Children.Add(myDoubleAnimation)
myStoryboard.Children.Add(myColorAnimation)
AddHandler myRectangle.MouseEnter, Sub(sender As Object, e As MouseEventArgs) myStoryboard.Begin(Me)
myStackPanel.Children.Add(myRectangle)
Me.Content = myStackPanel
End Sub
End Class
End Namespace
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을 대상으로 지정
이전 단원에서는 애니메이션이 해당 대상을 찾으려면 대상 이름과 애니메이션 효과를 줄 속성을 알아야 한다는 것을 언급했습니다. 애니메이션 효과를 줄 속성을 지정하는 것은 간단합니다. 단순히 애니메이션 효과를 줄 속성의 이름과 함께 Storyboard.TargetProperty를 설정하면 됩니다. 애니메이션에서 Storyboard.TargetName 속성을 설정하여 해당 속성에 애니메이션 효과를 주려는 개체의 이름을 지정합니다.
TargetName 속성이 작동하려면 대상으로 지정된 개체에 이름이 있어야 합니다. XAML에서 FrameworkElement 또는 FrameworkContentElement에 이름을 할당하는 것은 Freezable 개체에 이름을 할당하는 것과 다릅니다.
프레임워크 요소는 FrameworkElement 클래스에서 상속되는 클래스입니다. 프레임워크 요소의 예로는 Window, DockPanel, Button 및 Rectangle이 있습니다. 기본적으로 모든 창, 패널 및 컨트롤은 요소입니다. 프레임워크 콘텐츠 요소는 FrameworkContentElement 클래스에서 상속되는 클래스입니다. 프레임워크 콘텐츠 요소의 예로는 FlowDocument 및 Paragraph가 있습니다. 형식이 프레임워크 요소 또는 프레임워크 콘텐츠 요소인지 확실하지 않은 경우 Name 속성이 있는지 확인합니다. 이 속성이 있는 경우 형식은 프레임워크 요소 또는 프레임워크 콘텐츠 요소일 것입니다. 확실하게 하려면 해당 형식 페이지의 InheritanceHierarchy 섹션을 확인합니다.
XAML에서 프레임워크 요소 또는 프레임워크 콘텐츠 요소의 대상 지정을 사용하도록 설정하려면 해당 Name 속성을 설정합니다. 코드에서는 또한 RegisterName 메서드를 사용하여 NameScope를 만든 요소에 요소 이름을 등록해야 합니다.
이전 예제에서 가져온 다음 예제에서는 FrameworkElement 형식인 Rectangle에 MyRectangle이라는 이름을 할당합니다.
<Rectangle Name="MyRectangle"
Width="100"
Height="100">
Dim myRectangle As New Rectangle()
myRectangle.Name = "MyRectangle"
' Create a name scope for the page.
NameScope.SetNameScope(Me, New NameScope())
Me.RegisterName(myRectangle.Name, myRectangle)
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))
Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name);
Storyboard.SetTargetProperty(myDoubleAnimation,
new PropertyPath(Rectangle.WidthProperty));
Freezable 형식은 Freezable 클래스에서 상속되는 클래스입니다. Freezable의 예로는 SolidColorBrush, RotateTransform 및 GradientStop이 있습니다.
XAML에서 Freezable을 애니메이션 대상으로 지정할 수 있게 하려면 x:Name 지시문를 사용하여 이름을 할당합니다. 코드에서는 RegisterName 메서드를 사용하여 NameScope를 만든 요소에 해당 이름을 등록합니다.
다음 예제에서는 이름을 Freezable 개체에 할당합니다.
<SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
Dim mySolidColorBrush As New SolidColorBrush(Colors.Blue)
Me.RegisterName("MySolidColorBrush", mySolidColorBrush)
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.SetTargetName(myColorAnimation, "MySolidColorBrush");
Storyboard.SetTargetProperty(myColorAnimation,
new PropertyPath(SolidColorBrush.ColorProperty));
Storyboard 개체는 이름 범위를 사용하여 TargetName 속성을 확인합니다. WPF 이름 범위에 대한 자세한 내용은 WPF XAML 이름 범위를 참조하십시오. TargetName 속성이 생략된 경우 애니메이션은 애니메이션이 정의된 요소나 스타일이 지정된 요소(스타일의 경우)를 대상으로 합니다.
Freezable 개체에 이름을 할당할 수 없는 경우도 있습니다. 예를 들어 Freezable이 리소스로 선언되거나 스타일에서 속성 값을 설정하는 데 사용될 경우 이름을 제공할 수 없습니다. 이름이 없기 때문에 대상으로 직접 지정할 수는 없지만 간접적으로 대상이 될 수 있습니다. 다음 단원에서는 간접 대상 지정을 사용하는 방법에 대해 설명합니다.
간접 대상 지정
Freezable이 리소스로 선언되거나 스타일의 속성 값을 설정하는 데 사용되는 경우처럼 Freezable이 직접적으로 애니메이션의 대상이 될 수 없는 경우가 있습니다. 이러한 경우 대상으로 직접 지정할 수 없더라도 Freezable 개체에 계속해서 애니메이션 효과를 줄 수 있습니다. Freezable의 이름을 사용하여 TargetName 속성을 설정하는 대신에 Freezable이 "속하는" 요소의 이름을 제공합니다. 예를 들어 사각형 요소의 Fill을 설정하는 데 사용되는 SolidColorBrush는 해당 사각형에 속합니다. 브러시에 애니메이션 효과를 주려면 Freezable이 설정하는 데 사용된 프레임워크 요소 또는 프레임워크 콘텐츠 요소의 속성에서 시작하여 애니메이션 효과를 줄 Freezable 속성으로 끝나는 속성 체인을 사용하여 애니메이션의 TargetProperty를 설정합니다.
<ColorAnimation
Storyboard.TargetName="Rectangle01"
Storyboard.TargetProperty="Fill.Color"
From="Blue" To="AliceBlue" Duration="0:0:1" />
Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
Dim thePath As String = "(0).(1)"
Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath)
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 개체 개요를 참조하십시오.
또한 간접 속성 대상 지정을 사용할 경우 존재하지 않는 개체를 대상으로 할 수 있습니다. 예를 들어 실제로는 특정 단추의 배경을 설정하기 위해 LinearGradientBrush가 사용되었지만 해당 단추의 Background가 SolidColorBrush를 사용하여 설정되었다고 가정하고 해당 색에 애니메이션 효과를 줄 수 있습니다. 이러한 경우 예외가 throw되지 않습니다. LinearGradientBrush가 Color 속성의 변경 내용에 반응하지 않으므로 애니메이션은 시각적인 효과를 가지는 데 실패합니다.
다음 단원에서는 간접 속성 대상 지정 구문에 대해 자세히 설명합니다.
XAML에서 Freezable의 속성을 간접적으로 대상 지정
XAML에서 Freezable의 속성을 대상으로 하려면 다음 구문을 사용합니다.
ElementPropertyName.FreezablePropertyName |
Where
ElementPropertyName은 Freezable이 설정하는 데 사용되는 FrameworkElement의 속성입니다.
FreezablePropertyName은 애니메이션 효과를 주려는 Freezable의 속성입니다.
다음 코드 예제에서는 사각형 요소에서 다음 항목을 설정하는 데 사용되는 SolidColorBrush의 Color에 애니메이션 효과를 주는 방법을 보여 줍니다.
<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을 대상으로 하려면 다음 경로 구문을 사용합니다.
ElementPropertyName.Children[CollectionIndex].FreezablePropertyName |
여기서 CollectionIndex는 해당 배열 또는 컬렉션에 있는 개체의 인덱스입니다.
예를 들어 사각형에서 해당 RenderTransform 속성에 적용되는 TransformGroup 리소스가 있으며 포함된 변환 중 하나에 애니메이션 효과를 주려고 한다고 가정해 봅니다.
<TransformGroup x:Key="MyTransformGroupResource"
x:Shared="False">
<ScaleTransform />
<RotateTransform />
</TransformGroup>
다음 코드는 이전 예제에 있는 RotateTransform의 Angle 속성에 애니메이션 효과를 주는 방법을 보여 줍니다.
<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 형식의 배열을 만듭니다. 첫 번째 식별자 필드는 Freezable이 설정하는 데 사용되는 FrameworkElement 또는 FrameworkContentElement의 속성용입니다. 다음 식별자 필드는 대상으로 할 Freezable의 속성을 나타냅니다. 이것은 FrameworkElement 개체에 Freezable을 연결하는 속성 체인으로 간주할 수 있습니다.
다음은 사각형 요소의 Fill을 설정하는 데 사용된 SolidColorBrush의 Color를 대상으로 하는 종속성 속성 체인의 예제입니다.
Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
DependencyProperty[] propertyChain =
new DependencyProperty[]
{Rectangle.FillProperty, SolidColorBrush.ColorProperty};
또한 Path를 지정해야 합니다. Path는 해당 PathParameters를 해석하는 방법을 Path에 알려주는 String입니다. 다음 구문이 사용됩니다.
(OwnerPropertyArrayIndex).(FreezablePropertyArrayIndex) |
Where
OwnerPropertyArrayIndex는 Freezable이 설정하는 데 사용되는 FrameworkElement 개체 속성의 식별자를 포함하는 DependencyProperty 배열의 인덱스입니다.
FreezablePropertyArrayIndex는 대상으로 할 속성의 식별자를 포함하는 DependencyProperty 배열의 인덱스입니다.
다음 예제에서는 이전 예제에 정의된 PathParameters를 수반하는 Path를 보여 줍니다.
Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
Dim thePath As String = "(0).(1)"
DependencyProperty[] propertyChain =
new DependencyProperty[]
{Rectangle.FillProperty, SolidColorBrush.ColorProperty};
string thePath = "(0).(1)";
다음 예제에서는 사각형 요소의 Fill을 설정하는 데 사용되는 SolidColorBrush의 Color에 애니메이션 효과를 주기 위해 이전 예제의 코드를 결합합니다.
' Create a name scope for the page.
NameScope.SetNameScope(Me, New NameScope())
Dim rectangle01 As New Rectangle()
rectangle01.Name = "Rectangle01"
Me.RegisterName(rectangle01.Name, rectangle01)
rectangle01.Width = 100
rectangle01.Height = 100
rectangle01.Fill = CType(Me.Resources("MySolidColorBrushResource"), SolidColorBrush)
Dim myColorAnimation As New ColorAnimation()
myColorAnimation.From = Colors.Blue
myColorAnimation.To = Colors.AliceBlue
myColorAnimation.Duration = New Duration(TimeSpan.FromSeconds(1))
Storyboard.SetTargetName(myColorAnimation, rectangle01.Name)
Dim propertyChain() As DependencyProperty = {Rectangle.FillProperty, SolidColorBrush.ColorProperty}
Dim thePath As String = "(0).(1)"
Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
Storyboard.SetTargetProperty(myColorAnimation, myPropertyPath)
Dim myStoryboard As New Storyboard()
myStoryboard.Children.Add(myColorAnimation)
Dim myBeginStoryboard As New BeginStoryboard()
myBeginStoryboard.Storyboard = myStoryboard
Dim myMouseEnterTrigger As New EventTrigger()
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent
myMouseEnterTrigger.Actions.Add(myBeginStoryboard)
rectangle01.Triggers.Add(myMouseEnterTrigger)
// 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을 대상으로 해야 하는 경우가 있습니다. 예를 들어 사각형에서 해당 RenderTransform 속성에 적용되는 TransformGroup 리소스가 있으며 포함된 변환 중 하나에 애니메이션 효과를 주려고 한다고 가정해 봅니다.
<TransformGroup x:Key="MyTransformGroupResource"
x:Shared="False">
<ScaleTransform />
<RotateTransform />
</TransformGroup>
컬렉션에 포함된 Freezable을 대상으로 하려면 다음 경로 구문을 사용합니다.
(OwnerPropertyArrayIndex).( CollectionChildrenPropertyArrayIndex) [CollectionIndex ].(FreezablePropertyArrayIndex) |
여기서 CollectionIndex는 해당 배열 또는 컬렉션에 있는 개체의 인덱스입니다.
TransformGroup의 두 번째 변환인 RotateTransform의 Angle 속성을 대상으로 하려면 다음 Path 및 PathParameters를 사용합니다.
Dim propertyChain() As DependencyProperty = { Rectangle.RenderTransformProperty, TransformGroup.ChildrenProperty, RotateTransform.AngleProperty }
Dim thePath As String = "(0).(1)[1].(2)"
Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath)
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);
다음 예제에서는 TransformGroup 내에 포함된 RotateTransform의 Angle에 애니메이션 효과를 주기 위한 완전한 코드를 보여 줍니다.
Dim rectangle02 As New Rectangle()
rectangle02.Name = "Rectangle02"
Me.RegisterName(rectangle02.Name, rectangle02)
rectangle02.Width = 100
rectangle02.Height = 100
rectangle02.Fill = Brushes.Blue
rectangle02.RenderTransform = CType(Me.Resources("MyTransformGroupResource"), TransformGroup)
Dim myDoubleAnimation As New DoubleAnimation()
myDoubleAnimation.From = 0
myDoubleAnimation.To = 360
myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(1))
Storyboard.SetTargetName(myDoubleAnimation, rectangle02.Name)
Dim propertyChain() As DependencyProperty = { Rectangle.RenderTransformProperty, TransformGroup.ChildrenProperty, RotateTransform.AngleProperty }
Dim thePath As String = "(0).(1)[1].(2)"
Dim myPropertyPath As New PropertyPath(thePath, propertyChain)
Storyboard.SetTargetProperty(myDoubleAnimation, myPropertyPath)
Dim myStoryboard As New Storyboard()
myStoryboard.Children.Add(myDoubleAnimation)
Dim myBeginStoryboard As New BeginStoryboard()
myBeginStoryboard.Storyboard = myStoryboard
Dim myMouseEnterTrigger As New EventTrigger()
myMouseEnterTrigger.RoutedEvent = Rectangle.MouseEnterEvent
myMouseEnterTrigger.Actions.Add(myBeginStoryboard)
rectangle02.Triggers.Add(myMouseEnterTrigger)
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을 시작점으로 사용하여 간접적으로 대상 지정
이전 단원에서는 FrameworkElement 또는 FrameworkContentElement에서 시작하고 Freezable 하위 속성에 대한 속성 체인을 만들어서 간접적으로 Freezable을 대상으로 하는 방법에 대해 설명했습니다. Freezable을 시작점으로 사용하여 해당 Freezable 하위 속성 중 하나를 간접적으로 대상으로 할 수도 있습니다. Freezable을 간접 대상 지정을 위한 시작점으로 사용할 때 추가로 적용되는 한 가지 제한 사항은 간접적으로 대상으로 지정된 하위 속성과의 사이에서 시작 Freezable 및 모든 Freezable이 고정되지 않아야 한다는 것입니다.
XAML에서 대화형으로 Storyboard 제어
Extensible Application Markup Language (XAML)에서 Storyboard를 시작하려면 BeginStoryboard 트리거 동작을 사용합니다. BeginStoryboard는 애니메이션 효과를 줄 개체와 속성에 애니메이션을 배포한 다음 Storyboard를 시작합니다. (이 프로세스에 대한 자세한 내용은 애니메이션 및 타이밍 시스템 개요를 참조하십시오.) Name 속성을 지정하여 BeginStoryboard에 이름을 제공하면 제어 가능한 Storyboard로 만들 수 있습니다. 그러면 Storyboard를 시작한 후 대화형으로 제어할 수 있습니다. 다음은 Storyboard를 제어하기 위해 이벤트 트리거와 함께 사용하는 제어 가능한 Storyboard 작업 목록입니다.
PauseStoryboard: Storyboard를 일시 중지합니다.
ResumeStoryboard: 일시 중지한 Storyboard를 다시 시작합니다.
SetStoryboardSpeedRatio: Storyboard의 속도를 변경합니다.
SkipStoryboardToFill: Storyboard를 해당 전체 기간(있는 경우)의 끝으로 진행합니다.
StopStoryboard: Storyboard를 중지합니다.
RemoveStoryboard: Storyboard를 제거합니다.
다음 예제에서는 제어 가능한 Storyboard 작업을 사용하여 대화형으로 Storyboard를 제어합니다.
<Page
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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 클래스의 대화형 메서드를 사용하여 Storyboard를 제어할 수도 있습니다. Storyboard를 코드에서 대화형으로 만들려면 Storyboard의 Begin 메서드에 대한 적절한 오버로드를 사용하고 제어 가능하도록 true로 지정해야 합니다. 자세한 내용은 Begin(FrameworkElement, Boolean) 페이지를 참조하십시오.
다음 목록에서는 Storyboard를 시작된 후 조작하는 데 사용할 수 있는 메서드를 보여 줍니다.
이러한 메서드를 사용하면 Trigger 또는 TriggerAction 개체를 만들 필요가 없다는 이점이 있습니다. 조작할 제어 가능한 Storyboard에 대한 참조만 필요합니다.
참고: Clock에 대해 수행했으며 그에 따라 Storyboard에 대해서도 수행된 모든 대화형 작업은 다음 렌더링 직전에 발생하는 타이밍 엔진의 다음 Tick 시 발생합니다. 예를 들어 Seek 메서드를 사용하여 애네니메이션의 다른 지점으로 이동할 경우 속성 값은 즉시 변경되지 않으며 타이밍 엔진의 다음 Tick에서 값이 변경됩니다.
다음 예제에서는 Storyboard 클래스의 대화형 메서드를 사용하여 애니메이션을 적용 및 제어하는 방법을 보여 줍니다.
Imports Microsoft.VisualBasic
Imports System
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
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);
}
}
}
스타일에서 애니메이션 효과 주기
Storyboard 개체를 사용하여 Style에서 애니메이션을 정의할 수 있습니다. Style에서 Storyboard를 사용하여 애니메이션 효과를 주는 것은 다음과 같은 세 가지 예외를 제외하고는 다른 곳에서 Storyboard를 사용하는 것과 비슷합니다.
TargetName을 지정하지 않습니다. Storyboard는 Style이 적용되는 요소를 항상 대상으로 합니다. Freezable 개체를 대상으로 하려면 간접 대상 지정을 사용해야 합니다. 간접 대상 지정에 대한 자세한 내용은 간접 대상 지정 단원을 참조하십시오.
EventTrigger 또는 Trigger에 대한 SourceName을 지정할 수 없습니다.
동적 리소스 참조나 데이터 바인딩 표현식을 사용하여 Storyboard 또는 애니메니션 속성 값을 설정할 수 없습니다. 이는 Style 안의 모든 항목이 스레드로부터 안전하며 타이밍 시스템은 이러한 항목을 스레드로부터 안전하게 만들기 위해 Storyboard 개체에 Freeze을 수행해야 하기 때문입니다. Storyboard는 동적 리소스 참조 또는 데이터 바인딩 표현식이 자신이나 자식 Timeline에 포함된 경우 고정할 수 없습니다. 고정과 기타 Freezable 기능에 대한 자세한 내용은 Freezable 개체 개요를 참조하십시오.
XAML에서는 Storyboard 또는 애니메이션 이벤트에 대한 이벤트 처리기를 선언할 수 없습니다.
스타일에서 Storyboard를 정의하는 방법을 보여 주는 예제를 보려면 방법: 스타일에 애니메이션 효과 적용 예제를 참조하십시오.
ControlTemplate에서 애니메이션 효과 주기
Storyboard 개체를 사용하여 ControlTemplate에서 애니메이션을 정의할 수 있습니다. ControlTemplate에서 Storyboard를 사용하여 애니메이션 효과를 주는 것은 다음과 같은 두 가지 예외를 제외하고는 다른 곳에서 Storyboard를 사용하는 것과 비슷합니다.
TargetName은 ControlTemplate의 자식 개체만 참조할 수 있습니다. TargetName이 지정되지 않은 경우 애니메이션은 ControlTemplate이 적용되는 요소를 대상으로 합니다.
EventTrigger 또는 Trigger에 대한 SourceName은 ControlTemplate의 자식 개체만 참조할 수 있습니다.
동적 리소스 참조나 데이터 바인딩 표현식을 사용하여 Storyboard 또는 애니메니션 속성 값을 설정할 수 없습니다. 이는 ControlTemplate 안의 모든 항목이 스레드로부터 안전하며 타이밍 시스템은 이러한 항목을 스레드로부터 안전하게 만들기 위해 Storyboard 개체에 Freeze을 수행해야 하기 때문입니다. Storyboard는 동적 리소스 참조 또는 데이터 바인딩 표현식이 자신이나 자식 Timeline에 포함된 경우 고정할 수 없습니다. 고정과 기타 Freezable 기능에 대한 자세한 내용은 Freezable 개체 개요를 참조하십시오.
XAML에서는 Storyboard 또는 애니메이션 이벤트에 대한 이벤트 처리기를 선언할 수 없습니다.
ControlTemplate에서 Storyboard를 정의하는 방법에 대한 예제를 보려면 방법: ControlTemplate에 애니메이션 효과 적용 예제를 참조하십시오.
속성 값 변경 시에 애니메니션 효과 주기
스타일 및 컨트롤 템플릿에서 Trigger 개체를 사용하여 속성 변경 시에 Storyboard를 시작할 수 있습니다. 예제를 보려면 방법: 속성 값이 변경될 때 애니메이션 트리거 및 방법: ControlTemplate에 애니메이션 효과 적용를 참조하십시오.
속성 Trigger 개체에 의해 적용된 애니메이션은 EventTrigger 애니메이션 또는 Storyboard 메서드를 사용하여 시작된 애니메이션보다 복잡한 방식으로 작동합니다. 이러한 애니메이션은 다른 Trigger 개체에 의해 정의된 애니메이션과 "핸드오프"하지만 EventTrigger 및 메서드에서 트리거한 애니메이션으로 구성됩니다.