InkPresenter 방명록 만들기 - 3. Undo & Redo 구현하기


1. InkPresenter 객체 겉핥기 (InkPresenter XAML 구조)
2. InkPresenter를 사용한 간단한 샘플 만들어보기 (작동완구)
3. Undo & Redo 구현하기
4. InkPresenter User Control 만들기
5. Color Palette User Control 만들기
6. Ink Thickness Palette User Control 만들기
7. HTTP Request와 Response를 이용하여 정보 교환하기 (Get, Post 전송)
8. Page Navigation User Control 만들기


안녕하세요. 3부입니다.
불가*스가 1,200원으로 올라 아침부터 기분이 약간 상했습니다.
상한 기분을 강좌로 차분하게 달래 볼까합니다. ^^

(첨부된 파일은 2부 강좌의 누적 소스입니다.)

1. Page xaml에 Undo, Redo 버튼을 만들어 줍니다.

저같은 경우는 아래 그림같이 하고 넘어갔습니다.
하는 김에 Clean 버튼도 만들어 줍니다.
오른쪽의 밝은 색 버튼 보이시죠? 스토리보드 같은 사치스러운 것은 생략!

사용자 삽입 이미지






















사용자 삽입 이미지

XAML 트리에서 보시면

아래쪽에 cvUndo와 cvRedo라는
Canvas가 새로 추가되었습니다.

C# 코드로 이벤트를 할당하기 위해
손수 이름을 지어주었구요.

Rectangle 위에 Text를 위치하고
Canvas로 싼 다음에 Canvas에 이벤트를 주는
이유는 Rectangle에 이벤트를 주게되면
Text 위에 마우스를 올렸을 때
Rectangle의 Mouse Event가
일어나지 않기 때문입니다.







2. Undo, Redo Buffer 추가


Undo, Redo는 이거 하나면 끝입니다.

Page.xaml.cs 파일의 Page 클래스에 멤버 변수로 아래 것을 추가합니다.

// Undo, Redo용 버퍼
StrokeCollection UndoBuffer = new StrokeCollection();


3. Undo, Redo, Clear 버튼 이벤트

Page.xaml.cs 파일의 Page_Loaded 함수에 아래를 추가하고

// Undo, Redo Event
cvUndo.MouseLeftButtonUp += new MouseEventHandler(cvUndo_MouseLeftButtonUp);
cvRedo.MouseLeftButtonUp += new MouseEventHandler(cvRedo_MouseLeftButtonUp);

// Clear Event
cvClear.MouseLeftButtonUp += new MouseEventHandler(cvClear_MouseLeftButtonUp);

각각의 함수를 아래와 같이 구현합니다.

// Undo
void cvUndo_MouseLeftButtonUp(object sender, MouseEventArgs e)
{
    if (ink.Strokes.Count == 0)
        return;

    Stroke oUndo = ink.Strokes[ink.Strokes.Count - 1];
    UndoBuffer.Add(oUndo);
    ink.Strokes.RemoveAt(ink.Strokes.Count - 1);
}

// Redo
void cvRedo_MouseLeftButtonUp(object sender, MouseEventArgs e)
{
    if (UndoBuffer.Count == 0)
        return;

    Stroke oRedo = UndoBuffer[UndoBuffer.Count - 1];
    ink.Strokes.Add(oRedo);
    UndoBuffer.RemoveAt(UndoBuffer.Count - 1);
}

// Clear
void cvClear_MouseLeftButtonUp(object sender, MouseEventArgs e)
{
    ink.Strokes.Clear();
}


4. FlushBuffer 함수

사용자가 새로 획을 그을 때마다 UndoBuffer를 비워(Flush)주지 않으면,
원치 않는 결과를 초래할 수 있습니다. (간혹 원하는 사람도 있겠죠...)

예를 들어 [1]획, [2]획, [3]획까지 그리고 Undo를 누르면,
화면에는  [1], [2] 획이 표시되고, UndoBuffer에는 [3]획이 존재하게 됩니다.

여기서 사용자가 [4]획을 그은 후에, Redo 버튼을 누르면, 화면에는
[1], [2], [4], [3]이 표시되게 됩니다.

이런 결과를 원치 않으시는 분만 아래를 보시면 되겠습니다.

간단하게 FlushBuffer를 구현합니다.

void FlushUndoBuffer()
{
    UndoBuffer.Clear();
}

이제 이걸 언제, 어디서 불러줘야 할까요?
맞습니다. 새로 획을 그을 때마다 불러줘야 합니다.

2부에서 구현했던 StartNewStroke() 함수와
조금 전 구현한 Clear 버튼 MouseLeftButtonUp 이벤트 함수에 살포시 끼워 넣습니다.

void StartNewStroke()
{
    _strokeCurrent = AllocStroke();
    ink.Strokes.Add(_strokeCurrent);

    // Undo, Redo 버퍼 초기화
    FlushUndoBuffer();
}

...

// Clear
void cvClear_MouseLeftButtonUp(object sender, MouseEventArgs e)
{
    ink.Strokes.Clear();

    // Undo, Redo 버퍼 초기화
    FlushUndoBuffer();
}


3부는 이것으로 마칩니다.

샘플을 작동해보실 수 있는 모델하우스 :
http://www.shiverlight.net/InkPresenterSample/InkPresenterSample_UndoRedo


4부도 기대해 주세요.
감사합니다. 꾸벅!


설정

트랙백

댓글