프리지아 랩

Programming/Windows Phone +30


윈도우 폰 개발자라면 제 집처럼 드나들어야 할 곳이 바로 마이크로소프트의 앱 허브(APP HUB, http://create.msdn.com/ko-KR) 입니다. 이 앱 허브를 발이 닳도록 드나들면 윈도우 폰 개발자로 입문해서 고급 개발자가 되는 과정에 필요한 많은 지식과 최신 소식을 접할 수 있습니다.

지금 부터 앱 허브 탐구생활을 시작해봅시다. 먼저 앱 허브의 관문이 어떤 구조인지 부터 한 번 살펴봅시다.

앱 허브의 관문은 다음과 같이 생겼습니다.


[1] 내 언어 설정 / 로그인
앱 허브에 들어서면 제일 먼저 자기 언어권에 해당하는 옵션으로 바꿀 수 있는 부분 입니다. 현재 영어/중국어/일본어/한국어의 4가지 언어가 지원되고 있습니다. 아쉬운 점은 이렇게 언어를 바꿔도 대부분의 콘텐츠는 여전히 영어로 되어 있다는 점입니다. 결국 우리는 영어도 잘해야 합니다.

언어 설정 바로 밑에 [로그인] 메뉴가 있습니다. 이미 앱 허브 개발자로 등록했거나 등록은 하지 않았지만 Windows Live ID가 있으신분은 로그인해서 개발자 등록을 할 수 있습니다.

[2] 내 대시보드
[내 대시보드]메뉴에서는 현재 계정이 연동된 기기와 관련된 모든 정보를 확인하고 필요한 작업을 할 수 있습니다.

[3] 커뮤니티
[커뮤니티] 메뉴는 윈도우 폰 관련 전문가들의 블로그나 팀 블로그외 각종 커뮤니티 사이트, 소셜 네트워크를 통해 유통되는 리소스를 살펴볼 수 있습니다.

[4] 교육
[교육] 메뉴에서는 윈도우 폰 개발을 시작할 때 볼만한 팟 캐스트, 튜토리얼, 각종 기술 기고, 코드 샘플 등을 통해 윈도우 폰 개발의 실력 향상에 도움을 줍니다. 또한 라이브러리 문서와 개발자 리소스, 교육 기관, 유용한 서적 등을 소개합니다.

[5] 리소스
[리소스] 메뉴에서는 질문을 올리고 답변을 얻거나 앱 개발을 위한 팁과 트릭에 관해 배울 수 있는 부분이다. 마켓 FAQ와 애플리케이션 인증 가이드라인을 확인할 수 있습니다. 유로 계정을 등록한 경우에는 지원 티켓을 통해 앱 제출이나 앱 인증, 기기 잠금 해제에 도움을 얻을 수 있습니다. 또한 필요한 도구들을 다운로드하거나 파트너 제품을 확인할 수 있습니다.

[6] Download the free tools
[Download the free tools] 섹션에서는 윈도우 폰 7.5와 Xbox LIVE Indie Games 개발을 위한 각종 도구들을 다운로드 할 수 있습니다.  윈도우 폰 SDK 7.1과 폰용 광고 SDK 등이 이 섹션에서 제공됩니다.

[7] Join to submit your apps & games
[Join to submit your apps & games] 섹션에서는 윈도우 폰과 Xbox LIVE Indie Games를 위한 앱과 게임 개발자들의 활발한 커뮤니티의 일부가 되는 멤버십에 대해 안내합니다.

[8] news details
[news details] 섹션에서는 방문자가 관심을 가질만한 주목할 만한 소식과 이벤트 등의 세부 정보를 안내합니다.

[9] 뉴스
뉴스 섹션은 윈도우 폰과 Xbox 관련된 뉴스를 최근 날짜 순으로 소개합니다.

[A] 교육
교육 섹션에서는 윈도우 폰 개발에 도움이 되는 기사나 코드 샘플, 튜토리얼 등을 소개하는데, 이 섹션은 앞서 [4] 교육 메뉴의 주요 콘텐츠를 노출한 것입니다.

[B] answers
answers 섹션은 앱 허브 등록이나 앱 등록, 윈도우 폰 개발자 대시보드, 애플리케이션 인증 요구사항 등 중요한 가이드를 노출하는 영역입니다.

[C] Windows Phone Developer Blog
[Windows Phone Developer Blog] 섹션은 앞서 윈도우 폰 개발관련 블로그 기사 중에서 가장 최근의 기사를 노출하는 영역입니다.

[D] XNA Game Studio Team Blog
[XNA Game Studio Team Blog] 섹션은 앞서 Xbox 개발관련 블로그 기사 중에서 가장 최근의 기사를 노출하는 영역입니다.

[E] 스포트라이트
[스포트라이트] 섹션은 주목할만한 개발자를 소개하는 섹션입니다. 한국의 많은 개발자들이 윈도우 폰 앱을 개발하고 등록해서 이 코너에 소개되면 좋겠습니다.

Comment +0


에뮬레이터를 사용하다보면 단축키를 알고 있는 편이 작업하기 훨씬 수월합니다.
유용한 단축키를 몇 가지 공유합니다.

▒ [Pause/Break]
에뮬레이터에서 텍스트 상자와 같은 컨트롤에 문장을 입력해야 하는 경우 가상 키보드를 일일이 마우스로 누르는것은 무모한 짓이죠. 이 때 [Pause/Break]를 누르면 가상 키보드가 아니라 PC의 키보드를 사용해 입력할 수 있습니다.

▒ [Page Up(활성화)/Page Down(비활성화)]
가상 키보드를 활성화하거나 비활성화 합니다.

▒ [F1]
가상 키보드의 [Back] 버튼으로 동작합니다.

▒ [F2]
가상 키보드의 [Start] 버튼으로 동작합니다.
짧게 누르면 시작화면으로 이동하고, 길게 누르면 음성 동작 기능으로 이동합니다.

▒ [F7]
에뮬레이터의 [카메라] 버튼으로 동작합니다.

▒ [F9]/[F10]
[Volume Up]/[Volume Down] 버튼으로 동작합니다.

Comment +0


윈도우 폰 애플리케이션은 사용자가 해당 애플리케이션을 벗어날 때 잠재적으로 종료된다. 다음 주제는 실행 모델 이벤트를 처리하는 몇 가지 모범 사례다.

▩ 13 가지 모범 사례

1. [시작] 이나 설치된 애플리케이션 목록에서 사용자가 애플리케이션을 실행시킬때, 해당 사용자는 일관된 실행 경험을 얻어야 한다. 새로운 애플리케이션 인스턴스의 경험은 사용자에게 명확하게 와 닿아야 한다.

새로운 애플리케이션 인스턴스를 시작할 때, 이 인스턴스는 예를 들면 최근에 열었던 문서의 목록 처럼 이전 인스턴스에 관한 정보를 사용자에게 나타내야 하지만, 사용자는 이전 세션을 계속 유지하고 있다는 느낌은 받지 않아야 한다.

2. 사용자가 이전에 실행한 애플리케이션으로 돌아가 애플리케이션을 활성화 할 때, 사용자는 해당 애플리케이션이 비활성화 되었을 때 보여준 형태와 일관된 경험을 가져야 한다. 애플리케이션이 종료되고 재시작된 것이 사용자에게 구분되어야 한다.

3. 몇몇 윈도우 폰 기능은 실행된 애플리케이션에 상황별 정보를 전달하는 방식으로 해당 애플리케이션을 시작하는 메커니즘을 사용자에게 제공한다. 예를 들면  ShellToast와 Reminder, ShellTile 모두는 전달될 수 있는 쿼리 문자열에 NavigationUri 파라미터를 노출하고 MediaHistoryItem 클래스는 상황별 정보를 전달할 수 있는  PlayerContext 속성을 갖는다. 해당 애플리케이션은 이들 메커니즘 중 하나를 사용해 시작할 때 컨텍스트에 적절한 콘텐츠를 표시해야 한다.

4. PhoneApplicationService 클래스의 State 속성을 사용해  Deactivated 이벤트 핸들러의 일시적인 애플리케이션 상태를 저장하고  Activated 핸들러의 애플리케이션 상태를 가져온다.

5. PhoneApplicationPage 클래스의  State 속성을 사용해 OnNavigatedFrom 이벤트 핸들러의 일시적인 페이지 상태를 저장하고  OnNavigatedTo 이벤트 핸들러의 페이지 상태를 가져온다.

6. 애플리케이션이 삭제 표시된 후, 사용자는 해당 애플리케이션으로 돌아오지 않을 것이다. 이런 이유로 Deactivated 이벤트 핸들러와  Closing 이벤트 핸들러 둘 다에서 별도의 저장소에 지속적인 상태를 저장해야 한다. 코드의 중복을 피하기 위해 별도의 저장소에 항구적인 데이터를 저장하고 양쪽 이벤트 핸들러에서 동일한 메서드를 호출하는 하나의 메서드를 생성할 수 있다.

7. 애플리케이션은  Activated와 Deactivated, 10초 이하의 OnNavigatedTo와 OnNavigatedFrom과 같은 페이지 탐색 메서드 등의 모든 애플리케이션 이벤트 핸들러를 완료해야 한다. 애플리케이션에서 이들 이벤트를 완료하는데 10초 이상 걸린다면, 해당 애플리케이션은 종료된다.

8. 애플리케이션이 별도 저장소의 데이터에 의존한다면, 이벤트 핸들러 시작이나 Activated 이벤트 핸들러에서 이 데이터를 로드하지 않아야 한다.디스크 작업은  수 초가 걸릴 것이고 이들 이벤트는 애플리케이션이 로드되고 활성화되기 전에 호출되므로, 이들 핸들러에서 별도 저장소에 접근하는 것은 애플리케이션 로드하는데 시간이 많이 걸리게 만든다. 대신에 애플리케이션 로드가 끝난후 비동기로 별도 저장소를 로드해야 한다.

Deactivated와 Closing 이벤트 핸들러에서 별도 저장소에 데이터를 작성해야할 수 있지만, 이들 이벤트 핸들러가 완료하는데 허용되는 시간이 최대 10초이므로, 애플리케이션이 이들 이벤트 동안 저장해야 하는 데이터의 양을 최소화하도록 실행하는 동안 점진적으로 저장하는 것을 권장한다.

9. 애플리케이션은 휴면 상태로 저장되고 삭제 표시되지 않고 실행 상태로 반환될 수 있다. 애플리케이션이 비활성화 될 때 애플리케이션의 메모리 내 상태를 소멸시키지 않는지 확인하자.

10. 시작 관리자(Launcher) 나 선택자(Chooser) 호출은 항상 애플리케이션을 비활성화하고 애플리케이션이 삭제 표시되게 할 것이다. 애플리케이션이 다시 활성화될 때 애플리케이션에서 선택자 작업의 결과를 받는다는 것을 보장하기 위해 해당 선택자 개체는 PhoneApplicationPage 클래스 내에서 전역으로 선언되어야 하고 선택자를 초기화하고PhoneApplicationPage  생성자에서 Completed 이벤트 대리자를 할당해야 한다.

11. PhoneApplicationService  이벤트에 대한 핸들러는 Windows Phone SDK로 포함된 기본 윈도우 폰 애플리케이션 프로젝트 템플릿에서 스텁으로 나온다. 이들은 App.xaml.cs에서 찾을 수 있다.

12. PhoneApplicationService 클래스의 인스턴스는 윈도우 폰 애플리케이션 프로젝트 템플릿이 제공한다. 다음 코드를 사용해 애플리케이션에서 이 클래스의 State 사전을 접근하자.

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
    PhoneApplicationService.Current.State["key"] = "value";
}

13. State 사전에 저장하는 모든 데이터는 데이터 계약을 사용하거나 직접적으로 직렬화가능해야 한다.

※ 개별 폰 기능에 대한 실행 모델 고려사항

푸시 알림
애플리케이션이 시작될 때 마다, 해당 애플리케이션이 이전에  삭제 되었다는 표시에 상관없이, 애플리케이션은 해당 알림 채널이 더 이상 유효하지 않으며 재성성되어야 함을 가정한다. 알림 채널 생성에 대한 더 자세한 정보는 "윈도우 폰 애플리케이션에서 푸시 알림을 수신하는 방법"을 살펴보자.

Comment +0


정식 명칭이 Silverlight for Windows Phone Toolkit 이라고 하는 이 도구는 윈도우 폰 애플리케이션을 개발하는데 유용한 추가적인 도구들을 개발자들에게 제공합니다. 이 도구는 최신 윈도우 폰 7.1 SDK에 맞도록 풍부한 사용자 경험을 제공하도록 설계되었습니다. 물론 이전 7.0 버전에 맞는 툴킷도 다운로드 할 수 있습니다.

Silverlight for Windows Phone Toolkit 다운로드

위에 언급한 코드플렉스 사이트를 접속하면 아래의 화면을 볼 수 있습니다.
빨간색 사각형 박스 부분이 현재 최신 버전의 WPT를 다운로드 할 수 있는 위치입니다.
아래 노란색 박스 부분은 윈도우 폰 7.0 버전에 해당하는 WPT를 다운로드 할 수 있는 위치입니다.



다운로드 링크를 찾아 들어가면 아래의 다운로드 페이지를 볼 수 있습니다.
아래 그림에서 빨간색 사각형 박스 부분이 WPT 바이너리 실행 파일을 다운로드할 수 있는 링크이며 바로 밑에 있는 파란색 사각형 박스 부분은 WPT 소스와 샘플을 다운로드할 수 있는 링크입니다.


다운로드한 WPT 바이너리 실행 파일을 더블 클릭하고 설치 과정에 대한 화면은 아래 그림들을 참고 하세요. 이 툴킷은 마이크로소프트에서 만들었으며 마이크로소프트 퍼블릭 라이선스를 사용해 배포하고 있습니다.

 

자 이제 설치한 WPT는 어떻게 사용할까요?
설치한 WPT는 비주얼 스튜디오에서 간단한 설정만으로 도구 상자에 표시할 수 있습니다.

아래 그림처럼 비주얼 스튜디오 2010을 실행하고 [도구]-[도구 상자 항목 선택]을 클릭합니다.


[도구 상자 항목 선택] 대화상자에서 [Windows Phone 구성 요소]를 선택하고 [확인]을 클릭 하면 윈도우 폰 애플리케이션 프로젝트에서 해당 컨트롤을 도구 상자에 볼 수 있습니다.


 

Comment +0


앞으로 몇 차례에 걸쳐 윈도우 폰 애플리케이션 개발에 핵심이 되는 개념을 다뤄본다. 애플리케이션을 만들러 가기전에 이러한 개념에 익숙해지는 것이 먼저일것 같다.

제일 먼저 다뤄볼 내용은 윈도우 폰의 실행 모델(Execution Model) 이다.

윈도우 폰 실행 모델 하에서 애플리케이션은 사용자가 네비게이션을 중단할 때 전형적으로 동면상태에 놓인다. 하지만 폰 운영체제에서 동면 상태에 있는 애플리케이션을 종료할 수 있다. 이번 섹션은 이러한 실행 모델아래에서 중단없는 사용자 경험을 제공하는 애플리케이션을 만드는 방법을 설명한다.

▩ 우선 실행 모델이 어떤 것인지 대략 살펴보자.

윈도우 폰 실행 모델에서 애플리케이션이 시작될때 부터 종료될 때 까지 윈도우 폰에서 실행하는 애플리케이션의 수명 주기를 지배한다.

실행 모델은 최종 사용자에게 항상 빠른 응답 경험을 제공하고자 설계되었다.
이런 설계 목적을 달성하기 위해 윈도우 폰은 언제든 하나의 애플리케이션만 포그라운드에서 실행하게 한다. 
폰 운영체제는 애플리케이션이 더 이상 포그라운드에서 상호작용이 없을 때 애플리케이션을 동면 상태로 보낸다. 
포그라운드 애플리케이션을 위한 장치의 가용한 메모리가 좋은 사용자 경험에 불충분한 경우, 운영체제는 동면 상태 애플리케이션을 종료하기 시작한다. 이때  최근에 가장 적게 사용된 애플리케이션이 먼저 종료된다.

애플리케이션이 비활성화되고 다시 활성화될 때 상태를 관리하기 위해 프로그래밍 프레임워크가 제공된다.
이 프레임워크는 애플리케이션이 종료되고 다시 활성화될때에라도 사용자에게는 마치 하나의 애플리케이션 인스턴스인것으로 느끼게 해준다.

또한 실행 모델은 애플리케이션간의 일관된 네비게이션 경험을 사용자에게 제공한다.
윈도우 폰에서 사용자는 설치된 애플리케이션 목록이나 [Start]의 타일에서 애플리케이션을 시작한다.
사용자는 실행중인 애플리케이션의 페이지나 하드웨어 [뒤로가기] 버튼을 사용해 이전에 실행중인 애플리케이션의 스택에서 역방향 탐색을 할 수도 있다. 윈도우 폰 7.5는 하드웨어 [뒤로가기] 버튼을 누른 상태를 잠깐 유지하면 이전에 실행중인 애플리케이션으로 전환하는 기능도 더했다.

다음의 그림은 윈도우 폰 애플리케이션의 수명주기를 나타낸 것이다. 이 그림에서 원은 애플리케이션의 상태다. 사각형은 애플리케이션에서 자체의 상태를 관리해야 하는 애플리케이션이나 페이 수준 이벤트를 보여준다.


