다음을 통해 공유


이벤트 발생시키기

클래스에서 이벤트가 발생되도록 하려면 다음 세 가지 요소를 제공해야 합니다.

  • 이벤트 데이터를 제공하는 클래스

  • 이벤트 대리자

  • 이벤트를 발생시키는 클래스

이벤트 데이터를 제공하는 클래스 정의

.NET Framework의 규칙에 따라 이벤트가 발생하면 해당 이벤트 처리기에 이벤트 데이터가 전달됩니다. 이벤트 데이터는 System.EventArgs 클래스나 이 클래스의 파생 클래스에서 제공됩니다.

이벤트에 사용자 지정 데이터가 없는 경우 즉, 이벤트가 발생했다는 사실만으로 이벤트 처리기에 필요한 모든 정보가 제공되는 경우가 종종 있습니다. 이 경우 이벤트는 해당 처리기에 EventArgs 개체를 전달할 수 있습니다. EventArgs 클래스에는 System.Object에서 상속되지 않은 단일 멤버인 Empty만 포함됩니다. 이 멤버는 새 EventArgs 클래스를 인스턴스화하는 데 사용될 수 있습니다.

이벤트에 사용자 지정 데이터가 없으면 이벤트는 EventArgs에서 파생된 클래스의 인스턴스를 이벤트 처리기에 전달할 수 있습니다. 이벤트가 해당 처리기에 전달하는 정확한 데이터에 따라 .NET Framework의 기존 이벤트 데이터 클래스를 사용할 수도 있습니다. 예를 들어, 이벤트 처리기에서 취소될 이벤트와 연결된 동작을 허용하면 CancelEventArgs 클래스를 사용할 수 있습니다.

이벤트 처리기에 사용자 지정 데이터를 제공해야 하는 경우 기존 클래스를 사용할 수 없으면 사용자 고유의 이벤트 데이터 클래스를 정의할 수 있습니다. 이 클래스는 System.EventArgs에서 파생되어야 합니다. 규칙에 따라 이 클래스의 이름은 EventNameEventArgs로 지정됩니다. 다음 예제에서는 이러한 사용자 지정 이벤트 데이터 클래스를 보여 줍니다. 이 예제에서는 이벤트 처리기에 두 개의 데이터 항목을 제공하는 AlarmEventArgs라는 클래스를 정의합니다. 이 두 데이터 항목은 경보가 꺼진 시간을 나타내는 읽기 전용 Time 속성과 지정된 간격 이후에 경보를 다시 꺼야 하는지 여부나 이후의 경보를 취소해야 하는지 여부를 나타내는 Snooze 속성입니다.

Public Class AlarmEventArgs : Inherits EventArgs
   Private alarmTime As Date
   Private snoozeOn As Boolean = True

   Public Sub New(time As Date)
      Me.alarmTime = time
   End Sub

   Public ReadOnly Property Time As Date
      Get
         Return Me.alarmTime
      End Get
   End Property

   Public Property Snooze As Boolean
      Get
         Return Me.snoozeOn
      End Get
      Set
         Me.snoozeOn = value
      End Set   
   End Property   
End Class
public class AlarmEventArgs : EventArgs
{
   private DateTime alarmTime;
   private bool snoozeOn = true;

   public AlarmEventArgs(DateTime time)
   {
      this.alarmTime = time;
   }

   public DateTime Time
   {
      get { return this.alarmTime; }
   }

   public bool Snooze
   {
      get { return this.snoozeOn; }
      set { this.snoozeOn = value; }
   }   
}
public ref class AlarmEventArgs : public EventArgs
{
private: 
   System::DateTime^ alarmTime;
   bool snoozeOn;

public:
   AlarmEventArgs(System::DateTime^ time) 
   {
      this->alarmTime = time;
      this->snoozeOn = true;
   }

   property DateTime^ Time 
   {
      System::DateTime^ get()
      { return this->alarmTime; }
   }

   property bool Snooze
   {
      bool get()
      { return this->snoozeOn; }
      void set(bool snooze)
      { this->snoozeOn = snooze; }
   }
};

이벤트의 대리자 정의

이벤트 대리자는 이벤트의 시그니처를 정의하는 데 사용됩니다. 일반적으로 특정 이벤트 대리자는 특정 이벤트 데이터 클래스에 해당합니다. 규칙에 따라 .NET Framework의 이벤트에는 EventName(sender, e) 시그니처가 있습니다. 여기서 sender는 이벤트를 발생시킨 클래스 또는 구조체에 대한 참조를 제공하는 Object이고, e는 EventArgs 개체이거나 이벤트 데이터를 제공하는 EventArgs에서 파생된 개체입니다. 일반적으로 대리자 정의는 EventNameHandler(sender, e) 형식으로 되어 있습니다.

