'UserControl'에 해당되는 글 3건

  1. 2007/12/14 Blend를 통해 User Control 추가하기 (1)
  2. 2007/11/07 InkPresenter 방명록 만들기 - 5. Color Palette User Control 만들기 (2)
  3. 2007/10/23 InkPresenter 방명록 만들기 - 4. InkPresenter User Control 만들기
2007/12/14 13:02

Blend를 통해 User Control 추가하기

1. 자신의 어플리케이션에 User Control을 추가하는 두가지 방법

(1) 비하인드 코드에서 동적으로 생성하는 방법

MyUserControl oControl = new MyUserControl();
Children.Add(oControl);

(2) XAML 코드에 추가하는 방법

<MyProject:MyUserControl Width="510" Height="40" Canvas.Left="402" Canvas.Top="50" x:Name="oControl"/>


위와 같은 코드를 직접 XAML 파일에 적어 넣어도 되지만,
Microsoft Blend에서 User Control을 추가하면 XAML파일에 위와 같은 코드가 자동으로 추가됩니다.

(1)번 방법은 개수가 정해지지 않고 복수개 생성될 때 유리하고,
(2)번 방법은 한 두개 생성해서 쓰면서 전체 레이아웃에 적절히 배치해야 할 경우
Microsoft Blend를 통해 디자인 수정할 수가 있어서 유리합니다.


2. Blend를 통해 User Control을 추가하기

Blend에서 User Control을 추가하기 위해서 왼쪽 툴바의 Asset Library를 클릭합니다.

사용자 삽입 이미지

그러면 Asset Library 다이얼로그가 뜹니다. 거기서 Custom Controls 탭을 선택하시면
현재 솔루션에 포함된 Blend에서 XAML형태로 추가 가능한 User Control이 표시됩니다.

사용자 삽입 이미지

(혹시 자신이 만든 User Control이 안보인다면 - 아래 글 3번을 먼저 읽으십시오.)

여기서 Canvas에 추가하고 싶은 User Control을 클릭합니다.
그러면 왼쪽 툴바에 선택한 User Control 아이콘이 추가되고,
동시에 그 User Control을 추가할 수 있는 상태가 됩니다.

디자인 영역에 마우스로 적당한 위치에 클릭하시고 드래그 하시면,
User Control이 추가됩니다.

사용자 삽입 이미지

눈에 보이는 것은 없지만, 위치, 사이즈 등은 결정해 줄 수 있습니다.

그리고 실행을 해보면 다음과 같은 User Control이 정상적으로 생성되어서 보입니다.

사용자 삽입 이미지


3. XAML형태를 통해 추가하고자 하는 User Control이 지켜야 할 사항

그렇다면 내가 만든 User Control이 (Blend를 통하든 안통하든) XAML형태로 추가되려면 어떻게 해야하느냐?

기본 생성자를 반드시 가지고 있어야 합니다.

기본 생성자는 파라미터를 하나도 받지 않는 생성자를 말합니다.
이 규칙만 지켜주면 XAML 코드를 통해서도 생성이 가능합니다.

참고)
User Control이 기본 생성자를 가지고 있지만 Blend에서 보이지 않는 경우에는
Blend의 프로젝트 탐색기에서 솔루션에 오른쪽 클릭을 하시어 "Rebuild Solution"을 한 번
실행해 주신 다음에 다시 도전하시기 바랍니다.


4. 고려할 사항

- XAML 코드로 설정된 Width, Height 등의 프로퍼티는 User Control이 생성된 이후에 설정이 됩니다.
즉, 생성자에서 Width, Height 값은 초기값을 유지하고, Loaded 이벤트 함수에서부터
XAML 코드에서 설정해준 Width, Height 값을 가지고 있습니다.

- User Control의 기타 프로퍼티들도 XAML에서 지원 가능합니다.
단순한 프로퍼티들은 정의만 해 놓아도 XAML 코드를 통해 그 값을 입력하는 것이 가능합니다.
리스트, 콜렉션 형태의 것들은 좀 더 머리를 쓰셔야 합니다.

