본문 바로가기
프로그래밍/C# (WinForms)

C#, WinForms ] Event 와 delegate

by eteo 2023. 5. 14.

 

 

C#에서 이벤트를 사용하면 프로그램의 느슨한 결합(loose coupling)을 통해 객체 간 상호작용을 구현할 수 있다.

 

이벤트는 객체가 발생시키는 특정한 동작을 나타내며, 이벤트를 구독하는 다른 객체는 해당 이벤트를 수신하고 이벤트 처리기를 호출한다. 이를 통해 클래스 내부에서 발생한 동작을 외부에서 알림으로써 더욱 유연하고 효율적인 프로그래밍을 구현할 수 있다.

 

이벤트를 발생시키는 쪽이 Publisher이고 이벤트를 수신하고 처리하는 쪽이 Subscriber가 된다.

 

 

 

 

1. delegate 정의 및 이벤트 선언하기

 

Publisher 쪽에서 메서드를 참조하는 형식인 delegate를 사용하여 이벤트를 선언하면 된다.

직접 delegate 정의를 할 수도 있고 system namespace에 이미 정의된 EventHandler를 사용할 수도 있다.

 

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

// ...

public EventPublisher 
{
    public event EventHandler MyEvent;
}


또한 이벤트를 선언할 때 <TEventArgs> 부분에 원하는 타입의 인자를 명시할 수도 있다. EventArgs를 형변환하여 사용하는 것도 가능하지만 원하는 타입을 명시하는 것이 좀 더 안전한 방법이다.

 

public event EventHandler<int> MyEvent;

// 이벤트 핸들러
private void OnMyEvent(object sender, int e)
{
    // ...
}

 

 

 

 

2. 이벤트 구독하기

 

Subscriber 쪽에서 이벤트를 구독하고 이벤트 처리기를 작성한다.

 

 

public class EventSubscriber
{
    public EventSubscriber()
    {
    	// 이벤트 구독
        EventPublisher.MyEvent += MyEventHandler;
    }

    private void MyEventHandler(object sender, EventArgs e)
    {
        // 이벤트 처리 코드
    }
}

 

 

 

 

3. 이벤트 발생시키기

 

MyEvent 가 null 이 아닐때만 이벤트를 발생시키도록 하기 위해 ?. 연산자를 사용한다.

Invoke를 사용해 첫번째 매개변수인 object sender는 이벤트를 발생시킨 객체인 this를 전달하고 두번째 매개변수인 EventArgs e에는 전달할 내용이 없어 EventArgs.Empty를 전달하고 있다. 

 

public class EventPublisher
{
    public event EventHandler MyEvent;

    public void PublishEvent()
    {
        // 이벤트 발생
        MyEvent?.Invoke(this, EventArgs.Empty);
    }
}

 

 

 

 

4. 이벤트 구독 해제

 

public void Unsubscribe()
{
    publisher.MyEvent -= MyEventHandler
}

 

 

 

 

 

 

 

 

 

 

 

 

사용예시

 

자식 폼에서 Cancel 버튼 클릭시 부모 폼 Exit

 

 

 

1. delegate 직접 정의하는 방법

 

Publisher 클래스

public partial class DeviceListForm : Form
{
	// ...
    
    // 반환형과 파라미터가 void인 delegate 선언
    public delegate void OnCancelDelegate();
    // delegate를 이용 event 선언
    public event OnCancelDelegate OnCancel;
    
    private void buttonCancel_Click(object sender, EventArgs e)
    {
        // event 메서드 호출
        OnCancel();
		// 또는 OnCancel?.Invoke();
    }
    
    // ...
}

 

Subscriber 클래스

public partial class MainForm : Form
{
    private DeviceListForm deviceListForm;

	// ...

    private void MainForm_Load(object sender, EventArgs e)
    {
        deviceListForm = new DeviceListForm();
        // 이벤트 구독
        deviceListForm.OnCancel += deviceListForm_OnCancel;
    }

    private void MainForm_Shown(object sender, EventArgs e)
    {
        deviceListForm.Show();
    }

	// 이벤트 핸들러
    void deviceListForm_OnCancel()
    {
        Application.Exit();
    }
}

 

 

 

 

 

2. EventHandler delegate 타입 사용

 

Publisher 클래스

public partial class DeviceListForm : Form
{
	// ...
    
    // event 선언
    public event EventHandler OnCancel;
    
    private void buttonCancel_Click(object sender, EventArgs e)
    {
        // event 메서드 호출
        OnCancel?.Invoke(this, EventArgs.Empty);
    }
    
    // ...
}

 

Subscriber 클래스

public partial class MainForm : Form
{
    private DeviceListForm deviceListForm;

	// ...

    private void MainForm_Load(object sender, EventArgs e)
    {
        deviceListForm = new DeviceListForm();
        // 이벤트 구독
        deviceListForm.OnCancel += deviceListForm_OnCancel;
    }

    private void MainForm_Shown(object sender, EventArgs e)
    {
        deviceListForm.Show();
    }

	// 이벤트 핸들러
    void deviceListForm_OnCancel(object sender, EventArgs e)
    {
        Application.Exit();
    }
}