본문스크랩 이벤트 (Event)


C#에서 이벤트를 선언, 호출 및 연결하는 방법을 보여 줍니다.

 

설명

C#에서 이벤트는 개체에 어떤 일이 발생하면 클래스에서 해당 클래스의 클라이언트에게 알리는 방법입니다. 이벤트는 그래픽 사용자 인터페이스에서 가장 흔히 사용됩니다. 일반적으로, 인터페이스의 컨트롤을 나타내는 클래스에는 이벤트가 있어서 사용자가 단추를 클릭하는 것과 같이 컨트롤에 임의의 작업을 했을 때 알림을 받습니다.

그러나 이벤트를 그래픽 인터페이스에만 사용할 필요는 없습니다. 이벤트는 개체가 해당 개체의 클라이언트에게 유용할 수 있는 상태 변화를 신호로 알리는 유용한 방법을 제공합니다. 이벤트는 여러 프로그램에서 다시 사용할 수 있는 클래스를 만드는 데 중요한 빌드 블록입니다.

이벤트는 대리자를 사용하여 선언합니다. 아직 대리자 자습서 부분을 읽지 않았다면 반드시 읽은 후 계속하십시오. 대리자 개체는 메서드를 캡슐화하므로 메서드가 익명으로 호출될 수 있습니다. 이벤트는 이벤트 발생 시 호출해야 하는 메서드의 대리자를 클래스를 통해 클라이언트에서 제공하도록 하는 방법입니다. 이벤트가 발생하면 클라이언트에 의해 메서드에 주어진 대리자가 호출됩니다.

이 자습서에서는 이벤트 선언, 호출 및 연결에 대한 예제 외에도 다음 항목을 소개합니다.

  • 이벤트 및 상속
  • 인터페이스 내의 이벤트
  • .NET Framework 지침

예제 1

다음은 표준ArrayList클래스와 유사하지만 목록 내용이 변경될 때마다Changed이벤트도 호출하는ListWithChangedEvent클래스를 보여 주는 간단한 예제입니다. 이러한 범용 클래스는 큰 프로그램에서 여러 가지 방식으로 사용될 수 있습니다.

예를 들어, 워드 프로세서에서 열려 있는 문서의 목록을 관리하고 있다면 이 목록이 변경될 때마다 사용자 인터페이스가 업데이트되도록 워드 프로세서의 많은 다른 개체에 알려야 합니다. 이 이벤트를 사용하면 문서 목록을 관리하는 코드에서 알려야 할 대상을 알고 있을 필요가 없습니다. 즉, 일단 문서 목록이 변경되면 이벤트가 자동으로 호출되어 알려야 하는 모든 개체에 정확히 알립니다. 이벤트를 사용함으로써 프로그램의 모듈성이 증가합니다.

// events1.cs
using System;
namespace MyCollections
{
   using System.Collections;

   // A delegate type for hooking up change notifications.
   public delegate void ChangedEventHandler(object sender, EventArgs e);

   // A class that works just like ArrayList, but sends event
   // notifications whenever the list changes.
   public class ListWithChangedEvent: ArrayList
   {
      // An event that clients can use to be notified whenever the
      // elements of the list change.
      public event ChangedEventHandler Changed;

      // Invoke the Changed event; called whenever list changes
      protected virtual void OnChanged(EventArgs e)
      {
         if (Changed != null)
            Changed(this, e);
      }

      // Override some of the methods that can change the list;
      // invoke event after each
      public override int Add(object value)
      {
         int i = base.Add(value);
         OnChanged(EventArgs.Empty);
         return i;
      }

      public override void Clear()
      {
         base.Clear();
         OnChanged(EventArgs.Empty);
      }

      public override object this[int index]
      {
         set
         {
            base[index] = value;
            OnChanged(EventArgs.Empty);
         }
      }
   }
}

namespace TestEvents
{
   using MyCollections;

   class EventListener
   {
      private ListWithChangedEvent List;

      public EventListener(ListWithChangedEvent list)
      {
         List = list;
         // Add "ListChanged" to the Changed event on "List".
         List.Changed += new ChangedEventHandler(ListChanged);
      }