위 그림에서 실행 모델 이벤트와 그에 따른 애플리케이션 액션은 다음과 같다.

 이벤트 또는 메서드   애플리케이션 액션
 시작 이벤트  아주 적은양의 코드를 실행한다. 분리된 저장소 접근 같은 자원 집중적인 조작은 수행하지 않는다.
 OnNavigatedFrom 메서드  역방향 탐색이 아니라면, UI 상태를 State 사전에 저장한다.
 비활성화됨 이벤트  애플리케이션 상태를 애플리케이션이 삭제 표시된 것으로 State에 저장한다. 또한 애플리케이션이 종료되는 경우에 별도 저장소에 지속적인 상태를 저장한다. 애플리케이션이 동면상태인 경우 메모리에 있는 애플리케이션 상태를 소멸시키지 않는다.
 활성화됨 이벤트  IsApplicationInstancePreserved를 확인한다. 값이 참이면 아무것도 하지 않는다. 거짓이면 State의 데이터를 사용해 애플리케이션 상태를 복원한다.
 OnNavigatedTo 메서드  해당 페이지가 새로운 인스턴스인지 여부를 확인한다. 새로운 인스턴스가 아니라면, 해당 상태는 자동으로 원래대로 유지된다. 그렇지않고, State에 데이터가 있는 경우, 그 데이터를 사용해 UI를 복원한다.
 종료 이벤트  지속적인 애플리케이션 데이터를 별도 저장소에 저장한다.



Comment +0


싱가폴의 싱텔에서 판매하는 LG E900 윈도우 폰 모델입니다.

퀄컴 스냅드래곤 1GHz 프로세스를 내장했고, 블루투스, GPS, WiFi, 500만 화소 카메라 등, 최근 스마트폰이 갖추고 있는 대부분의 하드웨어 요소는 다 포함 되어 있습니다.

폴이 입수한 제품은 완전 새 제품은 아니며, 테스트용으로 사용된 제품을 박스채 인계 받았기에, 내용물을 확인하고, 초기 설정 작업을 아이폰 동영상으로 담았습니다.

Comment +0


조금 늦은 감이 있지만, 정보 공유 차원에서 포스팅합니다.
Windows Phone 7.0
Windows Phone 7.5 장치를 위한 애플리케이션과 게임을 개발하는데 필요한 Windows Phone SDK 7.1 RC(Release Candidate)가 지난 8월 중순에 발표되었습니다.

다운로드 주소는 아래 링크를 따라가세요.

http://www.microsoft.com/download/en/details.aspx?id=27153

아래 화면에서 vm_web2.exe를 다운 받아 인터넷으로 설치할 수 있습니다.


ISO
이미지 파일을 받아 가상 시디롬에 연결해 설치할 수도 있습니다.

아래 그림을 참조하세요.위에 소개한 다운로드 사이트에서 아래 나타낸 그림의 섹션 부분으로 가서 빨간색 상자의 링크를 클릭하면 다운로드 할 수 있습니다.

Comment +0


얼마 전에 Windows Phone7 SDK 7.1의 베타2가 발표되었습니다.
이 버전은 일반적으로 한국 마이크로소프트의 윈도우 폰 홈페이지를 통해서는 베타1버전(5/23)으로 연결됩니다.

아래 주소를 클릭하고 들어가면 6.29일자 베타2버전을 받을 수 있습니다.

Windows Phone7 SDK 7.1 Beta2 다운로드


[DOWNLOAD]버튼을 클릭해서 인터넷 설치 실행 파일(vm_web2.exe)다운 받아 설치하거나 아래 그림에 보이듯이 iso링크를 클릭해 ISO 이미지 파일을 받아 설치해도 된다.

설치 시에 아래 두 가지 주의 사항을 명심하세요.

        ·  Visual Studio 2010 SP1이 설치되어 있어야 함.
·  Windows Phone Developer Tools 7.1 Beta를 먼저 제거해야 함.아래 항목들을 제어판의 [프로그램 제거 또는 변경]에서 제거하세요.

Microsoft Windows Phone Developer Tools 7.1 (Beta) - ENU

Comment +1


윈도우 7 개발 툴이 7.1 업그레이드 되고 공식 다운로드가 가능하게 되어(아직은 베타 출시 입니다), 아래 마이크로소프트 사이트에서 다운로드 하고 실행했더니 다음과 같은 메시지가 뜨네요.


[그림 1] 망고 다운로드 사이트
 

내용을 보면 Visual Studio 2010 Service Pack 1 필요하다는 메시지를 띄웠네요.

그래서 개발 설치는 일단 종료합니다.

 


[그림 2] 망고 개발 도구 설치 오류 메시지

 

서비스 팩을 찾기 위해 아래 마이크로소프트 다운로드 사이트에 가서 다운로드하고 실행했습니다.

Visual Studio Service Pack 1 다운로드 사이트

인터넷 설치라서 광대역 연결에 111분이 걸린다고 나오지만, 넘기고 나면 본격적인 설치 진행화면이 아래와 같이 나옵니다.


서비스 설치가 계속 롤백되는 현상으로 윈도우 다시 부팅하는 우여곡절 끝에 다음과 같이 적용이 완료 되었네요. [마침]을 누르고 윈도우를 다시 시작합니다.

 
[그림 3] Visual Studio 2010 SP1 설치

이제 망고 베타버전을 다시 설치 시도해봅시다.

[그림 4] 망고 설치 초기 화면

[Accept] 클릭하고 다음 화면에서 [Install Now] 클릭하면 다음과 같은 설치진행화면이 나오겠죠.

[그림 5] 망고 설치 진행 화면

모든 설치가 끝나고 나면 다음과 같은 화면이 나옵니다.

[그림 6] 망고 설치 완료 화면

가운데 [Run the Product Now] 클릭 해보면, Visual Studio 2010 Express for Windows Phone 실행되고 [Help]-[About…] 메뉴를 클릭하면 업데이트된 윈도우 개발 도구 7.1 베타를 확인할 있습니다.

 

[그림 7] 비주얼 스튜디오에서 망고 개발 도구를 로드한 화면



Comment +0

 

최종회로 지난번에 만든 게임을 업데이트해서 다음 번에 게임을 실행했을 게임을 다시 시작할 있도록 게임의 상태를 저장할 있도록 만든다. 이를 위해 격리 저장소를 사용한다.


격리된
저장소는 관리된 애플리케이션이 지역 저장소에 정보를 저장하고 가져올 있게 해준다. 아키텍처는 실버라이트 4에서 사용한 것과 아주 비슷하다. 모든 I/O 작업은 격리 저장소의 범위로 제한되고 이들은 내부 운영체제 파일 시스템에 직접 접근하지 못한다.

격리된 저장소의 사용에서 생기는 몇 가지 이점은 다른 애플리케이션으로부터 데이터를 보호하고 할당량을 관리하며 애플리케이션이 자체의 고유 데이터만을 다루도록 보장하는 블라인드가 된다.


[어셈블리 참조와 다른 자원 추가하기]

격리된 저장소를 이용하려면 프로젝트에 헬퍼파일과 어셈블리 참조를 제공해야 한다.

1. [생애 번째 윈도우 7 애플리케이션 만들기 6] 단계를 완료했다면, 때의 솔루션을 계속 사용할 것이므로 해당 솔루션을 비주얼 스튜디오에서 연다.

2.  System.Servicemodel.Web 어셈블리에 대한 참조를 추가한다. [솔루션 탐색기]에서 [References] 오른 클릭하고 [Add Reference] 선택한다. [.NET] 탭을 선택하고 컴포넌트 목록에서 [System.Servicemodel.Web] 어셈블리를 선택한 뒤 [확인]을 클릭한다.

[그림 17] 프로젝트에 어셈블리 참조 추가하기


System.Servicemodel.Web 어셈블리는 분리된 저장소에 객체들을 보관하기 전에 애플리케이션이 JavaScript Object Notation (JSON) 사용해 객체를 직렬화하는데 사용하는  DataContractJsonSerializer 포함하고 있다.

3.  이제 분리된 저장소를 다루기 위해 헬퍼 클래스를 추가한다. [Solution Explorer]에서 프로젝트를 오른 클릭하고 [Add] 가리킨 [Existing Item] 선택한다. 랩의 소스 폴더(C:\WP7TrainingKitOffline\Labs\YourFirstWP7Application\Source\Assets) 찾아서 "IsolatedStorageHelper.cs" 선택하고 추가한다.

 "IsolatedStorageHelper" 클래스는 분리된 저장소에서 객체의 직렬화를 처리 하는 메서드를 포함하고 있다. 제공된 클래스는 실습에서 나중에 구현할 가지 메서드 스텁을 포함한다.


4.  참조와 헬퍼 클래스 파일을 추가한 , 솔루션 탐색기는 다음처럼 보인다.

 [그림 18] 새로 추가된 컴포넌트를 보여주는 솔루션 탐색기


[퍼즐 UI 업데이트]

이번
작업에서는 게임 페이지를 업데이트해서 사용자가 게임의 상태를 로드하고 저장, 삭제할 있는 가지 버튼을 제공한다. 이러한 목적을 위해 사용자 인터페이스의 XAML 마크업을 수정해 필요한 요소를 정의한 버튼에 대한 이벤트 핸들러를 생성한다. 마지막으로 "IsolatedStorageHelper" 클래스에서 필요로하는 메서드를 구현해리된 저장소에서 직렬화된 객체를 불러오고 저장, 삭제한다.


1. [솔루션 탐색기]에서 "PuzzlePage.xaml" 더블클릭해 해당 게임의 UI 담고 있는 페이지를 연다.

2. XAML 뷰로 전환한다.  해당 뷰를 변경하고 영역을 최대화 하기 위해, 디자이너 창의 오른편 끝에서 [XAML] 탭을 더블 클릭한다.

3. 다음의 강조된 XAML 마크업을 TapToContinueTextBlock 라는 마지막 "TextBlock" 요소 이후에 바로 삽입한다.

...
<Grid x:Name="LayoutRoot" Background="Transparent">
  <StackPanel Orientation="Vertical" VerticalAlignment="Top" Grid.Row="1">
    <Border x:Name="CongratsBorder"...>
      ...
    </Border>
    <Border x:Name="border"...>
      ...
    </Border>
    <TextBlock x:Name="TapToContinueTextBlock" HorizontalAlignment="Center" Text="Tap the picture to start the puzzle" TextWrapping="Wrap" Foreground="#FFD0D0D0" FontSize="17.333"/>
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" >
      <Button x:Name="LoadButton" Content="Load" Margin="10" />
      <Button x:Name="SaveButton" Content="Save" Margin="10" />
      <Button x:Name="ClearStorageButton" Content="Clear" Margin="10" />
    </StackPanel>
  </StackPanel>
</Grid>
...

4. [디자인] 뷰로 전환하면 새로운 버튼이 추가된 사용자 인터페이스의 변경사항을 있다. 이를 위해서는 디자이너 창의 오른편 끝에서 [디자인] 탭을 더블 클릭한다.

[그림 19] 갱신된 사용자 인터페이스를 보여주는 디자인


5. 버튼에 대한 이벤트 핸들러를 정의한다. 디자이너 화면에서 "Load"라는 버튼을 클릭해 선택하고 [F4] 눌러 [속성] 창을 연다.

6. [속성] 창에서 [Events] 탭을 클릭해 사용할 있는 이벤트 목록을 가진 창을 표시한다. 목록에서 [Click] 이벤트를 찾아서 이벤트 옆에 있는 텍스트 상자에 "LoadButton_Click"이라고 입력한다. [엔터] 누르면 이름의 이벤트 핸들러를 생성하고 코드 숨김 파일을 열어 비주얼 스튜디오가 생성한 메서드 스텁을 표시한다.

7. "LoadButton_Click" 이벤트 핸들러의 본문에 다음의 강조된 코드를 삽입한다.

private void LoadButton_Click(object sender, RoutedEventArgs e)
{
  var gameState = IsolatedStorageHelper.GetObject<PuzzleState>("PuzzleState");
  if (gameState == null)
  {
    MessageBox.Show("Sorry, no game state found.", "Oops!", MessageBoxButton.OK);
  }
  else
  {
    // set game state
    this.game.SetState(gameState);
  }
}

8. 코드 편집기 창을 오른 클릭하고 [View Designer] 선택해 다시 디자인 뷰로 전환한다. 디자이너화면에서 "Save"라는 버튼을 클릭하고 [F4] 눌러 해당 속성 창을 연다.

9. [속성] 창에서 [Events] 탭을 클릭해 사용할 있는 이벤트 목록을 가진 창을 표시한다. 목록에서 [Click] 이벤트를 찾아서 이벤트 옆에 있는 텍스트 상자에 "SaveButton_Click"이라고 입력한다. [엔터] 누르면 이름의 이벤트 핸들러를 생성하고 코드 숨김 파일을 열어 비주얼 스튜디오가 생성한 메서드 스텁을 표시한다.

10. "SaveButton_Click" 이벤트 핸들러의 본문에 다음의 강조된 코드를 삽입한다.

 

private void SaveButton_Click(object sender, RoutedEventArgs e)
{
// save game state
  PuzzleState gameState = this.game.GetState();
  IsolatedStorageHelper.SaveObject("PuzzleState", gameState);
}


11. 다시 한번 코드 편집기 창을 오른 클릭하고 [View Designer] 선택해 다시 디자인 뷰로 전환한다. 디자이너화면에서 "Clear"라는 버튼을 클릭하고 [F4] 눌러 해당 속성 창을 연다.

12. [속성] 창에서 [Events] 탭을 클릭해 사용할 있는 이벤트 목록을 가진 창을 표시한다. 목록에서 [Click] 이벤트를 찾아서 이벤트 옆에 있는 텍스트 상자에 "ClearStorageButton_Click"이라고 입력한다. [엔터] 누르면 이름의 이벤트 핸들러를 생성하고 코드 숨김 파일을 열어 비주얼 스튜디오가 생성한 메서드 스텁을 표시한다.

13. "ClearStorageButton_Click" 이벤트 핸들러의 본문에 다음의 강조된 코드를 삽입한다.

private void ClearStorageButton_Click(object sender, RoutedEventArgs e)
{
// remove state and image
  IsolatedStorageHelper.DeleteObject("PuzzleState");
}

14. [솔루션 탐색기]에서 "IsolatedStorageHelper.cs" 파일을 더블 클릭해서 연다.

15. [GetObject<T>] 메서드를 찾아서 다음의 강조된 코드로 바디를 대체한다.


 

public static T GetObject<T>(string key)
{
  if (IsolatedStorageSettings.ApplicationSettings.Contains(key))
  {
    string serializedObject = IsolatedStorageSettings.ApplicationSettings[key].ToString();
    return Deserialize<T>(serializedObject);
  }

return default(T);
}


 

GetObject<T> 메서드는 주어진 개체 키로리된 저장소에서 객체를 가져온다.  격리된 저장소에서 - 쌍의 딕셔너리를 저장하는 IsolatedStorageSettings 이용한다. 객체들은 System.ServiceModel.Web

어셈블리에서 제공된 DataContractJsonSerializer 사용해 직렬화된 형식으로 저장되는데, 메서드는 객체를 JSON으로 직렬화하고 JSON 데이터를 객체로 역직렬화한다.


16. 다음의 강조된 코드를 SaveObject<T> 메서드의 바디에 넣는다.

public static void SaveObject<T>(string key, T objectToSave)
{
    string serializedObject = Serialize(objectToSave);
    IsolatedStorageSettings.ApplicationSettings[key] = serializedObject;
}

SaveObject<T> 메서드는 주어진 개체 키로리된 저장소에 개체를 저장한다.

17. 마지막으로 다음의 강조된 코드를 사용해 [DeleteObject<T>] 메서드를 구현한다.

public static void DeleteObject(string key)
{
  IsolatedStorageSettings.ApplicationSettings.Remove(key);
}

DeleteObject 메서드는리된 저장소에서 주어진 개체의 키로 개체를 제거한다


18. 최종 변경을 테스트 하기 위해 [F5] 눌러 애플리케이션을 빌드하고 에뮬레이터로 다시 한번 배포한다. 잠깐 기다리면 시작 화면이 나타나고 [START] 버튼을 클릭해 새로운 게임을 시작한다.

19. 게임 페이지에서 [Load] 클릭해 저장된 상태의 복구를 시도한다. 아마 저장된 상태가 없다는 오류 메시지를 뿌릴 것이다. [OK] 클릭해 오류 메시지를 해제한다.

[그림 20] 이전 상태가 없을 load 작업이 실패한다.


20. 보드에서 퍼즐의 조각 일부를 드래그 한다. 하나 이상의 조각을 배치하는 경우 쉽게 기억할 있는 패턴으로 하는것이 상책이다. 나중에 게임 상태를 다시 로드한 동일한 패턴인지를 알아보기가 훨씬 쉽다.

21. [Save] 클릭해 게임의 현재 상태를 저장한다.

22. 이제 다른 배열로 조각을 계속 이동한 다음 이번에는 게임의 상태를 저장하지는 않는다.

23. 다시 한번 [Load] 클릭해 이전의 저장된 상태를 복원한다. 이번에는 해당 조각의 위치가 원래 저장했던 게임 상태와 동일한 패턴으로 복구된다.

24. 에뮬레이터 윈도우에서 뒤로 가기 버튼(<-) 눌러 시작화면을 담은 페이지로 간다. 다음 뒤로 가기 버튼을 다시 클릭해 애플리케이션을 나가면 [Quick Launch] 메뉴를 표시한다.

25.  이제, [Quick Launch] 메뉴에서 해당 애플리케이션을 시작하기 위해 다시 한번 [WindowsPhonePuzzle] 클릭한다.


[그림 21] Quick Launch 메뉴에서 애플리케이션을 시작한다.


26. [START] 클릭해 새로운 게임을 시작하고 게임 페이지에서 [Load] 클릭해 이전 상태를 로드 한다. 보드 패턴이 이전에 애플리케이션에서 저장했던 상태인지 확인한다.

27.  [Clear] 클릭해 분리된 저장소에서 저장된 상태를 지운다.

28. 이제 다시 한번 [Load] 클릭하면 앞서 저장된 상태가 없을 보았던 동일한 오류 메시지를 받게 된다.

Comment +0


 

[애니메이션 효과 주기]

 

