Creative Commons License

Microsoft .NET

닷넷!시작하기
닷넷! Ver 2.0~
닷넷!스킬업
웹개발
윈폼개발
실용모듈개발
Tip & Tech
하루 한 문법

Microsoft .NET 개발자들을 위한 공간입니다. 기초강의에서 부터 고급 기술 정보 및 팁등을 다루도록 하겠습니다.

.

실용모듈개발

간단하지만 실용적인 기능을 구현한 모듈 저작물을 공유하는 공간입니다.

모든 자식 컨트롤 가져오기

작성자 : 박종명
최초 작성일 : 2008-07-09 (수요일)
최종 수정일 : 2008-07-09 (수요일)
조회 수 : 13276

이번에 제작해 볼 유틸리티는 윈폼에서 유용하게 사용될 만한 유틸리티입니다.

윈폼에서 Panel 이나 Groubox , Form 같은 컨트롤들을 가리켜 자식 컨트롤을 포함할 수 있는
컨테이너(Container) 컨트롤 이라고 합니다.

이러한 컨테이너 컨트롤이 가진 모든 자식 컨트롤을 가져오는 기능를 가진 유틸을 제작해 보겠습니다.

아래와 같은 폼이 있다고 가정합니다.

그림에서 폼에는 총 6개의 컨트롤이 있습니다.
즉 폼(Form)이라는 부모 컨트롤 하위에 총 6개 컨트롤이 있습니다.

더 엄밀히 말하자면 폼(Form) 이라는 부모 컨트롤 하위에는 GroupBox, Panel 이라는 두 개의 컨트롤과 하나의
Button 컨트롤이 있고, GroupBox1 부모 컨트롤은 하나의 TextBox 컨트롤을 가지며 Panel 부모 컨트롤은
GroupBox2 컨트롤을 가지며 또 다시 GroupBox2 컨트롤은 Button2라는 컨트롤을 자식으로 가지고 있습니다.

즉 다음과 같은 계층적 구조로 컨트롤들이 배치되어 있는 것입니다.
Form
  - GroupBox1
       - TextBox1
  - Panel
       - GroupBox2
           - Button2
  - Button1
 


* System.Windows.Forms.Control.Controls 속성
윈도우 폼의 컨트롤들은 기본적으로 System.Windows.Forms.Control 클래스로 부터 파생된(상속받은)
클래스입니다. 따라서 Control 클래스의 Controls 라는 속성을 통해 자식 컨트롤들을 반환 받을 수 있습니다.
그러나 이 Controls 속성은 계층적 구조를 지원하지 않습니다. 즉 바로 밑의 자식 컨트롤만 반환하게 됩니다.

위 그림에서 폼에는 총 6개의 컨트롤이 있지만 폼(Form)의 바로 밑 계층에는 3개의 컨트롤만 있습니다.
위 그림과 같이 폼이 구성되었을 때 다음과 같은 코드를 작성하여 폼(Form)의 자식 컨트롤의 갯수를 불러오면
총 3개라는 결과가 나옵니다.

MessageBox.Show("자식 컨트롤 갯수: " + this.Controls.Count);


결과적으로 모든 계층의 컨트롤들을 다 가져오려고 한다면 다른 방법을 사용해야 한다는 것입니다.

이번에 제작할 유틸의 기능은 이와같이 계층적으로 구성된 컨테이너 컨트롤의 모든 자식 컨트롤을 반환하는
기능을 가지고 있습니다.

 

* 재귀호출을 통한 구현
이를 구현하기 위한 방법도 여러가지가 있을 수 있겠네요.
우선, 계층적 구조.. 하면 생각나는 재귀호출 기법을 통해 구현해 보도록 합니다.

static Control[] GetAllControlsUsingRecursive(Control containerControl)

