수색…
소개
이벤트 란 마우스 클릭과 같은 어떤 일이 발생했거나 경우에 따라 가격 변경과 같은 일이 발생한다는 알림입니다.
클래스는 이벤트를 정의 할 수 있으며 인스턴스 (객체)가 이러한 이벤트를 발생시킬 수 있습니다. 예를 들어, 버튼에는 사용자가 클릭했을 때 발생하는 Click 이벤트가 포함될 수 있습니다.
이벤트 핸들러는 해당 이벤트가 발생할 때 호출되는 메소드입니다. 폼에는 포함 된 모든 Button에 대한 Clicked 이벤트 핸들러가 포함될 수 있습니다.
매개 변수
매개 변수 | 세부 |
---|---|
EventArgsT | EventArgs에서 파생되고 이벤트 매개 변수를 포함하는 형식입니다. |
EventName | 이벤트 이름. |
처리기 이름 | 이벤트 처리기의 이름입니다. |
SenderObject | 이벤트를 호출하는 객체입니다. |
EventArguments | 이벤트 매개 변수를 포함하는 EventArgsT 유형의 인스턴스입니다. |
비고
이벤트를 제기 할 때 :
- 대리자가
null
인지 항상 확인하십시오. null 위임은 이벤트에 구독자가 없음을 의미합니다. 구독자가없는 이벤트를 발생NullReferenceException
합니다.
- null을 확인하거나 이벤트를 발생시키기 전에 대리자 (예 :
EventName
)를 로컬 변수 (예 :eventName
)에 복사합니다. 이렇게하면 멀티 스레드 환경에서 경쟁 조건을 피할 수 있습니다.
틀린 :
if(Changed != null) // Changed has 1 subscriber at this point
// In another thread, that one subscriber decided to unsubscribe
Changed(this, args); // `Changed` is now null, `NullReferenceException` is thrown.
오른쪽 :
// Cache the "Changed" event as a local. If it is not null, then use
// the LOCAL variable (handler) to raise the event, NOT the event itself.
var handler = Changed;
if(handler != null)
handler(this, args);
-
if
문에서 구독자에 대한 대리자를 null 확인하는 대신 메서드를 발생시키는 데 null 조건부 연산자 (?)를 사용합니다.EventName?.Invoke(SenderObject, new EventArgsT());
- Action <>을 사용하여 대리자 형식을 선언하는 경우 익명 메서드 / 이벤트 처리기 서명은 이벤트 선언의 선언 된 익명 대리자 형식과 동일해야합니다.
이벤트 선언 및 발생
이벤트 선언
다음 구문을 사용하여 모든 class
또는 struct
에서 이벤트를 선언 할 수 있습니다.
public class MyClass
{
// Declares the event for MyClass
public event EventHandler MyEvent;
// Raises the MyEvent event
public void RaiseEvent()
{
OnMyEvent();
}
}
이벤트를 선언하기위한 확장 구문은 이벤트의 전용 인스턴스를 보유하고 add
및 set
접근자를 사용하여 공용 인스턴스를 정의합니다. 구문은 C # 속성과 매우 유사합니다. 컴파일러는 여러 스레드가 클래스의 이벤트에 이벤트 처리기를 안전하게 추가하고 제거 할 수 있도록 코드를 생성하기 때문에 위에 설명 된 구문을 사용하는 것이 좋습니다.
이벤트 모금
private void OnMyEvent()
{
EventName?.Invoke(this, EventArgs.Empty);
}
private void OnMyEvent()
{
// Use a local for EventName, because another thread can modify the
// public EventName between when we check it for null, and when we
// raise the event.
var eventName = EventName;
// If eventName == null, then it means there are no event-subscribers,
// and therefore, we cannot raise the event.
if(eventName != null)
eventName(this, EventArgs.Empty);
}
이벤트는 선언 유형에 의해서만 제기 될 수 있습니다. 클라이언트는 가입 / 탈퇴 만 할 수 있습니다.
6.0 이전의 C # 버전에서 EventName?.Invoke
가 지원되지 않는 경우 예제와 같이 호출 전에 임시 변수에 이벤트를 할당하면 여러 스레드가 동일한 스레드를 실행하는 경우 스레드 안전성을 보장 할 수 있습니다. 암호. 이렇게하지 않으면 여러 스레드가 동일한 객체 인스턴스를 사용하는 경우에 NullReferenceException
이 발생합니다. C # 6.0에서 컴파일러는 C # 6의 코드 예제와 비슷한 코드를 내 보냅니다.
표준 이벤트 선언
이벤트 선언 :
public event EventHandler<EventArgsT> EventName;
이벤트 처리기 선언 :
public void HandlerName(object sender, EventArgsT args) { /* Handler logic */ }
이벤트 구독 :
동적으로 :
EventName += HandlerName;
디자이너를 통해 :
- 컨트롤의 속성 창에서 이벤트 버튼을 클릭합니다 (Lightening bolt).
- 이벤트 이름을 두 번 클릭하십시오.
- Visual Studio에서 이벤트 코드를 생성합니다.
private void Form1_Load(object sender, EventArgs e)
{
}
메소드 호출 :
EventName(SenderObject, EventArguments);
익명 이벤트 처리기 선언
이벤트 선언 :
public event EventHandler<EventArgsType> EventName;
람다 연산자 => 를 사용하고 이벤트에 가입하는 이벤트 핸들러 선언 :
EventName += (obj, eventArgs) => { /* Handler logic */ };
대리자 익명 메서드 구문을 사용하는 이벤트 처리기 선언 :
EventName += delegate(object obj, EventArgsType eventArgs) { /* Handler Logic */ };
이벤트의 매개 변수를 사용하지 않는 이벤트 핸들러의 선언 및 가입이므로 매개 변수를 지정하지 않아도 위의 구문을 사용할 수 있습니다.
EventName += delegate { /* Handler Logic */ }
이벤트 호출 :
EventName?.Invoke(SenderObject, EventArguments);
비표준 이벤트 선언
이벤트는 EventHandler
및 EventHandler<T>
뿐만 아니라 모든 대리자 유형이 될 수 있습니다. 예 :
//Declaring an event
public event Action<Param1Type, Param2Type, ...> EventName;
표준 EventHandler
이벤트와 유사하게 사용됩니다.
//Adding a named event handler
public void HandlerName(Param1Type parameter1, Param2Type parameter2, ...) {
/* Handler logic */
}
EventName += HandlerName;
//Adding an anonymous event handler
EventName += (parameter1, parameter2, ...) => { /* Handler Logic */ };
//Invoking the event
EventName(parameter1, parameter2, ...);
필드와 지역 변수와 비슷하게 단일 명령문에 같은 유형의 여러 이벤트를 선언 할 수 있습니다 (그러나 이것은 종종 나쁜 생각 일 수 있음).
public event EventHandler Event1, Event2, Event3;
이것은 EventHandler
유형의 세 가지 개별 이벤트 ( Event1
, Event2
및 Event3
)를 선언합니다.
참고 : 일부 컴파일러는 클래스뿐만 아니라 인터페이스에서도이 구문을 사용할 수 있지만 C # 사양 (v5.0 §13.2.3)에서는 허용하지 않는 인터페이스에 대한 문법을 제공하므로 인터페이스에서 사용하면 다른 컴파일러에서 신뢰할 수 없게 될 수 있습니다.
추가 데이터가 포함 된 사용자 지정 EventArg 만들기
사용자 정의 이벤트는 대개 이벤트에 대한 정보를 포함하는 사용자 정의 이벤트 인수가 필요합니다. MouseDown
또는 MouseUp
이벤트와 같은 마우스 이벤트에 사용되는 MouseEventArgs
에는 이벤트를 생성하는 데 사용 된 Location
또는 Buttons
에 대한 정보가 들어 있습니다.
새 이벤트를 만들 때 맞춤 이벤트 arg를 만들려면 :
-
EventArgs
에서 파생되는 클래스를 만들고 필요한 데이터에 대한 속성을 정의합니다. - 규약에 따라 클래스 이름은
EventArgs
끝나야합니다.
예
아래 예제에서는 클래스의 Price
속성에 대한 PriceChangingEventArgs
이벤트를 만듭니다. 이벤트 데이터 클래스에는 CurrentPrice
와 NewPrice
됩니다. 이 이벤트는 Price
속성에 새 값을 할당하고 소비자가 값이 변경되고 있음을 알리고 현재 가격과 새 가격을 알 수있게하면 발생합니다.
PriceChangingEventArgs
public class PriceChangingEventArgs : EventArgs
{
public PriceChangingEventArgs(int currentPrice, int newPrice)
{
this.CurrentPrice = currentPrice;
this.NewPrice = newPrice;
}
public int CurrentPrice { get; private set; }
public int NewPrice { get; private set; }
}
생성물
public class Product
{
public event EventHandler<PriceChangingEventArgs> PriceChanging;
int price;
public int Price
{
get { return price; }
set
{
var e = new PriceChangingEventArgs(price, value);
OnPriceChanging(e);
price = value;
}
}
protected void OnPriceChanging(PriceChangingEventArgs e)
{
var handler = PriceChanging;
if (handler != null)
handler(this, e);
}
}
소비자가 새 값을 변경하도록 허용 한 다음 값을 속성에 사용하여 예제를 향상시킬 수 있습니다. 이렇게하면 수업에서 이러한 변경 사항을 적용하는 것으로 충분합니다.
설정 가능한 NewPrice
의 정의를 변경하십시오.
public int NewPrice { get; set; }
e.NewPrice
을 호출 한 후 OnPriceChanging
를 속성의 값으로 사용하도록 Price
의 정의를 변경합니다.
int price;
public int Price
{
get { return price; }
set
{
var e = new PriceChangingEventArgs(price, value);
OnPriceChanging(e);
price = e.NewPrice;
}
}
취소 가능한 이벤트 만들기
그 예로서, 해제 할 수있는 동작을 수행하고있을 때 취소 가능한 이벤트 클래스에 의해 상승 될 수 FormClosing
(A)의 이벤트 Form
.
이러한 이벤트를 생성하려면 다음을 수행하십시오.
-
CancelEventArgs
에서 파생 된 새 이벤트 arg를 작성하고 이벤트 데이터에 대한 추가 특성을 추가하십시오. -
EventHandler<T>
를 사용하여 이벤트를 만들고 생성 한 새 cancel 이벤트 arg 클래스를 사용하십시오.
예
아래 예제에서는 클래스의 Price
속성에 대한 PriceChangingEventArgs
이벤트를 만듭니다. 이벤트 데이터 클래스에는 소비자가 새 정보를 알 수 있도록하는 Value
가 들어 있습니다. 이 이벤트는 Price
속성에 새 값을 할당하고 소비자가 값이 변경되고 있음을 알리고 이벤트를 취소하도록 할 때 발생합니다. 소비자가 이벤트를 취소하면 이전 Price
값이 사용됩니다.
PriceChangingEventArgs
public class PriceChangingEventArgs : CancelEventArgs
{
int value;
public int Value
{
get { return value; }
}
public PriceChangingEventArgs(int value)
{
this.value = value;
}
}
생성물
public class Product
{
int price;
public int Price
{
get { return price; }
set
{
var e = new PriceChangingEventArgs(value);
OnPriceChanging(e);
if (!e.Cancel)
price = value;
}
}
public event EventHandler<PriceChangingEventArgs> PropertyChanging;
protected void OnPriceChanging(PriceChangingEventArgs e)
{
var handler = PropertyChanging;
if (handler != null)
PropertyChanging(this, e);
}
}
이벤트 속성
클래스에서 이벤트 수가 많아지면 대리인 당 한 필드의 저장 비용이 용납되지 않을 수 있습니다. .NET Framework는 이러한 경우에 대한 이벤트 속성 을 제공합니다. 이렇게하면 EventHandlerList
와 같은 다른 데이터 구조를 사용하여 이벤트 대리자를 저장할 수 있습니다.
public class SampleClass
{
// Define the delegate collection.
protected EventHandlerList eventDelegates = new EventHandlerList();
// Define a unique key for each event.
static readonly object someEventKey = new object();
// Define the SomeEvent event property.
public event EventHandler SomeEvent
{
add
{
// Add the input delegate to the collection.
eventDelegates.AddHandler(someEventKey, value);
}
remove
{
// Remove the input delegate from the collection.
eventDelegates.RemoveHandler(someEventKey, value);
}
}
// Raise the event with the delegate specified by someEventKey
protected void OnSomeEvent(EventArgs e)
{
var handler = (EventHandler)eventDelegates[someEventKey];
if (handler != null)
handler(this, e);
}
}
이 접근법은 WinForms와 같은 GUI 프레임 워크에서 널리 사용됩니다. 여기에는 컨트롤에 수십 개 심지어 수백 개의 이벤트가있을 수 있습니다.
EventHandlerList
는 스레드로부터 안전하지 않으므로 클래스가 여러 스레드에서 사용될 것으로 예상되는 경우 잠금 문이나 기타 동기화 메커니즘을 추가하거나 스레드 안전성을 제공하는 저장소를 사용해야합니다.