- User Control의 이름이 바꾸었을 때, XAML 코드를 재검토 하여 변경해 줘야한다.
XAML 잘못된 User Control명이 들어가 있어도 컴파일 에러가 발생하지 않기 때문이다.

- 인텔리센스가 아직! 도와주지 않습니다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 1

Trackback : http://gilverlight.net/trackback/2674 관련글 쓰기

  1. 2007/12/14 15:18 address edit & del reply

    비밀댓글 입니다

2007/11/07 14:21

InkPresenter 방명록 만들기 - 5. Color Palette 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

체험장 :  http://shiverlight.net/InkPresenterSample/InkPresentationSample_Palette


1. Palette User Control 디자인 (UCColorPalette.xaml)

Expression Blend에서 원하는 모습으로 User Control을 디자인 합니다.

사용자 삽입 이미지

사용자 삽입 이미지

여러분 이제 오브젝트 트리만 봐도 감이 팍팍 오시죠?

왼쪽 부분을 통해 현재 색상을 표현해주고,
오른쪽 부분은 사용자가 색상을 고를 수 있게 합니다.

사용자 삽입 이미지

팔레트를 보였다 숨겼다하는 토글 방식 때 사용하기 위한 스토리보드를 두 개 정도 만들어 주었습니다.

사용자가 보게 될 각 색상 UI는 _cvColorSet에 직접 해당 색상이 있는 Rectangle 등을 통해서 직관적으로 작업할 수도 있습니다만,
색상이 많아 질수록 동적으로 생성해 주는 것이 더 편하다고 생각되어, 이 강좌에서는
코드로 생성하도록 하겠습니다.


2. Color Palette 비하인드 코드 작성 (UCColorPalette.xaml.cs)

UI 엘리먼트를 컨트롤 하기 위한 변수를 추가합니다.

//////////////////////////////////////////////////////////////////////////////////////
// UI Elements

// 기본
Canvas _cvMyself;

// 현재 색상
Canvas _cvCurColor;
Rectangle _btnCurColor;

// 컬러 셋
Canvas _cvColorSet;
Rectangle _rcPalette;

// 스토리보드 : 토글
Storyboard _sbToggleShow;
Storyboard _sbToggleHide;

생성자에서 FindName 함수를 이용하여 UI를 찾아서 해당변수에 할당합니다.

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

    _btnCurColor = _cvMyself.FindName("_btnCurColor") as Rectangle;
    _rcPalette = _cvMyself.FindName("_rcPalette") as Rectangle;

    _cvCurColor = _cvMyself.FindName("_cvCurColor") as Canvas;
    _cvColorSet = _cvMyself.FindName("_cvColorSet") as Canvas;

    _sbToggleShow = _cvMyself.FindName("ToggleShow") as Storyboard;
    _sbToggleHide = _cvMyself.FindName("ToggleHide") as Storyboard;
}

사용자 삽입 이미지

일단, 위 그림과 같은 것을 목표로 하여, 팔레트에 색상을 추가하기 위한 변수를 추가합니다.

// 팔레트 색상 수
int _nColor = 0;
public int Count { get { return _nColor; } }

// 색상 배치 관련
Size _szMargin = new Size(10,10); // 컬러셋 Rectangle과의 마진
Size _szColor = new Size(20, 20); // 한 개의 색상의 사이즈
double _dSpace = 5; // 한 색상과 다른 색상과의 거리

// 색상 리스트
List<Color> _oColorList = new List<Color>();

// 선택된 색상
Color _color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
public Color Color { get { return _color; } }

외부로 노출되는 AddColor 메서드를 작성합니다.
색상 값 하나를 받아 _szColor를 사이즈로 갖는 Ellipse를 하나 만든 뒤에,
_cvColorSet 캔버스에 추가시켜 줍니다.
이 때 알맞게, 위치도 결정해 주고, 색상 수 _nCount도 증가시킵니다.

