Tech/Silverlight2010. 1. 6. 17:11

1. Custom Animation?

Silverlight에서 Storyboard를 사용한 Animation을 적용하고자 할 때 특정한 Property에 대한 Animation 적용이 힘든 경우가 있다. (ex. Grid의 Margin)

그것을 위해서 사용자가 직접 Animation을 구현하는 Class를 작성하면 된다.

Custom Animation Class는 DependencyProperty로 Time, Target, From, To, TargetProperty를 구현한다.


2. Thickness Animation

Grid의 Margin은 Type이 Thickness이다. 이것의 Animation을 위한 ThicknessAnimation Class는 다음과 같이 구현할 수 있다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

using System.Windows;
using System.Windows.Media.Animation;

namespace CCPContentsList
{
    public class ThicknessAnimation  
    { 
        // The time along the animation from 0-1
        public static DependencyProperty TimeProperty = DependencyProperty.RegisterAttached(
            "Time", typeof(double), typeof(DoubleAnimation), new PropertyMetadata(OnTimeChanged));
        // The object being animated
        public static DependencyProperty TargetProperty = DependencyProperty.RegisterAttached(
            "Target", typeof(DependencyObject), typeof(ThicknessAnimation), null);
        // The thickness we're animating to
        public static DependencyProperty FromProperty = DependencyProperty.RegisterAttached(
            "From", typeof(Thickness), typeof(DependencyObject), null);
        // The tickness we're animating from
        public static DependencyProperty ToProperty = DependencyProperty.RegisterAttached(
            "To", typeof(Thickness), typeof(DependencyObject), null);
        // The target property to animate to.  Should have a property type of Thickness
        public static DependencyProperty TargetPropertyProperty = DependencyProperty.RegisterAttached(
            "TargetProperty", typeof(DependencyProperty), typeof(DependencyObject), null);

        /// <summary>
        /// Creates a Timeline used to animate the thickness of an object
        /// </summary>
        /// <param name="target">The object to animate</param>
        /// <param name="targetProperty">The property on the object to animate</param>
        /// <param name="duration">The length of the animation</param>
        /// <param name="from">The begining thickness</param>
        /// <param name="to">The final thickness</param>
        /// <returns>A timeline object that can be added to a storyboard</returns>
         public static Timeline Create(
             DependencyObject target, 
             DependencyProperty targetProperty, 
             Duration duration, 
             Thickness from, 
             Thickness to, 
             EasingFunctionBase ease)
         {
             DoubleAnimation timeAnimation = new DoubleAnimation() 
                    { From = 0, To = 1, Duration = duration, EasingFunction = ease };
             timeAnimation.SetValue(TargetProperty, target);
             timeAnimation.SetValue(TargetPropertyProperty, targetProperty);
             timeAnimation.SetValue(FromProperty, from);
             timeAnimation.SetValue(ToProperty, to);
             Storyboard.SetTargetProperty(timeAnimation, new PropertyPath("(ThicknessAnimation.Time)"));
             Storyboard.SetTarget(timeAnimation, timeAnimation); 
             return timeAnimation;
         }

         ///<summary>
         ///Silverlight's animation system is animating time from 0 to 1.  
         ///When time changes we update the thickness to be time
         ///percent between from and to 
         ///</summary>
         private static void OnTimeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
         {
             DoubleAnimation animation = (DoubleAnimation)sender;
             double time = GetTime(animation);
             Thickness from = (Thickness)sender.GetValue(FromProperty);
             Thickness to = (Thickness)sender.GetValue(ToProperty);
             DependencyProperty targetProperty = (DependencyProperty)sender.GetValue(TargetPropertyProperty);
             DependencyObject target = (DependencyObject)sender.GetValue(TargetProperty);
             target.SetValue(targetProperty, new Thickness((to.Left - from.Left) * time + from.Left,
             (to.Top - from.Top) * time + from.Top,
             (to.Right - from.Right) * time + from.Right,
             (to.Bottom - from.Bottom) * time + from.Bottom));
         } 

         public static double GetTime(DoubleAnimation animation)
         {
            return (double)animation.GetValue(TimeProperty);
         }

         public static void SetTime(DoubleAnimation animation, double value)
         {
            animation.SetValue(TimeProperty, value);
         }
    }
}

