GSI

사용자 삽입 이미지

Wpf Animation( Storyboard ) Demo

Xaml의 Storyboard를 추가 하고 cs 파일을 통해서 처리 해봤습니다.

- Button 을 누르면 해당 값을 설정하고 바로 에니메이션을 동작한다.
- SliderBar 을 누르면 해당 값을 설정하고 바로 에니메이션을 동작한다.

관련코드 :
Posted by gsi
:

Blend를 사용해서 Animation을 작성하다 보면 Blend에서 작성한 코드만 가지고 안될때가 많다. 코드 중간 중간 실시간적으로 받은 데이터의 값을 에니메이션 Value에 추가해서 사용해야 할때가 많아 진다.

이럴 경우 코드 비하인드에서 스토리 보드 부터 다 짜게 되면야.
값 접근하는게 어렵지는 않다. 하지만 에니메이션 정보를 코드로 다 짜준다는건 캐 노가다거나 거의 비효율적인 작업이 될 것이다. 그래서 몇가지 예제를 찾아 봤는데.

다른 방법이 하나 있긴 하다 공도님 사이트에서 본것 ^^..
이것 > http://gongdo.tistory.com/110

하지만 그것도 좀 그렇다. 왠지 작업량이 복잡해 지고 불편하다.

그래서 내부 구조를 조금씩 보면서 아래와 같은 접근 방법을 사용하였다.

<Storyboard x:Key="Timeline1">
 <DoubleAnimationUsingKeyFrames x:Name="TestAni1" BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
  <SplineDoubleKeyFrame x:Name="TestSpline1" KeyTime="00:00:00" Value="0"/>
  <SplineDoubleKeyFrame x:Name="TestSpline2" KeyTime="00:00:01" Value="192"/>
 </DoubleAnimationUsingKeyFrames>
 <DoubleAnimationUsingKeyFrames x:Name="TestAni2" BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">
  <SplineDoubleKeyFrame x:Name="TestSpline3" KeyTime="00:00:00" Value="0"/>
  <SplineDoubleKeyFrame x:Name="TestSpline4" KeyTime="00:00:01" Value="62.206"/>
 </DoubleAnimationUsingKeyFrames>
</Storyboard>

위의 코드도 결국 cs 파일에서 하는거 처름 다 추가 되는거라고 생각하고.
아래와 같이 분해 해보았다.

이런 XAML 코드가 있다고 하고 192라는 값을 코드 중간에 바꾸고자 할때
아래와 같이 하면 접근이 되는 것을 확인 하였다.

// 스토리 보드를 가져 온다.
Storyboard st = (Storyboard)this.FindResource("Timeline1");
// 스토리 보드의 내부 타임 라인 그룹정보를 가져 온다.
TimelineCollection tgroup = (TimelineCollection)st.Children;
// TimelineCollection 안에 있는 객체 하나를 가져 온다.
// 근데 여기서 int형 배열 정보만 받는다. 그럼 내가 몇번째 것을 제어 하고 싶은지
// 알아야 할거 같다.
DoubleAnimationUsingKeyFrames dAniFrame = (DoubleAnimationUsingKeyFrames)tgroup[0];
// SplineDoubleKeyFrame  정보를 가져 오기 위해서
// DoubleKeyFrameCollection 의 정보를 가져 온다.
DoubleKeyFrameCollection dAniFrameGroup = (DoubleKeyFrameCollection)dAniFrame.KeyFrames;
// SplineDoubleKeyFrame  정보를 가져 온다.
SplineDoubleKeyFrame spAniFrame = (SplineDoubleKeyFrame)dAniFrameGroup[1];
// Value 값을 조정할 수 있게 된다.
spAniFrame.Value = 500;

코드 량은 좀 되는거 같아도 접근을 할 수 있는거 같은데요.
사실 이거 말고 다른게 있을듯도 한데.. ms가 이거 만들면서 이런거 고민했을텐데.
사실 다른건 아직 방법을 찾지 못했네요.