.NET Framework 클래스 라이브러리나 타사 라이브러리에 이미 정의되어 있는 이벤트 데이터 클래스를 사용하는 경우 해당 이벤트 대리자도 이러한 라이브러리에 정의되어 있을 가능성이 있습니다. 예를 들어, EventHandler 대리자를 EventArgs 클래스와 함께 사용할 수 있습니다. 마찬가지로 CancelEventHandler 대리자를 CancelEventArgs 클래스와 함께 사용할 수 있습니다.

사용자 지정 이벤트 데이터 클래스를 정의하는 경우 이벤트 시그니처를 정의하는 사용자 지정 대리자도 정의하거나 제네릭 Action<T1, T2> 대리자를 사용할 수 있습니다.

다음 예제에서는 AlarmEventHandler라는 이벤트 대리자를 정의합니다.

Public Delegate Sub AlarmEventHandler(sender As Object, e As AlarmEventArgs)
public delegate void AlarmEventHandler(object sender, AlarmEventArgs e);
public delegate void AlarmEventHandler(System::Object^ sender, AlarmEventArgs^ e);

이벤트를 발생시키는 클래스 정의

이벤트를 발생시키는 클래스는 이벤트 선언을 제공하고 이벤트를 발생시키는 메서드를 정의해야 하며 클래스 속성 또는 메서드에서 이벤트를 발생시키기 위한 몇 가지 논리도 제공해야 합니다.

C#의 event 키워드나 Visual Basic의 Event 문을 사용하여 클래스에서 이벤트 멤버를 정의합니다. 컴파일러는 클래스에서 이벤트 선언을 발견하면 다음 전용 멤버를 만듭니다.

private EventNameHandler eh = null;

또한 컴파일러는 add_EventName과 remove_EventName이라는 두 가지 공용 메서드를 만듭니다. 이들 메서드는 이벤트 대리자 eh에 대리자를 조합하거나 제거하는 데 사용되는 이벤트 후크입니다. 상세 내용은 프로그래머가 볼 수 없도록 숨겨집니다.

참고

C# 및 Visual Basic 2005 이외의 언어에서는 이벤트 멤버에 해당하는 코드를 컴파일러에서 자동으로 생성하지 않을 수도 있는데, 이런 경우에는 사용자가 이벤트 후크나 전용 대리자 필드를 명시적으로 정의해야 합니다.

아래 예제에서는 AlarmEvent라는 이벤트를 선언합니다. 이 예제는 전체 소스 코드가 아래에 나와 있는 Alarm이라는 클래스에 대한 예제의 일부입니다. 여기에는 AlarmEventHandler 대리자의 시그니처가 있습니다.

Event AlarmEvent As AlarmEventHandler
public event AlarmEventHandler AlarmEvent;
public:
   event AlarmEventHandler^ AlarmEvent; 

이벤트 구현을 정의했으면 이벤트를 발생시킬 시기를 결정해야 합니다. 이벤트를 정의한 클래스 또는 파생 클래스에서 보호된 OnEventName 메서드를 호출하여 이벤트를 발생시킵니다. 그러면 OnEventName메서드가 이벤트를 발생시킵니다.

참고

또한 보호된 OnEventName 메서드는 대리자를 이벤트에 첨부하지 않고도 파생 클래스에서 이벤트를 재정의할 수 있게 합니다.파생된 클래스는 등록된 대리자가 이벤트를 수신할 수 있도록 기본 클래스의 OnEventName 메서드를 항상 호출해야 합니다.

다음 예제에서는 AlarmEvent 이벤트를 발생시키는 OnAlarmEvent 메서드를 정의합니다.

Protected Sub OnAlarmEvent(e As AlarmEventArgs)
   RaiseEvent AlarmEvent(Me, e)
End Sub  
protected void OnAlarmEvent(AlarmEventArgs e)
{
   AlarmEvent(this, e);
}  
protected:
   void OnAlarmEvent(AlarmEventArgs^ e)
   {
      AlarmEvent(this, e);
   }

다음 예제에서는 OnAlarmEvent 메서드를 호출하여 이벤트를 발생시키는 논리가 포함된 Set이라는 메서드를 정의합니다. 경보 시간의 시간 및 분이 현재 시간의 시간 및 분과 같으면 Set 메서드는 AlarmEventArgs 개체를 인스턴스화하고 이 인스턴스에 경보가 꺼진 시간을 제공합니다. 이벤트 처리기가 실행된 후 이 메서드는 Snooze 속성의 값을 확인합니다. Snooze가 false이면 경보 이벤트가 더 이상 발생하지 않고 Set 메서드가 종료될 수 있습니다. Snooze가 true이면 경보가 꺼지는 시간이 Interval 속성의 값만큼 증가합니다.