실버라이트에서 스토리보드가 애니메이션이다. 스토리보드는 프레임을 포함하는 타임라인을 정의한다. 프레임은 위치, 크기, 회전, 투명도, 그리고 심지어 전경 배경 같은 컨트롤 속성을 독립적으로 정의할 있다. 이러한 접근 방법을 사용해 사용자는 모든 단일 프레임을 정의해 애니메이션을 생성할 필요가 없고, 대신에 중요한 속성 변경을 표시하기 위해 타임라인에서 선택된 위치만 제공해야 한다. 실버라이트는 개의 인접한 프레임간의 애니메이션 속성의 값을 보간해서 중간 프레임을 생성하고 부드러운 전환을 제공한다.

 

스토리보드는 해당 페이지의 코드 숨김에서 사용할 있는 메서드와 이벤트를 가진 개체다. 이것은 애니메이션을 Begin, Stop, Pause하는 메서드를 포함한다. 단일 이벤트이벤트인 Completed 해당 애니메이션 재생이 완료될 발생한다.

스토리보드는  XAML 코드로 작성될 있고 익스프레션 블렌드로 쉽게 생성한다.

 

이번 시간에는 사용자가 퍼즐을 성공적으로 풀었을 재생할 스토리보드를 생성한다. 해당 애니메이션은 시각적 효과를 만들어 가운데 축을 중심으로 퍼즐의 이미지를 회전하고 점차적으로 희미해져 가는 메시지를 표시한다.

1. 먼저 새로운 Resources 섹션을 아래 보인 강조된 코드를 페이지로 삽입한다.

 

<phone:PhoneApplicationPage
  x:Class="WindowsPhonePuzzle.PuzzlePage" ...>

<phone:PhoneApplicationPage.Resources>
  </phone:PhoneApplicationPage.Resources>
  ...
  <Grid x:Name="LayoutRoot" Background="Transparent">
  </Grid>
</navigation:PhoneApplicationPage>

 

 Resources 정의된 개체와 값을  공통으로 사용하는 간단한 방법을 제공한다. 컨트롤 템플릿과 스타일, 브러시, 색상, 애니메이션 스토리보드를 포함하는 공통 항목에 대한 정의를 만들고 리소스 사전에 저장할 있다. 리소스 사전은 XAML 코드 군데서 사용할 있는 핵심 사전이다. 애플리케이션 구조에서 다른 범위로 리소스 사전을 생성할 있다. 페이지 수준이나 애플리케이션 리소스에서 리소스를 정의할 있다. 이번 작업에서는 해당 애니메이션 스토리보드의 정의를 저장하는 페이지의 리소스를 사용한다.


2. 다음으로 섹션 Resources 내에 사용자가 퍼즐을 발생하는 전환을 위한 애니메이션 스토리보드를 삽입한다. WinTransition 스토리 보드를 정의한 다음의 XAML 마크업을 아래처럼 삽입한다.

 

...
<phone:PhoneApplicationPage.Resources>
  <Storyboard x:Name="WinTransition">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="PreviewImage" Storyboard.TargetProperty="(UIElement.Opacity)">
      <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0.2"/>
      <EasingDoubleKeyFrame KeyTime="00:00:00.7000000" Value="1"/>
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
      <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
      <EasingDoubleKeyFrame KeyTime="00:00:00.7000000" Value="-1">
        <EasingDoubleKeyFrame.EasingFunction>
          <CubicEase EasingMode="EaseInOut"/>
        </EasingDoubleKeyFrame.EasingFunction>
      </EasingDoubleKeyFrame>
      <EasingDoubleKeyFrame KeyTime="00:00:01.7000000" Value="1">
        <EasingDoubleKeyFrame.EasingFunction>
          <CubicEase EasingMode="EaseInOut"/>
        </EasingDoubleKeyFrame.EasingFunction>
      </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="CongratsBorder" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
      <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
      <EasingDoubleKeyFrame KeyTime="00:00:00.7000000" Value="-1">
        <EasingDoubleKeyFrame.EasingFunction>
          <CubicEase EasingMode="EaseInOut"/>
        </EasingDoubleKeyFrame.EasingFunction>
      </EasingDoubleKeyFrame>
      <EasingDoubleKeyFrame KeyTime="00:00:01.7000000" Value="1">
        <EasingDoubleKeyFrame.EasingFunction>
          <CubicEase EasingMode="EaseInOut"/>
        </EasingDoubleKeyFrame.EasingFunction>
      </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="CongratsBorder" Storyboard.TargetProperty="(UIElement.Opacity)">
      <EasingDoubleKeyFrame KeyTime="00:00:01.2000000" Value="0"/>
      <EasingDoubleKeyFrame KeyTime="00:00:01.3000000" Value="0"/>
      <EasingDoubleKeyFrame KeyTime="00:00:01.4000000" Value="1"/>
    </DoubleAnimationUsingKeyFrames>
  </Storyboard>

</phone:PhoneApplicationPage.Resources>


WinTransition 스토리보드는 사용자가 게임을 이겼을 실행된다. 애니메이션은 가운데 축을 중심으로 해당 퍼즐에 대한 솔루션을 담은 이미지를 회전하고 점점 사라지는  축하 메시지를 가진 프레임을 이미지 주위에 표시한다. 익스프레션 블렌드와 같은 도구를 사용해 디자이너에서 시각적으로 속성을 애니메이션 하고 스토리보드를 정의하는데 필요한 XAML 마크업을 생성한다.


3. 마지막으로 게임을 시작할 마다 발생하는 전환을 위해 해당 스토리보드를 삽입한다.

...
<phone:PhoneApplicationPage.Resources>
  <Storyboard x:Name="WinTransition">
    ...
  </Storyboard>
  <Storyboard x:Name="ResetWinTransition">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="CongratsBorder" Storyboard.TargetProperty="(UIElement.Opacity)" Duration="00:00:00.0010000">
      <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="PreviewImage" Storyboard.TargetProperty="(UIElement.Opacity)" Duration="00:00:00.0010000">
      <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0.20000000298023224"/>
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="GameContainer" Storyboard.TargetProperty="(UIElement.Opacity)">
      <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    </DoubleAnimationUsingKeyFrames>
  </Storyboard>
</phone:PhoneApplicationPage.Resources>
...


 ResetWinTransition 스토리보드는 축하 메시지를 숨기고 퍼즐 이미지 투명도를 원래 값으로 복원한다.


4. [솔루션 탐색기]에서 PuzzlePage.xaml 오른 클릭해 [View Code] 선택해 페이지에 대한 코드 숨김 파일을 연다.

5. PuzzlePage  클래스의 생성자에서 GameOver 이벤트를 처리하는 익명 함수를 찾아서 메서드의 시작 부분에 다음의 강조된 코드 라인을 삽입한다.

 

public PuzzlePage()
{
  ...
  this.game.GameOver += delegate
  {
    this.WinTransition.Begin();
    this.TapToContinueTextBlock.Opacity = 1;
    this.StatusPanel.Visibility = Visibility.Visible;
    this.TotalMovesTextBlock.Text = this.game.TotalMoves.ToString();
  };
  ...
}


게임이 끝날 , 삽입된 코드는 스토리보드를 재생해 완료된 퍼즐 이미지에 대한 시각적 효과와 축하 메시지를 제공한다.


6. 여전히 PuzzlePage  클래스의 생성자에서 GameStarted 이벤트에 대한 핸들러를 찾아서 다음의 강조된 코드 라인을 추가한다.

 

public PuzzlePage()
{
  ...
  this.game.GameStarted += delegate
  {
    this.ResetWinTransition.Begin();
    this.StatusPanel.Visibility = Visibility.Visible;
    this.TapToContinueTextBlock.Opacity = 0;
    this.TotalMovesTextBlock.Text = this.game.TotalMoves.ToString();
  };
  ...
}


삽입된 코드는 게임이 시작할 ResetWinTransition 애니메이션 스토리보드를 시작한다. 스토리보드는 배경 이미지의 상태를 재설정하고 축하 메시지를 숨긴다


7. [F5] 눌러 빌드한 애플리케이션을 에뮬레이터로 배포하고, 잠깐 기다린 [START] 클릭해 새로운 게임을 시작해본다.

8. 보드의 퍼즐을 드래그해서 풀어보든지 아니면 [SOLVE] 버튼을 눌러 퍼즐을 해결하고 게임을 종료한다. 해당 게임이 종료할 해당 애니메이션을 일으키고 중간 축을 중심으로 보드를 회전시키면서 CONGRATULATIONS" 텍스트를 표시했다가 점차적으로 사라진다.

[그림 17] 축하 메시지를 표시하는 해결된 퍼즐


Comment +0


올해 들어 마이크로소프트의 윈도우 폰7 런칭 활동이 가속화 되고 있다.

애플과 구글에 어퍼컷 한방 씩을 맞고 쇠락의 기로에서 흔들리던 마이크로소프트가 절치부심 회심의 모바일 OS로 들고 나온 윈도우 폰7(Windows Phone 7)은 시작부터 철저하게 사용자를 겨냥했고, 사용자의 눈 높이에 맞추고자 노력한 흔적이 많이 보였다.
그럼에도 불구하고 윈도우 폰7은 아직 어렸고, 시장에서 이미 성장해 버린 경쟁사의 플랫폼을 따라가기에는 모자란 부분이 많은 것은 사실이었다.
 
하지만 이제 MS는 거의 동급의 풍부한 기능과 편의성으로 보강해 시장에서 한 번 맞짱 떠볼 수 있는 윈도우 폰7 판올림 버전을 내어 놓았다. 코드네임 Mango가 그것이다. 지난 4월 라스베가스에서 열린 MIX11 컨퍼런스에서 대중에게 소개된 망고는 윈도우 폰7을 기다려온 사용자나 개발자에겐 흥분 그 자체였던것 같다. 폴이 그 자리에 못 가본것이 못내 아쉽다.

현재 망고는 한국어가 포함된 16개의 언어를 추가지원하며 Windows Phone 7.1로 소개가 되고 있고 베타버전으로 개발툴이 배포되고 있다. 한국에서는 8월 경이면 국내 마켓플레이스가 오픈되고 그 사이 앱 등록절차도 간소화될 예정이라고 하니 많이 기다려진다.
 
윈도우 폰과 XBOX 360 개발자 사이트(http://create.msdn.com/en-US/)에 접속하면 다음과 같은 "The Windows Phone Developer Tools 7.1 Beta is Here"라는 문구가 걸린 헤드라인을 보게 될텐데, 여기를 클릭하고 들어가면 현재 공개된 망고의 세부 리소스에 접근할 수 있다.


아래 [new details] 섹션에서 망고의 공개와 함께 달라진 개발툴, 22개의 코드 샘플, 10개의 새로운 자가실습을 다운로드하는 링크를 접근할 수 있고, 개발 툴에서 새로워진 기능에 대한 공식 문서(물론 영어로 되어 있다)에 대한 링크를 통해 개발 플랫폼에서 변화된 세부적인 내용을 파악할 있다.  (Windows Phone OS 7.1 망고 개발 플랫폼에서 변화된 내용에 대해서는 다음 글에서 다룰 예정이다.)


▨ Windows Phone 7.1 - Mango관련 다운로드 링크

Comment +0

멀티 터치 입력을 사용하면 사용자가 동시에 여러 손가락 제스처를 적용할 수 있고 애플리케이션에 복잡한 명령을 제공하는 한 단위로 해석할 수 있으며 페이지의 요소를 직접 조정하는 시뮬레이션(예를 들면 한번에 확대하고 축소하는 동작)을 할 수 있다. 이번 시간에는 윈도우 폰 퍼즐 게임을 업데이트하고, 빈 슬롯으로 퍼즐 조각을 태핑하고 드래그하는 멀티 터치 입력을 받아 사용자가 퍼즐의 조각을 움직이게 할 수 있다.

1.
솔루션 탐색기]PuzzlePage.xaml 코드 숨김 파일을 연다.

2.
PuzzlePage 클래스에서 기존 멤버 변수 아래에 다음 선언(아래 강조된 항목) 입력한다.

public partial class PuzzlePage : PhoneApplicationPage
{
  private const double DoubleTapSpeed = 500;
  private const int ImageSize = 435;
  private PuzzleGame game;
  private Canvas[] puzzlePieces;
  private Stream imageStream;

  private long lastTapTicks;
  private int movingPieceId = -1;
  private int movingPieceDirection;
  private double movingPieceStartingPosition;

 
  public PuzzlePage()
  {
    InitializeComponent();
    ...
}


3. 편집 창을 오른 클릭하고 View Designer 선택해 [디자인] 보기로 전환한다.

4. 디자이너 화면에서 에뮬레이터 이미지를 둘러싼 공간을 클릭해 PhoneApplicationPage  요소를 선택하고  F4 눌러 [속성] 창을 연다. [속성] 창에서 [이벤트] 탭을 클릭해 사용할 있는 이벤트 목록을 확인한다.

[그림 13] Microsoft Visual Studio 2010 Express for Windows Phone에서 이벤트 핸들러 만들기


5. ManipulationStarted 이벤트에 대한 이벤트 핸들러를 정의한다. 목록에서 해당 항목을 더블 클릭해 이벤트를 구독한다. 작업을 하면 비주얼 스튜디오는 이벤트 핸들러를 생성하고 코드 숨김 파일을 열어 생성한 해당 메서드 스텁을 표시한다. 다음의 강조한 코드를 PhoneApplicationPage_ManipulationStarted 메서드의 본문에 삽입한다.

private void PhoneApplicationPage_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
  if (this.game.IsPlaying && e.ManipulationContainer is Image && e.ManipulationContainer.GetValue(FrameworkElement.NameProperty).ToString().StartsWith("PuzzleImage_"))
  {
    int pieceIx = Convert.ToInt32(e.ManipulationContainer.GetValue(FrameworkElement.NameProperty).ToString().Substring(12));
    Canvas piece = this.FindName("PuzzlePiece_" + pieceIx) as Canvas;
    if (piece != null)
    {
      int totalPieces = this.game.ColsAndRows * this.game.ColsAndRows;
      for (int i = 0; i < totalPieces; i++)
      {
        if (piece == this.puzzlePieces[i] && this.game.CanMovePiece(i) > 0)
        {
          int direction = this.game.CanMovePiece(i);
          DependencyProperty axisProperty = (direction % 2 == 0) ? Canvas.LeftProperty : Canvas.TopProperty;
          this.movingPieceDirection = direction;
          this.movingPieceStartingPosition = Convert.ToDouble(piece.GetValue(axisProperty));
          this.movingPieceId = i;
          break;
        }
      }
    }
  }
}


ManipulationStarted 이벤트는 사용자가  UIElement 터치(또는 마우스로 클릭) 조작할 발생하며 MouseDown 이벤트와 유사하다 이벤트에 대한 핸들러는 게임이 현재 진행 중인지 여부와 이벤트가 발생한 퍼즐 조각을 나타내는 이미지 요소들 중의 하나를 확인하고, 그렇지 않으면 이벤트를 무시한다. 조각에 대한 해당 Canvas 요소를 찾은 게임의 로직을 호출 해당 조각이 움직일 있는지 여부를 결정한다. 이것이 발생하려면 인접한 슬롯이 해당 조각에 대해 존재해야 한다. 다음 선택된 조각을 저장하고 조각이 움직일 있는 /방향을 기록한다.

6. 다음으로 ManipulationDelta 이벤트에 대한 핸들러를 생성한다. 다시 한번 코드 편집 창을 오른 클릭하고 View Designer 선택해 [디자인] 보기로 전환한다. 다음 디자인 영역에서 PhoneApplicationPage 요소를 선택하고 F4 눌러 [속성] 창을 연뒤 Events 탭을 선택한다. 다음 이벤트 목록에서 ManipulationDelta 이벤트를 찾아 해당 항목을 더블 클릭해 이벤트를 구독하고 스텁 메서드를 선택한다. 코드 숨김 파일에서 다음 강조된 코드를 PhoneApplicationPage_ManipulationDelta 메서드의 본문에 삽입한다.

private void PhoneApplicationPage_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
  if (this.movingPieceId > -1)
  {
    int pieceSize = ImageSize / this.game.ColsAndRows;
    Canvas movingPiece = this.puzzlePieces[this.movingPieceId];

// validate direction
    DependencyProperty axisProperty;
    double normalizedValue;

if (this.movingPieceDirection % 2 == 0)
    {
      axisProperty = Canvas.LeftProperty;
      normalizedValue = e.CumulativeManipulation.Translation.X;
    }
    else
    {
      axisProperty = Canvas.TopProperty;
      normalizedValue = e.CumulativeManipulation.Translation.Y;
    }

// enforce drag constraints
    // (top or left)
    if (this.movingPieceDirection == 1 || this.movingPieceDirection == 4)
    {
      if (normalizedValue < -pieceSize)
      {
        normalizedValue = -pieceSize;
      }
      else if (normalizedValue > 0)
      {
        normalizedValue = 0;
      }
    }
    // (bottom or right)
    else if (this.movingPieceDirection == 3 || this.movingPieceDirection == 2)
    {
      if (normalizedValue > pieceSize)
      {
        normalizedValue = pieceSize;
      }
      else if (normalizedValue < 0)
      {
        normalizedValue = 0;
      }
    }

// set position
    movingPiece.SetValue(axisProperty, normalizedValue + this.movingPieceStartingPosition);
  }
}


ManipulationDelta 이벤트는 사용자가 UIElement 조작하면서 손가락(또는 마우스 커서) 이동할 발생한다. 이벤트에 대한 핸들러는 현재 조각이 움직일지 여부를 확인한다. 움직일 있다면, 가능한 /방향과 델타 값을 잡아 낸다. 이렇게 하기 위해 해당 코드는 드래그 제약조건을 강제해서 가능한 경계 내에서 움직임을 검증해야 한다. 족각은 다른 조각들에 겹칠 수는 없다. 핸들러는 적절한 축에 대한 속성을 설정해서 해당 조각의 위치를 업데이트한다.

7. 마지막으로, 이전 단계를 반복하면서 이번에는 ManipulationCompleted 이벤트를 대신 선택한다. 코드 숨김 파일에서 다음의 강조한 코드를  PhoneApplicationPage_ManipulationCompleted 메서드의 본문에 집어 넣는다.

