Vizuális és eseményvezérelt programozás 2006 2007, II. félév BMF NIK Eseménykezelés A képviselő( delegate ) Képviselők C# nyelvi megvalósítása Metódushívás képviselőn keresztül Az esemény ( event ) Esemény közzététele Eseménykezelő létrehozása Feliratkozás eseményre miklos.arpad@nik.bmf.hu
Hallgatói tájékoztató A jelen bemutatóban található adatok, tudnivalók és információk a számonkérendő anyag vázlatát képezik. Ismeretük szükséges, de nem elégséges feltétele a sikeres zárthelyinek, illetve vizsgának. Sikeres zárthelyihez, illetve vizsgához a jelen bemutató tartalmán felül a kötelezőirodalomként megjelölt anyag, a gyakorlatokon szóban, illetve a táblán átadott tudnivalók ismerete, valamint a gyakorlatokon megoldott példák és az otthoni feldolgozás céljából kiadott feladatok önálló megoldásának képessége is szükséges. 2
A képviselő ( delegate ) A képviselőegy speciális nyelvi elem, melynek segítségével egy osztályhoz külső osztályok kapcsolódhatnak A képviselő(más kifejezéssel metódusreferencia vagy delegált ) előírja az osztályok közötti üzenetek formátumát. Ez a formátum tulajdonképpen az üzenetváltáshoz hívandómetódus szignatúrája, mivel az üzenetváltás OOP rendszerekben általában metódushívásként valósul meg. Tetszőleges külsőosztály kapcsolódhat képviselőn keresztül egy másik osztályhoz, ennek egyetlen feltétele az előírt formátum betartása. Képviselők segítségével egy osztály metódusai külsőosztályok metódusait ismeretlenül is meg tudják hívni A képviselők tehát közvetítenek a hívóés a hívott osztály között. Főbb felhasználási területeik: Üzenetküldési lehetőség külső osztályok részére Még nem is létezőosztályok metódusainak hívása (univerzális visszahívási funkció, értesítési funkció ) 3
Képviselők C# nyelvi megvalósítása Maguk a képviselők speciális (idegen metódusok tárolására alkalmas) osztályok Képviselők a delegatekulcsszósegítségével, saját névvel és az általuk képviselhető metódusok szignatúrájával deklarálhatók. public delegate void EventHandler(object sender, EventArgs e); Visszatérési érték típusa Paraméterlista típusokkal Az EventHandler típus példányai által képviselhetőmetódusok szignatúrája (a paraméterek neve nem lényeges) A képviselőosztály példányosítása úgy történik, hogy konstruktorának át kell adni paraméterül egy, a képviselőének megfelelő szignatúrájú metódust. (!) public EventHandler EH = new EventHandler(eventHandlerMethod); E metódus szignatúrája azonos vagy kompatibilis kell, hogy legyen a fent megadott szignatúrával * * Az átadott metódus visszatérési értékének típusa a képviselőnél megadott típus vagy annak bármely leszármazottja lehet (kovariancia), paramétereinek típusa pedig a képviselőnél megadott típus vagy annak bármely őse lehet (kontravariancia). 4
Metódushívás képviselőn keresztül (1) Egyszerű metódushívás delegate double Közvetítő(double d); static class Műveletek public static double Kétszerezés(double szám) return szám + szám; public static double NégyzetreEmelés(double szám) return szám * szám; class Program static void Main() Közvetítő[] műveletek = new Közvetítő[] new Műveletek.Kétszerezés, Közvetítő(Műveletek.Kétszerezés), new Közvetítő(Műveletek.NégyzetreEmelés) ; ; foreach (Közvetítő k in műveletek) System.Console.WriteLine( k(2.5) ); 5
Metódushívás képviselőn keresztül (2) Több metódus felfűzése ( multicast ) A képviselőlétrehozásakor paraméterként átadott metódus és az utólag a += operátorral átadott metódus hívása egymás után delegate void Feldolgozó(string szöveg); class Program static void KiírásNagybetűkkel(string s) System.Console.WriteLine( s.toupper() ); static void KiírásKisbetűkkel(string s) System.Console.WriteLine( s.tolower() ); static void Main() Feldolgozó f = new Feldolgozó(KiírásNagybetűkkel); f += new Feldolgozó(KiírásKisbetűkkel); f("a képviselőn keresztül futottam le."); System.Console.WriteLine(); KiírásNagybetűkkel("Egyszerű metódushívással futottam le."); 6
Metódushívás képviselőn keresztül (3) Képviselő típusú paraméterek delegate bool Összehasonlító(object bal, object jobb); class EgyszerűCserésRendező public static void Rendez(object[] rendezendőtömb, Összehasonlító nagyobb) for (int i = 0; i < rendezendőtömb.length; i++) for (int j = i + 1; j < rendezendőtömb.length; j++) if ( nagyobb(rendezendőtömb[j], rendezendőtömb[i]) ) object ideiglenes = rendezendőtömb[i]; rendezendőtömb[i] = rendezendőtömb[j]; rendezendőtömb[j] = ideiglenes; 7
Az esemény ( event ) Az eseményegy kifejezetten értesítési célúnyelvi elem (valójában egy korlátozott, biztonságosabbá tett képviselő) Az események segítségével valósul meg a külső osztályok értesítése. Az értesítési folyamat általános menete: 1. Az eseményt értesítési céllal felkínáló osztály közzéteszi az eseményt A közzétevő osztály erre a célra egy megfelelő képviselő típusú nyilvános mezőt deklarál. 2. Az esemény iránt érdeklődőosztályok egy saját metódus átadásával feliratkoznak az eseményt közzétevő osztálynál A feliratkozás során az osztályok egy-egy előre elkészített, meghatározott szignatúrájú metódust (ún. eseménykezelőt ) adnak át paraméterként a közzétevő osztálynak. A feliratkozás az esemény += operátorának segítségével történik, emellett utólagos leiratkozásra is van lehetőség a -= operátorral. Az esemény alapjául szolgálóképviselősaját listában tartja nyilván a feliratkozások során a += és a -= operátorokkal fel-, illetve leiratkozott metódusokat. 3. A közzétevő osztály valamely metódusában kiváltódik az esemény A bekövetkezett eseményről a közzétevőosztály (a képviselősegítségével) a feliratkozás során megadott eseménykezelő metódusok hívásával értesíti a feliratkozott osztályokat. 8
Esemény közzététele A közzétett események speciális mezők *, amelyek az event kulcsszósegítségével, saját névvel és a megfelelőképviselő(mint alaptípus) megnevezésével adhatók meg Az esemény alaptípusául szolgáló képviselő public event EventHandler Load; Az eseménymezők értéke az alaptípusukként szolgálóképviselőegy példánya, amelyek a megfelelőszignatúrájúmetódusok átadásával jön létre. A képviselőlétrehozásához feliratkozáskor a += operátorral, leiratkozáskor a -= operátorral kell a kívánt metódust a mező értékéül megadni. A külsőfelhasználóosztályok számára közzétett események általában nyilvános ( public ), a leszármazottak számára készített belsőesemények általában védett ( protected ) láthatóságúak. * Valójában az eseményekhez saját fel-és leiratkozási ( add, illetve remove ) metódusok is készíthetők egyéni tárolási megoldással, tehát az események szemantikája a mezők helyett inkább a tulajdonságokéhoz hasonlít, melyek szintén saját elérési metóduspárral rendelkeznek. A fenti leírás az egyszerűbb, a gyakorlatban jellemzően használt esetet veszi alapul. 9
Eseménykezelő létrehozása using System; using System.Windows.Forms; namespace WindowsApplication1 public partial class Form1 : Form public Form1() InitializeComponent(); private void Form1_Load(object sender, EventArgs e) this.text = "Hello, C# World"; Form1.cs 10
Feliratkozás eseményre #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() this.suspendlayout(); // // Form1 // this.autoscaledimensions = new System.Drawing.SizeF(6F, 14F); this.autoscalemode = System.Windows.Forms.AutoScaleMode.Font; this.clientsize = new System.Drawing.Size(292, 272); this.name = "Form1"; this.text = "Form1"; this.load += new System.EventHandler(this.Form1_Load); this.resumelayout(false); #endregion Form1.Designer.cs 11