      // This will be called whenever the list changes.
      private void ListChanged(object sender, EventArgs e)
      {
         Console.WriteLine("This is called when the event fires.");
      }

      public void Detach()
      {
         // Detach the event and delete the list
         List.Changed -= new ChangedEventHandler(ListChanged);
         List = null;
      }
   }

   class Test
   {
      // Test the ListWithChangedEvent class.
      public static void Main()
      {
      // Create a new list.
      ListWithChangedEvent list = new ListWithChangedEvent();

      // Create a class that listens to the list’s change event.
      EventListener listener = new EventListener(list);

      // Add and remove items from the list.
      list.Add("item 1");
      list.Clear();
      listener.Detach();
      }
   }
}

출력

This is called when the event fires.
This is called when the event fires.

 

코드 설명

이벤트 선언   클래스 내에 이벤트를 선언하려면 우선 이벤트의 대리자 형식이 이미 선언되어 있는지 확인하고 선언되어 있지 않으면 이를 선언해야 합니다.

public delegate void ChangedEventHandler(object sender, EventArgs e);

대리자 형식은 이벤트를 처리하는 메서드로 전달되는 인수 집합을 정의합니다. 여러 이벤트가 같은 대리자 형식을 공유할 수 있으므로 이미 선언된 적합한 대리자 형식이 없는 경우에만 이 단계가 필요합니다.

그 다음, 이벤트 자체를 선언합니다.

public event ChangedEventHandler Changed;

이벤트는 키워드event가 이벤트 선언 앞, 한정자 뒤에 온다는 점을 제외하면 대리자 형식의 필드처럼 선언됩니다. 이벤트는 일반적으로 공용으로 선언되지만 모든 액세스 가능성 한정자를 사용할 수 있습니다.

이벤트 호출   일단 클래스가 이벤트를 선언하면 해당 이벤트를 지정된 대리자 형식의 필드처럼 처리할 수 있습니다. 클라이언트가 대리자를 이벤트에 연결하지 않았으면 필드는 Null이 되거나 그렇지 않으면 이벤트를 호출할 때 호출해야 하는 대리자를 참조합니다. 따라서, 이벤트 호출은 일반적으로 우선 Null인지 확인한 다음 이벤트를 호출하여 실행합니다.

if (Changed != null)
Changed(this, e);

이벤트를 선언한 클래스 내에서만 이벤트를 호출할 수 있습니다.

이벤트 연결   이벤트를 선언한 클래스 밖에서 이벤트는 필드처럼 보이지만 해당 필드에 대한 액세스는 매우 제한되어 있습니다. 다음 작업만 가능합니다.

        1. 해당 필드에 새 대리자 작성

        2. 주로 복합 필드에서 대리자 제거

+=-=연산자로 작업합니다. 이벤트 호출 수신을 시작하려면 클라이언트 코드가 우선 이벤트에서 호출해야 하는 메서드를 참조하는 이벤트 형식의 대리자를 만듭니다. 그런 다음 클라이언트 코드는 이벤트가+=을 사용하여 연결할 수 있는 다른 대리자에 해당 대리자를 작성합니다.

// Add "ListChanged" to the Changed event on "List":
List.Changed += new ChangedEventHandler(ListChanged);

클라이언트 코드의 이벤트 호출 수신이 끝나면-=연산자를 사용하여 이벤트에서 대리자를 제거합니다.

// Detach the event and delete the list:
List.Changed -= new ChangedEventHandler(ListChanged);

 

 

이벤트 및 상속

파생될 수 있는 일반 구성 요소를 만들 때 이벤트에 종종 문제가 발생합니다. 이벤트를 선언한 클래스 내에서만 이벤트를 호출할 수 있으므로 파생 클래스는 기본 클래스에서 선언된 이벤트를 직접 호출할 수 없습니다. 이렇게 하는 것이 바람직할 때도 있지만 파생된 클래스가 이벤트를 자유롭게 호출할 수 있도록 하는 것이 더 적절합니다. 이것은 일반적으로 이벤트에 대한 보호 호출 메서드를 만들어 실행할 수 있습니다. 이 호출 메서드를 호출하면 파생된 클래스가 이벤트를 호출할 수 있습니다. 또한, 더 많은 융통성을 제공하기 위해 호출 메서드를 가상으로 선언하고 파생된 클래스가 이 메서드를 무시하도록 하는 경우도 있습니다. 이렇게 하면 파생 클래스가 자체 프로세스를 거쳐 기본 클래스에서 호출하는 이벤트를 가로챌 수 있습니다.