- 여기서 중요한 부분은 OnTimeChanged 함수이다. 이 함수로 들어온 DoubleAnimation으로 부터 설정한 애니메이션 정보를 얻은 다음에, Margin 값을 직접 수정하게 된다. (Margin의 Type은 Thickness)

- 이를 응용하면 애니메이션 적용이 힘든 다른 Property도 Custom Animation을 제작해 사용할 수 있다.


Posted by 알 수 없는 사용자
Tech/Silverlight2010. 1. 1. 14:21

Commands in Silverlight with SLExtensions - 1에서 이어집니다.

일단, 앞에서 새로 빌드한 SLExtensions.dll 파일을 프로젝트 참조에 추가해두고 다음으로 넘어가도록 합시다.

커맨드 제공자

첫 번째로는 커맨드들을 모아 둘 Commands 라는 정적 클래스를 만듭니다. 가령 무엇인가 삭제하는 Delete 라는 커맨드를 만든다고 하면 다음과 같은 Commands 클래스가 만들어지게 됩니다.

public static class Commands
{
public static Command DeleteCommand { get; private set; }

static Commands()
{
DeleteCommand = new Command("DeleteCommandName");
}
}

정적 생성자에서 정적 속성인 DeleteCommand를 초기화하는 것을 볼 수 있습니다. Command 개체의 생성자에 넣는 커맨드 이름은, 사용하려는 커맨드 이름과 동일하게 "DeleteCommand"라고 지정하는 것이 보통이겠으나 여기서는 확실히 구분을 주기 위해서 "DeleteCommandName"이라고 지정해 보았습니다.


ViewModel 연결

ViewModel 에서는 삭제 커맨드가 실행되었을 때 뭔가 삭제하는 작업을 수행해주어야 되겠죠. 커맨드가 실행되었다는 것을 알기 위해서 다음과 같이 생성자에서 Executed 이벤트를 구독합니다.

public MainPageViewModel()
{
Commands.DeleteCommand.Executed += new EventHandler<ExecutedEventArgs>(DeleteCommand_Executed);
}

DeleteCommand_Executed 라는 메서드에서 삭제 작업을 수행해 줄 것이라고 기대할 수 있겠습니다.


View 연결

이제 View에서 커맨드를 발생시키도록 합니다. 먼저 커맨드 관련 클래스들이 포함되어 있는 SLExtensions.Input 네임스페이스를 추가합니다.

xmlns:input="clr-namespace:SLExtensions.Input;assembly=SLExtensions"

다음으로는 삭제 버튼에 삭제 커맨드를 지정해줍니다.

<Button Content="Delete" input:CommandService.Command="DeleteCommandName"/>

DeleteCommandName 이라는 문자열을 사용해서 실행될 커맨드를 지정하고 있습니다. 이제 이 버튼을 클릭하면 삭제 커맨드가 실행되는 것이지요.


View - ViewModel 연결

한 번 실행해보기 위한 작업을 해 봅시다. 일단 ViewModel의 DeleteCommand_Executed 메서드에서 메시지 박스를 띄우도록 합니다.

void DeleteCommand_Executed(object sender, ExecutedEventArgs e)
{
MessageBox.Show("DeleteCommand");
}

그리고 View 생성 시 ViewModel이 같이 생성되도록 View의 xaml 파일을 수정합니다. 일단 프로젝트의 네임스페이스를 추가하고,

xmlns:local="clr-namespace:SilverlightApplication3"

ViewModel을 생성하도록 데이터 컨텍스트를 추가합니다. UserControl 태그의 여는 태그 바로 아래에 다음과 같은 내용을 추가합니다.

<UserControl.DataContext>
<
local:MainPageViewModel />
</
UserControl.DataContext>

이제 프로젝트를 실행해서 삭제 버튼을 누르면 메시지 박스가 뜨는 것을 볼 수 있을 것입니다.


이번에는 커맨드 패턴을 이용하여 어떻게 View와 ViewModel을 연결시키는지 간단히 살펴보았습니다. 다음 연재에서 좀 더 상세한 내용을 다뤄보도록 하겠습니다.

'Tech > Silverlight' 카테고리의 다른 글

[Silverlight Custom Font 적용]  (0) 2010.01.12
Custom Animation in Silverlight  (1) 2010.01.06
Commands in Silverlight with SLExtensions - 1  (0) 2009.12.26
Silverlight Pixel Shader 개발 팁  (0) 2009.10.28
Posted by wafe