Delegaatit ja tapahtumat

Tutustutaan hieman paremmin tapahtumankäsittelyyn (events) ja delegaatteihin. Opitaan määrittelemään omia delegaatteja ja tapahtumia omissa luokissa.

Luentoesimerkki (Esimerkki zip-paketissa)

Delegaatit- ja tapahtumat esimerkki (Esimerkki zip-paketissa)

Tapahtumat

Delegaatit

Delegaatti on sama asia kuin funktio-osoitin. Delegaattien avulla voidaan vasta ohjelman suoritusaikana päättää mitä funktiota kutsutaan.

Delegaatteja käytetään erityisesti tapahtumapohjaisessa ohjelmoinnissa eli esim. windows-ohjelmoinnissa.

  1. Määritellään delegaatti
    • Delegaattimäärittelyn palautustyyppi ja parametrit määräävät millaista funktiota voidaan käyttää
      public delegate int Esimerkki();
      public delegate void Esimerkki2(object sender, EventArgs e); // windows forms -tapahtumat
      
    • Tapahtuman aiheuttavassa luokassa luodaan delegaattityyppinen tai event delegaatti -tyypinen muuttuja:
      public Esimerkki tapahtuma;
      public event Esimerkki2 tapahtuma2;
      

      event-sana aiheuttaa tiettyjä rajoituksia: tapahtumaa voidaan kutsua vain luokan sisältä, event voidaan asettaa ja poistaa +=- ja -=-operaattoreilla ja tapahtuma pitää aina olla muotoa tapahtuma(object source, EventArgs e)

    • Jossain vaiheessa olion elämää se kutsuu delegaattiaan eli aiheuttaa tapahtuman:
      if ( tapahtuma != null) tapahtuma();
      if (tapahtuma2 != null) tapahtuma2(this, e);
      
    • Tapahtumalla pitää kuitenkin olla myös seuraaja eli joku, joka on luonut edellämainittua luokkaa olevan olion ja määritellyt seuraajan tapahtumalle:
                  Foo joku = new Foo;
                  joku.tapahtuma = new Esimerkki(funktio); // jos delegaatti palauttaa jotain niin vain yksi mahdollinen seuraaja
                  joku.tapahtuma2 += new Esimerkki2(funktio2); // jos delegaatti ei palauta mitään ja mahdollista olla useampi seuraaja
      	public int funktio() {
      
      	}
      	public void funktio2(object sender, EventArgs e) {
      
      	}
      
    • funktiota kutsutaan aina kun tapahtuu!

Tapahtumankäsittely explained

Idea on seuraava ajateltuna käyttämisen kannalta:

  1. Luot uuden Windows Forms -ohjelman eli aloitat ohjelman tekemisen tyhjällä lomakkeella.
  2. Haluat lomakkeelle painikkeen, jota painaessa esim. lomakkeen title-teksti vaihtuu
  3. Asetat siis painikkeen Click-tapahtumaan koodia, jonka haluat suoritettavan painiketta klikatessa. Teet tämän joko tuplaklikkaamalla painiketta tai etsimällä Events-listasta tuon Click-tapahtuman ja pääset kirjoittamaan haluamasi koodin
  4. Mitä jos haluaisit määritellä dynaamisesti ohjelman ajon aikana tämän koodin joka tapahtuu klikatessa? No sekin onnistuu eli lomakkeen koodissa yhdistät painikkeen OnClick-tapahtumaan oman funktion jotenkin seuraavalla tavalla:
    Painike.Click += new System.EventHandler(PainikeKlikattu);
    
    PainikeKlikattu on tässä kohtaa itse kirjoitettu metodi. System.EventHandler on delegaattityyppi jota Painike.Click vastaa

No mitäs jos tarkoitus on tehdä vastaavanlainen toiminta omaan komponenttiin eli haluat pystyä lomakkeessa tai jossain muussa ympäristössä "kuuntelemaan" mitä komponenttisi tekee.

Omassa komponentissa nämä onnistuvat samaan tapaan kuin PositiveNumberTextBoxissa eli pitää tehdä seuraavat:

Määritellään oma delegaattityyppi

public delegate void NegativeNumberHandler();

luodaan tämän oman delegaattityypin tyyppinen Event

public event NegativeNumberHandler OnNegativeNumber;

tämä event on käytännässä vain funktio-osoitin, jonka osoittamaa funktiota kontrolli kutsuu aina kun syötteenä on negatiivinen luku

Kolmanneksi se tärkein eli positivenumbertextboxissa kutsutaan luotua delegaattieventiä kuin se olisi tavallinen metodi. Kyseessä on siis funktio-osoitin. Kutsu tehdään silloin kun oma komponentti katsoo sen oikeaksi eli tässä tapauksessa silloin kun syötteenä on negatiivinen numero. Kutsussa pitää aina tarkistaa, että tuo event eli OnNegativeNumber on erisuuri kuin null. Jos tuo on null niin se tarkoittaa, että kukaan ei seuraa tapahtumaa eli esim. lomakkeella johom negativetextbox on raahattu, ei ole asetettu mitään funktiota tämän komponentin OnNegativeNumber-tapahtumaan. Jos taas eri suuri kuin null niin kaikki mahdolliset seuraavat funktiot kutsutaan. Kyseessä on siis oikeastaan funktio-osoitinlista koska samaa metodia voi seurata useampikin.

Alussa mainitussa painikkeessa, joka on siis valmiina tarjolla oleva Button-luokka, on siis jossain paikassa jokin tämänsorttin kutsu:

if (Click != null) Click();

jos halutaan liikutella tapahtumaliikenteessä parametreja niin sitten tarvitaan oma EventArgs-luokasta peritty luokka ja liikutellaan sitä mukana:

LiikkuvaAuto.cs

LiikkuvaAuto-luokassa ajastin_Tick-metodista näkee tuon käytön ja koodinlopussa on peritty oma luokka eventargsista.

Lisätietoa

Käyttäjien kommentit

Kommentoi Lisää kommentti
Kurssimateriaalien käyttäminen kaupallisiin tarkoituksiin tai opetusmateriaalina ilman lupaa on ehdottomasti kielletty!
http://appro.mit.jyu.fi/gko/luennot/luento4/
© Tommi Lahtonen (tommi.j.lahtonen@jyu.fi) <http://hazor.iki.fi/>
2016-09-29 17:43:28
Informaatioteknologia - Jyväskylän yliopiston informaatioteknologian tiedekunta