Silverlight/Tips

ChildWindow에서 VisualStateManager.GoToState(...)가 말을 안들을 때

길버트리 2009. 10. 16. 17:03
어느 실버라이트 개발자님께서 질문을 해주셔서 그 답변 내용을 포스팅합니다.
요즘 회사 일이 매우 바빠서 '세미나 소식' 이외에 제대로된 실버라이트 포스팅을 하지 못하고 있었는데
잘 되었군요.

#자식(ChildWindow)이 말을 잘 안들어!


photo by jon bradley @ flickr.com

현재 Silverlight 3에서는 

ChildWindow에서는 VisualStateManager.GoToState(...)로 VisualState 변경이 불가능합니다.

VisualState가 얼마나 편한데... 이걸 포기하는 것은 말도 안되죠!

하지만 VisualStateManager.GoToState를 호출해 봐야 깜깜 무소식에 false만 리턴해 올 뿐!

게다가 VisualStateManager.GetVisualStateGroups(this);을 실행해 보시면,
역시 정의해 놓으신 VisualStateGroup을 하나(Count = 0)도 못가져 올 거예요.

아마도 ContentTemplate과 관계된 내부설계상(By design)의 문제인 것 같은데요.
Silverlight 3에서는 일단 Workaround를 사용하셔야 할 것 같습니다.
 

#Workaround
 
본 건을 boxmile대표에게 의뢰해 본 결과 다음과 같은 Workaround가 나왔습니다.
(휴즈플로우에서는 Workaround를 주로 대표님에게 의뢰하는 전통이... ㅎㅎ 거의 국과수와 동급인 느낌이죠)

ChildWindow의 xaml.cs 소스에 OnApplyTemplate()을 아래와 같이 override 하시는 것입니다.
ApplyTemplate된 VisualStateGroup들을 호출이 유효한 장소로 재이동을 시켜주는 게 포인트입니다.
 
- 아래 -
 
public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    if (this.Content == null)
        return;

    Panel rootPanel = this.GetTemplateChild("Root") as Panel;
    if (rootPanel == null)
        return;

    System.Collections.IList sourceGroups = VisualStateManager.GetVisualStateGroups(this.Content as FrameworkElement);
    System.Collections.IList targetGroups = VisualStateManager.GetVisualStateGroups(rootPanel);

    // 이사
    for (int i = 0; i < sourceGroups.Count; i++)
    {
        // 원래 그룹에서 맨 앞의 노드를 추출해서 삭제
        object head = sourceGroups[0];
        sourceGroups.RemoveAt(0);

        // 목표 그룹에 추가
        targetGroups.Add(head);
    }
}
 
- 이상 -
       
매번 ChildWindow 만들 때마다 위 소스를 붙여넣기 하셔도 되지만,
저희가 VisualStudio를 위한 Item Template을 만들었습니다.
 
 
#ItemTemplate for Visual Studio
위에 첨부한 SLChildWindowSupportingVisualState.zip 파일을 아래 경로에 복사해 놓고 사용하시면 됩니다.
(빨간색 글자로 표시한 폴더들은 기본으로 존재하지 않으니 생성하시기 바랍니다.)
 
%USERPROFILE%\Documents\Visual Studio 2008\Templates\ItemTemplates\Visual C#\Silverlight
예) C:\Users\Gilbert\Documents\Visual Studio 2008\Templates\ItemTemplates\Visual C#\Silverlight
 
그리고 나서 새로 Visual Studio를 실행시키시면,
그 때부터는
프로젝트에 Add New Item하실 때, 아래 이미지처럼 아이템 템플릿에서 선택이 가능합니다.



이 아이템 템플릿을 통해 ChildWindow를 생성하시면 생성되는 xaml.cs 소스에 기본으로
위 Workarond 내용이 들어가 있게되어 편하게 사용하실 수 있죠.
 
제대로 작동하는 샘플프로젝트(ChildWindow3.zip) 아래 첨부하니 참고하시구요.
도움이 되시길 바랍니다.
감사합니다.