생애 첫 번째 윈도우 폰 7 애플리케이션 만들기 5회
1. 솔루션 탐색기]의 PuzzlePage.xaml의 코드 숨김 파일을 연다.
2.
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 메서드의 본문에 삽입한다.
{
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;
}
}
}
}
}
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;
}
}
movingPiece.SetValue(axisProperty, normalizedValue + this.movingPieceStartingPosition);
}
}
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.movingPieceStartingPosition = 0;
this.movingPieceDirection = 0;
this.lastTapTicks = DateTime.Now.Ticks;
}
}
8. 이전 단계를 완료한 후, 해당 페이지의 [속성] 창을 열어 알맞은 이벤트 해늗러를 생성했는지를 확인한다. 해당 페이지에 대한 XAML 마크업을 살펴보면, PhoneApplicationPage 요소에 정의된 해당 특성들을 보게 될 것이다.
[그림 14] manipulation 이벤트 핸들러를 보여주는 속성 창
[그림 15] 이벤트 구독을 보여주는 해당 페이지의 XAML 마크업
9. 추가된 멀티 터치에 대한 지원을 테스트하려면, [F5]를 눌러 애플리케이션을 빌드하고 에뮬레이터로 배포한다. 시작화면이 표시되기를 기다린 뒤 [START]를 클릭해 새로운 게임을 시작한다.
10. 보드의 조각을 드래그해서 퍼즐을 푼다. 조각을 움직이려면 해당 조각을 클릭하고 목적지로 드래그 한다. 조작을 더블클릭 하면 다음의 사용 가능한 슬롯으로 이동한다. 각 이동에 따라 퍼즐 보드 위의 카운터가 증가한다.
[그림 16] 퍼즐 풀기