Grafikus C# – Windows Forms tanfolyam › 8.1 lecke Windows Forms · 8.1 lecke · listavezérlők Az 1.5 és 1.6 leckében már használtad a listavezérlőket. A 8. fejezetben az összetett adatok kezelése következik, ezért először rendet teszünk: mi a három lista (ListBox, CheckedListBox és ComboBox részletesen
ListBox, CheckedListBox, ComboBox) közös alapja, miben térnek el, és melyiket mikor válaszd. Megtanulod a kijelölési módokat, a rendezést, a gyors feltöltést (BeginUpdate), a jelölőnégyzetes lista eseményeit, a ComboBox három stílusát és az automatikus kiegészítést.
A lecke végére
- megkülönbözteted a három listavezérlőt, és kiválasztod a helyzethez illőt;
- kezeled a
ListBoxkijelölési módjait (SelectionMode) és több kijelölt elemét; - a
CheckedListBoxjelölt elemeit és azItemCheckeseményt használod; - a
ComboBoxstílusait (DropDownStyle) és az automatikus kiegészítést beállítod; - sok elemet gyorsan töltesz fel (
BeginUpdate/EndUpdate,AddRange); - felismered a gyakori hibákat (
nullkijelölés, aComboBoxszabad szövege).
Mielőtt elkezded
Ehhez a leckéhez az 1.5–1.6 lecke (listák, ComboBox alapjai), az 5.5 lecke (SelectedIndexChanged, ItemCheck, jelző) és az 5.8 lecke (közös kezelő, rekurzív bejárás) szükséges.
ListBox: elemek listája
A ListBox az elemeket egymás alatt mutatja, a felhasználó kijelölhet egyet vagy többet. A SelectionMode határozza meg a kijelölés módját:
| SelectionMode | Jelentése |
|---|---|
One (alap) | Egyszerre egy elem. |
MultiSimple | Több elem: minden kattintás be- vagy kikapcsolja az elemet. |
MultiExtended | Több elem a megszokott módon: Ctrl+kattintás hozzáad, Shift+kattintás tartományt jelöl. |
None | Nem jelölhető ki elem (csak megjelenítés). |
lstTermekek.SelectionMode = SelectionMode.MultiExtended;
lstTermekek.Sorted = true; // az elemek ábécésorrendben jelennek meg
// gyors feltöltés sok elemmel: a rajzolás a végén történik egyszer
lstTermekek.BeginUpdate();
lstTermekek.Items.AddRange(new object[] { "Alma", "Körte", "Szilva", "Barack" });
lstTermekek.EndUpdate();
// kijelölt elemek bejárása (MultiExtended esetén több is lehet)
foreach (object elem in lstTermekek.SelectedItems)
{
lstValasztott.Items.Add(elem);
}
// keresés a listában
int hely = lstTermekek.FindString("Ba"); // az első, "Ba" kezdetű elem (-1, ha nincs)
int pontos = lstTermekek.FindStringExact("Barack"); // pontos egyezés
if (hely >= 0)
{
lstTermekek.SelectedIndex = hely;
}SelectedItem az (első) kijelölt elem, null, ha nincs. A SelectedItems az összes kijelölt elem gyűjteménye. A SelectedIndex a sorszám (-1, ha nincs).EndUpdate-nek mindig meg kell történnie (try–finally).Sorted = true ábécésorrendbe teszi az elemeket (szövegként). Rendezett listán az Insert(index, elem) hibát dob, mert a hely a rendezésből adódik.Items gyűjtemény object elemeket tárol: szöveget és saját objektumot is (a megjelenített szöveget a ToString() adja, 7.2 lecke).Jósolj!
A lista Sorted = true értékű, és a kódban lst.Items.Insert(0, "Új"); sor szerepel. Mi történik?
Jóslat ellenőrzése
A rendezett lista az elemet nem a megadott helyre teszi, hanem a rendezésnek megfelelő helyre (a hely paraméter figyelmen kívül marad, vagy a viselkedés kiszámíthatatlan). Rendezett listán az Add a helyes módszer; a helyre szúrás csak rendezetlen listán értelmes.
CheckedListBox: jelölőnégyzetes lista
A CheckedListBox minden elem mellett jelölőnégyzetet mutat. Két külön fogalom van: az elem kijelölése (kék sáv, SelectedIndex) és bejelölése (pipa, CheckedItems). Az alapértelmezés szerint a pipa bejelöléséhez két kattintás kell (az első kijelöl, a második jelöl). A CheckOnClick = true egyetlen kattintásra jelöl:
clbFeladatok.CheckOnClick = true;
// a bejelölt elemek
foreach (object elem in clbFeladatok.CheckedItems)
{
lblKesz.Text += elem + "; ";
}
int db = clbFeladatok.CheckedItems.Count;
// egy elem állapota és beállítása sorszám szerint
bool bejelolt = clbFeladatok.GetItemChecked(2);
clbFeladatok.SetItemChecked(2, true);
// az ItemCheck esemény a változás ELŐTT fut: az e.NewValue az új állapot (5.5 lecke)
private void clbFeladatok_ItemCheck(object sender, ItemCheckEventArgs e)
{
int uj = clbFeladatok.CheckedItems.Count + (e.NewValue == CheckState.Checked ? 1 : -1);
lblKesz.Text = uj + " kész / " + clbFeladatok.Items.Count;
}
// mindent kijelöl / töröl
for (int i = 0; i < clbFeladatok.Items.Count; i++)
{
clbFeladatok.SetItemChecked(i, true);
}CheckedItems.Count még a régit adja. Az e.NewValue alapján számolj (ahogy a kódban), vagy a számolást BeginInvoke-kal késleltesd.CheckedItems / CheckedIndices, a kijelölt: SelectedItem / SelectedIndex.CheckedListBox az adatkötést (8.5 lecke) csak korlátozottan támogatja: a bejelölt állapotot nem köti az adathoz, ezért a pipa állapotát külön kell kezelni (GetItemChecked, SetItemChecked).DataGridView jobb (8.3 lecke).Jósolj!
Az ItemCheck kezelő kiírja a CheckedItems.Count értéket, és a felhasználó bejelöl egy harmadik elemet (előtte kettő volt bejelölve). Mit ír ki a kezelő?
Jóslat ellenőrzése
2-t: az esemény az új állapot beállítása előtt fut, a gyűjtemény még a régi állapotot tükrözi. Ezért az e.NewValue alapján kell számolni (+1 vagy -1).
ComboBox: legördülő lista
A ComboBox egy szövegmező és egy legördülő lista együtt. A DropDownStyle háromféle viselkedést ad:
| DropDownStyle | Viselkedés | Mikor? |
|---|---|---|
DropDownList | Csak a listából lehet választani, a szöveg nem szerkeszthető. | Rögzített választék (ország, kategória). A legbiztonságosabb. |
DropDown (alap) | Választás a listából vagy szabad szöveg beírása. | Javaslatokkal segített szabad bevitel (keresés, cím). |
Simple | A lista mindig látszik (szövegmező + lista). | Ritka; helyigényes. |
cmbKategoria.DropDownStyle = ComboBoxStyle.DropDownList;
cmbKategoria.Items.AddRange(new object[] { "Gyümölcs", "Zöldség", "Pékáru" });
cmbKategoria.SelectedIndex = 0; // induló kiválasztás, különben üres
// automatikus kiegészítés: a szabad szöveges (DropDown) ComboBox-ban gépelés közben javasol
cmbTanar.DropDownStyle = ComboBoxStyle.DropDown;
cmbTanar.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
cmbTanar.AutoCompleteSource = AutoCompleteSource.ListItems; // a lista elemei a javaslatok
// a választás kiolvasása
string ertek = cmbKategoria.Text; // mindig a látható szöveg
object elem = cmbKategoria.SelectedItem; // null, ha a szöveg nem a lista eleme
private void cmbKategoria_SelectionChangeCommitted(object sender, EventArgs e)
{
// csak a felhasználó választására fut le (5.5 lecke)
lblInfo.Text = "Választott kategória: " + cmbKategoria.Text;
}DropDownList stílusú lista is üres marad, amíg nem állítasz be SelectedIndex értéket. Üres választásnál a SelectedItem null.DropDown stílusnál a Text bármi lehet (szabad szöveg), a SelectedItem csak akkor nem null, ha a szöveg egyezik egy listaelemmel.SelectedIndexChanged a kódból történő változásra is lefut, a SelectionChangeCommitted csak a felhasználó választására, a TextChanged minden szövegváltozásra (5.5 lecke).SuggestAppend javaslatlistát ad és kiegészíti a szöveget. Források: ListItems (a lista elemei), CustomSource (saját AutoCompleteStringCollection), FileSystem, HistoryList.Jósolj!
Egy DropDown stílusú ComboBox listájában „Alma”, „Körte” szerepel, a felhasználó beírja: „Banán”, és a kód cmb.SelectedItem.ToString() sort hajt végre. Mi történik?
Jóslat ellenőrzése
NullReferenceException: a „Banán” nem listaelem, ezért a SelectedItem null. Szabad szövegnél a Text tulajdonságot használd; rögzített választéknál állítsd DropDownList stílusra, és ellenőrizd a SelectedIndex >= 0 feltételt.
Melyiket mikor?
| Helyzet | Vezérlő |
|---|---|
| Egy érték választása néhány (3–15) lehetőségből, kevés helyen. | ComboBox (DropDownList) |
| Egy érték választása, szabad szöveg is megengedett (javaslatokkal). | ComboBox (DropDown + AutoComplete) |
| Sok elem megtekintése és egy vagy több kijelölése, a lista állandóan látszik. | ListBox |
| Több független igen/nem választás (jogosultságok, tevékenységek). | CheckedListBox (vagy külön CheckBox-ok, ha kevés) |
| Kevés (2–4) kölcsönösen kizáró lehetőség. | RadioButton csoport (6.3 lecke) |
| Több oszlopos, szerkeszthető adat. | DataGridView (8.3 lecke) |
Mit tegyél ide: egymás mellett a három vezérlő ugyanazzal a tartalommal: ListBox, CheckedListBox és kinyitott ComboBox.Javasolt fájlnév: winforms-8-1-listak.webp · Alt szöveg: ListBox, CheckedListBox és ComboBox
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. NullReferenceException a kijelölt elemnél
string nev = lst.SelectedItem.ToString(); // nincs kijelölt elem: nullHiba és javítás
Ellenőrizd: if (lst.SelectedIndex >= 0) { ... } vagy lst.SelectedItem != null.
2. A kijelölt elemek törlése kihagy elemeket
foreach (object elem in lst.SelectedItems)
{
lst.Items.Remove(elem); // a gyűjtemény módosul bejárás közben
}Hiba és javítás
A bejárt gyűjtemény módosul (InvalidOperationException). Készíts másolatot (object[] tomb = new object[lst.SelectedItems.Count]; lst.SelectedItems.CopyTo(tomb, 0);), vagy járj vissza a SelectedIndices indexein.
3. A CheckedListBoxban dupla kattintás kell a pipához
Az első kattintás csak kijelöl. Állítsd be a Ok és javítás
CheckOnClick = true tulajdonságot.
4. Az ItemCheck rossz számot mutat
A kijelzett bejelölt elemek száma mindig eggyel elmarad. Az esemény az állapotváltozás előtt fut. Használd az Ok és javítás
e.NewValue értéket (+1 vagy -1), vagy a számolást késleltesd.
5. A ComboBox üresen indul
Induláskor nincs kiválasztott érték, pedig a lista nem üres. Állítsd be a Ok és javítás
SelectedIndex = 0 értéket a Load-ban (ha van elem).
6. Lassú a feltöltés
Ezer elem hozzáadása másodpercekig tart. Használj Ok és javítás
BeginUpdate/EndUpdate párost és AddRange hívást (egy tömbbel egyszerre).
Mini projekt: kurzusjelentkezés
Készíts programot, amely mindhárom listavezérlőt használja:
cmbKategoria(DropDownList): Programozás, Grafika, Hálózat. A kiválasztás alstKurzusok(ListBox,MultiExtended,Sorted) tartalmát cseréli az adott kategória kurzusaira (BeginUpdate).- A Jelentkezés >> gomb a kijelölt kurzusokat a
clbJelentkezes(CheckedListBox,CheckOnClick) listába teszi, ismétlés nélkül; a << Vissza gomb a bejelölt elemeket törli a jelentkezések közül. - A
clbJelentkezesbejelölése jelzi, hogy a díj ki van fizetve; alblAllapotmutatja: 3 jelentkezés, ebből 1 kifizetve (ItemCheck,e.NewValue). - A
cmbTanar(DropDown,SuggestAppend,ListItems) a tanár neve: szabad szöveg is lehet; a Keres gomb kijelöli a kurzusok közül azokat, amelyekhez a név tartozik (ha nincs ilyen tanár, üzenet alblInfo-ban). - Teszteld: kategóriaváltás, több kurzus kijelölése, ismétlés, törlés a bejelöltekre, a számláló, a tanár keresése a listából és szabad szöveggel.
Megoldás megnyitása (próbáld ki előbb önállóan!)
A kurzusokat és a hozzájuk tartozó tanárt két párhuzamos tömb tartalmazza. A bejelölt elemek törlése visszafelé haladó ciklussal történik (a gyűjtemény módosul).
private readonly string[] kategoriak = { "Programozás", "Grafika", "Hálózat" };
private readonly string[][] kurzusok =
{
new string[] { "C# alapok", "Python kezdőknek", "Webfejlesztés" },
new string[] { "Digitális rajz", "Fényképszerkesztés" },
new string[] { "Hálózati alapok", "Biztonság" }
};
private readonly string[][] tanarok =
{
new string[] { "Kiss Péter", "Nagy Anna", "Kiss Péter" },
new string[] { "Tóth Eszter", "Tóth Eszter" },
new string[] { "Varga Gábor", "Nagy Anna" }
};
private void Form1_Load(object sender, EventArgs e)
{
lstKurzusok.SelectionMode = SelectionMode.MultiExtended;
lstKurzusok.Sorted = true;
clbJelentkezes.CheckOnClick = true;
cmbKategoria.DropDownStyle = ComboBoxStyle.DropDownList;
cmbKategoria.Items.AddRange(kategoriak);
cmbTanar.DropDownStyle = ComboBoxStyle.DropDown;
cmbTanar.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
cmbTanar.AutoCompleteSource = AutoCompleteSource.ListItems;
cmbTanar.Items.AddRange(new object[] { "Kiss Péter", "Nagy Anna", "Tóth Eszter", "Varga Gábor" });
cmbKategoria.SelectedIndex = 0;
}
private void cmbKategoria_SelectedIndexChanged(object sender, EventArgs e)
{
lstKurzusok.BeginUpdate();
try
{
lstKurzusok.Items.Clear();
lstKurzusok.Items.AddRange(kurzusok[cmbKategoria.SelectedIndex]);
}
finally
{
lstKurzusok.EndUpdate();
}
}
private void btnJelentkezes_Click(object sender, EventArgs e)
{
foreach (object elem in lstKurzusok.SelectedItems)
{
if (!clbJelentkezes.Items.Contains(elem))
{
clbJelentkezes.Items.Add(elem);
}
}
AllapotFrissit(0);
}
private void btnVissza_Click(object sender, EventArgs e)
{
for (int i = clbJelentkezes.Items.Count - 1; i >= 0; i--)
{
if (clbJelentkezes.GetItemChecked(i))
{
clbJelentkezes.Items.RemoveAt(i);
}
}
AllapotFrissit(0);
}
private void AllapotFrissit(int valtozas)
{
lblAllapot.Text = clbJelentkezes.Items.Count + " jelentkezés, ebből " + (clbJelentkezes.CheckedItems.Count + valtozas) + " kifizetve";
}
private void clbJelentkezes_ItemCheck(object sender, ItemCheckEventArgs e)
{
AllapotFrissit(e.NewValue == CheckState.Checked ? 1 : -1);
}
private void btnKeres_Click(object sender, EventArgs e)
{
string nev = cmbTanar.Text.Trim();
int kategoria = cmbKategoria.SelectedIndex;
lstKurzusok.ClearSelected();
int db = 0;
for (int i = 0; i < kurzusok[kategoria].Length; i++)
{
if (tanarok[kategoria][i].Equals(nev, StringComparison.CurrentCultureIgnoreCase))
{
lstKurzusok.SetSelected(lstKurzusok.FindStringExact(kurzusok[kategoria][i]), true);
db++;
}
}
lblInfo.Text = db == 0 ? "Ebben a kategóriában nincs ilyen tanár: " + nev : db + " kurzus kijelölve.";
}Három önálló gyakorlófeladat
Egyszerre csak egyet csinálj, és csak utána nyisd ki a megoldást.
1. Mindent kijelöl / semmit
Két gomb (Mind, Egyik sem) a Ciklus a CheckedListBox összes elemét bejelöli, illetve törli. Hogyan?Egy lehetséges megoldás
SetItemChecked hívással.private void Mind(bool allapot)
{
for (int i = 0; i < clb.Items.Count; i++)
{
clb.SetItemChecked(i, allapot);
}
}
2. Szűrő a listához
Egy szövegmező gépelés közben szűri a Az eredeti listát egy külön ListBox elemeit (azok maradnak, amelyek tartalmazzák a szöveget). Honnan veszed az eredeti elemeket?Egy lehetséges megoldás
List<string> őrzi, a ListBox csak a szűrt részt mutatja.private readonly List<string> mind = new List<string> { "Alma", "Körte", "Almalé", "Barack" };
private void txtSzuro_TextChanged(object sender, EventArgs e)
{
string minta = txtSzuro.Text.Trim();
lst.BeginUpdate();
lst.Items.Clear();
foreach (string s in mind)
{
if (s.IndexOf(minta, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
lst.Items.Add(s);
}
}
lst.EndUpdate();
}
3. Kiválasztott elem a ComboBoxból
A A DropDown ComboBox-ban beírt új szöveg bekerül a listába is, ha még nincs benne (Enter hatására). Hogyan ellenőrzöd?Egy lehetséges megoldás
KeyDown eseményben az Enter után a Items.Contains ellenőrzés.private void cmbTanar_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter && cmbTanar.Text.Trim().Length > 0 && !cmbTanar.Items.Contains(cmbTanar.Text.Trim()))
{
e.SuppressKeyPress = true;
cmbTanar.Items.Add(cmbTanar.Text.Trim());
}
}
Gyakorlótár: 6 további feladat
Alap, közepes és kihívás szinten gyakorolhatsz. Csak a próbálkozás után nyisd le a megoldást.
Alap szint
1. Melyik vezérlő?
Válassz: (a) ország; (b) értesítések típusa (e-mail, SMS, push, egyenként); (c) 200 termék, több kijelölhető. (a) Megoldás megnyitása
ComboBox DropDownList; (b) CheckedListBox (vagy három CheckBox); (c) ListBox MultiExtended.
2. Kijelölés számlálása
Mit ad a 0 (nem SelectedItems.Count, ha nincs kijelölt elem?Megoldás megnyitása
null): a SelectedItems gyűjtemény létezik, csak üres. A SelectedItem ellenben null.
Közepes szint
3. Elemek mozgatása a listák között
Két A kijelölteket előbb egy tömbbe másold, és csak utána add hozzá/töröld, mert a ListBox (Elérhető, Kiválasztott) között a kijelölt elemek átkerülnek. Mire kell vigyázni?Megoldás megnyitása
SelectedItems a törlés közben módosul.private void Atrak(ListBox honnan, ListBox hova)
{
object[] tomb = new object[honnan.SelectedItems.Count];
honnan.SelectedItems.CopyTo(tomb, 0);
foreach (object elem in tomb)
{
hova.Items.Add(elem);
honnan.Items.Remove(elem);
}
}
4. Szabad szöveg érvényesítése
A A DropDown ComboBox-ban csak a listában szereplő értéket fogadod el. Hol ellenőrzöd, és mit jelzel?Megoldás megnyitása
Validating eseményben (6.6 lecke): !cmb.Items.Contains(cmb.Text) esetén ErrorProvider. Egyszerűbb: DropDownList stílus.
Kihívás szint
5. Saját megjelenítés
A lista elemei A Termek objektumok. Hogyan mutatja a lista az Alma – 250 Ft szöveget?Megoldás megnyitása
ToString() felülírásával (7.2 lecke), vagy az adatkötés DisplayMember tulajdonságával (8.5 lecke).public class Termek
{
public string Nev = "";
public int Ar = 0;
public override string ToString()
{
return Nev + " – " + Ar + " Ft";
}
}
6. Több oszlopos ListBox
Hogyan jeleníted meg 100 rövid elemet több oszlopban, vízszintes görgetéssel?Megoldás megnyitása
MultiColumn = true, és a ColumnWidth az oszlop szélessége. A HorizontalScrollbar a hosszú szövegek vízszintes görgetésére való egyoszlopos listában.
Gyors önellenőrzés
1. Mi a SelectionMode.MultiExtended?
Több elem kijelölése a megszokott módon: Ctrl hozzáad, Shift tartományt jelöl.
2. Mi a kijelölt és a bejelölt elem különbsége?
A kijelölt a kék sáv (SelectedItem), a bejelölt a pipa (CheckedItems).
3. Mikor fut az ItemCheck?
Az állapotváltozás előtt: az e.NewValue az új állapot.
4. Melyik DropDownStyle a legbiztonságosabb rögzített választéknál?
DropDownList.
5. Mire való a BeginUpdate?
Felfüggeszti a rajzolást sok elem hozzáadásakor; az EndUpdate újraindítja.
6. Miért nem jó a foreach a kijelöltek törlésére?
A gyűjtemény módosul bejárás közben: másolatot vagy visszafelé haladó ciklust használj.
7. Mi az AutoCompleteSource.ListItems?
A javaslatok forrása a ComboBox saját listaelemei.
Mit tudsz már?
- Kiválasztod a helyzethez illő listavezérlőt.
- Kezeled a kijelölési módokat, a jelölőnégyzetes lista eseményeit és a
ComboBoxstílusait. - Gyorsan töltesz fel listákat, és automatikus kiegészítést állítasz be.
- Felismered a gyakori hibákat (
nullkijelölés, törlés bejárás közben).
Következő lecke: Items, SelectedItem és SelectedIndex
A listák elemeinek kezelése mélyebben: saját objektumok a listában, kijelölés követése, elemek mozgatása és cseréje.



