Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

Chapter 89: Events

Parameter

Details

EventArgsT

The type that derives from EventArgs and contains the event parameters.

EventName

The name of the event.

HandlerName

The name of the event handler.

SenderObject

The object that's invoking the event.

EventArguments An instance of the EventArgsT type that contains the event parameters.

An event is a notification that something has occurred (such as a mouse click) or, in some cases, is about to occur (such as a price change).

Classes can define events and their instances (objects) may raise these events. For instance, a Button may contain a Click event that gets raised when a user has clicked it.

Event handlers are then methods that get called when their corresponding event is raised. A form may contain a Clicked event handler for every Button it contains, for instance.

Section 89.1: Declaring and Raising Events

Declaring an Event

You can declare an event on any class or struct using the following syntax:

public class MyClass

{

//Declares the event for MyClass public event EventHandler MyEvent;

//Raises the MyEvent event

public void RaiseEvent()

{

OnMyEvent();

}

}

There is an expanded syntax for declaring events, where you hold a private instance of the event, and define a public instance using add and set accessors. The syntax is very similar to C# properties. In all cases, the syntax demonstrated above should be preferred, because the compiler emits code to help ensure that multiple threads can safely add and remove event handlers to the event on your class.

Raising the Event

Version ≥ 6.0

private void OnMyEvent()

{

EventName?.Invoke(this, EventArgs.Empty);

}

Version < 6.0

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;

GoalKicker.com – C# Notes for Professionals

494

//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);

}

Note that events can only be raised by the declaring type. Clients can only subscribe/unsubscribe.

For C# versions before 6.0, where EventName?.Invoke is not supported, it is a good practice to assign the event to a temporary variable before invocation, as shown in the example, which ensures thread-safety in cases where multiple threads execute the same code. Failing to do so may cause a NullReferenceException to be thrown in certain cases where multiple threads are using the same object instance. In C# 6.0, the compiler emits code similar to that shown in the code example for C# 6.

Section 89.2: Event Properties

If a class raises a large the number of events, the storage cost of one field per delegate may not be acceptable. The

.NET Framework provides event properties for these cases. This way you can use another data structure like EventHandlerList to store event delegates:

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);

}

}

This approach is widely used in GUI frameworks like WinForms where controls can have dozens and even hundreds of events.

Note that EventHandlerList is not thread-safe, so if you expect your class to be used from multiple threads, you will need to add lock statements or other synchronization mechanism (or use a storage that provides thread

GoalKicker.com – C# Notes for Professionals

495

safety).

Section 89.3: Creating cancelable event

A cancelable event can be raised by a class when it is about to perform an action that can be canceled, such as the

FormClosing event of a Form.

To create such event:

Create a new event arg deriving from CancelEventArgs and add additional properties for event data.

Create an event using EventHandler<T> and use the new cancel event arg class which you created.

Example

In the below example, we create a PriceChangingEventArgs event for Price property of a class. The event data class contains a Value which let the consumer know about the new . The event raises when you assign a new value to Price property and lets the consumer know the value is changing and let them to cancel the event. If the consumer cancels the event, the previous value for Price will be used:

PriceChangingEventArgs

public class PriceChangingEventArgs : CancelEventArgs

{

int value; public int Value

{

get { return value; }

}

public PriceChangingEventArgs(int value)

{

this.value = value;

}

}

Product

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);

}

GoalKicker.com – C# Notes for Professionals

496

}

Section 89.4: Standard Event Declaration

Event declaration:

public event EventHandler<EventArgsT> EventName;

Event handler declaration:

public void HandlerName(object sender, EventArgsT args) { /* Handler logic */ }

Subscribing to the event:

Dynamically:

EventName += HandlerName;

Through the Designer:

1.Click the Events button on the control's properties window (Lightening bolt)

2.Double-click the Event name:

3. Visual Studio will generate the event code:

private void Form1_Load(object sender, EventArgs e)

{

}

Invoking the method:

GoalKicker.com – C# Notes for Professionals

497