delegate 02. Event
이벤트는 대리자와 같은 개념으로, 대리자를 이해한 후 이벤트를 학습해야 한다.
이벤트가 대리자와 다른점은, 이벤트는 메서드 안에서만 호출해서 사용 가능하다는 점이다.
이벤트가 시작되는 로직과, 이벤트에 영향을 받아 동작하는 로직을 구분하는것이 먼저다.
아래 예제는, 버튼이 눌려지면, 레이블에 문자열이 수정되는 구조를 구현한다고 가정하자.
eg) [버튼 클릭 > 이벤트(대리자)] > 레이블 수정
1. 이벤트 선언 방법
이벤트는 대리자를 event 한정자로 수식해서 만든다.
[ event 키워드 ] [ 대리자 ] [ 이벤트이름 ];
2. 이벤트 선언의 목적
위 예제 구조에서 구현된 이벤트는, 이벤트를 형태의 선언이 목적이 아니다.
레이블의 수정이 목적이다.
시작은 Button 객체의 click 함수의 실행
목적은 Label 객체의 show 함수의 실행이다.
이벤트는 click 함수가 show 함수를 실행하게 만드는 것이다.
* 이벤트는 목적함수인 show 함수를 기반으로 선언된다.
namespace ConsoleApp2
{
delegate void pass(string msg);
class Button
{
public event pass EventHandler;
public void click(string x) // 2.1 함수의
{
EventHandler(x); // 2.2 이벤트 동작
}
}
class Label
{
public void show(string x) // 4.1 함수의
{
Console.WriteLine("Lable print >> " + x); // 4.2 매개변수 전달받아 동작
}
}
internal class Program
{
static void Main(string[] args)
{
Button btn = new Button();
Label lbl = new Label();
// 버튼 객체의 이벤트(=대리자)에, 레이블 객체의 함수를 등록한다.
btn.EventHandler += new pass(lbl.show); // 3. 이벤트에 연결된 lbl.show() 동작
btn.click("click~!!"); // 1. 버튼의 click 함수가 실행되면
}
}
}
3. 이벤트 이해
이벤트를 발생(시작)시키는 객체의 실행로직과,
발생된 이벤트가 영향받는(목적) 객체의 실행로직 구분이, 이벤트 기반(Event Driven) 구조의 이해다.
// 버튼을 누르면, 레이블에 출력된다고 가정한다.
using System;
namespace EventTest
{
delegate void Callback(string message);
class Button
{
public event Callback CollbackEvent;
public void Check369(int number) // [2]
{
int temp = number % 10;
if (temp != 0 && temp % 3 == 0)
CollbackEvent(String.Format("{0} : 짝", number)); // [3]
}
}
class Label
{
public void ShowMsg(string message) // [5]
{
Console.WriteLine(message); // [6]
}
}
class MainApp
{
static void Main(string[] args)
{
Button btn = new Button();
Label lbl = new Label();
// 버튼 객체의 이벤트(=대리자)에, 레이블 객체의 함수를 등록한다.
// 버튼 객체의 이벤트(=대리자)에, 레이블 객체의 함수
btn.CollbackEvent += new Callback(lbl.ShowMsg); // [4]
// 버튼이 눌려진다고 가정한다.
// 버튼이 눌려질 때마다 정수 1~30을 순차적으로 전달한다.
// 1. 버튼이 눌려지고 -> 2. Check369() 함수가 실행되고
// 3. CollbackEvent가 실행되고, 매개변수로 "문자열"이 전달된다.
// 4. CollbackEvent에 연결된, 레이블의 ShowMsg함수가 실행된다.
for (int i = 1; i < 30; i++)
btn.Check369(i); // [1]
}
}
}
// 이것이 c#이다. 교재 496쪽 소스코드
using System;
namespace EventTest
{
delegate void EventHandler(string message);
class MyNotifier
{
public event EventHandler SomethingHappened;
public void DoSomething(int number)
{
int temp = number % 10;
if ( temp != 0 && temp % 3 == 0)
{
SomethingHappened(String.Format("{0} : 짝", number));
}
}
}
class MainApp
{
static public void MyHandler(string message)
{
Console.WriteLine(message);
}
static void Main(string[] args)
{
MyNotifier notifier = new MyNotifier();
notifier.SomethingHappened += new EventHandler(MyHandler);
for (int i = 1; i < 30; i++)
{
notifier.DoSomething(i);
}
}
}
}
이벤트 실행 흐름
예제 1
카운팅이라는 로직을 가진 객체의 이벤트가 동작할때마다, 텍스트박스 객체에 출력된다고 가정한다.
using System;
namespace delegate_test4
{
delegate void A (string sender);
class TextBox
{
private string title;
public TextBox(string name)
{
this.title = name;
}
public void run(string run_msg)
{
Console.WriteLine( run_msg + title + "에서 출력!");
}
}
class Program
{
static void Main(string[] args)
{
TextBox TB1 = new TextBox("텍스트창1");
TextBox TB2 = new TextBox("텍스트창2");
TextBox TB3 = new TextBox("텍스트창3");
TextBox TB4 = new TextBox("텍스트창4");
Counting cnt = new Counting();
cnt.Cnt_EventHandler += TB1.run;
cnt.Cnt_EventHandler += TB2.run;
cnt.Cnt_EventHandler += TB3.run;
cnt.Cnt_EventHandler += TB4.run;
cnt.nCnt();
}
}
class Counting
{
public event A Cnt_EventHandler;
public void nCnt()
{
for (int i = 0; i < 10; i++)
{
Cnt_EventHandler($"이벤트, {i+1}회 실행 >> ");
}
}
}
}
예제3
button1 이라는 객체에, button1.Click 이벤트에, Form1의 button1_click( ) 함수가 등록되었다.
"Button 객체의 Event" 라는 대리자가 실행되면, 윈폼의 함수, 윔폼의 컨트롤, 또는 특정 실행 로직을 가진 함수가 실행되도록 구현하는 개념이다.
예제4
윈폼 파일 복사 (동기)
해당 로직은 동기화 방식으로, 파일 복사 실행중에는 UI가 멈춤
event_test 프로젝트 경로에 "파일 복사"에 사용 할 파일 src.mp4 파일이 있어야 합니다.
(TCP/IP 서버-클라이언트 구조에서 파일 전송으로 가정하고 접근합니다.)
이벤트 제공자 : button1.click
이벤트 가입자 : FileManager
환경: Visual Studio 2022, net8.0
예제5
윈폼 파일 복사 (비동기)
event_test 프로젝트 경로에 "파일 복사"에 사용 할 파일 src.mp4 파일이 있어야 합니다.
이벤트 제공자 : FileManager
이벤트 가입자 : Form1
환경: Visual Studio 2022, net8.0