InkPresenter 방명록 만들기 - 4. InkPresenter User Control 만들기


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 만들기

안녕하세요 오랜만입니다.

0. Sample Project

샘플 프로젝트 먼저 보는 것으로 4부를 시작하겠습니다.
백문이 불여일견. 코드 아무리 보면 뭐합니다. 일단 만져보는게 백번 낫죠?

체험장 : http://www.shiverlight.net/InkPresenterSample/InkPresentationSample_UserControl/

사용자 삽입 이미지

일단 배경 이미지 다섯 개를 준비했습니다.
랜덤하게 배경을 깔아주고 그 위에 Ink로 쓰실 수 있습니다.

Save 버튼 위에 있는 버튼을 누르면 배경을 바꿀 수 있습니다. (랜덤입니다.)

Save 버튼을 누르면 바로 전까지 그림 그리면 가지고 놀던 그 UserControl이
아래 List에 추가됩니다. 그리고 새 UserControl이 준비됩니다.
이것은 어디까지나 샘플입니다 DB같은데 저장되는 것은 아닙니다.

자세한 설명은 생략하겠습니다.
첨부한 프로젝트의 소스코드를 보시면 다 이해하실 것이라 믿습니다.


PS. 첨부한 프로젝트는 이전 강좌의 누적판으로 준비했습니다.


1. User Control 구상 (UCInk.xaml)

User Control을 만들어 사용할 때의 이점은 모두 다 아시리라 믿고 본론 들어갑니다.

일단 아래와 같은 스펙을 구상해 볼 수 있겠습니다.

사용자 삽입 이미지

하나 더, 외부에서 사이즈를 줘서 마음먹은 크기로 만들 수 있게 하면 좋겠죠.


2. UCInk.xaml 생성하고 프로퍼티 준비

새 실버라이트 프로젝트를 생성한 후,
VS2008의 솔루션 탐색기에서 프로젝트 이름에 오른쪽 클릭하고 추가 - 새 항목을 누릅니다.
새 항목 추가 대화상자의 템플릿 중, Silverlight User Control을 선택하고,

이름을 UCInk.xaml 이라 합니다.

UCInk.xaml 파일에 아래와 같이 이름이 "ink"인 InkPresenter 객체를 추가합니다.

<Canvas xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Background="White"
        >
  <InkPresenter x:Name="ink" Background="White"/>
</Canvas>


그리고 UCInk.xaml의 코드 비하인드인 UCInk.xaml.cs 파일을 열어,

User Control 내부의 객체를 컨트롤 하기 위 UCInk 클래스에 아래 프로퍼티를 추가합니다.

InkPresenter _ink;
Canvas _cvMyself;

생성자를 아래와 같이 변경합니다.

public UCInk()
{
    System.IO.Stream s =
 this.GetType().Assembly.GetManifestResourceStream("InkPresentationSample_UserControl.UCInk.xaml");
    _cvMyself = this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd()) as Canvas;

    _ink = _cvMyself.FindName("ink") as InkPresenter;
}

이제 여러분은 _ink를 통해서 InkPresenter 객체를 콘트롤 할 수 있게 된 것입니다.


InkPresenter의 배경이미지와 편집 가능여부를 자유롭게 변경하기 위해 아래 프로퍼티를 또 추가합니다.

public bool Editable { get; set; }

Uri _BackImage = null;
public Uri BackImage { get { return _BackImage; } set { SetBackgroundImage(value); } }

기본 생성자를 아래와 같이 변경하고,
SetBackgroundImage, UpdateSize 함수를 추가합니다.

public UCInk(Size sz, bool bEditable)
{
    System.IO.Stream s =
 this.GetType().Assembly.GetManifestResourceStream("InkPresentationSample_UserControl.UCInk.xaml");
    _cvMyself = this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd()) as Canvas;

    _ink = _cvMyself.FindName("ink") as InkPresenter;

    // 사이즈 설정
    UpdateSize(sz);

    // 편집 가능 여부
    Editable = bEditable;
}