private void PhoneApplicationPage_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
  if (this.movingPieceId > -1)
  {
    int pieceSize = ImageSize / this.game.ColsAndRows;
    Canvas piece = this.puzzlePieces[this.movingPieceId];

// check for double tapping
    if (TimeSpan.FromTicks(DateTime.Now.Ticks - this.lastTapTicks).TotalMilliseconds < DoubleTapSpeed)
    {
      // force move
      this.game.MovePiece(this.movingPieceId);
      this.lastTapTicks = int.MinValue;
    }
    else
    {
      // calculate moved distance
      DependencyProperty axisProperty = (this.movingPieceDirection % 2 ==0) ?    
Canvas.LeftProperty : Canvas.TopProperty;

      double minRequiredDisplacement = pieceSize / 3;
      double diff = Math.Abs(Convert.ToDouble(piece.GetValue(axisProperty)) - this.movingPieceStartingPosition);

// did it get halfway across?
      if (diff > minRequiredDisplacement)
      {
        // move piece
        this.game.MovePiece(this.movingPieceId);
      }
      else
      {
        // restore piece
        this.AnimatePiece(piece, axisProperty, this.movingPieceStartingPosition);
      }
    }

    this.movingPieceId = -1;
    this.movingPieceStartingPosition = 0;
    this.movingPieceDirection = 0;
    this.lastTapTicks = DateTime.Now.Ticks;
  }
}


ManipulationCompleted 이벤트는 UIElement를 조작한 후 사용자가 화면에서 손가락을 (또는 마우스 버튼을 놓을 ) 발생하고 MouseUp 이벤트와 유사하다. 이벤트에 대한 핸들러는 퍼즐 조각이 현재 움직일지 여부를 확인한다. 움직일 있다면, 마지막 ManipulationCompleted 발생하는 시기를 결정하고 제공한 시간 간격은 DoubleTapSpeed 의해 지정된 보다 느리므로. 이벤트를 Double Tap 이벤트(또는 더블 클릭)으로 해석하고 해당 조각을 인접한 슬롯으로 이동한다. 그렇지 않으면 해당 조각에서 대상 위치로의 오프셋 거기를 계산하고. 조각이 적어도 자기 크기의 1/3 가까운 슬롯으로 옮겨갔다면, 해당 조각을 슬롯으로 이동을 완료한다. 그렇지 않다면 원리의 위치로 조각을 되돌린다.

8. 이전 단계를 완료한 , 해당 페이지의 [속성] 창을 열어 알맞은 이벤트 해늗러를 생성했는지를 확인한다. 해당 페이지에 대한 XAML 마크업을 살펴보면, PhoneApplicationPage  요소에 정의된 해당 특성들을 보게 것이다.

[그림 14] manipulation 이벤트 핸들러를 보여주는 속성


[
그림 15] 이벤트 구독을 보여주는 해당 페이지의 XAML 마크업


9. 추가된 멀티 터치에 대한 지원을 테스트하려면, [F5]를 눌러 애플리케이션을 빌드하고 에뮬레이터로 배포한다. 시작화면이 표시되기를 기다린 뒤 [START]를 클릭해 새로운 게임을 시작한다.

10. 보드의 조각을 드래그해서 퍼즐을 푼다. 조각을 움직이려면 해당 조각을 클릭하고 목적지로 드래그 한다. 조작을 더블클릭 하면 다음의 사용 가능한 슬롯으로 이동한다. 각 이동에 따라 퍼즐 보드 위의 카운터가 증가한다.

[그림 16] 퍼즐 풀기


Comment +0

[퍼즐 애플리케이션의 로직 프로그래밍]

 이번 시간에는 애플리케이션 로직을 프로그래밍 한다. 로직에는 퍼즐 보드를 초기화 하고 애플리케이션의 리소스에서 이미지를 읽고 사용자 인터페이스로 부터 이벤트에 대한 핸들러를 생성한다.

1.  프로젝트에 게임의 로직을 담는 클래스를 추가한다. [솔루션 탐색기]에서  WindowsPhonePuzzle 프로젝트 노드를 오른 클릭하고 [추가]|[기존 항목] 선택한다. [기존 항목 추가] 대화 상자에서, 설치한 랩의 [Source]폴더의 [Assets] 찾아서 PuzzleGame.cs 선택하고 [추가] 클릭한다.


[그림 10] 추가된 프로젝트 파일 표시


추가한 클래스는 새로운 게임을 시작하고 퍼즐 조각을 옮기며, 게임의 상태를 저장하고 복원한다. 여기서는 클래스의 소스 코드 자체를 자세히 살펴보지는 않는다.

2.  3회에서 생성한 퍼즐 페이지의 코드 숨김 파일을 열고 PuzzlePage.xaml 파일을 오른 클릭한 [코드 보기] 선택한다.

3.  PuzzlePage.xaml.cs에 다음 네임스페이스 선언을 삽입한다.

using System.IO;
using System.Windows.Media.Imaging;
using System.Windows.Resources;

4. PuzzlePage 클래스에서 아래 강조 표시한 멤버 변수 선언을 삽입한다.

 

public partial class PuzzlePage : PhoneApplicationPage
{
  private const double DoubleTapSpeed = 500;
  private const int ImageSize = 435;
  private PuzzleGame game;
  private Canvas[] puzzlePieces;
  private Stream imageStream;

public PuzzlePage()
  {
    InitializeComponent();
  }
}


5. 이제 아래 코드 조각에서 강조 표시한 ImageStream 속성을 추가한다.

 

public partial class PuzzlePage : PhoneApplicationPage
{
  ...
  public Stream ImageStream
  {
    get
    {
      return this.imageStream;
    }

set
    {
      this.imageStream = value;

BitmapImage bitmap = new BitmapImage();
      bitmap.SetSource(value);
      this.PreviewImage.Source = bitmap;

int i = 0;
      int pieceSize = ImageSize / this.game.ColsAndRows;
      for (int ix = 0; ix < this.game.ColsAndRows; ix++)
      {
        for (int iy = 0; iy < this.game.ColsAndRows; iy++)
        {
          Image pieceImage = this.puzzlePieces[i].Children[0] as Image;
          pieceImage.Source = bitmap;
          i++;
        }
      }
    }
  }

public PuzzlePage()
  {
    InitializeComponent();
  }
}


 ImageStream 속성은 퍼즐 이미지용으로 사용하는 스트림을 반환한다. 이것은 배경 이미지와 퍼즐 조각을 새로 고침한다. 해당 속성을 모든 유효한 비트맵을 담고 있는 새로운 Stream으로 설정해 퍼즐 이미지를 대체할 있다. 예를 들면 폰의 카메라에서 이미지를 가져올 있다.

6. 아래 코드 조각에서 강조 표시한 PuzzlePage의 생성자를 업데이트 한다.

 

public partial class PuzzlePage : PhoneApplicationPage
{
  ...
  public PuzzlePage()
  {
    InitializeComponent();

SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;

// Puzzle Game
    this.game = new PuzzleGame(3);

this.game.GameStarted += delegate
    {
      this.StatusPanel.Visibility = Visibility.Visible;
      this.TapToContinueTextBlock.Opacity = 0;
      this.TotalMovesTextBlock.Text = this.game.TotalMoves.ToString();
    };

this.game.GameOver += delegate
    {
      this.TapToContinueTextBlock.Opacity = 1;
      this.StatusPanel.Visibility = Visibility.Visible;
      this.TotalMovesTextBlock.Text = this.game.TotalMoves.ToString();
    };

this.game.PieceUpdated += delegate(object sender, PieceUpdatedEventArgs args)
    {
      int pieceSize = ImageSize / this.game.ColsAndRows;
      this.AnimatePiece(this.puzzlePieces[args.PieceId], Canvas.LeftProperty, (int)args.NewPosition.X * pieceSize);
      this.AnimatePiece(this.puzzlePieces[args.PieceId], Canvas.TopProperty, (int)args.NewPosition.Y * pieceSize);
      this.TotalMovesTextBlock.Text = this.game.TotalMoves.ToString();
    };

this.InitBoard();
  }
}


생성자는 PuzzleGame 클래스에 의해 은닉된 게임 로직을 초기화 이벤트에 결합한다. PuzzleGame 클래스는 다음의 이벤트를 정의한다.

GameStarted: 이벤트는 새로운 게임이 시작할 일어난다. 이벤트에 대한 핸들러는 움직인 조각의 수를 패널에 표시하고 게임을 시작하는 방법을 지시하는 범례를 숨긴 움직인 조각의 수를 설정한다.

GameOver: 이벤트는 퍼즐을 풀었을 일어난다. 이벤트에 대한 핸들러는 게임을 시작하는 방법을 지시하는 범례를 표시 움직인 카운트를 업데이트한다.

PieceUpdated: 이벤트는 조각 이동이 일어날 마다 발생한다. 이벤트에 대한 핸들러는 움직인 조각을 애니메이션 이동 카운트를 업데이트한다.

 
마지막으로 이벤트 핸들러를 구독한 , 생성자는 InitBoard  메서드를 호출해 게임 보드를 초기화 한다.


7. 다음 PuzzlePage 클래스에서 InitBoard 메서드를 정의해 게임 보드를 초기화 한다.

 

private void InitBoard()
{
  int totalPieces = this.game.ColsAndRows * this.game.ColsAndRows;
  int pieceSize = ImageSize / this.game.ColsAndRows;

this.puzzlePieces = new Canvas[totalPieces];
  int nx = 0;
  for (int ix = 0; ix < this.game.ColsAndRows; ix++)
  {
    for (int iy = 0; iy < this.game.ColsAndRows; iy++)
    {
      nx = (ix * this.game.ColsAndRows) + iy;
      Image image = new Image();
      image.SetValue(FrameworkElement.NameProperty, "PuzzleImage_" + nx);
      image.Height = ImageSize;
      image.Width = ImageSize;
      image.Stretch = Stretch.UniformToFill;
      RectangleGeometry r = new RectangleGeometry();
      r.Rect = new Rect((ix * pieceSize), (iy * pieceSize), pieceSize, pieceSize);
      image.Clip = r;
      image.SetValue(Canvas.TopProperty, Convert.ToDouble(iy * pieceSize * -1));
      image.SetValue(Canvas.LeftProperty, Convert.ToDouble(ix * pieceSize * -1));

this.puzzlePieces[nx] = new Canvas();
      this.puzzlePieces[nx].SetValue(FrameworkElement.NameProperty, "PuzzlePiece_" + nx);
      this.puzzlePieces[nx].Width = pieceSize;
      this.puzzlePieces[nx].Height = pieceSize;
      this.puzzlePieces[nx].Children.Add(image);
      this.puzzlePieces[nx].MouseLeftButtonDown += this.PuzzlePiece_MouseLeftButtonDown;
      if (nx < totalPieces - 1)
      {
        this.GameContainer.Children.Add(this.puzzlePieces[nx]);
      }
    }
  }

// Retrieve image
  StreamResourceInfo imageResource = Application.GetResourceStream(new Uri("WindowsPhonePuzzle;component/Assets/Puzzle.jpg", UriKind.Relative));
  this.ImageStream = imageResource.Stream;

this.game.Reset();
}


InitBoard 메서드는 해당 퍼즐의 조각을 담고 있는 Canvas 컨트롤들을 생성한다. 조각은 퍼즐에 사용된 전체 이미지의 잘라낸 일부분이다.

8.  PuzzlePage 클래스에 AnimatePiece 삽입하기

 

private void AnimatePiece(DependencyObject piece, DependencyProperty dp, double newValue)
{
    Storyboard storyBoard = new Storyboard();
    Storyboard.SetTarget(storyBoard, piece);
    Storyboard.SetTargetProperty(storyBoard, new PropertyPath(dp));
    storyBoard.Children.Add(new DoubleAnimation
    {
        Duration = new Duration(TimeSpan.FromMilliseconds(200)),
        From = Convert.ToInt32(piece.GetValue(dp)),
        To = Convert.ToDouble(newValue),
        EasingFunction = new SineEase()
    });
    storyBoard.Begin();
}


9.  MouseLeftButtonDown 이벤트에 대한 핸들러를 추가한다. 방법은 PuzzlePage 클래스에 다음의 강조 표시한 코드를 삽입한다.

 

private void PuzzlePiece_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
  if (!this.game.IsPlaying)
  {
    this.game.NewGame();
  }
}


이벤트 핸들러는 보드 표면을 클릭해 발생하고 이미 하나가 진행 중이지 않는 새로운 게임을 시작한다.

10. 이제 "Solve" 버튼의 Click 이벤트에 대한 핸들러를 추가한다.

 

private void SolveButton_Click(object sender, RoutedEventArgs e)
{
    this.game.Reset();
    this.game.CheckWinner();
}


Solve 버튼에 대한 이벤트 핸들러는 게임을 재설정시켜 원래 이미지를 표시하고 퍼즐을 있도록 한다. PuzzleGame 클래스에서  PuzzleGame.CheckWinner 메서드를 호출한다. 메서드는 모든 조각이 알맞은 위치에 있는지 확인 축하 메시지를 표시하는 UI 나타내는 GameOver 이벤트를 일으킨다.


11.  [F5] 눌러 애플리케이션을 빌드하고 윈도우 에뮬레이터로 배포한다. 잠깐 기다리면 시작화면이 표시되고 바로 [START] 클릭한다.

[그림 11] 게임 시작하기


12.  에뮬레이터 윈도우에서 이미지를 터치하면 퍼즐이 시작한다. 이미지는 여러 조각으로 나눠지고 랜덤한 방식으로 보드에 배열된다. AnimatePiece 메서드가 적용된 애니메이션 스토리보드의 결과로 부드럽게 조각이 슬라이딩 되지 않고 순간적으로 조각들이 위치를 바꾼다. 메서드는 퍼즐의 왼쪽 위쪽 좌표를 움직여  변형한다.

[그림 12] 게임 시작 보드에서 임의로 배열된 퍼즐 조각


13. 조각을 선택해 드래그를 시도해 보면, 현재는 아무런 효과도 없을 것이다.  부분은 다음 시간에 멀티 터치를 지원하는 코드를 추가해 것이다.

14. 이제 [SOLVE] 버튼을 클릭하고 보드의 조각들이 재배치 되어 원리의 이미지를 표시하는 것을 확인하자.

15. [SHIFT+F5] 눌러 디버깅 세션을 종료한다.

Comment +0


 

이번에는 4번 거쳐 퍼즐 보드를 표시하고 게임을 실행하는 페이지를 만들어 본다. 페이지는 클릭 시에 여러 조각으로 나눠진 랜덤 방식으로 보드에 재배치된 이미지를 표시 한다.  게임의 로직은 PuzzleGame 클래스에 포함되어 있다. 페이지의 컨트롤들의 레이아웃을 생성한 보드를 초기화하고 사용자 인터페이스 이벤트에 응답하는데 필요한 애플리케이션 로직을 추가한다. 다음 멀티 터치 지원을 추가해 사용자가 손가락으로 보드상의 퍼즐 조각을 드래그해 배열하도록 해준다. 마지막 단계로, 퍼즐을 풀어 성공할 멋있는 시각적 효과를 생성하는 애니메이션 스토리 보드를 만든다

이번 3회에서는 새로운 페이지를 애플리케이션에 추가해 퍼즐 보드를 표시하고 게임을 하는 동안 수행한 전체 이동 횟수를 가지는 상태 패널 뿐만 아니라 퍼즐 이미지를 표시하는데 필요한 사용자 인터페이스 요소를 추가한다.

1. 앞서 "생애 첫 번째 윈도우 폰 7 애플리케이션 만들기2"에서 완료한 단계 이후로 이어진다. [솔루션 탐색기]에서  WindowsPhonePuzzle 프로젝트 노드를 오른 클릭하고 [Add]|[New Item] 선택한다. [Add New Item] 대화상자에서 템플릿 목록의 [Windows Phone Portrait] 페이지를 선택하고 이름을 "PuzzlePage.xaml" 설정한 [Add] 클릭해 프로젝트에 새로운 페이지를 추가한다.

[그림 7] 프로젝트 새로운 페이지 추가하기


2. 새로운 페이지의 XAML뷰에서  LayoutRoot 요소의 RowDefinitions 섹션을 찾아 번째 행에 대한 Height 속성의 값을 0.2* 설정한다.

[그림 8] 컨테이너 그리드의 레이아웃 구성하기

높이를 별표(*) 지정하는 것은 해당 행이 다른 모든 행이 할당된 후에 레이아웃 그리드에서 가능한 영역까지 늘어난다는 뜻이다. 그림 8 정의에서 번째 행의 경우 처럼 배율 크기 조정 높이가 승수를 포함 , 사용되지 않은 공간은 승수의 값에 기반을 모든 "배율 크기 조정" 사이에 비례해 할당된다. 따라서 정의의 번째 행은 가용한 공간의 1/6째를 차지 한다.


3. LayoutRoot 그리드 내부에서, 기본 페이지 템플릿의 일부로 포함된 기존 TitlePanel와 ContentPanel 요소를 삭제한다.

4.  RowDefinitions 바로 아래 다음의 강조된 코드에서 보인 것처럼 StackPanel 컨테이너 요소 개를 삽입한다.

<Grid x:Name="LayoutRoot" Background="Transparent">
  <Grid.RowDefinitions>
    <RowDefinition Height="0.2*"/>
    <RowDefinition Height="*"/>
  </Grid.RowDefinitions>
  <StackPanel Orientation="Vertical" VerticalAlignment="Stretch">
  </StackPanel>
  <StackPanel Orientation="Vertical" VerticalAlignment="Top" Grid.Row="1">
  </StackPanel>
</Grid>


5.  번째 StackPanel 요소에서 다음의 강조된 XAML 마크업을 삽입한다.

 

