요즘은 달봉이가 맡았던 업무를 전산실 직원에게 백업을 하는 것이 주요 하루 일과다. 오늘 백업도중 어쩌다 .NET의 이벤트 핸들링 패턴에 대한 얘기가 나왔었다. 예전에 달봉이가 처음 이벤트를 배울려고 했을때 잘 이해하지 못했던 부분이 있었는데, 생각난 김에 함 정리를 해 볼려고 한다.

우리는 어떤 이벤트를 이용하기 위해서 사용하는 방법에 대해서 알고 있다.
- 이벤트( 멤버)에 이벤트 핸들러를  등록하거나
- 또는 해당 이벤트 On이벤트 메소드를 오버라이드하기

이 두 방법의 차이점은 무엇일까? 이 두 방법을 모두 이용할 수 있는 것은 .NET의 이벤트 핸들링 패턴 때문이다. 다음 코드는 이벤트 "Loaded"라는 것을 정의해서 이 이벤트에 대한 핸들링을 하는 두 방법을 보여주고 있다. 다시 한번 상기시키면 다음 코드는 개발자가 작성하는 코드이다.


 
public class DerivedControl : BaseControl
  {
     
public DerivedControl()
      {
         //이벤트 핸들링 방법 2.1
         
this.Loaded += new LoadedEventHandler(this.LoadedEventHandler);
     
}
     //이벤트 핸들링 방법 1
     
protected override void OnLoaded(EventArgs e)
      {
         
//이곳에서 필요한 작업을 한다.

          //베이스의 OnLoaded()를 호출한다.
         
base.OnLoaded(e);
     
}
      //이벤트 핸들링 2.2
     
private void LoadedEventHandler(object sender, EventArgs e)
      {
         
//이곳에서 필요한 작업을 한다.
     
}
  }

개발자가 DerivedControl을 가지고 작업을 할때 이벤트 핸들링 1 방법을 사용해도 되고 2 방법을 사용해도 된다. 

이벤트 핸들링 1 : On메소드 오바라이딩 사용.
이벤트 핸들링 2 : 이벤트 핸들러 사용

이벤트 핸들러를 사용하는 방법은 2.1과 2.2 가 필요하다. 즉 핸들러 메소드를 제작(2.2)해야 하고  이 핸들러를 해당 이벤트에 등록(2.1)해야 한다.

이벤트 핸들러를 사용하는 것에 대한 더 이상의 얘기는 하지 않겠다. 여기서는 On메소드 오버라이딩 방법을 사용했을 경우 어떻게 이 DerivedControl.OnLoaded() 메소드가 호출되는지를 알아볼 것이다. 그러기 위해서는 베이스 클래스 BaseControl의 구조를 머리에 그릴 수 있어야 한다.  지금부터 함 BaseControl을 그려보자.

 
//Loaded이벤트용 델리게이트 정의
  
public delegate void LoadedEventHandler(object sender, EventArgs e);

  
//베이스 클래스
  
public class BaseControl  : System.Windows.Forms.UserControl
   {
       //이벤트 멤버 : Loaded
      
public LoadedEventHandler Loaded = null;
       protected virtual void
OnLoaded(EventArgs e)
       {
          
if (Loaded != null)
           {
              //이벤트 발생
               Loaded(
this, e);
          
}
       }
   }


베이스 클래스 BaseControl에는 이처럼 이벤트 Loaded와 그것을 호출하는 가상 메소드 OnLoaded()가 정의되어 있을 것이다.

.NET 이벤트 발생 패턴에서는 직접 Loaded를 호출하는 대신에 이렇게 On이벤트 메소드를 제공해서 이 메소드내에서 이벤트를 호출하도록 하고 있다.

컨트롤이 로딩되고 나서 프레임워크쪽 또는 BaseControl쪽의 어디에선가 Loaded 이벤트를 발생시키기 위해서 OnLoaded()를 호출하게 된다. 예를 들어 다음과 같은 코드가 있을 수 있다.

private void BaseControl쪽의메소드(...)
{
....
//이곳은 BaseControl쪽 코드
this.OnLoaded(e);  // 순전히 예를 위한 호출이다.
}


이제 개발자가 다음과 같은 코드를 작성했다고 보자.

BaseControl ctrl = new DerivedControl();
윈폼객체.Control.Add(ctrl);

이렇게 생성된 컨트롤 ctrl을 윈폼이나 컨테이너 컨트롤에 Add 시켜서 로딩시켰다고 하자. 그리고 Loaded 이벤트를 발생시켜야 하는 시점에서 즉 BaseControl쪽의메소드() 내부에서 this.OnLoaded(e) 호출했다고 하자. BaseControl의 OnLoaded()가 호출될까?

BaseControl.OnLoaded()가 호출되는 것이 아니라 DerivedControl.OnLoaded()가 호출된다. this가 가리키는 것은 new DerivedControl() 객체이기때문이다.

즉 우리가 원하는 이벤트 핸들링이 이뤄진것이다.

호출되는 DerivedControl.OnLoaded()의 내용을 보면 코드에서처럼 그곳에서는 다시 베이스의 OnLoaded()를 호출해야 한다.

//베이스의 OnLoaded()를 호출한다.
base.OnLoaded(e);


이 메소드를 호출해야 base.OnLoaded()에서 Loaded 이벤트를 호출해서, 다른 곳에서 Loaded에 등록했을지도 모를 다른 핸들러들을 실행시켜야 하기 때문이다.

따라서 메소드 실행 순서를 정리해보면 다음과 같다.

DerivedControl.OnLoaded() -> BaseControl.OnLoaded() -> Loaded 이벤트 핸들러

이벤트 핸들링 하는 방법으로 On메소드을 오버라이딩하는 것과 이벤트 핸드러를 사용하는 것에 대해서 알아봤다.

다 써놓고 보니까 또 내가 이것을 왜 썼나 싶다.-_-;; 히잉~
Posted by dalbong2