Grafikus C# – Windows Forms tanfolyam › 5.2 lecke Windows Forms · 5.2 lecke · eseményparaméterek Minden eseménykezelő két paramétert kap: sender, EventArgs és eseményparaméterek
object sender és EventArgs e. Eddig többnyire figyelmen kívül hagytuk őket. Pedig kincsek: a sender megmondja, ki váltotta ki az eseményt, az e pedig részleteket hoz: hová kattintottak, melyik billentyűt nyomták le, megszakítható-e a bezárás. Ebben a leckében megtanulod ezeket használni, és kétirányú kommunikációt is látsz: a kezelő nemcsak olvas az e-ből, hanem vissza is szólhat neki (e.Cancel, e.Handled).
A lecke végére
- a
senderparamétert típusátalakítással (as,is, kasztolás) használod, és ismered a buktatóit; - tudod, hogy az
EventArgsegy családnak az őse, és melyik eseményhez melyik leszármazott tartozik; - használod a
MouseEventArgs,KeyEventArgs,KeyPressEventArgs,FormClosingEventArgsésPaintEventArgsfontos tagjait; - érted, hogyan szól vissza a kezelő az eseménynek (
Cancel,Handled,SuppressKeyPress); - felismered a leggyakoribb hibákat (hibás átalakítás, rossz paramétertípus, a koordináták eltérése).
Mielőtt elkezded
Ehhez a leckéhez az 5.1 lecke (események, delegáltak) és a 3.9 lecke (osztályok, öröklődés fogalma) szükséges. Új projektben próbáld ki a példákat.
A sender: ki váltotta ki az eseményt?
A sender az eseményt kiváltó objektum: a megnyomott gomb, a módosított szövegmező, az ablak. A típusa object (a legáltalánosabb típus), mert az EventHandler minden objektumhoz használható. Ha a konkrét típus tulajdonságait el akarod érni, át kell alakítani:
private void Gomb_Click(object sender, EventArgs e)
{
// 1. kasztolás: hibát dob, ha a sender nem Button
Button gomb = (Button)sender;
MessageBox.Show("A gomb felirata: " + gomb.Text);
// 2. as: null értéket ad, ha a sender nem Button
Button masik = sender as Button;
if (masik != null)
{
MessageBox.Show("A neve: " + masik.Name);
}
// 3. is + névvel: ellenőrzés és átalakítás egyben (C# 7)
if (sender is Button g)
{
MessageBox.Show("Szélessége: " + g.Width);
}
// 4. az alaposztály: minden vezérlő Control, ezért a közös tulajdonságok így is elérhetők
Control vezerlo = (Control)sender;
MessageBox.Show("Név: " + vezerlo.Name + ", Bal: " + vezerlo.Left);
}sender nem Button, InvalidCastException hibát dob. Akkor használd, ha biztosan tudod a típust.null értéket ad. Mindig vizsgáld a null értéket használat előtt.g változó a Button típusú hivatkozás.Button, a TextBox, a Label és a Panel mind a Control leszármazottja, ezért a közös tulajdonságok (Name, Text, Left, BackColor) minden vezérlőnél elérhetők a Control típuson át.Nem minden sender vezérlő
A Timer komponens Tick eseményének sender paramétere a Timer, amely nem Control (nincs Name-je és Left tulajdonsága). A menüelemek (ToolStripMenuItem) szintén nem Control típusúak. Ezért ha több különböző típusú objektum is ugyanazt a kezelőt használja, a (Control)sender hibát dobhat: ilyenkor az is vagy az as a biztonságos.
Jósolj!
Ugyanazt az eseménykezelőt (Gomb_Click) egy Button és egy Label Click eseményéhez is hozzákötöd. A kezelőben Button gomb = (Button)sender; áll. Mi történik a címkére kattintva? Hogyan javítanád?
Jóslat ellenőrzése
A címkére kattintva InvalidCastException keletkezik: a Label nem alakítható Button típusúra. A javítás: if (sender is Button gomb) { ... }, vagy a közös Control típusra alakítás, ha csak a közös tulajdonságok kellenek (Control c = (Control)sender;).
Az EventArgs család
Az EventArgs az eseményadatok alaposztálya. A Click esemény csak jelzi, hogy kattintottak, ezért az EventArgs üres. Más eseményeknél a .NET az EventArgs leszármazott osztályát adja, amely az esemény részleteit tartalmazza. A kezelő paraméterének típusa ezért eseményenként eltér:
| Esemény | Paraméter típusa | Mit tartalmaz? |
|---|---|---|
Click, TextChanged, Load | EventArgs | Semmi érdemit (csak jelez). |
MouseDown, MouseUp, MouseMove, MouseClick | MouseEventArgs | Button (melyik gomb), X, Y, Location, Clicks, Delta (görgetés). |
KeyDown, KeyUp | KeyEventArgs | KeyCode (melyik billentyű), Control, Shift, Alt, Modifiers, Handled, SuppressKeyPress. |
KeyPress | KeyPressEventArgs | KeyChar (a beírt karakter), Handled. |
FormClosing | FormClosingEventArgs | CloseReason (miért zárul), Cancel (megszakítható). |
Validating | CancelEventArgs | Cancel. |
Paint | PaintEventArgs | Graphics (rajzolóobjektum), ClipRectangle. |
CellClick (DataGridView) | DataGridViewCellEventArgs | RowIndex, ColumnIndex. |
Hogyan tudod meg, mit tartalmaz az e?
A kezelő paraméterlistájában az e típusa megmutatja a családot. Írd be az e. szöveget a kezelőben, és az IntelliSense listázza az elérhető tagokat. Ha egy új eseményt használsz, a Visual Studio a duplakattintással létrehozott metódusban már a helyes típust adja. Ha kézzel írod a metódust, a típust az esemény dokumentációjából vagy az IntelliSense-ből (az esemény nevére állva) olvashatod ki.
Jósolj!
Egy TextBox KeyPress eseményéhez ezt a kezelőt írod: private void txtSzam_KeyPress(object sender, KeyEventArgs e), és a tervezőben kijelölöd. Lefordul-e, és mi történik, amikor hozzákötöd?
Jóslat ellenőrzése
A KeyPress esemény delegáltja KeyPressEventHandler, amely KeyPressEventArgs típusú paramétert vár, nem KeyEventArgs-t. A Designer.cs-ben a feliratkozás fordítási hibát ad: CS0123: A „txtSzam_KeyPress” egyetlen túlterhelése sem felel meg a delegált típusnak. A javítás: a paraméter típusa legyen KeyPressEventArgs. A szabály: az e típusát az esemény határozza meg, nem te.
Egér és billentyű: az eseményadatok használata
MouseEventArgs: hová és melyik gombbal kattintottak?
Tegyél az ablakra egy pnlTer panelt és egy lblInfo feliratot:
private void pnlTer_MouseMove(object sender, MouseEventArgs e)
{
lblInfo.Text = $"X: {e.X}, Y: {e.Y}";
}
private void pnlTer_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
lblInfo.Text = "Bal gomb: " + e.Location;
}
else if (e.Button == MouseButtons.Right)
{
lblInfo.Text = "Jobb gomb: " + e.Location;
}
}
private void pnlTer_MouseWheel(object sender, MouseEventArgs e)
{
lblInfo.Text = "Görgetés: " + e.Delta; // előre: 120, hátra: -120
}e.Location egy Point, amely a két értéket együtt adja.MouseButtons.Left, Right, Middle.KeyEventArgs és KeyPressEventArgs: melyik billentyű?
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
lblInfo.Text = "Ctrl+S: mentés";
e.SuppressKeyPress = true;
}
else if (e.Shift && e.KeyCode == Keys.F5)
{
lblInfo.Text = "Shift+F5";
}
else
{
lblInfo.Text = "Billentyű: " + e.KeyCode;
}
}
private void txtSzam_KeyPress(object sender, KeyPressEventArgs e)
{
// csak számjegy és vezérlőkarakter (például Backspace) engedélyezett
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true; // a karakter nem kerül a szövegmezőbe
}
}Keys.S, Keys.Enter, Keys.F5). Nem különbözteti meg a kis- és nagybetűt.a és A különbözik).Jósolj!
Egy TextBox KeyDown eseményében e.KeyCode == Keys.A feltételre írsz kódot. Nagy A-t és kis a-t gépelsz. Lefut-e mindkettőnél? És ha ugyanezt a KeyPress eseményben az e.KeyChar == 'a' feltétellel próbálod?
Jóslat ellenőrzése
A KeyDown KeyCode értéke a fizikai billentyű, ezért az A és az a megnyomásakor is Keys.A: mindkettőnél lefut. A KeyPress KeyChar értéke a beírt karakter, ezért csak a kis a-nál igaz az == 'a' feltétel, a nagy A ('A') más karakter. A szabály: a billentyűkombinációkhoz és a vezérlőbillentyűkhöz KeyDown, a beírt szöveg szűréséhez KeyPress való.
Visszaszólás az eseménynek: Cancel és Handled
Az eseményadat nemcsak információt hoz: bizonyos eseményeknél a kezelő vissza is szólhat a kibocsátónak, és befolyásolhatja a folytatást. Az eseményadat (e) egy osztály példánya, ezért a kezelő által beállított értéket a kibocsátó a kezelő lefutása után kiolvassa:
// 1. FormClosing: a bezárás megszakítható
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason != CloseReason.UserClosing)
{
return; // a Windows leállítása vagy más ok: ne kérdezzünk
}
if (MessageBox.Show("Biztosan kilépsz?", "Kilépés", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true; // az ablak nem záródik be
}
}
// 2. Validating: a fókusz elhagyása megakadályozható
private void txtNev_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
if (txtNev.Text.Trim().Length == 0)
{
epHiba.SetError(txtNev, "A név kötelező!");
e.Cancel = true; // a kurzor a mezőben marad
}
else
{
epHiba.SetError(txtNev, "");
}
}
// 3. KeyPress: a karakter bekerülésének megakadályozása
private void txtKod_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsLower(e.KeyChar))
{
e.KeyChar = char.ToUpper(e.KeyChar); // a karakter megváltoztatható is: nagybetű lesz
}
}FormClosing), vagy a fókusz a mezőben marad (Validating).KeyPress-ben ez azt jelenti, hogy a karakter nem kerül a szövegmezőbe.KeyDown eseményben megakadályozza, hogy a billentyű a vezérlőbe kerüljön (és a csengő hang elmaradjon). A Handled önmagában itt nem mindig elég.UserClosing, WindowsShutDown, TaskManagerClosing): érdemes csak a felhasználói bezárásnál rákérdezni.Jósolj!
A Form1_FormClosing kezelőben nincs CloseReason ellenőrzés, mindig rákérdez. A felhasználó a Windows leállítását kéri, miközben a program fut. Mi történik?
Jóslat ellenőrzése
A kérdés megjelenik a leállítás közben is. Ha a felhasználó a Nem gombot választja, vagy nem válaszol, a program megakadályozhatja a Windows leállítását (a rendszer jelzi, hogy egy program nem engedi). Ez zavaró, és egy kész programban kerülendő. Ezért ellenőrizd az e.CloseReason értékét: csak a UserClosing esetén kérdezz, minden más oknál engedd a bezárást (a mentetlen adatokat pedig automatikusan mentsd el, ha lehet).
Hibakeresés: te vagy a hibadetektív
Mi a baj, és hogyan javítod?
Gondold végig az okot, és csak utána nyisd le a megoldást.
1. InvalidCastException a sender átalakításakor
Button gomb = (Button)sender; // a sender egy Timer, vagy egy LabelHiba és javítás
A sender nem Button. Ellenőrizd az is vagy as használatával: if (sender is Button gomb) { ... }. Ha ugyanazt a kezelőt több típushoz kötötted, mindig számolj a nem várt típussal.
2. NullReferenceException az as átalakítás után
Button gomb = sender as Button;
gomb.Text = "Kész"; // ha a sender nem Button, a gomb nullHiba és javítás
Az as sikertelen átalakításnál null értéket ad. Használat előtt vizsgáld meg: if (gomb != null), vagy használd az is Button gomb mintát, amely egyben ellenőriz.
3. A kezelő paraméterének típusa nem egyezik
private void txtSzam_KeyPress(object sender, KeyEventArgs e)
// CS0123: a metódus egyetlen túlterhelése sem felel meg a KeyPressEventHandler delegáltnakHiba és javítás
A KeyPress esemény KeyPressEventArgs típusú paramétert ad. A paraméter típusát az esemény határozza meg. A legbiztosabb: duplakattintás a Properties ablak Events nézetében, a Visual Studio a helyes szerkezetet generálja.
4. Hiányzó tag az e paraméteren
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyChar == 'a') { } // CS1061: a KeyEventArgs nem tartalmaz KeyChar definíciót
}Hiba és javítás
A KeyDown esemény KeyEventArgs típusú, amelyben nincs KeyChar, csak KeyCode (e.KeyCode == Keys.A). A KeyChar a KeyPressEventArgs-ban van. A két esemény különböző adatot ad.
5. A tiltott karakter mégis bekerül
A A KeyDown eseményben megpróbálod megakadályozni a betűk beírását e.Handled = true sorral, de a betű mégis megjelenik.Ok és javítás
KeyDown eseményben a karakter megakadályozásához az e.SuppressKeyPress = true kell. A Handled a KeyPress eseményben megakadályozza a karaktert, a KeyDown esetén azonban a KeyPress esemény még ettől függetlenül lefuthat. A legegyszerűbb: a karakterek szűrését a KeyPress eseményben végezd (e.Handled = true).
6. Az egér koordinátája eltér
A Az pnlTer_MouseMove kezelőben az e.X értéke más, mint a Cursor.Position.X.Ok és javítás
e.X és e.Y a vezérlőhöz képest adja az egér helyét (a vezérlő bal felső sarka (0, 0)). A Cursor.Position a képernyőhöz képest, így a kettő eltér. A koordináták átszámolásához a PointToClient (képernyő → vezérlő) és a PointToScreen (vezérlő → képernyő) metódus használható.
Mini projekt: egér- és billentyűfigyelő
Készíts programot, amely az eseményadatokat valós időben megjeleníti:
- Az ablakon: egy nagy
pnlTerpanel, fölötte négy felirat (lblPoz,lblGomb,lblGorgetes,lblBillentyu), egylstNaplo(ListBox) és egytxtSzamTextBox. - A panel
MouseMoveeseménye a pozíciót (X: 120, Y: 45), aMouseDowna lenyomott gombot (Bal, Jobb, Közép), aMouseWheela görgetés mértékét jeleníti meg. - A Form
KeyDowneseménye (KeyPreview: True) kiírja a billentyű nevét a módosítókkal együtt (Ctrl+Shift+S), és azlstNaplofelső sorába is beírja. - A
txtSzammező csak számjegyet és Backspace-t enged be (KeyPress). - A
FormClosingcsak felhasználói bezárásnál (CloseReason) kérdez rá a kilépésre. - A panel
MouseDowneseményére egy közös,object senderalapján működő kezelő is felirat: kiírja a panel nevét (Controlátalakítással). - Teszteld: az összes egérgomb, a görgetés, billentyűkombinációk, betű beírása a számmezőbe, a kilépés megszakítása.
Megoldás megnyitása (próbáld ki előbb önállóan!)
A módosítók szövegét egy segédmetódus állítja össze az e.Control, e.Shift, e.Alt alapján. A MouseWheel eseményt kódból kell hozzákötni (a Properties ablak Events nézetében nem szerepel mindig). A panel nem kap fókuszt, ezért a görgetéshez pnlTer.Focus() kell a MouseEnter eseményben.
private void Form1_Load(object sender, EventArgs e)
{
this.KeyPreview = true;
pnlTer.MouseWheel += pnlTer_MouseWheel; // kódból kötjük
pnlTer.MouseEnter += (s, ev) => pnlTer.Focus();
}
private void pnlTer_MouseMove(object sender, MouseEventArgs e)
{
lblPoz.Text = $"X: {e.X}, Y: {e.Y}";
}
private void pnlTer_MouseDown(object sender, MouseEventArgs e)
{
string gomb = "Más";
if (e.Button == MouseButtons.Left)
{
gomb = "Bal";
}
else if (e.Button == MouseButtons.Right)
{
gomb = "Jobb";
}
else if (e.Button == MouseButtons.Middle)
{
gomb = "Közép";
}
Control vezerlo = (Control)sender;
lblGomb.Text = $"{gomb} gomb ({vezerlo.Name})";
}
private void pnlTer_MouseWheel(object sender, MouseEventArgs e)
{
lblGorgetes.Text = "Görgetés: " + e.Delta;
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
string szoveg = "";
if (e.Control)
{
szoveg = szoveg + "Ctrl+";
}
if (e.Shift)
{
szoveg = szoveg + "Shift+";
}
if (e.Alt)
{
szoveg = szoveg + "Alt+";
}
szoveg = szoveg + e.KeyCode;
lblBillentyu.Text = szoveg;
lstNaplo.Items.Insert(0, szoveg);
}
private void txtSzam_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason != CloseReason.UserClosing)
{
return;
}
if (MessageBox.Show("Biztosan kilépsz?", "Kilépés", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
}Mit tegyél ide: a futó program: az egér a panel felett, a feliratokon a pozíció és a lenyomott gomb, a naplóban néhány billentyűkombináció.Javasolt fájlnév: winforms-5-2-kesz.webp · Alt szöveg: Az egér- és billentyűfigyelő program
Három önálló gyakorlófeladat
Egyszerre csak egyet csinálj: tervezd meg, írd meg, futtasd, ellenőrizd, és csak utána nyisd ki a megoldást.
1. Egérgombonként más üzenet
Egy A btnProba gombon a bal, a jobb és a középső egérgomb MouseDown eseménye különböző üzenetet jelenítsen meg a lblUzenet feliraton. Miért nem elég a Click esemény?Egy lehetséges megoldás
Click esemény EventArgs típusú, amely nem mondja meg, melyik gombbal kattintottak (és a jobb gombra a gomb Click eseménye általában nem is fut le). A MouseDown MouseEventArgs-ot ad, amelynek Button tulajdonsága megkülönbözteti a gombokat.private void btnProba_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
lblUzenet.Text = "Bal gombbal kattintottál";
}
else if (e.Button == MouseButtons.Right)
{
lblUzenet.Text = "Jobb gombbal kattintottál";
}
else if (e.Button == MouseButtons.Middle)
{
lblUzenet.Text = "A görgőt nyomtad meg";
}
}
2. Csak számjegy, tizedesjellel
A A tizedesjelet csak akkor engedjük, ha a szöveg még nem tartalmaz (txtAr mező csak számjegyet, Backspace-t és legfeljebb egy tizedesjelet (,) engedjen be. Hogyan ellenőrzöd, hogy már van-e tizedesjel?Egy lehetséges megoldás
Text.Contains). A beillesztéssel (Ctrl+V) bekerülő szöveg nem a KeyPress eseményen megy át, ezért az ellenőrzést a Validating eseményben is érdemes elvégezni (decimal.TryParse).private void txtAr_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsDigit(e.KeyChar) || char.IsControl(e.KeyChar))
{
return;
}
if (e.KeyChar == ',' && !txtAr.Text.Contains(","))
{
return;
}
e.Handled = true;
}
3. Kilépés csak mentetlen adatnál
Az ablak csak akkor kérdezzen rá a bezárásra, ha a A jelzőt a txtJegyzet mező módosult (bool modosult jelző), és csak felhasználói bezárásnál. A Mégse esetén az ablak maradjon nyitva.Egy lehetséges megoldás
TextChanged esemény állítja igazra. A FormClosing csak akkor kérdez, ha a jelző igaz és a bezárás oka a felhasználó. A kérdés három gombos (Igen: mentés, Nem: bezárás mentés nélkül, Mégse: maradás).private bool modosult = false;
private void txtJegyzet_TextChanged(object sender, EventArgs e)
{
modosult = true;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (!modosult || e.CloseReason != CloseReason.UserClosing)
{
return;
}
DialogResult valasz = MessageBox.Show("Mented a jegyzetet?", "Kilépés", MessageBoxButtons.YesNoCancel);
if (valasz == DialogResult.Cancel)
{
e.Cancel = true;
}
else if (valasz == DialogResult.Yes)
{
// a mentés kódja
}
}
Gyakorlótár: 6 további feladat
Három szinten gyakorolhatsz: alap, közepes és kihívás. Csak a próbálkozás után nyisd le a megoldást.
Alap szint
1. A megnyomott gomb felirata
Három gomb ( A btnA, btnB, btnC) ugyanazt a Gomb_Click kezelőt használja, és az lblEredmeny a megnyomott gomb feliratát mutassa. Hogyan használod a sender paramétert?Megoldás megnyitása
sender a megnyomott gomb. Az as átalakítással érjük el a Text tulajdonságát, és ellenőrizzük a null értéket.private void Gomb_Click(object sender, EventArgs e)
{
Button gomb = sender as Button;
if (gomb != null)
{
lblEredmeny.Text = "Megnyomtad: " + gomb.Text;
}
}
2. Koordináták kijelzése
Egy Az pbRajz PictureBox fölött az egér mozgásakor a lblKoord mutassa az egér helyét a PictureBoxhoz képest, és külön a képernyő-koordinátát is (Cursor.Position). Mi a különbség?Megoldás megnyitása
e.X, e.Y a vezérlőhöz mérten adja a helyet, a Cursor.Position a teljes képernyőhöz. A PointToClient a képernyő-koordinátát vezérlő-koordinátává alakítja.private void pbRajz_MouseMove(object sender, MouseEventArgs e)
{
Point kepernyo = Cursor.Position;
Point vezerlo = pbRajz.PointToClient(kepernyo); // megegyezik az e.Location-nel
lblKoord.Text = $"Vezérlő: {e.X}, {e.Y} | Képernyő: {kepernyo.X}, {kepernyo.Y}";
}
Közepes szint
3. Billentyűkombináció
A A módosítókat az Ctrl+Shift+T kombináció váltsa át az ablak háttérszínét sötétre, a Ctrl+L világosra. A kombináció ne kerüljön a szövegmezőbe, és kezeld le a KeyDown eseményben.Megoldás megnyitása
e.Control és e.Shift adja, a billentyűt az e.KeyCode. A SuppressKeyPress megakadályozza, hogy a billentyű a fókuszban lévő vezérlőbe kerüljön. A KeyPreview legyen igaz, hogy a Form is megkapja az eseményt.private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.Shift && e.KeyCode == Keys.T)
{
this.BackColor = Color.FromArgb(40, 40, 48);
e.SuppressKeyPress = true;
}
else if (e.Control && e.KeyCode == Keys.L)
{
this.BackColor = SystemColors.Control;
e.SuppressKeyPress = true;
}
}
4. Kötelező mező a Validating eseménnyel
A A txtEmail mező elhagyásakor ellenőrizd, hogy a szöveg tartalmaz-e @ jelet. Ha nem, ErrorProvider jelezzen, és a kurzor maradjon a mezőben. Mit kell tenned, hogy az ablak bezárható legyen akkor is, ha a mező hibás?Megoldás megnyitása
Validating esemény CancelEventArgs-ot ad: az e.Cancel = true a fókuszt a mezőben tartja. A hibás mező ilyenkor az ablak bezárását is megakadályozhatja: a Form AutoValidate tulajdonságát EnableAllowFocusChange értékre állítva a fókusz elhagyható, vagy a bezáró gomb CausesValidation tulajdonsága False (a Mégse gombnál ez a szokás).private void txtEmail_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
if (!txtEmail.Text.Contains("@"))
{
epHiba.SetError(txtEmail, "Az e-mail címnek tartalmaznia kell a @ jelet.");
e.Cancel = true;
}
else
{
epHiba.SetError(txtEmail, "");
}
}
// a Mégse gombnál a tervezőben: CausesValidation = False
Kihívás szint
5. Egy kezelő több típushoz
Egy közös A Kozos_Click kezelő egy Button, egy Label és egy Panel Click eseményét is kezeli, és az lblInfo-ban kiírja a vezérlő típusát és nevét. A gombnál a feliratot is. Hogyan kezeled biztonságosan a különböző típusokat?Megoldás megnyitása
sender is Button gomb minta ellenőriz és átalakít, így nem kell a null értéket külön vizsgálni. A közös Control típusra mindegyik átalakítható (Name), a típus nevét a GetType().Name adja.private void Kozos_Click(object sender, EventArgs e)
{
Control vezerlo = (Control)sender;
string szoveg = vezerlo.GetType().Name + ": " + vezerlo.Name;
if (sender is Button gomb)
{
szoveg = szoveg + " (felirat: " + gomb.Text + ")";
}
lblInfo.Text = szoveg;
}
6. DataGridView cellaesemény
Egy A dgvLista táblázat CellClick eseményében írd ki az lblInfo feliratra a kattintott cella sor- és oszlopszámát és értékét. Mire kell vigyázni a fejlécre kattintáskor?Megoldás megnyitása
DataGridViewCellEventArgs a RowIndex és ColumnIndex értéket adja. A fejlécre (oszlopnév) kattintva a RowIndex értéke -1, ezért a sor eléréséhez előbb ellenőrizni kell (e.RowIndex >= 0), különben hibát kapsz.private void dgvLista_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0 || e.ColumnIndex < 0)
{
return; // fejlécre kattintottak
}
object ertek = dgvLista.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
lblInfo.Text = $"Sor: {e.RowIndex}, oszlop: {e.ColumnIndex}, érték: {ertek}";
}
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. Az eseményt kiváltó objektum. Azért A kasztolás hibát dob, ha a típus nem egyezik. Az Az esemény részleteit hordozza. Az alaposztály üres, a leszármazottak adatot adnak ( A A kezelő visszaszól az eseménynek: a Az egér helyét a vezérlőhöz képest. A A 1. Mi a sender, és miért object típusú?
object, mert az eseménykezelő szerkezete minden típushoz azonos: a konkrét típust szükség esetén át kell alakítani.2. Mi a különbség a kasztolás, az as és az is között?
as null értéket ad. Az is logikai értéket ad, és mintával egyben átalakít is (is Button g).3. Mi az EventArgs szerepe?
MouseEventArgs, KeyEventArgs, ...).4. Mi a különbség a KeyDown és a KeyPress között?
KeyDown a fizikai billentyűt adja (KeyCode, módosítók), a KeyPress a beírt karaktert (KeyChar).5. Mire való az e.Cancel és az e.Handled?
Cancel megszakítja a folyamatot (bezárás, fókuszváltás), a Handled jelzi, hogy az eseményt már kezeltük (a karakter nem kerül a vezérlőbe).6. Mit ad az e.X és e.Y, és miben tér el a Cursor.Position-től?
Cursor.Position a képernyőhöz képest adja.7. Mikor érdemes az e.CloseReason értékét vizsgálni?
FormClosing kezelőben: csak a felhasználói bezárásnál (UserClosing) kérdezzünk, hogy ne akadályozzuk meg például a Windows leállítását.
Mit tudsz már?
- A
senderparamétert biztonságosan átalakítod (as,is, kasztolás). - Tudod, hogy az
etípusát az esemény határozza meg, és használod a fontos tagjait. - Egér- és billentyűadatokat dolgozol fel (
Button,X,Y,KeyCode,KeyChar, módosítók). - Visszaszólsz az eseménynek (
Cancel,Handled,SuppressKeyPress). - Felismered a gyakori eseménykezelési hibákat.
Következő lecke: Click, DoubleClick és egérműveletek
Most, hogy az eseményadatokat ismered, részletesen megnézzük az egérműveleteket: a Click és a DoubleClick különbségét, az egérgombok eseményeit és a húzást.