public void AddColor(Color color)
{
    // 색상 리스트에 추가
    _oColorList.Add(color);

    // 원형 색상 UI 추가
    Ellipse el = new Ellipse();
    el.Width = _szColor.Width;
    el.Height = _szColor.Height;
    el.Fill = new SolidColorBrush(color);
    el.Cursor = Cursors.Hand;

    el.SetValue(Canvas.LeftProperty, _szMargin.Width + _nColor * (_szColor.Width + _dSpace));
    el.SetValue(Canvas.TopProperty, _szMargin.Height);

    _cvColorSet.Children.Add(el);

    // 색상 수 증가
    _nColor++;

    UpdateUI();
}

이때 색상 수가 늘어남에 따라 UI가 변경되어야 하기 때문에 UpdateUI를 작성하여 호출합니다.

void UpdateUI()
{
    _rcPalette.Width = _szMargin.Width * 2 + (_szColor.Width + _dSpace) * _nColor - _dSpace;
    _cvColorSet.Width = _rcPalette.Width;
}

자, 이제 어떤 색상이 선택되었을 때 발생시킬 이벤트를 준비합니다.

클래스 정의 외부에 적당한 delegate를 하나 준비합니다.

namespace InkPresentationSample_Palette
{
    public delegate void PaletteEventHandler(Color color);

    public class UCColorPalette : Control
    {

아래와 같은 프로퍼티를 추가해 줍니다.

// 이벤트
public event PaletteEventHandler ColorChanged;

이벤트 하나 작성합니다.

void OnColorChanged()
{
    if (ColorChanged != null)
    {
        ColorChanged(_color);
    }
}

자 이제 이 함수를 적당한 곳에서 호출해 주기만 하면 이벤트 준비가 끝나겠죠?
어디가 적당할까요? 사용자가 ColorSet 중의 색상을 클릭할 때가 되겠죠!

AddColor 함수로 돌아가 아래와 같이 이벤트에 대한 함수를 작성합니다.

public void AddColor(Color color)
{
    // 색상 리스트에 추가
    _oColorList.Add(color);

    // 원형 색상 UI 추가
    Ellipse el = new Ellipse();
    el.Width = _szColor.Width;
    el.Height = _szColor.Height;
    el.Fill = new SolidColorBrush(color);
    el.Cursor = Cursors.Hand;
    el.MouseLeftButtonUp += new MouseEventHandler(el_MouseLeftButtonUp);

    el.SetValue(Canvas.LeftProperty, _szMargin.Width + _nColor * (_szColor.Width + _dSpace));
    el.SetValue(Canvas.TopProperty, _szMargin.Height);

    _cvColorSet.Children.Add(el);

    // 색상 수 증가
    _nColor++;

    UpdateUI();
}

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

    Ellipse el = sender as Ellipse;
    SolidColorBrush brush = el.Fill as SolidColorBrush;

    SetColor(brush.Color);
}

void SetColor(Color color)
{
    _color = color;
    _btnCurColor.Fill = new SolidColorBrush(_color);

    // 이벤트 발생
    OnColorChanged();
}
   
el_MouseLeftButtonUp -> SetColor -> OnColorChanged
결국 이벤트는 위와 같은 경로로 발생하게 되었구요.
User Control 내부에서든, 외부에서든, 컬러가 변경되게 되면 궁극적으로는
SetColor 함수를 호출하도록 신경을 써주시면 됩니다.

이제 아래 그림과 같이 왼쪽 부분을 누르면 ColorSet이 생겼다 없어졌다하는 토글 기능을
구현합니다.

사용자 삽입 이미지

클래스 정의 외부에 enum 타입으로 Style의 Domain을 정의합니다.
항상 보이기와, 토글 두 가지의 스타일을 지원합니다.

namespace InkPresentationSample_Palette
{
    public enum Style { AlwaysShow, Toggle }
    public delegate void PaletteEventHandler(Color color);

