16
Tags:
c#
Skrevet af
Bruger #2730
@ 09.05.2005
Denne artikel omhandler delegates og events samt hvordan de hænger sammen.
Hvad er events
Events er beskeder der sker i et system når der sker en bestemt hændelse. En bestemt hændelse kan for eksempel være når brugeren trykker på en knap eller når brugeren laver et flueben i en checkbox. Alle disse hændelser har det til fælles at de tilbyder en event. Det betyder at jeg som programmør kan sige til knappen eller til checkboksen at jeg grene vil have noget specielt kode kørt når denne event bliver udført. Een ting er at en knap tilbyder en event, noget andet er at der skal også noget til at håndtere når der så er blevet trykket på knappen, dette er en eventhandler. En eventhandler indeholder kode der bliver eksekveret når eventen bliver "raised". Hvis man har forsøgt sig med at lave en simpel applikation i C# og tilføjet en knap til sin form, og i design mode dobbeltklikket på den, så kommer man ned i koden hvor man kan skrive hvad der skal ske når der bliver trykket på knappen, dette er rent faktisk event handleren til knappens "Click" event. Mere om events efter delegates.
Hvad er delegates?
Delegates er essentielle i forbindelse med events, det er i bund og grund type-sikre funktionspointere, der tillader dig at sende en reference til en metode og eksekvere denne metode, uden direkte at kalde metoden. Når man laver en delegate skal den have samme signatur som den metode den skal eksekvere (samme parametre og samme return type).
//en simpel delegate deklarering
public delegate int myDelegate(int first, int second);
Ovenstående er en simpel delegate der forventer en metode der tager to integers som parametre og returnerer et integer. Når man så skal have kaldt en delegate skal man erklære en ny instans af delegaten og tildele den navnet på den metode der skal eksekveres.
//metoden der skal kaldes af vores delegate
public int multiply(int num1, int num2)
{
return num1 * num2;
}
//vores delegate deklarering
public void enmetode
{
myDelegate mydelegate = new myDelegate(multiply);
mydelegate(5,6);
}
Når først vores delegate er instantieret kan den kaldes som alle andre metoder, den skal blot have de samme parametre med som delegaten (og metoden) kræver.
Delegates og events
Når man erklærer en event benyttes
event nøgleordet, ligesom man ved erklæring af delegates benytter
delegate nøgleordet. At oprette en event er direkte knyttet til delegates i C# skal man direkte angive hvilken delegate ens event vil benytte. Dette ser således ud:
public delegate void multiplyDelegate(int first, int second);
public event multiplyDelegate multiplyComplete;
Som vi kan se er vores event af typen multiplyDelegate, som er nødvendigt for at en event. Hvis vi et sted i vores kode skal kalde vores event (raise den) kan vi blot kalde vores event.
multiplyComplete(6,5);
For også at få noget kode eksekveret når denne event opstår skal vi også have en eventhandler, ellers er der ingenting der "fanger" vores event. Der kan tildeles en eller flere event handlere til den samme event. Når vi så har lavet vores eventhandler skal vi associere vores event med vores eventhandler, ellers sker der ingenting. For at associere eventen til event handleren laver vi en ny instans af vores delegate og benytter += operatoren til at lave selve associationen, += operatoren kan også bruges til at lave en association til en allerede eksisterende delegate, ligeledes kan -= operatoren benyttes til at fjerne associationen. Indtil nu har vi benyttet simple multiplicerings methoder, nu laver vi et lille objekt der kan lidt mere, et bil objekt.
public class Car
{
private string model;
private string licenseplate;
private Color carcolor;
public delegate void StartCar();
public event StartCar CarStarted;
public Car()
{
model = "Mercedes";
licenseplate = "AB 123456";
carcolor = Color.Red;
}
public string Model
{
get { return model; }
set { model = value; }
}
public string LicensePlate
{
get { return licenseplate; }
set { licenseplate = value; }
}
public Color CarColor
{
get { return carcolor; }
set { carcolor = value; }
}
}
En simpel klasse der repræsenterer en bil. Som man kan se er der en delegate der hedder StartCar og en event der hedder CarStarted. For at indikere at vores bil er started, kalder vi vores event CarStarted i vores constructor, på denne måde starter vores bil når vi instantierer te nyt Car objekt.
public class Car
{
private string model;
private string licenseplate;
private Color carcolor;
public delegate void StartCar();
public event StartCar CarStarted;
public Car()
{
model = "Mercedes";
licenseplate = "AB 123456";
carcolor = Color.Red;
CarStarted();
}
public string Model
{
get { return model; }
set { model = value; }
}
public string LicensePlate
{
get { return licenseplate; }
set { licenseplate = value; }
}
public Color CarColor
{
get { return carcolor; }
set { carcolor = value; }
}
}
For at kunne "lytte" på vores event skal vi også have lavet en eventhandler der håndterer vores event, denne eventhandler kan enten laves i en ekstern klasse (på den måde kan man sende informationer til alle afkroge af sit program) i dette eksempel har jeg valgt at lave eventhandleren direkte i min constructor, for at holde det mere overskueligt.
public class Car
{
private string model;
private string licenseplate;
private Color carcolor;
public delegate void StartCar();
public event StartCar CarStarted;
public Car()
{
model = "Mercedes";
licenseplate = "AB 123456";
carcolor = Color.Red;
CarStarted+=new StartCar(Car_CarStarted);
CarStarted();
}
public string Model
{
get { return model; }
set { model = value; }
}
public string LicensePlate
{
get { return licenseplate; }
set { licenseplate = value; }
}
public Color CarColor
{
get { return carcolor; }
set { carcolor = value; }
}
private void Car_CarStarted()
{
Console.Write("Car was started...");
}
}
Som det kan ses har jeg indsat associationen til min eventhandler før jeg kalder min event, hvis ikke jeg gjorde dette ville jeg rent faktisk aldrig få en event, da kaldet ville ske før jeg havde associeret en event handler med min event. I Visual Studio (VS) er det nemt at lave dette, man skriver sin event samt += operatoren, så laver VS en lille informationsboks, hvor der står at hvis man trykker på tab, så implementerer den eventhandleren for en, nemmere kan det vist ikke blive. Og som vi kan se så har vores eventhandler (Car_CarStarted) samme signatur som vores delegate. Skulle jeg teste ovenstående eksempel ville jeg lave en instans af min Car klasse.
Car mycar = new Car();
Hvorefter min eventhandler ville reagere på eventen der bliver raised i min constructor og skrive følgende til min output konsol:
Car was started...
Multiple event handlere
Der er ikke noget i vejen for at man kan bruge den samme eventhandler til flere events, det er blot et spørgsmål om at lave flere associeringer. Et eksempel på dette kunne fx, være med en button i en form
button1.Click += new System.EventHandler(ClickHandler);
button2.Click += new System.EventHandler(ClickHandler);
Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.
Del også gerne artiklen med dine Facebook venner:
Kommentarer (7)
Hvad er fordelen ved at benytte Events istedet for at bruge delegaten direkte? Kunne man med andre ord have undladt eventnøgleordet? Det gør jeg på et tidspunkt, men jeg ved ikke om det er galt, det virker udemærket!
Jeg synes fordelen ved at bruge events er at jeg kan "lytte" på dem og lade dem alarmere mig, hvis der sker noget i mit program, det vil sige det er en "push" i stedet for en "pull"
/// <summary>
/// Delegate used to tell the surrounding world that changes has occured
/// </summary>
/// <param name="sender">this TreeViewHandler</param>
public delegate void isChangedEventHandler(TreeViewHandler sender);
/// <summary>
/// The EventHandler that sends a callback message when a new item is
/// selected in the TreeView
/// </summary>
public newItemSelectedEventHandler newItemSelected; //eventhandler
Ja jeg kan ikke lige finde ud af at indsætte kode, men...
Jeg er ny i Delegate afdelingen og da jeg så læste din artikel opdagede jeg at jeg laver det på den måde jeg lige har postet. Altså hvor jeg definerer min delegate, herefter opretter jeg et nyt objekt af denne type.
Resultatet bliver at hvis jeg vil sende beskeder skriver jeg bare fx:
newItemSelected(this)
men jeg bruger ikke noget event nøgle ord?
Det virker selvfølgelig men jeg ville lige forhøre mig hos kodeguruen Brian Hvarregaard
Det er også korrekt! men det er ikke en event. Det du laver er "bare" en delegate, og de er også utroligt nyttige. Men du er stadig afhængig af at du selv skal kalde din delegate: newItemSelected(this); Hvad nu hvis man forestillede sig at din metode blev kaldt "automatisk" dvs. at når der skete noget i dit program så blev din event kaldt, og alle der "abonnerer" på den event kunne sætte noget i gang, det er næste skridt. Hvis vi sammenligner med bilen i eksemplet, så kunne jeg godt have nøjet med en delegate, men hvad nu hvis der var andre eksterne interessenter der skulle vide når bilen startede.. fx. parkeringsvagten, eller lign. I dit eksempel skal du manuelt give parkeringsvagten besked ved at kalde en delegate eller lign. på ham, mens ved events kan parkeringsvagten "bare" lytte på bilens event, således at når bilen starter, skal bilen ikke gøre mere, end blot sige at "jeg starter" og så er det alle andre der skal tage stilling til det... håber det gav mening
Det er det der er hele mit dilemma fordi jeg netop bruger newItemSelected fuldstændigt som en event uden nogensinde at bruge event nøgleordet.
Altså:
Inde i klassen ser det således ud:
public delegate void newItemSelectedEventHandler(treeViewHandler sender);
public newItemSelectedEventHandler newItemSelected
Udefra skriver jeg bare de berømte ord:
newItemSelected += new TreeViewHandler.newItemSelectedEventHandler([metoden der skal kaldes])
(hvor TreeViewHandler er min instans af treeViewHandler klassen)
jeg kan derfor melde så mange listeners på listen som jeg har lyst til med += operatoren.
Jeg ved ikke om det giver nogen mening det som jeg prøver at beskrive?
Det var en god artikel. Den gav lige den sidste viden jeg manglede, og som jeg ikke har kunnet finde via google.
Du skal være
logget ind for at skrive en kommentar.