void SetBackgroundImage(Uri uri)
{
    if (uri == null)
        return;

    _BackImage = uri;

    ImageBrush ib = new ImageBrush();
    ib.ImageSource = _BackImage;
    _ink.Background = ib;
}

void UpdateSize(Size sz)
{
    // Control 사이즈
    Width = sz.Width;
    Height = sz.Height;

    // 무시해도 좋지만 해주면 좋음
    _cvMyself.Width = Width;
    _cvMyself.Height = Height;

    // InkPresenter 사이즈
    _ink.Width = Width;
    _ink.Height = Height;
}


Ink 쓰기를 가능하게 하기 위해, 3부에서 많이 익숙해지신 아래 녀석들을 클래스 프로퍼티로 추가합니다.

// Ink 쓰기와 관련
Stroke _strokeCurrent = null;
StrokeCollection _oUndoBuffer = new StrokeCollection();


3. Ink 쓰기 구현

3부에서 했던 것이라 쉽습니다.

생성자에 Ink 쓰기 이벤트 4종 세트를 추가합니다.

// InkPresenter Mouse Event 필수 4종세트
_ink.MouseLeftButtonDown += new MouseEventHandler(ink_MouseLeftButtonDown);
_ink.MouseMove += new MouseEventHandler(ink_MouseMove);
_ink.MouseLeftButtonUp += new MouseEventHandler(ink_MouseLeftButtonUp);
_ink.MouseLeave += new EventHandler(ink_MouseLeave);

각각 함수는 아래와 같이 구현됩니다. 3부에서 보신 함수와 거의 같습니다만,
편집 가능/불가능 여부를 지원하기 위해 ink_MouseLeftButtonDown함수에서
변수 Editable을 체크하고 있습니다.

void ink_MouseLeftButtonDown(object sender, MouseEventArgs e)
{
    if (Editable == false)
        return;

    _ink.CaptureMouse();
    StartNewStroke();
}

void ink_MouseMove(object sender, MouseEventArgs e)
{
    if (_strokeCurrent == null)
        return;

    _strokeCurrent.StylusPoints.AddStylusPoints(e.GetStylusPoints(_ink));
}

void ink_MouseLeftButtonUp(object sender, MouseEventArgs e)
{
    _ink.ReleaseMouseCapture();
    _strokeCurrent = null;
}

void ink_MouseLeave(object sender, EventArgs e)
{
    _strokeCurrent = null;
}

아래 AllocStroke, StartNewStroke, Flush_oUndoBuffer 함수에 대한 내용은 3부에서
다뤘으므로 설명을 생략하도록 하겠습니다.

Stroke AllocStroke()
{
    // 스트로크 준비 흰색
    Stroke stroke = new Stroke();
    stroke.DrawingAttributes.Color = Colors.White;
    stroke.DrawingAttributes.OutlineColor = Colors.Black;
    stroke.DrawingAttributes.Width = 2;
    stroke.DrawingAttributes.Height = 2;

    return stroke;
}

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

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

void Flush_oUndoBuffer()
{
    _oUndoBuffer.Clear();
}


4. public Method 구현 (Undo, Redo, Clear)

public void Undo()
{
    if (_ink.Strokes.Count == 0)
        return;

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

public void Redo()
{
    if (_oUndoBuffer.Count == 0)
        return;

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

public void Clear(bool bClearBackImage)
{
    _ink.Strokes.Clear();
    if (bClearBackImage == true)
    {
        _ink.Background = null;
    }

    Flush_oUndoBuffer();
}

Undo, Redo는 3부에서 다룬 내용과 다르지 않습니다.
Clear에 보시면, 배경이미지를 함께 지울 것인지 파라미터로 받고 있습니다.

감사합니다.
그럼 다음 5부에서 또 뵙겠습니다.



설정

트랙백

댓글