    public class UCColorPalette : Control
    {

프로퍼티를 추가합니다.

// 토글
Style _Style = Style.Toggle;
bool _bToggleShow = false;

여기서는 동적으로 Style을 변경할 수 있게 지원 안하고 ^^;
생성할 당시에 운명이 정해지도록 하겠습니다.
생성자에 아래와 같이 작업을 합니다.

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

    _btnCurColor = _cvMyself.FindName("_btnCurColor") as Rectangle;
    _rcPalette = _cvMyself.FindName("_rcPalette") as Rectangle;

    _cvCurColor = _cvMyself.FindName("_cvCurColor") as Canvas;
    _cvColorSet = _cvMyself.FindName("_cvColorSet") as Canvas;

    _sbToggleShow = _cvMyself.FindName("ToggleShow") as Storyboard;
    _sbToggleHide = _cvMyself.FindName("ToggleHide") as Storyboard;

    _Style = style;

    // 접혀있는 상태
    if (_Style == Style.Toggle)
    {
        _bToggleShow = false;
        _cvColorSet.Opacity = 0;
        _btnCurColor.MouseLeftButtonUp += new MouseEventHandler(_btnCurColor_MouseLeftButtonUp);
    }
}

void _btnCurColor_MouseLeftButtonUp(object sender, MouseEventArgs e)
{
    // Palette 펼쳤다 접었다.
    _bToggleShow = !_bToggleShow;

    if (_bToggleShow == true)
    {
        ShowPalette();
    }
    else
    {
        HidePalette();
    }
}

public void ShowPalette()
{
    _sbToggleShow.Begin();
    _cvColorSet.IsHitTestVisible = true;
    _bToggleShow = true;
}

public void HidePalette()
{
    _sbToggleHide.Begin();
    _cvColorSet.IsHitTestVisible = false;
    _bToggleShow = false;
}

사용자가 ColorSet에서 색상을 골랐을 때도 Hide가 되게 합니다.

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

    Ellipse el = sender as Ellipse;
    SolidColorBrush brush = el.Fill as SolidColorBrush;

    SetColor(brush.Color);
    HidePalette();