Public Sub [Set]()
   Do
      System.Threading.Thread.Sleep(2000)
      Dim currentTime As DateTime = Date.Now
      ' Test whether it is time for the alarm to go off.
      If currentTime.Hour = alarmTime.Hour And _
         currentTime.Minute = AlarmTime.Minute Then
         Dim args As New AlarmEventArgs(currentTime)
         OnAlarmEvent(args)
         If args.Snooze = False Then 
            Exit Sub
         Else
            Me.alarmTime = Me.alarmTime.AddMinutes(Me.interval)
         End If      
      End If          
   Loop
End Sub 
public void Set()
{
   while (true) {
      System.Threading.Thread.Sleep(2000);
      DateTime currentTime = DateTime.Now;
      // Test whether it is time for the alarm to go off.
      if (currentTime.Hour == alarmTime.Hour && 
          currentTime.Minute == alarmTime.Minute)
      {    
         AlarmEventArgs args = new AlarmEventArgs(currentTime);
         OnAlarmEvent(args);
         if (! args.Snooze) 
            return;
         else
            this.alarmTime = this.alarmTime.AddMinutes(this.interval);
      }
   }
} 
void Set()
{
   do {
      Thread::Sleep(2000);
      System::DateTime^ currentTime = DateTime::Now;
      // Test whether it's time for the alarm to go off.
      if (currentTime->Hour == alarmTime->Hour && currentTime->Minute == alarmTime->Minute)
      {
         AlarmEventArgs^ args = gcnew AlarmEventArgs(currentTime);
         OnAlarmEvent(args);
         if (args->Snooze == false)
            return;
         else
            this->alarmTime = this->alarmTime->AddMinutes(this->interval);
      }
   } while (true);
}

다음 예제에는 Alarm 클래스의 모든 소스 코드가 포함되어 있습니다.

Public Class Alarm
   Private alarmTime As Date
   Private interval As Integer = 10

   Event AlarmEvent As AlarmEventHandler

   Public Sub New(time As Date)
      Me.New(time, 10)
   End Sub

   Public Sub New(time As Date, interval As Integer)
      Me.alarmTime = time
      Me.interval = interval
   End Sub

   Public Sub [Set]()
      Do
         System.Threading.Thread.Sleep(2000)
         Dim currentTime As DateTime = Date.Now
         ' Test whether it is time for the alarm to go off.
         If currentTime.Hour = alarmTime.Hour And _
            currentTime.Minute = AlarmTime.Minute Then
            Dim args As New AlarmEventArgs(currentTime)
            OnAlarmEvent(args)
            If args.Snooze = False Then 
               Exit Sub
            Else
               Me.alarmTime = Me.alarmTime.AddMinutes(Me.interval)
            End If      
         End If          
      Loop
   End Sub 

   Protected Sub OnAlarmEvent(e As AlarmEventArgs)
      RaiseEvent AlarmEvent(Me, e)
   End Sub  
End Class
public class Alarm
{
   private DateTime alarmTime;
   private int interval = 10;

   public event AlarmEventHandler AlarmEvent;

   public Alarm(DateTime time) : this(time, 10)
   {
   }

   public Alarm(DateTime time, int interval)
   {
      this.alarmTime = time;
      this.interval = interval;
   }

   public void Set()
   {
      while (true) {
         System.Threading.Thread.Sleep(2000);
         DateTime currentTime = DateTime.Now;
         // Test whether it is time for the alarm to go off.
         if (currentTime.Hour == alarmTime.Hour && 
             currentTime.Minute == alarmTime.Minute)
         {    
            AlarmEventArgs args = new AlarmEventArgs(currentTime);
            OnAlarmEvent(args);
            if (! args.Snooze) 
               return;
            else
               this.alarmTime = this.alarmTime.AddMinutes(this.interval);
         }
      }
   } 

   protected void OnAlarmEvent(AlarmEventArgs e)
   {
      AlarmEvent(this, e);
   }  
}
public ref class Alarm 
{
private:
   System::DateTime^ alarmTime;
   int interval;

public:
   event AlarmEventHandler^ AlarmEvent; 
   Alarm(System::DateTime^ time) : alarmTime(time), interval(10) { };
   Alarm(System::DateTime^ time, int interval) : alarmTime(time), interval(interval) {};

   void Set()
   {
      do {
         Thread::Sleep(2000);
         System::DateTime^ currentTime = DateTime::Now;
         // Test whether it's time for the alarm to go off.
         if (currentTime->Hour == alarmTime->Hour && currentTime->Minute == alarmTime->Minute)
         {
            AlarmEventArgs^ args = gcnew AlarmEventArgs(currentTime);
            OnAlarmEvent(args);
            if (args->Snooze == false)
               return;
            else
               this->alarmTime = this->alarmTime->AddMinutes(this->interval);
         }
      } while (true);
   }

protected:
   void OnAlarmEvent(AlarmEventArgs^ e)
   {
      AlarmEvent(this, e);
   }
};

참고 항목

작업

방법: 이벤트 발생 및 사용

방법: 클래스에 이벤트 구현

개념

이벤트 및 대리자

기타 리소스

이벤트 처리 및 발생