{

    List<Control> allControls = new List<Control>();

 

    foreach (Control control in containerControl.Controls)
{
     //
자식 컨트롤을 컬렉션에 추가한다

           allControls.Add(control);

//만일 자식 컨트롤이 또 다른 자식 컨트롤을 가지고 있다면

            if (control.Controls.Count > 0)

            {

    //자신을 재귀적으로 호출한다

                allControls.AddRange(GetAllControlsUsingRecursive(control));

            }

}    

//모든 컨트롤을 반환한다

     return allControls.ToArray();

}

 

코드는 자식의 자식(또 자식의 자식...) 이라는 계층적 구조를 모두 훓어가기 위한 재귀 호출 기법을 사용하고 있습니다. 이렇게 하여 폼의 모든 컨트롤이 반환될 수 있습니다.

 

이 코드를 테스트 해 보겠습니다. 클라이언트 코드를 다음과 같이 작성하고 결과를 보겠습니다.

 

//폼 자신(this)을 매개변수로 전달

Control[] controls = GetAllControlsUsingRecursive(this);

 

//자식 컨트롤 갯수

MessageBox.Show("자식 컨트롤 갯수: " + controls.Length);

 

//자식 컨트롤을 하나씩 출력해 본다

foreach (Control control in controls)

{

     MessageBox.Show(control.ToString());

}

 


결과를 보면 폼이라는 컨테이너 컨트롤 하위 모든 계층의 컨트롤이 반환되었음을 확인할 수 있습니다.

 


* 두 개의 컬렉션을 이용한 구현
앞서, 재귀호출을 통해 컨테이너 컨트롤의 모든 자식 컨트롤을 반환할 수 있었는데요..
사실 재귀호출은 성능 이슈로 조금 꺼려하기도 합니다.

이번에는 완전 똑 같은 일을 하지만 재귀호출을 사용하지 않고 두 개의 컬렉션을 이용해서 구현해 보도록 합니다.
참고로 이 구현 방법은 'C#을 이용한 윈도우 폼 프로그래밍(저자:크리스셀즈)' 이라는 책에서 제시한 코드를
닷넷 2.0의 지네릭 버전으로 변경한 코드입니다.
아래 코드를 보시죠..

static Control[] GetAllControls(Control containerControl)

{

    List<Control> allControls = new List<Control>();

 

    Queue<Control.ControlCollection> queue = new Queue<Control.ControlCollection>();

    queue.Enqueue(containerControl.Controls);

 

    while (queue.Count > 0)

    {

        Control.ControlCollection controls

                    = (Control.ControlCollection)queue.Dequeue();

        if (controls == null || controls.Count == 0) continue;

 

        foreach (Control control in controls)

      {

            allControls.Add(control);

            queue.Enqueue(control.Controls);

        }

    }

 

    return allControls.ToArray();

}


앞서 예제와 동일하게 리스트 컬렉션은 모든 컨트롤을 담기 위한 컬렉션이며

큐(Queue) 컬렉션이 바로 이전의 재귀호출 부분을 대신하는 컬렉션입니다.

큐에 바로 밑 계층의 자식 컨트롤들을 담고(Enqueue) 리스트에 추가한 뒤 빼고(Dequeue) 다시 자식컨트롤이 있을경우 큐에 삽입하고.. 를 반복하면서 모든 계층을 돌아 다니는 로직입니다.

이상 두 개의 메서드는 완전 동일한 기능을 제공하며 입맛에 따라 골라 쓰시면 되겠습니당~!~

∵Commented by Lee at 2013-12-09 오전 8:46:18  
ToolTip등과 같은 = New System.Windows.Forms.ToolTip(Me.components) 로 디자인이 생성된 컨트롤은 얻어 올수 가 없습니다.

ToolTip등도 얻어와서 Name이라던가 해당 Text의 값을 얻어 올수 없을까요??
이름
비밀번호
홈페이지
WY <- 왼쪽의 문자를 오른쪽 박스에 똑같이 입력해 주세요