본문 바로가기
개발언어/C#

[C#] (강의) 5. 사용자 정의 컨트롤

by 창용이랑 2021. 4. 12.
728x90

m.cafe.daum.net/smbitpro/R7EG/12

 

5. 사용자 정의 컨트롤

사용자 정의 컨트롤 UsingUserControl.zip 이번에는 사용자 정의 컨트롤에 대해 살펴보기로 하자. 사용자 정의 컨트롤은 재 사용 가능하게 기존의 컨트롤을 합성하여 컨트롤을 정의하는 것을 말한다.

m.cafe.daum.net

사용자 정의 컨트롤

 

 UsingUserControl.zip

이번에는 사용자 정의 컨트롤에 대해 살펴보기로 하자.

 

사용자 정의 컨트롤은 재 사용 가능하게 기존의 컨트롤을 합성하여 컨트롤을 정의하는 것을 말한다. 사용자 정의 컨트롤은 UserControl에서 파생한다.

 

사용자 정의 컨트롤은 이를 소유하는 컨트롤에서 속성을 설정할 수 있고 이벤트 핸들러를 정의할 수 있고 노출된 메서드를 사용할 수 있어야 할 것이다.

 

이에 대한 설명을 하기 위해 다음과 같은 모습과 기능을 갖는 사용자 정의 컨트롤을 만들어 활용하는 예를 들고자 한다.

 

 

 

 

작성하고자 하는 컨트롤의 명칭은 MyControl 컨트롤이다.

해당 컨트롤에는 TrackBar의 최소값은 0으로 고정되어 있고 최대값은 설정이 가능하다.

해당 컨트롤에는 트랙바 시작위치에서의 상대적 거리와 색을 선택하여 아이템 추가를 할 수 있다. 해당 컨트롤은 쇼를 시작할 수 있다.

쇼가 시작되면 TrackBar가 움직이면서 보관된 아이템에 따라 Panel1의 배경 색상이 바뀐다.

해당 컨트롤에서는 색상이 바뀌게 되면 발생하는 이벤트가 있으며 이에 대한 이벤트 핸들러는 소유 컨트롤에서 정의할 수 있다.

해당 컨트롤에서는 TrackBar가 끝 위치에 가게 되면 발생하는 이벤트가 있으며 이에 대한 이벤트 핸들러는 소유 컨트롤에서 정의할 수 있다.

 

사용자 컨트롤을 활용하는 예제 프로그램의 모습과 시나리오는 다음과 같다.

 

 

폼에는 MyControl 이 배치되어 있고 현재 색상을 보여주기 위한 Label과 추가할 아이템의 상대적 거리와 추가할 색상을 선택하기 위한 콤보 박스와 아이템 추가 버튼, 쇼를 시작하기 위한 시작 버튼으로 구성할 것이다.

 

1. MyControl

먼저, Windows Forms 컨트롤 라이브러리 형태의 프로젝트를 생성한다.

그리고, UserControl1.cs의 속성 창에서 파일 명을 MyControl.cs로 변경하자.

코드 보기를 해 보면 클래스 명도 MyControl로 변경됨을 알 수 있다.

 

 

 

먼저 SplitContainer를 추가하고 분활자 방향을 가로 분활자 방향으로 변경한다.

TrackBar컨트롤을 패널 아래에 넣고 Dock속성을 Fill로 하자.

 

소유 컨트롤에서 설정 가능한 속성에 대해 정의하자.

MyControl TrackBar의 최대 크기는 설정 가능해야 할 것이다.

또한, 시작 시 Panel1의 배경 색도 설정 가능하면 좋을 것이다.

 

다음은 이에 해당하는 코드이다.

 

public Color InitColor

{

    get;

    set;

}

 

public int Max

{

    get

    {

       return trackBar1.Maximum;

    }

    set

    {

        trackBar1.Maximum = value;

    }

}

 

MyControl의 생성자에서는 Timer 개체 생성, Timer개체의 interval 설정, 초기 Color설정 및 Timer개체의 Tick이벤트 핸들러를 설정해야 할 것이다.

 

Timer timer = null;

public MyControl()

{

    InitializeComponent();

    InitColor = Color.White;

    splitContainer.Panel1.BackColor = InitColor;

    trackBar1.Minimum = 0;

timer = new Timer();

    timer.Interval = 100;

    timer.Tick += new EventHandler(timer_Tick);           

}

 

MyControl에서는 TrackBar의 위치에 따라 색상이 변경이 되어야 하는데 이를 위해 상대적 거리와 Color를 쌍으로 갖는 item을 보관해야 한다. 여기에서 상대적 거리와 Color를 쌍으로 갖는 item MyControlItem 클래스로 정의하였다.

 

class MyControlItem:IComparable

{

    public int Diff

    {

        get;

        private set;

    }

    public Color Color

    {

        get;

        private set;

    }

    public MyControlItem(int diff, Color color)

    {

        Diff = diff;

        Color = color;

    }

    #region IComparable 멤버

    public int CompareTo(object obj)

    {

        MyControlItem other = obj as MyControlItem;

        if (other == null)

        {

            throw new ApplicationException("MyControlItem 개체가 아닙니다.");

        }

        return Diff - other.Diff;

    }

    #endregion

}

 

 

MyControl MyControlItem을 보관하는 컬렉션이 있어야 할 것이다.

 

List<MyControlItem> list = new List<MyControlItem>();

 

MyControl에는 TrackBar가 움직이면서 설정한 MyControlItem에 따라 배경 색상이 바뀌게 되는데 이에 대한 처리가 필요하고 소유자에게 이를 통보하기 위한 이벤트가 있어야 한다.

또한, TrackBar가 마지막 위치에 가게 되면 이를 통보하기 위한 이벤트가 있어야 한다.

다음은 이러한 이벤트를 위한 delegate event 선언이다.

 

public delegate void StopDele();

public delegate void ChangeColorDele(Color color);

public event StopDele StopEventHandler;

public event ChangeColorDele ChangeColorEventHandler;

public void OnStop()

{

    if (StopEventHandler != null)

    {

        StopEventHandler();

    }

    }

public void [안내]태그제한으로등록되지않습니다-xxOnChangeColor(Color color)

{

    if (ChangeColorEventHandler != null)

    {

        ChangeColorEventHandler(color);

    }

}

 

타이머에 의해 Tick이벤트가 발생하면 tracBar 1 증가하고 이 값이 최대값이면 timer를 정지하고 초기값들로 변경하고 이러한 사실을 소유자에게 알리기 위해 OnStop 메서드를 호출해야 할 것이다.

그리고, TrackBar의 위치에 따른 색을 설정해야 할 것이다.

 

void timer_Tick(object sender, EventArgs e)

{

    trackBar1.Value++;

    if (trackBar1.Value == trackBar1.Maximum)

    {

        timer.Stop();

        trackBar1.Value = 0;

        splitContainer.Panel1.BackColor = InitColor;

        OnStop();

    }

    SetColor();

}

 

다음은 TrackBar의 위치에 따라 Panel1의 색을 변경하기 위해서는 다음의 로직을 따르면 될 것이다.

초기 색으로 설정 한다.

Loop:

List에 보관된 MyControlItem을 얻어온다.(순차적으로)

TrackBar의 위치와 아이템의 상대적 거리를 비교

비교한 값이 TrackBar의 위치가 크거나 같으면

Color를 아이템의 색으로 변경한다.

그렇지 않으면 반복문 탈출(List에는 상대적 거리 순으로 sort된 상태를 유지)

Panel1의 배경 색을 변경한다.

색이 변경된 사실을 통보한다.

 

다음은 이에 해당하는 코드이다.

 

private void SetColor()

{

    splitContainer.Panel1.BackColor = InitColor;

    Color color = splitContainer.Panel1.BackColor;

    foreach (MyControlItem myItem in list)

    {

        if (trackBar1.Value >= myItem.Diff)

        {

            color = myItem.Color;

        }

        else

        {

            break;

        }

    }

 

    splitContainer.Panel1.BackColor = color;

    [안내]태그제한으로등록되지않습니다-xxOnChangeColor(color);

}

 

사용자가 TrackBar를 움직일 경우 Scroll이벤트가 발생한다. 이런 경우에도 Panel1의 배경색을 적절한 색으로 변경해야 할 것이다.

 

 

private void trackBar1_Scroll(object sender, EventArgs e)

{

    SetColor();

}

 

쇼를 시작하기 위한 메소드를 제공해 주어야 할 것이다.

쇼를 시작하기 위해서는 Timer를 시작하면 된다.

 

public void Start()

{           

    timer.Start();

}

 

마지막으로 상대적 거리와 색의 조합인 MyCotrolItem을 추가하는 메소드가 있어야 할 것이다.

 

public void Start()

{           

    timer.Start();

}

 

2. UsingUserControl

 

이번에는 MyControl을 사용하는 예를 살펴보자.

 

 

먼저, Windows Forms 응용 프로그램 프로젝트를 생성한 후 앞에서 작성한 MyControl.dll을 참조한다.

도구 상자를 통해 MyControl을 추가하고 위의 그림과 같이 버튼과 Label, ComboBox를 추가한다.

구성 요소 명

타입

설명

myControl1

MyControl

사용자 정의 컨트롤 개체

buttonOfStart

Button

시작 버튼

buttonOfAddItem

Button

아이템(상대적 거리, ) 추가 버튼

labelOfColor

Label

색상 정보 레이블

comboBoxOfDiff

ComboBox

상대적 거리 선택할 콤보 박스

comboBoxOfColor

ComboBox

색상을 선택할 콤보 박스

 

이 외에 현재 색상, 거리, 색상에 해당하는 레이블을 추가한다.

 

Form1의 생성자에서는 comboBoxOfDiff의 항목 초기화 및 comboBoxOfColor의 항목 초기화,

myControl1의 최대값 설정 및 색상 변경 이벤트 핸들러와 TrackBar가 끝을 만나 쇼가 종료되었을 때의 이벤트 핸들러를 설정한다.

 

const int maxdiff = 100;

public Form1()

{

    InitializeComponent();

    InitDiffComboBox();

    InitColorComboBox();

    myControl1.Max = maxdiff;

    myControl1.ChangeColorEventHandler += new MyControl.MyControl.ChangeColorDele(myControl1_ChangeColorEventHandler);

    myControl1.StopEventHandler += new MyControl.MyControl.StopDele(myControl1_StopEventHandler);                      

}

private void InitColorComboBox()

{

    for(int i = 0;i<maxdiff;i++)

    {

        comboBoxOfDiff.Items.Add(i);

    }

}

 

private void InitDiffComboBox()

{

    comboBoxOfColor.Items.Add(Color.Blue);

    comboBoxOfColor.Items.Add(Color.Black);

    comboBoxOfColor.Items.Add(Color.White);

    comboBoxOfColor.Items.Add(Color.Red);

    comboBoxOfColor.Items.Add(Color.Green);

    comboBoxOfColor.Items.Add(Color.Yellow);

    comboBoxOfColor.Items.Add(Color.Brown);

}

void myControl1_StopEventHandler()

{

    buttonOfStart.Enabled = true;

}

 

void myControl1_ChangeColorEventHandler(Color color)

{

    labelOfColor.Text = color.ToString();

}

 

시작 버튼을 눌렀을 때에는 시작 버튼을 비활성화 시키고 myControl Start메서드를 호출하면 될 것이다.

 

private void buttonOfStart_Click(object sender, EventArgs e)

{

    buttonOfStart.Enabled = false;

    myControl1.Start();

}

 

아이템 추가 버튼을 누러면 상대적 거리와 색상 콤보 박스에서 선택한 값을 얻어와 myControl AddItem메서드를 호출하면 될 것이다. 그리고, 각 콤보 박스를 초기 상태로 변경하면 된다.

private void buttonOfAddItem_Click(object sender, EventArgs e)

{

    if ((comboBoxOfColor.SelectedItem != null) && (comboBoxOfDiff.SelectedItem != null))

    {

        Color color = (Color)comboBoxOfColor.SelectedItem;

        int diff = (int)comboBoxOfDiff.SelectedItem;

        myControl1.AddItem(diff, color);

    }

    comboBoxOfColor.SelectedItem = null;

    comboBoxOfDiff.SelectedItem = null;

}

 

여러분이 각자가 어떠한 사용자 정의 컨트롤을 만들고 어떻게 활용하면 이에 대한 내용을 자신의 것으로 만들 수 있는지 고민하고 실천해 보길 바란다.