이전 예제에서는OnChanged메서드를 사용하여 이 작업을 실행하였습니다. 필요한 경우 파생 클래스는 이 메서드를 호출하거나 무시할 수 있었습니다.

 

 

인터페이스 내의 이벤트

이벤트와 필드의 또 다른 차이점은 이벤트는 인터페이스 안에 있을 수 있지만 필드는 그렇지 않다는 점입니다. 인터페이스를 구현할 때 구현 클래스는 인터페이스를 구현하는 클래스에 해당 이벤트를 입력해야 합니다.

 

 

.NET FREAMWORK 지침

C# 언어를 사용하면 이벤트에서 모든 대리자 형식을 사용할 수 있지만 .NET Framework에서는 이벤트에 사용해야 하는 대리자 형식에 대한 엄격한 지침이 몇 가지 있습니다. 구성 요소를 .NET Framework에서 사용하려면 다음 지침을 따라야 합니다.

.NET Framework지침에는 이벤트에 사용된 대리자 형식이 두 가지 매개 변수를 사용하도록 되어 있으며, 이는 이벤트 원본을 나타내는 "개체 원본" 매개 변수와 이벤트에 대한 모든 추가 정보를 캡슐화하는 "e" 매개 변수입니다. "e" 매개 변수 형식은EventArgs클래스에서 파생됩니다. 추가 정보를 사용하지 않는 이벤트에 대해서는 .NET Framework에서 이미 적절한 대리자 형식인EventHandler를 정의해 두었습니다.

 

 

예제 2

다음 예제는 .NET Framework 지침을 따르는 예제 1의 수정된 버전으로EventHandler대리자 형식을 사용합니다.

// events2.cs
using System;
namespace MyCollections
{
   using System.Collections;

   // A class that works just like ArrayList, but sends event
   // notifications whenever the list changes:
   public class ListWithChangedEvent: ArrayList
   {
      // An event that clients can use to be notified whenever the
      // elements of the list change:
      public event EventHandler Changed;

      // Invoke the Changed event; called whenever list changes:
      protected virtual void OnChanged(EventArgs e)
      {
         if (Changed != null)
            Changed(this,e);
      }

      // Override some of the methods that can change the list;
      // invoke event after each:
      public override int Add(object value)
      {
         int i = base.Add(value);
         OnChanged(EventArgs.Empty);
         return i;
      }

      public override void Clear()
      {
         base.Clear();
         OnChanged(EventArgs.Empty);
      }

      public override object this[int index]
      {
         set
         {
            base[index] = value;
            OnChanged(EventArgs.Empty);
         }
      }
   }
}

namespace TestEvents
{
   using MyCollections;

   class EventListener
   {
      private ListWithChangedEvent List;

      public EventListener(ListWithChangedEvent list)
      {
         List = list;
         // Add "ListChanged" to the Changed event on "List":
         List.Changed += new EventHandler(ListChanged);
      }

      // This will be called whenever the list changes:
      private void ListChanged(object sender, EventArgs e)
      {
         Console.WriteLine("This is called when the event fires.");
      }

      public void Detach()
      {
         // Detach the event and delete the list:
         List.Changed -= new EventHandler(ListChanged);
         List = null;
      }
   }

   class Test
   {
      // Test the ListWithChangedEvent class:
      public static void Main()
      {
      // Create a new list:
      ListWithChangedEvent list = new ListWithChangedEvent();

      // Create a class that listens to the list’s change event:
      EventListener listener = new EventListener(list);

      // Add and remove items from the list:
      list.Add("item 1");
      list.Clear();
      listener.Detach();
      }
   }
}

출력

This is called when the event fires.
This is called when the event fires.

 


답글 남기기

이메일 주소는 공개되지 않습니다.