혹시 아시면 코멘트 부탁해요.

Posted by gsi
:

xaml 코드에서 Completed="OnCompleted" 를 사용해서 에니메이션이 완료 되었을때 처리코드를 추가 할 수 있다.

<
Window.Resources>
  <
Storyboard x:Key="sb1" Completed="OnCompleted"
>
     <
DoubleAnimation  Storyboard.TargetName="deactiveAnimationRectangle" Storyboard.TargetProperty="Width" From="20" To="400" Duration="0:0:5"
/>
     <
DoubleAnimation Storyboard.TargetName="holdEndAnimationRectangle" Storyboard.TargetProperty="Width" From="10" To="400" Duration="0:0:1.5" BeginTime="0:0:0.5"
/>
</
Storyboard
>
</
Window.Resources
>

Being able, when animation ended, to set rectangle Width using: holdEndAnimationRectangle.Width = 250;

Also tried:

void OnCompleted (object sender, EventArgs e)
{
  Storyboard sb = (Storyboard)this.FindResource("sb1"
);
  sb.FillBehavior = FillBehavior
.Stop;
  holdEndAnimationRectangle.Width = 250;
}

Posted by gsi
:

Storyboard 를 사용한 TransformGroup를 C#에서 처리 하는 방법


Blend에서 Timeline을 생성하고 오브젝트를 움직이면 에니메이션 처리를 할수 있다.
가장 간단하게 하면서도 효과적인 에니메이션을 구현할 수 있다.

에니메이션 쪽을 보면 Transform에 여러개의 객체가 붙을수 있다.

만약 Button 의 이름이 btn이라고 하고 예로 들어 보겠다.

btn.RenderTransform 에 붙을수 있는 것은 아래와 같을 것이다.

btn.RenderTransform = new RotateTransform(0);
btn.RenderTransform = new ScaleTransform(1, 1);
btn.RenderTransform = new SkewTransform(0, 0);
btn.RenderTransform = new TranslateTransform(10, 10);



그리고 위의 4개를 통합해서 사용할 수 있는것으로 TransformGroup를 들수 있다.

...
btn.RenderTransform = tGroup;



위에서 보는 것과 같이 5개의 속성을 연결 시킬 수가 있다.

몇가지 테스트를 해봤고,
RenderTransform에 TransformGroup를 붙이지 않고 개별적인
속성을 붙이게 되면 Animation할때도 그 속성에 대한 정보만 제어 할 수 있다.
즉, 이동만을 하고 싶은 것이라면 TranslateTransform만 연결해서 사용하면 될듯 하다.

구체적인 예제를 만들지는 않았지만.
궁금하면 질문 해주기 바랍니다.

아래의 코드는 4개의 속성 정보를 다 연동하고 난 후에 제어 하는
아주 심플한 예제 입니다.
물론 자료형을 사용해서 배열로 정보들을 저장하고 조금더
깔끔하고 효과적으로 처리 할 수도 있을거 같다.
그리고 현재 코드는 2D의 처리만 가능한 것이다.

-------------------------------------------------------------------------
전제조건 :
Blend에서 기본 오브젝트를 우선 제작한다.
1. 버튼 두개를 제작한다.
2. 텍스트 박스를 하나 만든다. 이름은 TextBox2로 지정한다.

자.. 프로그램 코드는 *.cs 파일에서만 구동되므로 바로 설명 하겠다.

제어에 필요한 변수를 아래와 같이 만들었습니다.

//에니메이션 이름에 사용할 것을 지정
private string aniTrans = "_aniTrans";
private string aniSkew = "_aniSkew";
private string aniScale = "_aniScale";
private string aniRotate = "_aniRotate";

//트랜스폼을 제어 하기 위해서 변수를 설정
private TransformGroup group;
private RotateTransform rotate;
private ScaleTransform scale;
private SkewTransform skew;
private TranslateTransform trans;

//스토리 보드의 속성정보를 저장할 변수 설정
private Storyboard transStoryX;
private Storyboard transStoryY;
private Storyboard RotateStory;