    // 이벤트 발생
    OnColorChanged();
}

자 이제 마지막으로 이 컨트롤을 가지고 작업할 프로그래머 편의를 위한 함수를
2개 정도만 추가하고 마무리합니다.

이 Palette가 현재 어떤 어떤 색상을 가지고 있는지 알 수 없기 때문에,
Index를 통해서 색상을 지정해 줄 수 있는 SelectColor(int nIndex) 함수와,
User Control의 위치를 손쉽게 변경할 수 있게 Position(Point pt) 함수를
서비스로 작성해 줍니다.

public void SelectColor(int nIndex)
{
    if (nIndex < 0 || nIndex >= _oColorList.Count)
        return;

    SetColor(_oColorList[nIndex]);
}

public void Position(Point pt)
{
    SetValue(Canvas.LeftProperty, pt.X);
    SetValue(Canvas.TopProperty, pt.Y);
}


3. 샘플 프로젝트에 적용

Page에서 Palette를 사용하기 위해 프로퍼티를 추가합니다.

Page.xaml.cs에서

UCColorPalette _oPalette = null;

Page_Loaded 함수 안에서 Palette를 생성합니다.
CreateInkEditor보다 먼저 생성해야 합니다.
이유는 곧 아시게 됩니다.

public void Page_Loaded(object o, EventArgs e)
{
    ....

    // 배경이미지 준비
    LoadBackImages();

    // Palette 생성
    CreatePalette();

    // Editor 생성
    CreateInkEditor();

    ...
}

void CreatePalette()
{
    _oPalette = new UCColorPalette(Style.Toggle);
    _oPalette.Position(new Point(405, 50));
    Children.Add(_oPalette);

    // 색상 추가 : 닥치는 대로
    _oPalette.AddColor(Color.FromRgb(0xC1, 0x31, 0x31));
    _oPalette.AddColor(Color.FromRgb(0xE3, 0x62, 0x1D));
    _oPalette.AddColor(Color.FromRgb(0xE3, 0xCF, 0x1D));
    _oPalette.AddColor(Color.FromRgb(0xB7, 0xE3, 0x1D));
    _oPalette.AddColor(Color.FromRgb(0x1D, 0xE3, 0x68));
    _oPalette.AddColor(Color.FromRgb(0x1D, 0xE3, 0xA7));
    _oPalette.AddColor(Color.FromRgb(0x1D, 0xD5, 0xE3));
    _oPalette.AddColor(Color.FromRgb(0x1D, 0x7A, 0xE3));
    _oPalette.AddColor(Color.FromRgb(0x80, 0x1D, 0xBD));
    _oPalette.AddColor(Color.FromRgb(0xFF, 0xFF, 0xFF));
    _oPalette.AddColor(Color.FromRgb(0xCC, 0xCC, 0xCC));
    _oPalette.AddColor(Color.FromRgb(0x99, 0x99, 0x99));
    _oPalette.AddColor(Color.FromRgb(0x7F, 0x7F, 0x7F));
    _oPalette.AddColor(Color.FromRgb(0x66, 0x66, 0x66));
    _oPalette.AddColor(Color.FromRgb(0x4D, 0x4D, 0x4D));
    _oPalette.AddColor(Color.FromRgb(0x33, 0x33, 0x33));
    _oPalette.AddColor(Color.FromRgb(0x1C, 0x1C, 0x1C));
    _oPalette.AddColor(Color.FromRgb(0x00, 0x00, 0x00));
    _oPalette.SelectColor(9); // White
    _oPalette.ColorChanged += new PaletteEventHandler(_oPalette_ColorChanged);
}

여기서 드디어 ColorChanged 이벤트 핸들러를 사용합니다.
_oPalette_ColorChanged 함수를 구현하기에 앞서 UCInk.xaml.cs를 방문합니다.

UCInk.xaml.cs에서 외부에서 색상을 입력 받을 프로퍼티를 추가합니다.

public Color StrokeColor { get; set; }

그리고 새 Stroke를 생성할 때 마다 그 색상을 가져다 쓰도록 합니다.

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

    return stroke;
}

다시 Page.xaml.cs로 돌아와 못다한 일을 마칩니다.

void _oPalette_ColorChanged(Color color)
{
    _oInkEditor.StrokeColor = color;
}

마지막으로 새 작품을 만들 때, UCInk의 Stroke가 팔레트에 현재 색상을
가져다 쓸 수 있도록 CreateInkEditor 함수를 손봐줍니다.

void CreateInkEditor()
{
    // 새 InkPresenter Editor 생성
    _oInkEditor = new UCInk(_szInk, true);
    _oInkEditor.BackImage = GetImageRandom();

    if (_oPalette != null)
        _oInkEditor.StrokeColor = _oPalette.Color;

    // Canvas에 추가
    cvEditor.Children.Add(_oInkEditor);
}

여기서 _oPalette를 사용하기 때문에 CreateInkEditor보다 CreatePalette를 먼저 호출해 주셔야 한다고
그랬던 겁니다.

자, 끝났습니다.


별거 아닌데 말이 너무 길었습니다. ^^;;;
감사합니다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 2

Trackback : http://gilverlight.net/trackback/2647 관련글 쓰기

  1. taeyo 2007/11/08 16:12 address edit & del reply

    강좌가 상당히 깔끔하네요^^
    인상적입니다

  2. BlogIcon 길버트 2007/11/08 23:07 address edit & del reply

    감사합니다. 혹시 taeyo.net의 taeyo님 이신가요?
    영광입니다!

2007/10/23 14:33

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부에서 또 뵙겠습니다.


이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0

Trackback : http://gilverlight.net/trackback/2631 관련글 쓰기