...
<Grid x:Name="LayoutRoot" Background="Transparent">
  ...
  <StackPanel Orientation="Vertical" VerticalAlignment="Stretch">
    <Button x:Name="SolveButton" Content="SOLVE" Margin="10" HorizontalAlignment="Center" Click="SolveButton_Click" />
    <StackPanel x:Name="StatusPanel" Orientation="Horizontal" HorizontalAlignment="Center" Visibility="Collapsed">
      <TextBlock HorizontalAlignment="Center" Text="Your Moves: " TextWrapping="Wrap" Foreground="#FFD0D0D0" FontSize="17.333"/>
      <TextBlock x:Name="TotalMovesTextBlock" HorizontalAlignment="Center" Text="N" TextWrapping="Wrap" Foreground="#FFFFB000" FontSize="17.333"/>
    </StackPanel>
  </StackPanel>
  <StackPanel Orientation="Vertical" VerticalAlignment="Top" Grid.Row="1">
  </StackPanel>
</Grid>
...


6. 다음으로 번째 StackPanel 요소 내에 다음의 강조된 XAML 마크업을 삽입한다.

 

...
<Grid x:Name="LayoutRoot" Background="Transparent">
  ...
  <StackPanel Orientation="Vertical" VerticalAlignment="Top" Grid.Row="1">
    <Border x:Name="CongratsBorder" Height="30" Background="#FFF10DA2" HorizontalAlignment="Center" Width="443" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" Opacity="0">
      <Border.RenderTransform>
        <TransformGroup>
          <ScaleTransform/>
          <SkewTransform/>
          <RotateTransform/>
          <TranslateTransform/>
        </TransformGroup>
      </Border.RenderTransform>
      <TextBlock HorizontalAlignment="Center" Text="CONGRATULATIONS!" TextWrapping="Wrap" Foreground="White" FontSize="17.333" VerticalAlignment="Center" FontWeight="Bold"/>
    </Border>
  </StackPanel>
</Grid>



 

Border 요소는 퍼즐을 풀었을 표시되는 메시지를 담는다. Border RenderTransform을 포함한다. 변환은 나중에 시각적 효과를 만들 애니메이션 스토리보드에 필요하다.


7. 아래쪽 StackPanel의 콘텐트를 완료하기위해 다음의 강조된 XAML 이전 단계에서 삽입한 마크업 바로 아래에 넣는다.
 

...
<Grid x:Name="LayoutRoot" Background="Transparent">
  ...
  <StackPanel Orientation="Vertical" VerticalAlignment="Top" Grid.Row="1">
    <Border x:Name="CongratsBorder"...>
    </Border>
    <Border x:Name="border" BorderThickness="3" Background="#FF262626" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="1" RenderTransformOrigin="0.5,0.5">
      <Border.RenderTransform>
        <TransformGroup>
          <ScaleTransform/>
          <SkewTransform/>
          <RotateTransform/>
          <TranslateTransform/>
        </TransformGroup>
      </Border.RenderTransform>
      <Border.BorderBrush>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
          <GradientStop Color="#FFF10DA2" Offset="0"/>
          <GradientStop Color="#FFEE7923" Offset="1"/>
        </LinearGradientBrush>
      </Border.BorderBrush>
      <Canvas Height="435" Width="435">
        <Image x:Name="PreviewImage" Height="435" Width="435" Opacity="0.2" />
        <Canvas x:Name="GameContainer" Width="435" Height="435" />
      </Canvas>
    </Border>
    <TextBlock x:Name="TapToContinueTextBlock" HorizontalAlignment="Center" Text="Tap the picture to start the puzzle" TextWrapping="Wrap" Foreground="#FFD0D0D0" FontSize="17.333"/>
  </StackPanel>
</Grid>

 

위의 XAML 마크업은 여러 색을 사용하는 선형 그라데이션 브러시로 그린 Border 요소를 정의한다. 요소는 시각적 효과를 제공하기 위해 애니메이션 스토리보드를 생성할 필요한 RenderTransform 을 지정한다. Border  요소 내에는 하나의 Canvas 요소가 있다. 컨테이너 요소는 해당 영역에 상대적인 좌표를 사용해 다른 자식 요소를 명시적으로 위치시키는데 사용된다. Canvas 자식 요소들 중에는 퍼즐의 해답(PreviewImage) 미리보기를 가진 워터마크를 보여주는 Image 요소와 퍼즐의 조각을 담는 내부 Canvas(GameContainer) 있다. 또한 마크업은  게임 시작 방법 지시를 표시하는 TextBlock 요소 (TapToContinueTextBlock)를 포함한다. 요소는 게임이 진행되는 동안 숨겨져 있다.


8.  디자인 뷰로 전환해 페이지의 레이아웃을 확인한다.

[그림 9] 윈도우 퍼즐 애플리케이션 사용자 인터페이스

Comment +0


벌써 작년이군요. 2010년 7월에 뉴올리언즈에서 개최된 마이크로소프트 TechED에 다녀왔던 시간이...
다녀온지 얼마 되지 않은것 같은데, 시간이 참 빠릅니다. 그때 TechED에서 정식 윈도우 폰7이 출시 되기전에 행사에서 공개되었던 사진 몇 점 공개합니다. 물론 이제는 정식 윈도우 폰7이 출시 되었고, 반응은 다양하지만, 그래도 아이폰 UI에 이미 식상하신 분이라면 또 한번의 새로운 경험이 될 만한 사용자 경험을 하리라 봅니다.

Comment +2


 이번 시간에는 처리되지 않은 예외가 발생할 마다 에러 페이지를 표시하도록 애플리케이션을 업데이트 한다. 처리되지 않은 예외를 관리하려면, 우선 해당 에러에 관한 정보를 표시하도록 새로운 페이지를 애플리케이션에 추가한다. 다음 UnhandledException 이벤트에 관한 이벤트 핸들러를 생성한다. 이벤트는 애플리케이션에서 예외가 잡히지 않을 마다 발생한다. 핸들러에서 해당 예외에 관한 정보를 전달해 에러 페이지를 찾게 된다.

1. 먼저 프로젝트에 새로운 페이지를 추가한다. [솔루션 탐색기]에서, WindowsPhonePuzzle 프로젝트 노드를 오른 클릭하고, [Add]|[New Item]을 선택한다. [ Add New Item] 대화상자에서, 템플릿 목록의 [Windows Phone Portrait Page]를 선택하고, 이름을 [ErrorPage.xaml]로 설정한 뒤 [Add]를 클릭한다.

[그림 4] 프로젝트에 새로운 페이지 추가하기

2. ErrorPage.xaml에서 LayoutRoot Grid 요소를 찾아서 아래 XAML 마크업으로 해당 요소의 자식 컨트롤을 대체한다. 이 XAML은 애플리케이션의 제목과 페이지 제목을 정의한다. 또한, 지정된 TextBlock 객체를 x:Name="ErrorText"로 정의해 향후 나타나는 모든 예외들에서 에러 텍스트를 표시한다.

 

...

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

<!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
        <TextBlock x:Name="ApplicationTitle" Text="WINDOWS PHONE PUZZLE" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="error" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>
    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1">
        <Border BorderBrush="White">
            <TextBlock x:Name="ErrorText" Style="{StaticResource PhoneTextSmallStyle}" TextWrapping="Wrap" />
        </Border>
    </Grid>
</Grid>

...


3. 새로운 페이지의 코드 숨김 파일을 열어, 다음의 네임스페이스 지시문을 파일의 상단에 삽입한다.

using System.Windows.Navigation;

4. ErrorPage  클래스에 다음 코드를 삽입한다. 코드는 Exception 객체를 설정해 ErrorText.text 연결시킨다.

 

public partial class ErrorPage : PhoneApplicationPage
{
  public ErrorPage()
  {
    InitializeComponent();
  }

public static Exception Exception;

// Executes when the user navigates to this page.
  protected override void OnNavigatedTo(NavigationEventArgs e)
  {
    ErrorText.Text = Exception.ToString();
  }
}


5. 일단 페이지가 준비 되면, 이벤트 핸들러를 연결해 에러 페이지를 탐색하고 처리되지 않은 예외가 발생할 때마다 에러 메시지를 표시한다. [솔루션 탐색기]에서, App.xaml 코드 숨김 파일을 표시한다.

6. App 클래스에서 Application_UnhandledException 이벤트 핸들러를 찾아서 메서드의 본문을 다음의 코드로 대체 한다.

 

// Code to execute on Unhandled Exceptions
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
  if (System.Diagnostics.Debugger.IsAttached)
  {
    // An unhandled exception has occurred; break in the debugger
    System.Diagnostics.Debugger.Break();
  }

e.Handled = true;
  ErrorPage.Exception = e.ExceptionObject;
  (RootVisual as Microsoft.Phone.Controls.PhoneApplicationFrame).Source =
      new Uri("/ErrorPage.xaml", UriKind.Relative);
}


이제 애플리케이션을 빌드하고 윈도우 에뮬레이터로 배포한 다음, 결과를 확인해보자. 결과를 확인하는 절차는 다음과 같다.

1. 비주얼 스튜디오에서 [CTRL +F5] 눌러 디버깅 없이 애플리케이션을 윈도우 에뮬레이터로 실행한다. 잠깐 기다리면 애플리케이션이 실행하고 메인 페이지를 표시한다.

[그림 5] 에뮬레이터에서 애플리케이션 실행 시작화면

2. [START] 버튼을 클릭한다. 애플리케이션에서 앞서 정의한 처리되지 않은 예외 에러 페이지를 표시한다. 버튼에 대한 핸들러가 아직 정의하지 않은 PuzzlePage.xaml 페이지를 탐색하기 때문에 이런 결과가 나오는 것이다.

[그림 6] 처리되지 않은 예외 에러 페이지

Comment +0


지난 강좌에서 만들어 본 Hello phone 프로젝트는 워밍업으로 생각하고, 이제 본격적으로 첫 애플리케이션을 만들어 보자. 이번 강좌도 윈도우 폰 개발 도구로 무료 Microsoft Visual Studio 2010 Express for Windows Phone과 윈도우 폰 에뮬레이터를 이용한다. 또한 윈도우 폰 7 트레이닝킷을 기본 경로로 설치했다는 가정하에 진행한다.

먼저 Visual Studio에서 윈도우 폰 애플리케이션 프로젝트를 생성하자. 생성하는 방법은 다음의 단계를 따른다.

1. [시작] | [모든 프로그램] | [Microsoft Visual Studio 2010 Express] | [Microsoft Visual Studio 2010 Express for Windows Phone] 클릭.

2. [File] | [New Project] 클릭.

3. [New Project] 대화 상자에서 [Silverlight for Windows Phone] 범주의 [Windows Phone Application] 템플릿을 선택하고, [이름]은 "WindowsPhonePuzzle"로 정한 뒤 [위치]는 앞서 설치한 윈도우 폰 7 트레이닝 킷의 위치(C:\WP7TrainingKitOffline\Labs\YourFirstWP7Application\Source\Ex1-CreatingWP7Apps)를 선택한다. 솔루션 이름은 편의상 "Begin"으로 입력한다.

위의 프로젝트 생성단계를 마치고 나면  Visual Studio의 솔루션 탐색기에 관련 하나의 솔루션과 하나의 프로젝트가 로드된다.

[그림 1] 솔루션 탐색기에 로드된 WindowsPhonePuzzle 애플리케이션


이제 홈 페이지를 위한 UI를 만들어 보자. 이번 작업에서는 애플리케이션의 홈 페이지에 대한 사용자 인터페이스를 만든다. 이 페이지는 시작 화면을 표시한다. 여기에는 애플리케이션을 나타내는 이미지와 시작 화면을 해제하고 게임 페이지를 찾는 버튼을 포함한다.

1. 우선 프로젝트에서 폴더를 만들어 애플리케이션이 사용하는 이미지를 포함하도록 한다. [솔루션 탐색기]에서, [WindowsPhonePuzzle] 프로젝트를 오른 클릭하고 [Add]|[New Folder]를 선택한다. 폴더 이름을 [Assets]으로 변경한다.

[그림 2] 새로운 Assets 폴더를 나타낸 솔루션 탐색기

2. 이제, 프로젝트에서 애플리케이션에서 사용하는 이미지를 추가한다. [솔루션 탐색기]에서 [Assets]를 오른 클릭하고 [Add]|[Existing Item]를 선택한다. [Add Existing Item] 대화상자에서 추가할 이미지 SplashImage.jpg와 Puzzle.jpg를 찾아서 등록한다. (해당 이미지는 최초에 설치한 트레이닝 킷의 [Source] 폴더에서 찾는다.)

비주얼 스튜디오에서 Silverlight for Windows Phone 프로젝트에 리소스 파일을 추가한 후 [Build Action] 값을 설정해 배포용으로 이들을 구성할 수 있다. 각 추가된 이미지는 프로젝트에 포함되어 빌드 동작에서 Resource로 설정되는데, 이는 프로젝트 어셈블리로 파일을 내장하는 것이다.


3. [솔루션 탐색기]에서 MainPage.xaml을 더블 클릭해 디자이너에서 이 파일을 로드한다.

4. [디자인] 뷰에서, "MY APPLICATION"이라는 TextBlock을 선택하고 [F4]를 눌러 속성창을 연다. [Text] 속성의 값을 "WINDOWS PHONE PUZZLE"로 변경한다.

[그림 3] 속성 창의 UI 요소 구성


5. "pane name"이라고 되어 있는 TextBlock을 선택하고 나서 [Text] 속성을 "start"로 변경한다.

6. 기본 윈도우 폰 애플리케이션 템플릿에서 생성한 XAML 마크업에서 "LayoutRoot"이라는 Grid 요소를 찾는다. 이 요소의 목적은 페이지의 요소를 배열하는 것이다. 루트 Grid 요소는 각각을 Grid.Row 속성을 정의해 바깥 그리드의 다른 행에 할당한 다른 중첩 요소를 포함할 수 있다. row1에 할당된 ContentPanel이라는 Grid 요소를 찾아서 다음 XAML 마크업을 넣는다.

<Grid x:Name="LayoutRoot" Background="Transparent">
  ...
  <!--ContentPanel - place additional content here-->
  <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.RowDefinitions>
      <RowDefinition Height=".8*" />
      <RowDefinition Height=".2*" />
    </Grid.RowDefinitions>
    <Image Source="Assets/SplashImage.jpg" VerticalAlignment="Center" HorizontalAlignment="Center" Width="471" Height="492"  />
    <Button Content="START!" Name="StartButton" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" />
  </Grid>
</Grid>


추가한 마크업은 두개의 행을 만든다. 첫 번째 행은 시작화면에 대한 이미지를 포함하고, 두 번째 행은 페이지를 해제하고 메인 퍼즐 페이지를 탐색하는 버튼을 담는다.

7. 해당 버튼에 대한 이벤트 핸들러를 생성한다. 디자이너 화면의 [START]라는 버튼을 더블 클릭한다. "Click" 이벤트에 대한 구독이 만들어지고 코드 숨김파일이 열리며 커서가 StartButton_Click 이벤트 핸들러 메서드에 위치한다. 다음의 코드를 이 메서드의 바디에 붙여 넣는다.

private void StartButton_Click(object sender, RoutedEventArgs e)
{
  // navigate
  this.NavigationService.Navigate(new Uri("/PuzzlePage.xaml", UriKind.Relative));
}

PhoneApplicationPage 클래스는 NavigationService속성을 통해 페이지를 탐색하는 메서드와 속성을 제공한다. NavigationService의 Navigate 메서드를 호출하고 그 페이지에 매개변수로 URI를 넘길수 있다. GoBack과 GoForward 메서드를 사용해 탐색 이력의 정방향/역방향 탐색을 할 수 있다. 하드웨어 뒤로가기 버튼 또한 애플리케이션 내에서의 역방향 탐색을 제공한다. 위에서 나타낸 이벤트 핸들러는 NavigationService를 사용해 PuzzlePage.xaml로 간다.

Comment +0

이번 시간에는 지난 시간에 이어 키 프레임들 간의 보정을 변경해 애니메이션을 부드럽게 만들고, 전체 프로젝트를 최종완성해서 실행해 볼것이다.

1. 타임라인에서 회색 원 아이콘 내부를 클릭해 첫 번째 키 프레임을 선택 한다.
프레임을 선택할 때, 디자이너 뷰가 업데이트 되어 UI 요소의 상태를 보여주는데, 이 경우는 배너 텍스트가 거울에 비친것 처럼 표시된다.
이제, [Properties] 창에서, [Easing] 범주 아래 [EasingFunction]을 선택하고, 드롭 다운 목록을 확장해 가능한 기능 목록을 표시한 뒤, [Cubic Out] 기능을 선택한다.

이 특별한 감속/가속 기능은 전환시에 키 프레임에 가까워짐에 따라 감/가속율을 줄인다.

[그림 69] 감속/가속 기능을 적용해 키 프레임간에 상호보간을 수행한다

키 프레임 보간은 속성 변경으로 두 개의 키 프레임 사이의 시간에 걸쳐 애니메이션하는 방법을 기술한다. 감/가속 기능을 전이과정 동안 적용해 키 프레임 보간 값을 수정하면 더 실제같은 애니메이션을 얻을 수 있다.

2. 두 번째 키 프레임에 대해서도 감/가속 기능을 구성하는 이전 단계를 반복한다. 이번에는 [Cubic InOut] 기능을 선택해 저속에서 변화를 시작하고, 점차 속도를 높이다가 최종적으로 마지막 프레임에 가까워짐에 따라 속도를 줄인다.

[그림 70] CubicInOut 감/가속 기능 선택

3. 애니메이션에서 감/가속 기능의 효과를 테스트하려면, 타임라인 위의 [Play]를 누른다.
배너가 고속으로 회전을 시작한 뒤, 텍스트가 반사되어 표시됨에 따라 느려지고, 다시 속도가 오른 뒤에 최종적으로 한 번더 느려지면서 원래의 위치로 돌아간다.