//에니메이션 변수 설정
private DoubleAnimation myTransX;
private DoubleAnimation myTransY;
private DoubleAnimation myRotate;

public Window1()
{
    ...
    group = new TransformGroup();
    rotate = new RotateTransform(0);
    scale = new ScaleTransform(1, 1);
    skew = new SkewTransform(0, 0);
    trans = new TranslateTransform(50, 50);

    group.Children.Add(rotate);
    group.Children.Add(scale);
    group.Children.Add(skew);
    group.Children.Add(trans);

    this.RegisterName(aniTrans, trans);
    this.RegisterName(aniSkew, skew);
    this.RegisterName(aniScale, scale);
    this.RegisterName(aniRotate, rotate);

    TextBox2.RenderTransform = group;
}

private void OnLoaded(object sender, RoutedEventArgs e)
{
    myTransX = new DoubleAnimation();
    myTransY = new DoubleAnimation();
    myRotate = new DoubleAnimation();

    Storyboard.SetTargetName(myTransX, aniTrans);
    Storyboard.SetTargetProperty(myTransX, new PropertyPath(TranslateTransform.XProperty));
    Storyboard.SetTargetName(myTransY, aniTrans);
    Storyboard.SetTargetProperty(myTransY, new PropertyPath(TranslateTransform.YProperty));
    Storyboard.SetTargetName(myRotate, aniRotate);
    Storyboard.SetTargetProperty(myRotate, new PropertyPath(RotateTransform.AngleProperty));

    transStoryX = new Storyboard();
    transStoryX.Children.Add(myTransX);
    transStoryY = new Storyboard();
    transStoryY.Children.Add(myTransY);
    RotateStory = new Storyboard();
    RotateStory.Children.Add(myRotate);
}

private void OnClick(object sender, RoutedEventArgs e)
{
    myTransX.To = -50;
    myTransX.Duration = new Duration(TimeSpan.FromMilliseconds(800));
    myTransY.To = -50;
    myTransY.Duration = new Duration(TimeSpan.FromMilliseconds(800));
    myRotate.To = -50;
    myRotate.Duration = new Duration(TimeSpan.FromMilliseconds(800));

    transStoryX.Begin(this);
    transStoryY.Begin(this);
    RotateStory.Begin(this);
}

private void OnClick2(object sender, RoutedEventArgs e)
{
    myTransX.To = 120;
    myTransX.Duration = new Duration(TimeSpan.FromMilliseconds(800));
    myTransY.To = 150;
    myTransY.Duration = new Duration(TimeSpan.FromMilliseconds(800));
    myRotate.To = 270;
    myRotate.Duration = new Duration(TimeSpan.FromMilliseconds(800));

    transStoryX.Begin(this);
    transStoryY.Begin(this);
    RotateStory.Begin(this);
}


아.. 내용이 많아 지네욤..

우선 한번만 지정하는 부분과 매번 동작상황에 맞게 값을 입력해줘야 하는것으로
세분화를 해봤습니다.
Windows1()에 있는 내용은 기본적으로 설정할 부분이며,

OnClick(), OnClick1() 에는 버튼에 대한 이벤트 입니다.
아무래서 여기서 From, To, Duration을 설정해 줘야 할듯 합니다.

아. 참고로 From을 설정하지 않으면 현재 위치에서 To까지의 진행을
하게 됩니다. 처음에 이게 궁금했는데 아주 편한듯 합니다. ^^

그리고 Storyboard 여기 설정하는 부분이 솔직이 아직 다 이해가 가질 않습니다.
위의 코드 처름 하나하나의 속성을 처리 하는 부분에서는 별다른
문제가 없지만 path 형태의 처리는 아직 공부 중입니다. ^^

음.. 대충 설명은 이것으로 마치겠습니다.
샘플 받아서 실행해 보시고 분석해 보시면 더 도움 될거 같아욤.
아무쪼록 좋지 않은 내용을 봐주셔서 감사 ^^

Posted by gsi
: