Tapahtumat ovat toimintoja, jotka yleensä ilmoittavat ohjelman muuttuneesta tilasta. Niitä käytetään paljon graafisten (työpöytä)käyttöliittymien ohjelmoinnissa. Esim. painikkeen klikkaaminen laukaisee yleensä tapahtuman.

Tapahtumat eivät itse tee mitään, vaan sitä varten ovat tapahtumankäsittelijät. Tapahtumaa voisi verrata radioon ja tapahtumankäsittelijöitä kuuntelijoiksi. Yhdellä tapahtumalla (lähettäjä) voi olla useita käsittelijöitä (kuuntelijat) eivätkä käsittelijät tiedä toisistaan. Kukin käsittelijä reagoi tapahtumaan itsenäisesti.

Tapahtumat vaikuttavat Delegaatit instansseilta, mutta tapahtuman ja normaalin delegaatin käytössä on joitain eroja. Tapahtumat liittyvät lähettäjään ja siksi lähettäjän ulkopuolelta ei saisi

Tapahtumat tehdään delegaatilla EventHandler, joka ei ota argumenttia ja sen geneerisellä versiolla EventHandler, jossa T on argumenttina annettava luokka. Tämän lisäksi tarvitaan avainsana event.

public class TapahtumaLuokka
{
	// tapahtuma, joka ei ota argumenttia
	public event EventHandler JotainTehty = delegate { };
	// tapahtuma, joka ottaa argumenttina ArvoMuuttuiEventArgs-objektin
	public event EventHandler<ArvoMuuttuiEventArgs> ArvoMuuttui = delegate { };

	public string Nimi { get; set; }

	private int arvo;
	public int Arvo
	{
		get
		{
			return arvo;
		}
		set
		{
			if (arvo == value)
			{
				// jos uusi arvo on sama kuin vanha
				// ei tehdä mitään
				return;
			}

			// otetaan vanha arvo talteen
			int vanha = arvo;
			// sijoitetaan uusi arvo
			arvo = value;
			// ilmoitetaan muuttuneesta arvosta
			ArvoMuuttui(this, new ArvoMuuttuiEventArgs(Nimi,vanha, arvo));
		}
	}

	public TapahtumaLuokka(string nimi, int arvo)
	{
		Nimi = nimi;
		this.arvo = arvo;
	}
	public void TeeJotain()
	{
		// tässä tehdään jotain
		Console.WriteLine("{0} tekee jotain", Nimi);
		// ilmoitetaan, että jotain on tehty
		JotainTehty(this, EventArgs.Empty);
	}
}

Argumenttina annettava luokka kokoaa tapahtumaan liittyvät tiedot yhteen. Tällaisen luokan nimen tulisi päättyä EventArgs. Esim. luokka, joka kokoaa yhteen muuttuneen arvon tietoja.

public class ArvoMuuttuiEventArgs : EventArgs
{
	// olion nimi
	public string Nimi { get; set; }
	// vanha arvo
	public int Vanha { get; set; }
	// uusi arvo
	public int Uusi { get; set; }

	public ArvoMuuttuiEventArgs(string nimi, int vanha, int uusi)
	{
		Nimi = nimi;
		Vanha = vanha;
		Uusi = uusi;
	}
}

Ja vielä käyttöesimerkki.

class Program
{
	static void Main(string[] args)
	{
		TapahtumaLuokka t1 = new TapahtumaLuokka("eka", 1);
		// lisätään tapahtumankäsittelijä
		t1.JotainTehty += new EventHandler(t1_JotainTehty);
		// lisätään tapahtumankäsittelijä
		t1.ArvoMuuttui += new EventHandler<ArvoMuuttuiEventArgs>(testi_ArvoMuuttui);

		t1.TeeJotain();
		t1.Arvo = 10;
	}
	static void t1_JotainTehty(object sender, EventArgs e)
	{
		Console.WriteLine("t1 teki jotain");
	}
	// huomaa argumenttina tuleva ArvoMuuttuiEventArgs
	static void testi_ArvoMuuttui(object sender, ArvoMuuttuiEventArgs e)
	{
		Console.WriteLine("{0}:n vanha arvo oli {1} ja uusi arvo on {2}",e.Nimi, e.Vanha, e.Uusi);
	}
}

add- ja remove-aksessorit

Tapahtumankäsittelijöiden lisäämiseen ja poistamiseen saa enemmän hallintaa, kun lisää add- ja remove-aksessorit, jotka muistuttavat pitkälti ominaisuuksien get- ja set-aksessoreita.

Lisätään edellä olleeseen TapahtumaLuokkaan nuo aksessorit

public class TapahtumaLuokka2
{
	// tapahtuma, joka ottaa argumentin
	private event EventHandler<ArvoMuuttuiEventArgs> arvoMuuttui = delegate { };
	public event EventHandler<ArvoMuuttuiEventArgs> ArvoMuuttui
	{
		add
		{
			// lisätään käsittelijä
			arvoMuuttui += value;
			Console.WriteLine("Lisätty käsittelijä: {0}", value.Method.Name);
		}
		remove
		{
			// poistetaan käsittelijä
			arvoMuuttui -= value;
			Console.WriteLine("Poistettu käsittelijä: {0}", value.Method.Name);
		}
	}
}