4. 지금까지 배너 텍스트에 대한 애니메이션 스토리보드를 만들었지만, 프로젝트에서는 사용되지 않은 리소스이다. 애니메이션을 실행하려면, 이벤트에 반응해 스토리보드를 트리거해야 하는데, 이 경우는 [Click Me] 버튼을 누를 때 마다 발생해야한다. 이 버튼에 대한 [Click] 이벤트 처리기는 다음의 작업순서로 열어본다.

  • 활성 워크스페이스를 다시 디자인 워크스페이스로 전환한다. [Window]| [Workspaces]| [Design]을 선택한다.
  • [Projects] 창에서, MainPage.xaml 옆에 있는 화살표를 클릭해 코드 숨김 파일을 표시한다.
  • MainPage.xaml.cs를 더블 클릭해 코드 숨김 뷰를 연다.
    애니메이션을 실행하는 이벤트 처리기를 업데이트하려면, 다음 코드 조각을 종료 괄호전에 바로 삽입한다.
  • private void ClickMeButton_Click(object sender, RoutedEventArgs e)
    {
      BannerTextBlock.Text = MessageTextBox.Text;
      MessageTextBox.Text = String.Empty;
      this.AnimateBanner.Begin();
    }


5. [F5]를 눌러 애플리케이션을 빌드하고 윈도우 폰 에뮬레이터에 배포한다. 잠깐 기다리면 애플리케이션이 시작되고 메인 페이지가 나타난다.

6. 텍스트 상자에 약간의 텍스트를 입력한다.

7. [Tab] 키를 한 번 누르면 버튼이 포커스를 받고 버튼 주위에 테두리가 나타난다.

8. 버튼을 클릭하면 배너의 텍스트를 설정하고 버튼의 위치를 이동해 버튼이 눌러졌음을 가리킨다. 버튼을 클릭할 때 배너 텍스트의 애니메이션 실행을 살펴보자.

[그림 71] 윈도우 폰 에뮬레이터에서 업데이트한 애플리케이션을 실행한다.


9. 테스트 완료후, 에뮬레이터 창의 오른쪽 상단 구석의 [Close] 아이콘을 클릭해 종료하고 디버깅 세션을 마친다.

이로써 간단한 Hello Phone 프로젝트를 통해 윈폰 7 프로그래밍의 간결함과 도구들의 멋진 기능을 잠깐 맛 보았다.

Comment +0


애니메이션은 부드러운 시각적 전환의 시작과 끝 위치를 정의하는 키 프레임을 기반으로 한다. 익스프레션 블렌드에서 애니메이션을 만들려면, 스토리 보드를 만들고, 그 스토리보드에서 타임라인에 키 프레임을 설정해 속성 변화를 표시한다. 예를 들면 0초 표시에 키 프레임을 설정해 아트보드의 왼편에서 사각형의 위치를 기록하고나서, 1초 표시에서 키 프레임을 설정해 아트 보드의 오른편에서 동일한 사각형의 위치를 기록한다. 결과로 나타나는 애니메이션은 초당 사각형의 X와 Y의 속성이 바뀌는 변환에 기반한다. 애니메이션 스토리보드를 실행할 때, 익스프레션 블렌드는 지정된 기간에 걸친 속성 변화에 중간값을 채우고 애플리케이션에 그 결과를 표시한다. 이런 방법으로 아트보드에서 객체가 속하는 모든 속성, 심지어 비 시각적 속성까지도 움직일 수 있다.

이번 시간에는 익스프레션 블렌드에서 스토리보드를 생성해 버튼을 누를 때 마다 배너에서 텍스트를 애니메이션할 것이다.

1. 활성 워크스페이스를 애니메이션 워크스페이스로 전환하자. [Window]|[Workspaces]|[Animation]을 선택한다.
타임라인을  편집할 수 있는 공간을 최대화 하기 위해 창드을 재배치 할 텐데, 워크스페이스를 기본 상태로 돌리고 싶다면, [Window] | [Reset Current Workspace]를 선택한다.

2. 필요한경우, 버튼 컨트롤 템플릿의 편집 영역을 빠져나간다. [Objects and Timeline] 패널에서  FancyButton (Button Template) 옆에 있는 [Scope Up] 버튼을 클릭해 페이지의 요소 트리를 표시한다.

컨트롤 템플릿을 편집할때, [Objects and Timeline] 패널만 그 템플릿에 대한 요소 트리를 표시한다. 페이지의 다른 요소를 편집하려면 현재 영역을 빠져나가야 한다.


3. [Objects and Timeline] 패널에서 New를 클릭해 스토리보드를 생성한다. 이것은 + 표시의 레이블을 가진 버튼으로 해당 패널의 우측 상단 구석에 있다.

[그림 61] 애니메이션 모드의 [Objects and Timeline] 창


4. [Create Storyboard Resource] 대화상자에서, [Name]에 AnimateBanner를 설정하고 [OK]를 클릭한다.

[그림 62] 새로운 스토리보드를 생성해 배너 텍스트를 애니메이션한다.

5. 애니메이션에서 키 프레임을 생성하려면, 먼저 [Objects and Timeline] 패널의 요소 트리에서 [BannerTextBlock] 요소를 클릭해 선택한다. 필요한 경우, 그리드 부모 요소를 확장해 표시한다.

6. 그 다음 타임라인 플레이헤드의 현재 위치를 클릭해 1초의 오프셋으로 드래그한다.

[그림 63] 타임라인 플레이헤드의 타임 오프셋 변경하기

플레이헤드는 타임라인의 맨위에 위치한 노란색 마커다. 페이지의 해당 요소에 대한 모든 변경은 타임라인 플레이헤드의 위치에서 키 프레임으로 기록된다.


7.  다음으로, [Properties] 패널로 전환하고, [Transform ] 범주를 확장한 뒤, [Scale] 변환을 선택한다. X 속성의 값을 -1로 설정한다. 이 변환은 수평 축을 따라서 해당 요소를 반영한다.

[그림 64] 텍스트를  반영하기 위해 스케일 변환을 적용한다.


8. 다시 타임라인 패널로 전환한다.
선택한 타임 오프셋에서 회색 원이 가리키는 새로운 키 프레임을 담고 있는데, 이것은 타임라인 레코딩이 활성화된 상태의 트리에서 요소 변경의 결과다.

[그림 65] 애니메이션 스토리보드에서 새로운 키 프레임 생성하기

9. 이제 타임라인 플레이헤드를 2초의 오프셋으로 변경한다.

10. 다시한번, [Properties] 패널로 전환하고, [Transform] 범주를 확장한 뒤, [Scale] 변환을 선택한다. 다시 X 속성의 값을 1로 변경해 해당 요소를 원래 상태로 복원한다. 두 번째 키 프레임은 이 변경 때문에 스토리보드 타임라인에 표시된다.

[그림 66] [Objects and Timeline] 패널이 삽입된 키 프레임을 보여준다.

11. 디자이너에서 애니메이션을 테스트하려면, 약간의 텍스트를 배너에 추가해야 한다. 우선 해당 패널의 왼쪽 상단에서 AnimateBanner 스토리보드 이름의 왼쪽에 있는 빨간 원을 클릭해 레코딩을 임시로 끈다.

[그림 67] 레코딩 모드 끄기

12. 이제 디자이너 화면의 BannerTextBlock 요소를 클릭하고 오른쪽 버튼을 클릭한 뒤 [Edit Text]를 선택한다. 해당 배너에 대한 적절한 텍스트를 입력하고 [ENTER]를 누른다.

13. 애니메이션을 테스트하기 위해, 타임라인 위의 Play 버튼을 누른다.
해당 텍스트가 가운데 축을 중심으로 어떻게 배너를 수평으로 회전하는지 그리고 전체 애니메이션 주기를 통해 어떻게 이동을 균일하게 하는지 주목하자. 다음 단계에서 키 프레임들 간의 보정을 변경하고 더 자연스러운 애니메이션을 만들어내는 기능을 적용해볼 것이다.

[그림 68] 디자이너에서 애니메이션 실행하기

Comment +0


지난 시간에 이어 이번에는 컨트롤 템플릿을 업데이트 해서 버튼이 포커스를 가질 때 아웃라인을 보여줄 수 있고 페이지에서 버튼이 눌러졌을 때 그  위치를 옮길 수 있는 다른 시각적 상태를 추가할 것이다.

1. [Objects and Timeline] 패널에서, [Border] 컨트롤을 선택한다.
2. 이제 [States] 패널로 전환해 해당 버튼 컨트롤에 대해 사용할 수 있는 시각적 상태를 검토해보자.

[그림 57] 상태 패널은 선택된 Base를 보여준다



[States] 패널은  해당 컨트롤의 모든 시각적 상태를 표시한다. [Base]  상태는 모든 상태에 공통으로 존재하는 요소를 정의한다.이 상태에서 해당 컨트롤의 기본 모양을 정의하는 템플릿을 조정할 수 있다. 그 다음 다른 상태의 각각에 대해,  해당 상태의 시각적 신호를 제공하는 식으로 템플릿을 변경한다.예를 들면 [Focused] 상태에서는 컨트롤 주의의 테드리를 표시한다.


3. [FocusStates] 범주 아래에서, [Unfocused] 상태를 선택해 버튼이 포커스를 가지지 못할 때 해당 상태가 신호하는 것을 기록하도록 만든다. 이 모드 동안의 해당 템플릿에 대한 모든 변경은 특정 상태에만 적용한다.

[그림 58] 익스프레션 블렌드에서 상태 기록



상태를 선택할 때 몇 가지 변경이 발생한다. 먼저 선택한 상태의 레이블 옆에 있는 붉은 색 원은 현재 활성이라는 것을 가리킨다. 그 다음 디자인 영역 주위에 붉은 색 아웃라인이 나타난다. 마지막으로 디자인 영역의 왼쪽 구성에 캡션이 표시되고 상태 기록이 켜졌음을 가리킨다. 이 모드에서 템플릿의 해당 요소에 대한 모든 변경은 기록되고 XAML 문서에 저장된다. 실행시, 이러한 변경은 그 상태가 활성화 될 때 기본 템플릿에 적용된다.


4. 버튼이 포커스를 잃을 때 버튼 주위의 테두리를 숨기려면, 다음의 작업을 수행한다.

  • [Objects and Timeline] 패널에서 [Border]를 선택한다.
  • [속성] 창에서 [Brushes] 범주를 확장하고 [BorderBrush] 속성을 선택한다.
  • [Show advanced properties] 아이콘을 클릭하고 브러시의 [Opacity] 속성을 0으로 설정한다.

[그림 59] [Unfocused] 상태일 경우 테두리를 투명하게 만들기



5. Go back to the [States] 패널로 다시 돌아가서  [CommonStates] 범주에서 [Pressed] 상태를 선택해 마우스가 클릭될 때 발생한 상태를 기록하도록 만든다.

6. [Properties] 패널에서, [Transform] 범주를 확장하고 [Translate] 변환을 선택한다. X 와 Y 값을 2로 설정한다. 이렇게 하면 버튼이 클릭될 때 마다 버튼의 위치를 약간 이동해서, 버튼이 눌러졌다는 것을 알려준다.

[그림 60] [Pressed] 상태 동안 버튼의 위치 이동하기


7. 마지막으로, [States] 패널에서 [Base] 템플릿을 선택해 레코딩 모드를 끈다.

8. [CTRL + S]를 눌러 갱신된 파일을 저장한다.

9. 이제 커스텀 컨트롤에 대한 시각적 상태 추가를 완료 했으므로, 업데이트된 버튼을 테스트할 준비가 되었다.

  • [F5]를 눌러 애플리케이션을 빌드하고 실행한다.
  • 텍스트를 입력하고 Tab 키를 눌러 버튼으로 입력 포커스를 변경한다.
  • 버튼이 포커스를 받을 때, 버튼이 활성화되었음을 가리키기 위해 테두리가 버튼 주위에 표시된다.
  • 이제 스페이스 바를 누르거나 버튼을 클릭해 버튼의 위치가 얼마나 이동하는지 보자.

     

Comment +0


대개 실버라이트 컨트롤은 템플릿을 사용해 시각적 모양과 로직을 분리한다. ControlTemplate은 컨트롤의 시각적 구조와 동작을 지정한다. 기본 ControlTemplate 설정을 수정해 컨트롤의 모양을 조정할 수 있다. 이것을 사용하면 컨트롤의 기능을 변경하지 않고도 모양을 변경할 수 있다. 예를 들면 애플리케이션에서 버튼을 기본 사각형 모양이 아니라 모서리를 둥글게 처리할 수 있지만, 이 버튼은 여전히 Click 이벤트를 일으킨다.

이번 시간에는 익스프레션 블렌드에서 이전에 작업한 비주얼 스튜디오 프로젝트를 열어서 버튼의 ControlTemplate을 대체해 룩앤필을 수정한다. XAML에서 ControlTemplate을 생성하기 때문에 코드를 작성할 필요 없이 컨트롤의 모양을 변경할 수 있다. (이번 실습은 앞서 주인장이 쓴 글을 따라왔다는 전제하에 이어진다.)

1. [시작]|[모든 프로그램]|[Microsoft Visual Studio 2010 Express for Windows Phone]에서 윈도우 폰용 비주얼 스튜디오 2010 익스프레스를 시작한다.

2. 앞서의 Hello Phone 프로젝트를 잘 따라왔다면, 랩의 Source 폴더에서 HelloPhone\Ex2-WP7AppUXDesignWithBlend\Begin에 있는 Begin.sln을 연다.

3. 비주얼 스튜디오에서 [솔루션 탐색기]에 있는 MainPage.xaml을 오른 클릭하고나서, [Open in Expression Blend]를 선택한다. 보안 위험 경고가 표시되면, [Yes]를 클릭해 닫는다.

[그림 43] 익스프레션 블렌드로 솔루션 열기



4. 익스프레션 블렌드에서 MainPage.xaml이 디자이너 창에서 열렸는지 그리고 현재 워크스페이스가 [Design]으로 설정되었는지를 확인한다. 현재 워크스페이스를 보려면 [Windows] 메뉴에서 [Workspaces]를 선택하고 [Design] 옵션이 체크되었는지 확인한다.

[그림 44] 익스프레션 블렌드에서 현재 워크스페이스 선택하기



익스프레션 블렌드의 워크스페이스는 모든 시각적 인터페이스 요소로 구성된다. 여기에는 아트보드와 각종 패널, 도구 패널, 워크스페이스 구성, 저작 뷰, 메뉴가 포함된다.


5. 디자이너 창에서, "Click Me" 버튼을 오른 클릭한 뒤, 메뉴에서 [Object]|[Edit Template]|[Create Empty]를 선택한다.

6. [Create ControlTemplate Resource] 대화 상자에서 [Name]을 "FancyButton"으로 설정하고 [Define in]옵션의 "This document"를  현재 값으로 유지하고 [OK]를 클릭한다.

[그림 45] 해당 버튼에 대한 빈 컨트롤 템플릿을 생성한다



Resources는 정의된 객체와 값을 공통으로 재사용하는 간단한 방법을 제공한다. 컨트롤 템플릿과 스타일, 브러시, 컬러, 애니메이션 등의 공통 항목에 대한 정의를 만들고 리소스 사전에 저장할 수 있다. 리소스 사전은 XAML과 코드 둘 다에서 사용할 수 있는 핵심 개체의 사전이다. 애플리케이션 구조에서 다른 범위에서 리소스 사전을 만들 수 있고 페이지 수준에서 리소스를 정의하거나 애플리케이션 리소스로 정의할 수 있다.

위에 보인 대화상자는 전역 Application 범위에서 컨트롤 템플릿을 정의하는 옵션을 제공하는데, 이 옵션의 경우는 App.xaml에 저장되어 있고 애플리케이션의 다른 페이지에서 이 템플릿을 재사용할 수 있으며, 그렇지 않고 This document에서 저장하도록 하면 동일한 페이지 내에서만 리소스를 사용할 수 있다.


7. [Objects and Timeline] 패널이 보이지 않으면, [Window]|[Objects and Timeline]을 선택해 이 패널을 표시한다. 만일 기본 상태로 워크스페이스를 재설정하고 싶은 경우는 [Window]|[Reset Current Workspace]를 선택한다.

새로운 템플릿을 만들때, 익스프레션 블렌드는 새로운 템플릿을 보고 편집할 수 있는 모드로 들어간다. [Objects and Timeline] 패널에서 새로운 요소 트리의 루트에 있는 [Template]은 편집중인 현재 범위를 가리킨다.

8. 현재 템플릿의 루트 레이아웃 컨테이너를 변경하자. [Objects and Timeline] 패널에서, [Template]내의 자식 [Grid] 요소를 오른 클릭하고 [Change Layout Type]|[Border]를 선택한다.

[그림 46] 템플릿의 루트 레이아웃 컨테이너를 변경한다.


ControlTemplate을 만들때, FrameworkElement 개체를 결합해 하나의 컨트롤을 만든다. ControlTemplate은 루트 요소로서 하나의 FrameworkElement만 가져야 한다. 루트 요소는 보통 다른 FrameworkElement 개체들을 포함한다. 개체의 조합을 통해 컨트롤의 시각적 구조를 만든다.


9. [Objects and Timeline] 패널에서 [Borde] 요소가 선택된 상태에서 [Properties] 패널로 전환하고 [Appearance] 아래에서 [BorderThickness] 속성의 값을 각각 2로 설정한뒤 CornerRadius 속성의 값을 15로 설정한다.

[그림 47] 테두리 요소의 모양을 구성한다


10. 이제 [Brushes] 섹션에서 [Background] 속성을 선택하고 [Gradient brush] 옵션을 사용한다. 왼쪽 그라데이션 중지점을 클릭해  옅은 회색으로 값을 설정한다(예를 들면 #FFADADAD). 다음으로 오른쪽 그라데이션 중지점을 선택하고 값을 진한 회색으로 설정한다(예를 들면 #FF0A0A0A).

[그림 48] 버튼 배경색에 대해 그라데이션 브러시를 구성한다



11. [Brushes] 섹션에서, [BorderBrush] 속성을 선택하고 [Solid color brush]를 클릭하고 연한 회색(예를 들면, #FFC0C0C0)을 선택한다.

[그림 49] 버튼 테두리에 대한 단색 브러시 구성

12. 버튼에 대한 배경을 만들었다면, 다음 단계는 캡션을 추가하는 것이다. 먼저 [Objects and Timeline] 패널에서 Border 요소가 선택되어있는지 확인한다.
 
13. 다음으로 [Assets] 패널로 전환하고 [Controls] 범주를 선택한 뒤, 범주의 오른쪽에 표시된 스크롤을 내려서 TextBlock 컨트롤을 찾는다. 그 뒤 목록에서 해당 항목을 더블 클릭해 이 컨트롤의 인스턴스를 템플릿의 Border 요소내에 삽입한다.

[그림 50] 도구상자에서 TextBlock 컨트롤을 삽입한다

[그림 51] Border 요소내에 중첩된 새로운 TextBlock을 보여주는 [Objects and Timeline] 패널

14. 이제 [Tools] 패널에서 [Selection] 도구를 선택하거나 [V]를 눌러 선택 모드로 돌아 간다.

TextBlock을 삽입한 후, 디자이너는 삽입 모드를 유지하고 이 모드를 빠져나가기 전까지는 다른 TextBlock 요소를 계속추가할 수 있다.

 
15. [Objects and Timeline] 패널에서 새로 추가한 TextBlock 요소를 선택한다. 그 다음 [Properties] 패널에서 [Brushes] 범주를 확장하고 Foreground 브러시를 밝은 색(예를 들면, #FFFFFFFF)으로 설정한다.

[그림 52] 버튼의 전경색 설정



16. 다음으로 Layout 범주를 확장하고 HorizontalAlignment과 VerticalAlignment의 값을 가운데로 설정한다. 그 다음 [Margin] 속성의 값을 왼쪽과 오른쪽에 대해서는 10으로, 위쪽과 아래쪽의 경우는 4로 설정한다.

[그림 53] 캡션의 여백과 정렬 속성 구성



17. 템플릿에서 TextBlock 컨트롤의 Text 속성을 버튼 템플릿 컨트롤의 Content 속성과 연결한다. 이를 위해서는 다음의 작업을 수행한다.

  • [Common Properties] 범주를 확장한다.
  • [Advanced property options]를 클릭한다. 속성의 값 옆에 있는 작은 사각형 아이콘이다.
  • [Template Binding]을 선택해 이 속성에 바인딩할 템플릿 컨트롤의 속성 목록을 표시한다.
  • 이 목록에서 Content 속성을 선택한다.

 Text 속성의 값을 "Click Me"로 변경한다. 이 값은 버튼의 현재 Content 속성을 설정한다. 이 속성을 바인딩하고 나면 아이콘의 모양이 노란색으로 바뀐다.

[그림 54] 템플릿의 Text 속성을 바인딩한다.

18. [CTRL + S]를 눌러 파일을 저장한다.
이제 새로운 커스텀 버튼을 시험할 준비가 되었다. Expression Blend for Windows Phone을 사용해 실제 폰 장치나 에뮬레이터에서 윈도우 폰 애플리케이션을 실행할 수 있다. Device 패널 (Window 메뉴)을 열어보면, 애플리케이션을 미리보기할 대상을 선택할 수 있다. 익스프레션 블렌드에서 기본 값은 윈도우 폰 에뮬레이터다.

[그림 55] 애플리케이션을 실행해볼 대상 설정

19. [F5]를 눌러 애플리케이션을 빌드하고 실행한다. 약간의 텍스트를 입력하고 버튼을 클릭해보자.

[그림 56] 익스프레션 블렌드에서 애플리케이션 실행


Comment +1


이번 시간에는 만든 애플리케이션을 빌드, 배포하고 윈도우 폰 에뮬레이터에서 실행해서 제대로 동작하는지 시험한다. 그리고 중단점을 설정해, 디버거를 사용해 소스코드를 단계별 진행하면서 변수의 값을 검사하는 과정을 통해 비주얼 스튜디오를 사용해 에뮬레이터에서 실행하는 애플리케이션을 디버깅하는 짧은 경험을 해본다.

1. [솔루션 탐색기]에서 MainPage.xaml 파일을 오른 클릭해서 [View Code]를 선택해 코드 숨김 파일을 열자.

2. “Click Me”버튼에 대한 이벤트 처리기에서 실행을 중지하도록 중단점을 정의한다. 중단점은 소스 파일의  ClickMeButton_Click 메서드의 첫 번째 줄을 찾아서 편집창의 왼편에 위치한 회색 영역을 클릭한다. 붉은색으로 채워진 원이 삽입된 중단점을 가리킨다. 다른 방법으로 편집장의 해당 줄을 클릭하고 [F9]를 눌러도 된다.

[그림 37] 비주얼 스튜디오에서 중단점 설정



3. [F5]를 눌러 애플리케이션을 빌드하고 윈도우 폰 에뮬레이터로 배포한 뒤 디버깅 세션을 시작한다. 애플리케이션이 실행되고 메인 페이지를 표시할 때까지 기다린다.

4. 에뮬레이터 창에서 텍스트 상자를 클릭해 포커스 옮긴다. 소프트웨어 입력 패널(SIP)가 자동으로 열린다. 패널을 사용하거나 PAUSE/BREAK 키를 눌러 데스크톱 키보드를 사용해 메시지를 입력할 수 있다. 텍스트 상자에 약간의 텍스트를 입력한 후, 그 옆에 있는 버튼을 클릭한다.

[그림 38] 에뮬레이터에서 입력하기
 


5. 다시 비주얼 스튜디오로 돌아오면 이전에 설정한 중단점에서 실행이 중지되어 있고 실행할 다음 문장이 노란색으로 강조되어 있다.

[그림 39] 디버거로 코드 단계별 실행하기



6. 디버거에서 텍스트 상자의 현재 내용을 확인해보자. 소스 창에서 MessageTextBox.Text 속성위에 마우스를 올린다. 툴팁 창(일반적으로 데이터팁이라 한다)이 팝업되어 해당 속성의 현재 값을 표시하는데, 이것은 에뮬레이터 창에서 입력한 텍스트와 같다. 커서를 Text 부분위에 올리지 않으면 MessageTextBox 객체에 관한 정보가 대신 표시된다. 

[그림 40] 디버거에서 변수의 값 확인하기

7. [F10]을 눌러 현재 구문을 한번에 넘어가 배너의 텍스트를 텍스트 상자의 내용으로 설정한다. 배너 텍스트의 값이 해당 텍스트 상자의 내용과 일치하는지 확인하기 위해 BannerTextBlock.Text 속성에 대한 데이터팁을 표시해본다.

 [F10]을 사용하면 디버거에서 현재 구문을 넘어가도록 지시한다. [F11]을 사용하면 현재 구문속으로 들어갈 수 있다. 이런 경우는 해당 구문이 메서드 호출을 포함하는 경우, 디버거가 대상 메서드 속으로 들어가 디버깅을 하도록 해준다.

8. 일단 [F10]을 다시 한번 눌러 다음 구문을 실행하고 텍스트 상자의 내용을 지운다. 다시 한번 더  MessageTextBox.Text 속성에 대한 데이터팁을 표시해보고 값이 비었는지 확인하자.

9. 마지막으로 [F5]를 눌러 해당 애플리케이션의 실행을 계속한다. 필요한 경우 에뮬레이터 창의 화면 잠금을 해제 한다.

구성 설정에 의존하기 때문에, 윈도우 폰 에뮬레이터는 잠깐동안 애플리케이션에 입력이 없는 상태로 존재할 때마다 잠금 화면을 보일 수 있다. 애플리케이션으로 돌아가려면, "긋기" 제스처를 사용하자. 이 제스처는 에뮬레이터 창을 클릭하고 이어서 마우스 버튼을 누른채 빠르게 위로 이동하는 것이다.


[그림 41] 윈도우 폰 에뮬레이터에서 실횅중인 HelloPhone 애플리케이션



10. 에뮬레이터에서 [Back] 버튼을 클릭해 이전 페이지를 탐색한다. 이렇게 하면 애플리케이션의 디버깅 세션이 종료되고 첫 페이지를 벗어나게 디고 현재 실행중인 이전 애플리케이션이 없기 때문에 에뮬레이터는 시작 메뉴를 표시한다.

현재 세션 종료후 다시 디버깅을 하려면, [F5]를 눌러 애플리케이션 다시 실행하고 디버거를 연결하면 된다. 하지만 이 작업은 애플리케이션을 다시 시작하게 되고 이전 상태는 더 이상 유지하지 않는다. 에뮬레이터를 종료하면 애플리케이션을 중지하고 디버거를 분리한다. 이렇게 할 경우 비주얼 스튜디오는 디버거를 분리하고 해당 장치에 대한 연결을 잃었다는 메시지를 표시한다.


[그림 42] 애플리케이션 사용을 끝낼 경우 디버깅 세션 종료


 

Comment +0


이번에는 버튼 클릭 이벤트와 같은 사용자 인터페이스의 동작에 응답하는 이벤트 핸들러를 정의한다.해당 페이지의 코드 숨김 파일에서 코드로 이벤트 핸들러를 정의한다.

1. 디자이너의 모드가 "Design"으로 설정되었는지를 확인한다. 그렇지 않다면 디자이너 윈도우의 오른쪽 끄트머리의 디자인 탭을 더블클릭한다. 마우스 커서를 각 탭에 올려보면 툴팁으로 이름을 식별하도록 도와준다.

2. 디자이너 영역에서 "Clieck Me"라는 버튼을 클릭하고나서 F4를 눌러 [속성] 창을 연다.

3. 속성 창에서 [이벤트] 탭을 클릭해 현재 사용가능한 이벤트의 목록을 가진 창을 표시한다. 해당 목록에서 Click 이벤트를 찾아 이 이벤트 옆에 위치한 텍스트 상자에서 "ClickMeButton_Click"라고 입력한다. [엔터]를 누르면 이 이름을 가진 이벤트 핸들러를 생성하고 코드 숨김 파일을 열어 비주얼 스튜디오에서 생성한 메서드 스텁을 표시한다.

[그림 35] 버튼에 대한 이벤트 처리기 생성



[그림 36] XAML 뷰에서 Click 이벤트에 연결된 새로운 처리기를 표시한다.


4.메서드 구현은  MainPage.xaml.cs 파일에서 한다. 다음 코드를 ClickMeButton_Click 메서드의 본문내에 삽입한다.

private void ClickMeButton_Click(object sender, RoutedEventArgs e)
{
    BannerTextBlock.Text = MessageTextBox.Text;
    MessageTextBox.Text = String.Empty;

}

Comment +1

이번 시간에는 HelloPhone 애플리케이션에 대한 UI 요소를 만들어 본다. 이 애플리케이션은 아주 단순하다. 작업을 완료하면, 애플리케이션 UI는 캡션과 텍스트 상자, 그리고 버튼을 포함하게 된다. 이 애플리케이션을 사용하는 방법은 텍스트 상자에 약간의 텍스트를 입력하고 단추를 클릭하면, 애플리케이션에서 입력한 텍스트로 배너를 표시한다.

1. [솔루션 탐색기]에서 MainPage.xaml을 더블클릭해 디자이너에서 이 파일을 연다.

디자이너는 XAML 파일을 편집하기 위한 두 가지의 별도 뷰인 Design 뷰와 XAML 뷰를 제공한다. 디자인 모드에서 도구상자에서 컨트롤을 끌어다 놓는 인터랙티브 캔버스를 제공하고 있고 여기서 컨트롤들의 선택과 크기 변경, 이동, 속성 설정을 할 수 있다. XAML 모드에서는 마크업 편집기를 제공하므로 해당 페이지의 XAML을 편집할 수 있다. 디자이너 창의 탭으로 모드 변경을 한다. 분할 모드를 선택할 수도 있는데, 이 때는 편집 창이 동시에 두 개의 모드를 표시한다. 분할 모드에서 ExpandPane/CollapesePane 단추를 사용해 현재 모드의 보기 영역을 최대화 할 수 있다.

2. IDE에서 디자인 모드로 개체를 조작할 수 있지만, 이 작업에서는 XAML을 직접 편집하는데 초점을 둔다. 편집을 완료하고나면, 디자인 보기로 돌아와서 작업 결과를 검토해볼 것이다. 편집 모드를 XAML 보기로 설정하고 보기 영역을 최대화 하려면, 디자이너 창의 오른쪽 끝에 있는 XAML 탭을 더블 클릭한다. 마우스 커서를 탭위에 가져가면 해당 탭에 대한 툴팁을 표시한다.

[그림 32] XAML 뷰를 보여주는 XAML 디자이너

3. 기본 윈도우 폰 애플리케이션 템플릿이 생성한 XAML 마크업에서 LayoutRoot라는 Grid 컨테이너 요소를 찾는다. 이 것은 해당 페이지에서 요소들을 배치하기 위한 목적을 가진다. Grid 컨테이너의 RowDefinition 속성내에서 두 개의 기존 열 사이에 열을 추가하고 Height 속성을 Auto로 설정한다. 이 행에는 곧 텍스트 상자와 버튼을 하나 포함할 것이다.

...
  <Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
     ...
  </Grid>
</phone:PhoneApplicationPage>

Grid는 다른 컨트롤에 대한 컨테이너로 동작하는 레이아웃 요소다. 주요 목적은 자식 컨트롤의 위치를 정하고 배치하는 것이다. 몇몇 레이아웃 컨트롤은 대체 레이아웃 동작을 제공하기 위해 존재한다.

Canvas: 캔버스 영역에 상대적인 좌표를 사용해 자식 요소를 명시적으로 배치할 수 있는 영역을 정의한다.
Grid: 열과 행을 구성하는 유연한 그리드 영역을 정의한다.
StackPanel: 가로 또는 세로로 지정할 수 있는 한 줄에 자식 요소들을 배치한다.

더 자세한 내용은 실버라이트 레이아웃 시스템(
http://msdn.microsoft.com/ko-kr/library/cc645025(VS.95).aspx)을 참조하자.

4. 루트 Grid 요소는 다른 중첩 요소를 담고 있는데 각각은 Grid.Row 속성을 정의해 바깥 Grid의 다른 행에 할당된다. TitlePanel이라는 Grid 요소를 찾는다. 안쪽 Grid 내부의 첫 번째 TextBlock 요소의 Text 속성을 "Windows Phone 7" 문자열로 설정한다. 마찬가지로, 두 번째 TextBlock 요소의 Text 속성을 "Hello Phone"으로 설정한다.

[그림 33] 애플리케이션 캡션 설정

자식 요소를 컨테이너 그리드의 주어진 행에 할당하려면, 자식 요소 각각은 연결된 속성인 Grid.Row 속성에 대한 값을 지정해야 한다. 연결된 속성을 사용하면 다른 자식 요소에 부모 요소에서 정의한 속성에 대한 고유한 값을 지정할 수 있다. 이 경우 Grid 요소에 속하는 Row 속성이다.


5. 이제 ContentPanel이라는 Grid 요소를 찾아서 이 요소 내에 다음 XAML 마크업을 붙여 넣자

...
<Grid x:Name="LayoutRoot" Background="Transparent">
  ...
  <!--ContentPanel - place additional content here-->
  <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBox Grid.Column="0" Name="MessageTextBox" FontSize="{StaticResource PhoneFontSizeExtraLarge}" Margin="20,20,10,20"/>
    <Button Grid.Column="1" Name="ClickMeButton" Content="Click Me" HorizontalAlignment="Right" Padding="4" Margin="10,20,20,20" />
  </Grid>
</Grid>
...

Grid는 ColumnDefinitions 컬렉션에서 정의한 대로 각 열의 너비를 기반으로 페이지에서 자식 컨트롤을 배열한다. 첫 번째 열의 너비는 *로 지정되어 있는데, 이는 다른 모든 열이 할당된 이후 해당 행에서 사용되지 않은 공간을 채우도록 확장한다. 그리고 두 번째 열의 Auto는 해당 열의 콘텐츠에 맞도록 열의 크기를 조정한다.

6. 페이지의 디자인을 완료하기 위해, 사용자가 입력한 메시지를 배너로 담는 3 번째 행을 추가한다. 이 행을 만들려면, 다음 XAML 마크업을 바깥 Grid의 종료 태그 바로 전에 삽입한다.

...
<Grid x:Name="LayoutRoot" Background="Transparent">
  ...
  <Grid Grid.Row="2">
    <TextBlock Name="BannerTextBlock" Style="{StaticResource PhoneTextExtraLargeStyle}"
               Foreground="#FFFF9A00" HorizontalAlignment="Stretch"
               TextWrapping="Wrap" TextAlignment="Center" FontWeight="Bold" />
  </Grid>
</Grid>
...

7. 해당 창의 오른쪽 끝에 있는 [Design] 탭을 클릭해서 디자인 모드로 전환한다. 페이지의 컨트롤 레이아웃이 아래 그림과 같은지 검토한다.

[그림 34] 디자인 모드에서 페이지를 확인한다.

Comment +0


이번 시간에는 간단히 애플리케이션을 빌드하고 윈도우 폰 에뮬레이터로 배포한 뒤 실행하면서  일반적인 개발 주기를 이해해 보기로 하자.

1. [디버그] 메뉴에서 [Windows]-[Output]을 선택해 출력 창을 연다.
2. [Build] 메뉴에서 [Build Solution]을 선택하거나 [SHIFT]+[F6] 키 를 눌러 솔루션의 프로젝트를 컴파일 한다.
3. 출력창을 확인하고 빌드 과정에서 나온 메시지를 훑어 보자.

[그림 26] 비주얼 스튜디오에서 애플리케이션 빌드하기


4. 이 단계에서 오류가 발생할 일은 없지만, 혹 오류가 발생했다면, 출력창에 표시될 것이다. 이런 종류의 오류를 다루려면, [Error List] 창이 도움이 된다. 이 창은 에러의 심각도를 기준으로 걸러내고 분류하여 컴파일러에서 생성한 오류, 경고, 그리고 메시지를 표시한다. 더욱이 목록에 표시된 항목을 더블 클릭하면 관련 소스코드 파일을 자동으로 열어 오류가 난 부분을 찾아 준다. [Error List] 창을 열기위해서는 [View]-[Other Windows]-[Error List]를 선택한다.

[그림 27] 빌드 과정 동안 발생한 에러를 보여주는 오류 목록 창

5. 개발 대상이 윈도우 폰 에뮬레이터인지를 확인한다. 툴 바에서 [Start Debugging] 단추 옆에 있는 [Select Target] 드롭다운에서 [Windows Phone 7 Emulator]가 선택되어있는지 확인한다.

[그림 28] 애플리케이션을 배포할 대상 장치를 선택한다.


6. F5를 누르면 윈도우 폰 에뮬레이터에서 애플리케이션이 실행된다. 장치 에뮬레이터 창이 표시되고 비주얼 스튜디오에서 에뮬레이터 환경을 설정하고 애플리케이션 이미지를 배포하는 과정을 거치게 된다.

[그림 29] 윈도우 폰 에뮬레이터에 애플리케이션 이미지를 배포한다.


7. 폰 에뮬레이터가 준비되면, 에뮬레이터는 시작 페이지를 표시하고 바로 이어서 에뮬레이터 창에 애플리케이션을 표시한다.

[그림 30] 윈도우 폰 에뮬레이터에서 애플리케이션 실행


8. 사용자 인터페이스를 만들고 애플리케이션 로직을 프로그래밍 할 때까지는 이 단계에서 애플리케이션으로 할 수 있는 일이 거의 없다. 툴 바에서 [SHIFT]+[F5]를 누르거나 [Stop] 단추를 클릭해 디버깅 세션을 종료한다. 에뮬레이터 창은 종료하지 않는다.

[그림 31] 디버깅 세션 종료


팁) 디버깅 세션을 시작할 때, 에뮬레이터 환경을 설정하고 애플리케이션을 실행하는데 시간이 제법 걸린다. 디버깅 경험의 능률을 올리려면, 비주얼 스튜디오에서 소스 코드를 작업하는 동안 에뮬레이터를 종료하지 않도록 한다. 에뮬레이터를 일단 실행하면, 현재 세션을 중지하고 소스 코드를 편집 한 뒤, 애플리케이션의 새로운 이미지를 빌드하고 배포해 새로운 디버깅 세션을 시작하는데 시간을 단축할 수 있다.

Comment +0


Microsoft Visua Studio 2010(앞으로 VS 2010으로도 표시한다)나 Microsoft Visual Stuido 2010 Express for Windows Phone(VS 2010 Express와 Windows Phone 개발자 도구를 설치한 경우)를 실행하고 "Silverlight for Windows Phone Application" 프로젝트를 통해서 첫 번째 애플리케이션을 만들어 보자.

1. [시작]-[모든 프로그램]-[Microsoft Visua Studio 2010]-[Microsoft Visua Studio 2010]을 클릭하고 VS 2010을 실행한다.

2. [File]-[New Project]를 선택한다.

3. [New Project] 대화상자의 템플릿 목록에서 "Silverlight for Windows Phone" 범주의 "Windows Phone Application" 템플릿을 선택한다. 그 다음 [Location] 필드에 앞 시간에 설치한 트레이닝 킷 Lab의 Source 폴더에서 "Ex1-CreatingWP7AppsWithVisualStudio"를 선택하고 Name 필드에 "HelloPhone"이라고 입력한다. [Solution Name] 필드에는 "Begin"이라 입력하고 [OK]를 클릭한다.

[그림 19]


4. 솔루션 탐색기에서 윈도우 폰 애플리케이션 템플릿이 생성한 솔루션의 구조를 살펴보자. 모든 Visual Studio 솔루션은 관련된 프로젝트들을 위한 컨테이너다. 이 경우 HelloPhone이라는 하나의 "Silverlight for Windows Phone" 프로젝트를 담고 있다.

[그림 20]

HelloPhone 프로젝트에 표시된 항목들을 다음 [표 1]에서 설명했다.

[표 1]

 항목  설명
 App.xaml/App.xaml.cs  애플리케이션의 진입점을 정의하고 애플리케이션에 사용되는 리소스를 초기화 하며, 애플리케이션 사용자 인터페이스를 표시한다.                               
 MainPage.xaml / MainPage.xaml.cs  애플리케이션의 사용자 인터페이스를 가진 페이지를 정의한다.
 ApplicationIcon.png  폰의 애플리케이션 목록에서 해당 애플리케이션 아이콘을 표시하는 이미지 파일이다.
 Background.png  시작 화면에서 애플리케이션 아이콘을 나타내는 이미지 파일이다.
 SplashScreenImage.jpg  애플리케이션을 실행할 때 처음 표시될 이미지다. 스플래시 스크린은 사용자에게 애플리케이션일 실행중라는 피드백을 제공하고 첫 번째 페이지에 대한 탐색이 완료될 때까지 표시된다. 스플래시 스크린은 애플리케이션을 빠르게 로드하는 인상을 주기위해 첫 번째 페이지와 유사한 인상을 준다.
 Properties\AppManifest.xml  애플리케이션 메니페스트 파일로 애플리케이션 패키지를 생성하는데 필요하다.
 Properties\AssemblyInfo.cs  생성된 어셈블리에 내장된 이름과 버전 메타데이터를 담고 있다.
 Properties\WMAppManifest.xml  윈도우 폰 실버라이트 애플리케이션에 관련된 특정 메타데이터를 포함하는 메니페스트 파일로, Silverlight for Windows Phone에 대해서만 사용가능한 특정 기능을 담고 있다.
 References 폴더  애플리케이션이 동작하는데 필요한 서비스와 기능을 제공하는 라이브러리(어셈블리) 목록


5. 먼저 [솔루션 탐색기]에서 App.xaml을 오른클릭하고 [View Designer]를 선택한다. 이 파일은 Application 이라는 루트 요소와 그 내부에 Application.Resources 섹션을 가진 XAML 마크업을 담고 있다. Application.Resources 섹션안에서 애플리케이션에 사용되는 색상, 브러시, 스타일 개체와 같은 애플리케이션 수준 리소스를 정의할 수 있다.

이 XAML 코드는 Application 의 ApplicationLifetimeObjects 속성을 초기화해 PhoneApplicationService 개체를 생성한다. PhoneApplicationService 클래스는 애플리케이션의 수명주기의 여러 측면에 대한 접근을 제공한다. 이것은 애플리케이션의 이상적인 동작의 관리와 이 서비스가 활성화되거나 비활성화 될 때 애플리케이션의 관리를 포함한다.

[그림 21] Windows Phone 애플리케이션 템플릿으로 생성한 기본 App.xaml 파일


6. [솔루션 탐색기]에서 App.xaml을 오른클릭하고 [View Code]를 선택해 코드 숨김 파일을 연다. 생성자에서 이 Application에서 상속된 클래스는 이미 UnhandledException 이벤트에 대한 핸들러를 이미 구독하고 있다. Applicaton 클래스에서 RootFrame 속성 부분은 해당 애플리케이션의 시작 페이지를 식별한다. 모든 윈도우 폰 애플리케이션은 하나의 최상위 수준 컨테이너 요소를 가지고 있고 이 요소의 데이터 타입은 PhoneApplicationFrame이다. 이 프레임은 애플리케이션에 대한 콘텐츠를 나타내는 하나 이상의 PhoneApplicationPage 요소를 호스트 한다. 이 프레임은 페이지간의 탐색도 처리한다.

[그림 22] 전역 이벤트 핸들러를 표시하는 애플리케이션 코드 숨김 파일


Silverlight for Windows Phone 애플리케이션에 의해 만들어진 Application 클래스는 Launching과 Closing 이벤트에 대한 핸들러도 포함한다. 이들 메서드를 업데이트해 윈도우 폰 애플리케이션을 시작하고 종료할 때 커스텀 코드를 실행할 수 있다.


7. 만들어진 프로젝트에는 애플리케이션의 주 UI를 정의하는 XAML 마크업을 담고 있는 기본문서를 포함한다. 디자이너에서 이 파일을 보려면, [솔루션 탐색기]에서 MainPage.xaml을 더블클릭한다.

기본적으로 디자이너는 해당 문서를 분할 뷰로 표시한다. 한 창은 XAML 마크업을 표시하고 다른 창은 사용자 인터페이스 요소의 WYSIWYG 화면으로 디자인 뷰를 표시한다.애플리케이션 이름과 제목을 표시하기위해 템플릿에 의해 포함된 요소들(필요하지 않다면 제거 가능)을 제외하면, XAML 문서는 빈 캔버스를 제공하는데, 여기에 컨트롤들을 추가해 애플리케이션의 사용자 인터페이스를 만든다.

[그림 23] 애플리케이션의 주 사용자 인터페이스를 표시하는 XAML 디자이너

XAML(Extensible Application Markup Language)은 선언형 언어다. 선언형 XAML 마크업으로 UI 요소를 만들 수 있다. 별도의 코드 숨김 파일을 사용해 이벤트에 응답하고 XAML로 선언한 개체를 조작할 수 있다. XAML 기반 선언형 언어는 아주 직관적이어서 프로토타입에서 제품이 되는 인터페이스를 만드는데 유용하며, 특히 웹 디자인과 기술에 배경을을 가진 사람들에게 편리하다.


8. Application.png 파일은 폰의 빠른 실행 화면에서 애플리케이션을 식별하는 아이콘을 담고 있다. [솔루션 탐색기]에서 해당 항목을 더블클릭해 파일을 열어 관련 그림 편집 도구로 편집할 수 있다.

9. 윈도우 폰 애플리케이션은 전형적으로 기초가 되는 플랫폼이나 다른 라이브러리에 의해 제공되는 서비스를 이용한다. 이 기능을 사용하려면, 애플리케이션은 이들 서비스를 구현하는 해당 어셈블리를 참조해야 한다. 프로젝트에서 참조하는 어셈블리를 표시하려면 [솔루션 탐색기]에서 [References] 노드를 확장하고 해당 목록을 살펴보자. 여기에는 정규 실버라이트 어셈블리 뿐만 아니라 윈도우 폰 플랫폼관련 어셈블리가 있다.

[그림 24] 솔루션 탐색기에서 프로젝트가 참조하는 어셈블리 표시 



10. 아래 그림에서 보인것 처럼 프로젝트의 속성 창에서 WP 메니페스트 파일을 편집한다. 이 창을 열어보려면, [솔루션 탐색기]에서 HelloPhone 프로젝트를 오른 클릭하고 [속성]을 선택한다.

[그림 25] 프로젝트 속성 창


윈도우 폰 프로젝트 속성 창을 사용하면 폰 관련 속성을 수정할 수 있다. 이들 속성은 장치상의 애플리케이션 배포와 표시에 관련된다. 이 파라미터들은 WMAppManifest.xml 파일에 저장된다. XML 파일을 직접 변경했더라도 이 창에서 프로젝트 설정을 변경하고 저장할 때마다 덮어쓰게 된다.


 

Comment +0


2. Windows Phone 개발도구와 트레이닝 킷 설치

앞서 [Windows Phone 개발 준비하기]에서 다운로드해 놓은 도구들을 설치 해보자. 개발 도구를 설치하기 위해서는 반드시 Visual Studio 2010이 먼저 설치되어 있어야 한다. 다운로드한 설치파일의 크기는 3.2 MB 정도이나 실제 설치를 진행해 보면 인터넷을 통해 356 MB 정도의 파일을 내려 받으면서 설치가 진행된다. 따라서 사용하는 컴퓨터는 반드시 인터넷에 연결된 상태여야 한다.

다운로드 받은 "vm_web.exe"을 더블 클릭하면 초기화 과정을 거쳐 실행된. [그림 10]의 [라이선스 동의] 화면에서 [Accept]를 클릭하면 [그림 11]과 같은 [설치 방법] 선택 화면이 표시된다.

[그림 10]

[그림 11]

[Install Now]를 선택하면 웹에서 설치파일을 다운로드 하면서 설치과정이 진행된다([그림 12] 참조).

[그림 12]


설치과정을 모두 완료하고 [시작]-[모든 프로그램]-[Microsoft Visual Studio 2010 Express for Windows Phone]을 클릭하면([그림 13] 참조) [그림 14]와 같은 화면이 실행된다.

[그림 13]


[그림 14]


개발 도구의 설치가 성공적으로 끝났다면, 이제 학습을 위한 트레이닝 킷을 설치 해보자. 다운로드 받은 166 MB 정도의 크기를 가진 트레이닝 킷을 더블클릭 한다. 라이선스 동의 화면([그림 15])에서 [Accept]를 클릭하고 설치 위치([그림 16])를 선택한 다음 [Install]을 클릭한다.

[그림 15]


[그림 16]

설치과정이 모두 완료되고 나면 트레이닝 킷의 웹 메인화면이 표시된다 ([그림 17] 참조). 관련 소스코드와 트레이닝 킷 콘텐츠는 [그림 18] 처럼 트레이닝 킷의 설치 위치를 찾아보면 된다.

[그림 17]

[그림 18]


와우! 이제 Windows Phone 7 학습을 위한 모든 준비가 끝났다. 다음 시간 부터 트레이닝 킷을 통해 본격적으로 Windows Phone 개발을 경험해 보자.

Comment +0

1. Visual Studio 2010 다운로드와 설치

현재 구매하여 사용가능한 Visual Studio 2010의 제품 라인업은 PROFESSIONAL, PREMIUM, ULTIMATE, TEST PROFESSIONAL의 4가지가 있으며 각 버전 별 비교 내용은 다음의 웹사이트를 참고하자.

http://www.microsoft.com/visualstudio/ko-kr/products

평가판으로 사용가능한 Visual Studio 2010 버전은 아래 사이트에서 다운로드 가능하다.
http://www.microsoft.com/visualstudio/ko-kr/download

완전히 무료로 사용할 수 있는 Visual Studio 2010 Express 버전도 사용할 수 있다. 무료 버전으로는, Visual Basic 2010 Express, Visual C# 2010 Express, Visual C++ 2010 Express, Visual Web Developer 2010 Express가 있으며, 각각의 버전을 따로 다운로드 받을 수도 있고 전체를 하나로 만들어 놓은 이미지 파일을 받을 수도 있다.  다운로드 사이트는 다음과 같다.

http://www.microsoft.com/express/Downloads/

여기서 웹 설치 보다는 나중에 오프라인에서도 설치가 가능한 버전을 원한다면 All-OfflineInstall ISO image file을 클릭하면 펼쳐지는 드롭다운 목록에서 사용할 언어를 선택한다([그림 1] 참조). 이제 [그림 2]와 같이 다운로드가 실행된다.

[그림 1]


[그림 2]

대략 1.7GB 정도의 ISO 이미지 파일을 모두 다운로드 하고 나면 이제 설치 과정을 진행해보자.

ISO 이미지에서 설치프로그램을 실행하기 위해 ISO 이미지를 가상 장치로 연결할 수 있는 도구인 데몬툴즈를 이용한다. 데몬툴즈는 아래 사이트에서 다운로드 할 수 있다.

http://www.daemon-tools.cc/kor/downloads

[그림 3]에서처럼 ISO 이미지를 연결하면 [그림 4]와 같은 [자동 실행] 창이 뜬다.
 
[그림 3]


[그림 4]

"setup.hta 실행"을 클릭하면 [그림 5]와 같은 [Visual Studio 2010 설치 시작] 화면이 표시되고 여기서 [Visual C# 2010 Express]를 선택해서 설치를 진행하자([그림 6] 참조).

[그림 5]

[그림 6]

[설치 완료] 화면이 표시되면 [마침]을 클릭하고 [그림 7]의 화면에서 [지금 다시 시작]을 클릭해 윈도우를 다시 시작한다.

[그림 7]


윈도우를 다시 시작하고 [시작]-[모든 프로그램]-[Microsoft Visual Studio 2010 Express]를 클릭하면([그림 8] 참조) [그림 9]와 같은 Microsoft Visual C# 2010 Express가 실행된다.

[그림 8]


[그림 9]

Comment +0


Windows  Phone 7은 이미 미국에서는 출시 되었지만, 한국 출시는 2011년 중반 이후로 점쳐지고 있습니다. 현재의 스마트폰 시장은 아이폰과 안드로이드 폰의 대결 구도이고 기능상으로는 어느하나 빠지지 않는 강력한 하드웨어를 자랑하지만 혁신으로 대표되는 ios와 개방으로 대표되는 안드로이드는 사용자에게는 풍부한 애플리케이션을 쉽게 이용할 수 있고  편리한 인터넷 접속 환경의 제공과 강력한 콘텐츠 소비 디바이스로 다가 왔고, 개발자에게는 골드러시를 연상케하는 앱 개발 붐을 낳았습니다.

이제 여기에 새로운 하나의 스마트폰인 Windows Phone 7을 들고 등장한 마이크로소프트는 잠깐 방심한 사이에 빼앗겨버린 스마트폰의 주도권을 가져오고자 각고의 노력의 하고 있습니다. 이제 바야흐로 신 스마트폰 삼국지가 시작되고 있습니다. 2011년은 스마트폰 삼국지와 수 많은 태블릿의 등장으로 모바일 디바이스의 홍수를 이룰것이며, 사용자는 다양한 선택의 기로에서 즐거움을 누리지 않을 까요?

이제 Windows Phone 7 개발에 살짤 발을 담그고 멀게만 느껴졌던 스마트폰 앱 개발을 시작해 볼까요.
Windows Phone 7 개발에는 필요한 기술 요소는 다음과 같습니다.

  • C#
  • Silverlight
  • UX 디자인
  • XNA

Windows Phone 7 개발에 필요한 도구로는 이런게 필요합니다.


Windows Phone 7 개발을 학습하는데 유용한 리소스로는 마이크로소프트가 제공하는 다음의 자료들이 있습니다. 이번에 연재하는 강의는 입문 성격의 강의로 개발자 트레이닝 킷의 내용을 필요한 부분 위주로 한글화 하여 설명합니다.

Comment +0