Grafikus C# – Windows Forms tanfolyam › 8.7 lecke Windows Forms · 8.7 lecke · rendezés és szűrés Száz sor fölött a táblázatban már nem lehet „átfutni” az adatokat: kell a rendezés (a legolcsóbb elöl), a szűrés (csak a papírok) és a keresés (hol van a „radír”). A Rendezés, keresés és szűrés
DataGridView ezekhez nem ad mindent magától: attól függ, mire kötötted. Ebben a leckében megtanulod, miért nem rendezhető a BindingList, hogyan oldja meg a DataTable és a DataView (Sort, RowFilter), hogyan szűrsz LINQ-val egy sima listát, hogyan lesz a keresés ékezetfüggetlen, és hogyan építesz kényelmes kereső-felületet.
A lecke végére
- tudod, mely adatforrásnál rendezhető automatikusan a
DataGridView(és mely nem); - kézzel rendezel listát (
List.Sort) magyar ábécé szerint, rendezési nyíllal (SortGlyphDirection); - a
BindingSource.SortésFiltertulajdonságot használodDataTablefelett; - helyes
RowFilterkifejezést építesz (idézőjelek,LIKE, számok, hibák); - LINQ-val szűrsz listát, és ékezetfüggetlen keresést írsz;
- kereső felületet készítesz (szöveg, kategória, tartomány, találatszám, üres eredmény).
Mielőtt elkezded
Ehhez a leckéhez a 8.3–8.4 lecke (DataGridView, BindingList, BindingSource), a 3.8 lecke (DataTable) és az 5.5 lecke (TextChanged) szükséges.
Rendezés: mikor működik a fejlécre kattintás?
| Adatforrás | Fejlécre kattintva rendez? | Megjegyzés |
|---|---|---|
DataTable (vagy BindingSource felette) | Igen, automatikusan | A DataView támogatja a rendezést és a szűrést. |
List<T>, BindingList<T> | Nem | Nincs beépített rendezés: a rács a fejlécre kattintva semmit sem csinál. Kézzel kell megoldani. |
| Rács adatforrás nélkül (kézzel feltöltött sorok) | Igen (dgv.Sort, SortCompare) | Szöveg szerint rendez; számoknál a SortCompare eseményt kell kezelni. |
private List<Termek> adatok = new List<Termek>();
private string rendezOszlop = "";
private ListSortDirection irany = ListSortDirection.Ascending;
private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
DataGridViewColumn oszlop = dgv.Columns[e.ColumnIndex];
// ugyanarra az oszlopra kattintva az irány fordul, új oszlopnál növekvő
if (rendezOszlop == oszlop.DataPropertyName)
{
irany = irany == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
}
else
{
rendezOszlop = oszlop.DataPropertyName;
irany = ListSortDirection.Ascending;
}
Rendez();
}
private void Rendez()
{
int elojel = irany == ListSortDirection.Ascending ? 1 : -1;
switch (rendezOszlop)
{
case "Nev":
// StringComparison.CurrentCulture: a magyar ábécé szerint (cs, sz, ö, ő...)
adatok.Sort((a, b) => elojel * string.Compare(a.Nev, b.Nev, StringComparison.CurrentCultureIgnoreCase));
break;
case "Netto":
adatok.Sort((a, b) => elojel * a.Netto.CompareTo(b.Netto));
break;
case "Keszlet":
adatok.Sort((a, b) => elojel * a.Keszlet.CompareTo(b.Keszlet));
break;
}
bs.ResetBindings(false); // a rács újrarajzolja a (már rendezett) listát
// a rendezési nyíl a fejlécben
foreach (DataGridViewColumn o in dgv.Columns)
{
o.HeaderCell.SortGlyphDirection = o.DataPropertyName == rendezOszlop
? (irany == ListSortDirection.Ascending ? SortOrder.Ascending : SortOrder.Descending)
: SortOrder.None;
}
}BindingList/List rendezéséhez magát az adatot rendezed (List.Sort), majd frissíted a rácsot (ResetBindings). A rács csak megjeleníti a lista sorrendjét.Sort lambdája negatív, nulla vagy pozitív számot ad: az elojel szorzó fordítja az irányt. A számokat CompareTo, a szöveget string.Compare hasonlítja.StringComparison.CurrentCulture (IgnoreCase változat) a magyar rendezési szabályt követi (a, á, b, c, cs...). Az Ordinal összehasonlítás a karakterkód szerint rendez, ezért az ékezetes betűk a lista végére kerülnek: kerüld felhasználói listáknál.DataTable), ezt automatikusan teszi; kézi rendezésnél be kell állítani.Jósolj!
A dgv.DataSource egy BindingList<Termek>, az oszlopok SortMode értéke Automatic. A felhasználó a Nettó ár fejlécre kattint. Mi történik?
Jóslat ellenőrzése
Gyakran semmi (a sorrend nem változik, nincs nyíl): a BindingList<T> nem támogatja a rendezést, a rács pedig nem rendez helyette. Ezért kell a ColumnHeaderMouseClick kezelő és a lista kézi rendezése, vagy DataTable használata.
DataView, Sort és RowFilter
A DataTable rendezését és szűrését a DataView (a DefaultView tulajdonság) vagy a BindingSource (Sort, Filter tulajdonságok) végzi: nem módosítja az adatot, csak a nézetet. A szűrő és a rendezés szöveges kifejezés:
DataTable tabla = new DataTable();
tabla.Columns.Add("Nev", typeof(string));
tabla.Columns.Add("Kategoria", typeof(string));
tabla.Columns.Add("Ar", typeof(decimal));
tabla.Columns.Add("Keszlet", typeof(int));
BindingSource bs = new BindingSource();
bs.DataSource = tabla;
dgv.DataSource = bs;
// rendezés: oszlopnév, ASC (növekvő) vagy DESC (csökkenő), vesszővel több oszlop
bs.Sort = "Kategoria ASC, Ar DESC";
// szűrés: SQL-szerű feltétel
bs.Filter = "Kategoria = 'Papír' AND Ar >= 100";
bs.Filter = "Nev LIKE '%fü%'"; // tartalmaz (a % bármi)
bs.Filter = "Keszlet > 0 OR Kategoria = 'Technika'";
bs.Filter = ""; // a szűrő törlése: minden sor látszik
lblDb.Text = bs.Count + " / " + tabla.Rows.Count + " termék";
// a feltételben szereplő szöveg biztonságos beírása
private string Idezo(string s)
{
return s.Replace("'", "''"); // az aposztróf kettőzve
}
private string LikeSzoveg(string s)
{
// a LIKE speciális karaktereit szögletes zárójellel semlegesítjük, előbb a [ jelet
return s.Replace("[", "[[]").Replace("%", "[%]").Replace("*", "[*]").Replace("'", "''");
}
// a szám a feltételben mindig pont tizedessel (kultúrafüggetlenül)
string szamSzoveg = 1250.5m.ToString(CultureInfo.InvariantCulture); // "1250.5"| Cél | Szűrőkifejezés |
|---|---|
| Egyenlő (szöveg) | Kategoria = 'Papír' (szöveg aposztrófok között) |
| Tartalmaz / kezdődik / végződik | Nev LIKE '%fü%', Nev LIKE 'fü%', Nev LIKE '%et' |
| Szám összehasonlítása | Ar >= 100 AND Ar <= 500 (a tizedes pont) |
| Több lehetőség | Kategoria IN ('Papír', 'Technika') |
| Tagadás | NOT (Keszlet = 0), Kategoria <> 'Papír' |
| Dátum | Datum >= #2026-10-01# (a # jelek között, kultúrafüggetlen alak ellenőrzendő) |
Filter és a Sort a megjelenítést változtatja: a DataTable sorai megmaradnak, a törölt szűrő után újra látszanak. A bs.Count a szűrt sorok számát adja, a tabla.Rows.Count az összeset.O'Neil nevet keres, az aposztróf megtöri a kifejezést (SyntaxErrorException), és ez kifejezés-beszúrás (injection) is lehet. Mindig kettőzd ('').% és * a LIKE-ban helyettesítő karakter, a [ pedig tartomány kezdete. Ha a felhasználó ezeket szó szerint keresi, szögletes zárójelbe kell tenni őket.12,5.ToString() magyar gépen 12,5 lenne: használj CultureInfo.InvariantCulture-t.Jósolj!
A felhasználó a keresőmezőbe beírja: d'Artagnan, a kód pedig a szűrőt "Nev LIKE '%" + txtKeres.Text + "%'" módon építi, escape nélkül. Mi történik?
Jóslat ellenőrzése
Az aposztróf megtöri a kifejezést, és a Filter beállítása kivételt dob (SyntaxErrorException/EvaluateException), a program összeomlik a gépelés közben. A szűrőkifejezés összeállításakor az Idezo (és LikeSzoveg) segédmetódus elengedhetetlen, és a Filter beállítását érdemes try–catch védelemmel is ellátni.
Szűrés és keresés listán: LINQ és ékezetfüggetlenség
Ha az adat egy sima listában van (List<Termek>), a szűrést LINQ végzi (using System.Linq;): az eredmény új lista, amelyet a rácsra kötsz. A kereséshez érdemes az ékezeteket figyelmen kívül hagyni: aki „fuzet”-et gépel, találja meg a „füzet”-et:
// ékezetek és kis-nagybetű nélküli alak: ő → o, Á → a
private static string Egyszerusit(string szoveg)
{
string bontott = (szoveg ?? "").Normalize(NormalizationForm.FormD); // a betű és az ékezet szétválik
StringBuilder epito = new StringBuilder();
foreach (char c in bontott)
{
if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
{
epito.Append(c); // az ékezetet (kombináló jel) kihagyjuk
}
}
return epito.ToString().Normalize(NormalizationForm.FormC).ToLowerInvariant();
}
private void Szur()
{
string keres = Egyszerusit(txtKeres.Text.Trim());
decimal maxAr = nudMax.Value;
List<Termek> talalat = adatok
.Where(t => keres.Length == 0 || Egyszerusit(t.Nev).Contains(keres))
.Where(t => cmbKat.SelectedIndex <= 0 || t.Kategoria == cmbKat.Text)
.Where(t => maxAr == 0 || t.Netto <= maxAr)
.OrderBy(t => t.Nev, StringComparer.CurrentCultureIgnoreCase)
.ToList();
dgv.DataSource = new BindingList<Termek>(talalat);
lblDb.Text = talalat.Count + " / " + adatok.Count + " termék";
}
// keresés a rácsban: a következő egyező sorra ugrik, a végén körbe
private bool KovetkezoKeres(string keresett)
{
string k = Egyszerusit(keresett);
int kezdet = dgv.CurrentRow == null ? 0 : dgv.CurrentRow.Index + 1;
for (int lepes = 0; lepes < dgv.Rows.Count; lepes++)
{
int i = (kezdet + lepes) % dgv.Rows.Count;
if (Egyszerusit(Convert.ToString(dgv.Rows[i].Cells["colNev"].Value)).Contains(k))
{
dgv.ClearSelection();
dgv.CurrentCell = dgv.Rows[i].Cells["colNev"]; // kijelöli és láthatóvá görgeti
return true;
}
}
return false;
}Where a feltételnek megfelelő elemeket, az OrderBy a rendezettet adja; a ToList() kiértékeli az eredményt (a halasztott végrehajtás miatt enélkül a lekérdezés minden használatkor újra lefutna).FormD alak a ő betűt o + kombináló kettős ékezet jelre bontja; az ékezet-jelek (NonSpacingMark) kihagyásával marad az alap betű. A ToLowerInvariant a kis-nagybetű különbséget is eltünteti.BindingList: a dgv.DataSource újrakötése frissíti a rácsot. Az eredeti adatok lista változatlan, a szűrő törlése után újra elérhető.dgv.CurrentCell beállítása kijelöli a cellát és szükség esetén odagörgeti a rácsot. A keresés a végén az elejére ugrik (% osztásmaradék).Jósolj!
A keresés a t.Nev.Contains(keres) hívással történik (egyszerűsítés nélkül), a lista egyik elemének neve Füzet. A felhasználó azt keresi: füzet, majd azt: fuzet. Melyiket találja meg?
Jóslat ellenőrzése
Egyiket sem: a Contains(string) kis- és nagybetű-érzékeny (a Füzet nagy F-fel kezdődik), az ékezetes és ékezet nélküli alak is különbözik. A füzet keresés csak az IndexOf(..., StringComparison.CurrentCultureIgnoreCase) hívással találna meg, a fuzet pedig csak ékezetfüggetlen (Egyszerusit) összehasonlítással.
Kényelmes kereső felület
| Elem | Jó megoldás | Miért? |
|---|---|---|
| Szűrés időpontja | Minden gépelésnél (TextChanged), nagy adatnál késleltetve (Timer 300 ms) | A felhasználó azonnal látja az eredményt; a késleltetés megspórolja a felesleges számolást. |
| Kategória | ComboBox Összes kategória első elemmel | A szűrő kikapcsolása is választható (SelectedIndex == 0). |
| Ártartomány | Két NumericUpDown (-tól, -ig), a nulla jelenti a „nincs korlát” értéket | Nincs külön kapcsoló. |
| Találatszám | 12 / 50 termék felirat | A felhasználó látja a szűrés hatását. |
| Nincs találat | Barátságos szöveg a rács felett (Nincs a feltételeknek megfelelő termék. Módosítsd a szűrőt.) | Az üres rács megtévesztő. |
| Szűrők törlése | Szűrők törlése gomb, amely mindent alaphelyzetbe állít | Nem kell mezőnként törölni. |
| Rendezés és szűrés együtt | A szűrés megőrzi a rendezési sorrendet | Ne ugorjon vissza a sorrend szűréskor. |
private void Szuro_Valtozott(object sender, EventArgs e)
{
tmrSzur.Stop(); // minden gépelés újraindítja a várakozást
tmrSzur.Start();
}
private void tmrSzur_Tick(object sender, EventArgs e)
{
tmrSzur.Stop();
Szur(); // csak akkor szűrünk, ha a felhasználó 300 ms-ig nem gépelt
}
private void btnTorol_Click(object sender, EventArgs e)
{
txtKeres.Clear();
cmbKat.SelectedIndex = 0;
nudMin.Value = 0;
nudMax.Value = 0;
chkRaktaron.Checked = false;
Szur();
txtKeres.Focus();
}Jósolj!
A szűrés minden gépelésnél lefut, 50 000 soros listán, és a szűrő LINQ-val újraépíti a listát. Mit érez a felhasználó gyors gépelésnél?
Jóslat ellenőrzése
A gépelés akadozik: minden betű után lefut a teljes szűrés (és a rács újrarajzolása), a program lassúnak tűnik. A késleltetett szűrés (Timer, 300 ms) csak a gépelés szünetében számol. Nagyon nagy adatnál az adatbázis szűrése (SQL, 3. fejezet) a helyes út.
Mit tegyél ide: az árlista kereső: a szűrősor (kereső, kategória, ártartomány), a rács rendezési nyíllal és a „12 / 50 termék” felirat.Javasolt fájlnév: winforms-8-7-kereso.webp · Alt szöveg: Árlista kereső szűrőkkel
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. A fejlécre kattintva nem rendez a rács
A A lista nem támogatja a rendezést. Kezeld a BindingList<T>-ra kötött rács nem rendez.Ok és javítás
ColumnHeaderMouseClick eseményt, rendezd a listát (Sort), és frissítsd a rácsot; vagy használj DataTable-t.
2. A szűrés összeomlik aposztrófnál
bs.Filter = "Nev LIKE '%" + txtKeres.Text + "%'"; // d'Artagnan → kivételHiba és javítás
Az aposztrófot kettőzni kell, a LIKE speciális karaktereit zárójelbe kell tenni (LikeSzoveg), a Filter beállítását try–catch védje.
3. A szűrő nem működik tizedes számra
bs.Filter = "Ar <= " + nudMax.Value; // magyar gépen: Ar <= 99,5 → hiba vagy rossz eredményHiba és javítás
A tizedesvessző miatt a kifejezés érvénytelen. Használd az InvariantCulture alakot: nudMax.Value.ToString(CultureInfo.InvariantCulture).
4. A szűrő törlése után sem látszik minden sor
A szűrő törlése után is hiányoznak sorok. A LINQ-szűrőnél a rácsra kötött lista a szűrt lista, nem az eredeti. A szűrő törlésekor az eredeti Ok és javítás
adatok listából építsd újra a nézetet (Szur() üres feltételekkel), ne a már szűrt listából.
5. Az ékezetes keresés nem talál
A „fuzet” keresésre nem jelenik meg a „Füzet”. A Ok és javítás
Contains ékezet- és kisbetű-érzékeny. Használj Egyszerusit (Normalize + ToLowerInvariant) mindkét oldalon.
6. A rendezés a szűrés után elvész
A rendezett táblázat szűréskor visszaáll az eredeti sorrendbe. A szűrés új listát épít rendezés nélkül. A szűrés végén alkalmazd újra az aktuális rendezést (Ok és javítás
Rendez() vagy OrderBy), vagy DataTable esetén a Sort tulajdonság megmarad a Filter módosításakor.
Mini projekt: árlista kereső
Készíts árlista-keresőt egy DataTable felett:
- Adat: egy
DataTable(Nev,Kategoria,Ardecimal,Keszletint) legalább 30 sorral (kód generálja, ismétlődő kategóriákkal: Irodaszer, Papír, Technika, Sport), ékezetes nevekkel (Füzet, Radír, Tűzőgép, Ceruza, Ollő…). - Felület:
txtKeres,cmbKat(Összes kategória + a kategóriák),nudMin,nudMax(0 = nincs korlát),chkRaktaron(Csak raktáron),btnTorol,cmbRendez(Név szerint, Ár szerint növekvő, Ár szerint csökkenő, Kategória, majd név),dgv,lblDb(12 / 30 termék),lblUres(nincs találat üzenet). - A
BindingSourceFiltertulajdonsága a mezők alapján épül (kategória, tartalmazza a keresett szöveget, ártartomány, készlet), az aposztróf és a LIKE speciális karakterei védve, a számokInvariantCulturealakban. - A szöveges keresés legyen kis- és nagybetű-független; (bónusz) ékezetfüggetlen: a DataTable LIKE ékezetérzékeny lehet, ezért a bónuszhoz külön
EgyszerusitettNevoszlopot tölts fel (Egyszerusit(Nev)), és abban keress. - A rendezés legördülő listából és a fejlécre kattintva is működik; a rács a
bs.Sortértékét követi. - A szűrés késleltetett (
Timer300 ms); a Szűrők törlése gomb mindent alaphelyzetbe állít. - Ha nincs találat, a
lblUreslátszik a rács fölött (nem üres fehér terület). - Teszteld: minden szűrő külön és együtt,
d'Artagnan,%,[a keresőben, tizedes ár (99,5), üres szűrő, nincs találat, rendezés szűrés közben.
Megoldás megnyitása (próbáld ki előbb önállóan!)
A szűrőkifejezést egy Szurot_Epit() metódus állítja össze a mezőkből; a try–catch védi a Filter beállítását. A rendezést a legördülő lista a bs.Sort szövegére képezi le.
private DataTable tabla = new DataTable();
private BindingSource bs = new BindingSource();
private readonly string[] rendezesek = { "Nev ASC", "Ar ASC", "Ar DESC", "Kategoria ASC, Nev ASC" };
private void Form1_Load(object sender, EventArgs e)
{
tabla.Columns.Add("Nev", typeof(string));
tabla.Columns.Add("Kategoria", typeof(string));
tabla.Columns.Add("Ar", typeof(decimal));
tabla.Columns.Add("Keszlet", typeof(int));
string[] nevek = { "Füzet", "Radír", "Tűzőgép", "Ceruza", "Ollő", "Toll", "Jegyzettömb", "Hátizsák", "Focilabda", "Mappa" };
string[] kategoriak = { "Irodaszer", "Papír", "Technika", "Sport" };
Random r = new Random(7);
for (int i = 0; i < 40; i++)
{
tabla.Rows.Add(nevek[i % nevek.Length] + " " + (i / nevek.Length + 1), kategoriak[r.Next(kategoriak.Length)], Math.Round((decimal)(r.Next(500, 25000)) / 10, 1), r.Next(0, 80));
}
bs.DataSource = tabla;
dgv.DataSource = bs;
cmbKat.Items.Add("Összes kategória");
cmbKat.Items.AddRange(kategoriak);
cmbKat.SelectedIndex = 0;
cmbRendez.Items.AddRange(new object[] { "Név szerint", "Ár szerint növekvő", "Ár szerint csökkenő", "Kategória, majd név" });
cmbRendez.SelectedIndex = 0;
Szur();
}
private string Idezo(string s) { return s.Replace("'", "''"); }
private string LikeSzoveg(string s)
{
return s.Replace("[", "[[]").Replace("%", "[%]").Replace("*", "[*]").Replace("'", "''");
}
private string SzurotEpit()
{
List<string> feltetelek = new List<string>();
string keres = txtKeres.Text.Trim();
if (keres.Length > 0)
{
feltetelek.Add("Nev LIKE '%" + LikeSzoveg(keres) + "%'");
}
if (cmbKat.SelectedIndex > 0)
{
feltetelek.Add("Kategoria = '" + Idezo(cmbKat.Text) + "'");
}
if (nudMin.Value > 0)
{
feltetelek.Add("Ar >= " + nudMin.Value.ToString(CultureInfo.InvariantCulture));
}
if (nudMax.Value > 0)
{
feltetelek.Add("Ar <= " + nudMax.Value.ToString(CultureInfo.InvariantCulture));
}
if (chkRaktaron.Checked)
{
feltetelek.Add("Keszlet > 0");
}
return string.Join(" AND ", feltetelek);
}
private void Szur()
{
try
{
bs.Filter = SzurotEpit();
bs.Sort = rendezesek[cmbRendez.SelectedIndex];
}
catch (Exception ex)
{
bs.Filter = "";
MessageBox.Show(this, "A szűrő nem alkalmazható: " + ex.Message, "Szűrés", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
lblDb.Text = bs.Count + " / " + tabla.Rows.Count + " termék";
lblUres.Visible = bs.Count == 0;
dgv.Visible = bs.Count > 0;
}
private void Szuro_Valtozott(object sender, EventArgs e)
{
tmrSzur.Stop();
tmrSzur.Start();
}
private void tmrSzur_Tick(object sender, EventArgs e)
{
tmrSzur.Stop();
Szur();
}
private void btnTorol_Click(object sender, EventArgs e)
{
txtKeres.Clear();
cmbKat.SelectedIndex = 0;
nudMin.Value = 0;
nudMax.Value = 0;
chkRaktaron.Checked = false;
Szur();
txtKeres.Focus();
}Mit tegyél ide: a kész árlista kereső szűrt találatokkal és a „nincs találat” üzenettel.Javasolt fájlnév: winforms-8-7-kesz.webp · Alt szöveg: A kész árlista kereső 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. Rendezés több oszlopra
Írd meg a Ha az első összehasonlítás nem nulla, azt adod vissza; különben a másodikat. LINQ-val: List<Termek> rendezését kategória, majd azon belül ár szerint csökkenően. Mi a kulcs egy összetett összehasonlításban?Egy lehetséges megoldás
OrderBy(...).ThenByDescending(...).adatok.Sort((a, b) =>
{
int kat = string.Compare(a.Kategoria, b.Kategoria, StringComparison.CurrentCultureIgnoreCase);
return kat != 0 ? kat : b.Netto.CompareTo(a.Netto); // a kategórián belül az ár csökkenő
});
// LINQ változat:
var rendezett = adatok.OrderBy(t => t.Kategoria, StringComparer.CurrentCultureIgnoreCase).ThenByDescending(t => t.Netto).ToList();
2. IN feltétel kategóriákkal
A Ha nincs kipipálva semmi, ne legyen kategória-feltétel (minden kategória látszik): az üres CheckedListBox kipipált kategóriái szerint szűrj (Kategoria IN ('Papír', 'Sport')). Mi legyen, ha egy kategória sincs kipipálva?Egy lehetséges megoldás
IN () kifejezés érvénytelen lenne.List<string> kivalasztott = new List<string>();
foreach (object o in clbKat.CheckedItems)
{
kivalasztott.Add("'" + o.ToString().Replace("'", "''") + "'");
}
if (kivalasztott.Count > 0)
{
feltetelek.Add("Kategoria IN (" + string.Join(", ", kivalasztott) + ")");
}
3. A talált szöveg kiemelése a rácsban
A keresett szöveget tartalmazó sorok háttere sárga legyen (és ne szűrjön). Melyik eseményben állítod a színt? A Egy lehetséges megoldás
CellFormatting eseményben (soronként hívódik): a sor háttere a cella értékétől függ. A színt a kijelölés és a kontraszt miatt világos árnyalatra állítsd (6.9 lecke).private void dgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e){
string keres = Egyszerusit(txtKeres.Text.Trim());
if (keres.Length == 0 || e.RowIndex < 0) { return; }
string nev = Convert.ToString(dgv.Rows[e.RowIndex].Cells["colNev"].Value);
dgv.Rows[e.RowIndex].DefaultCellStyle.BackColor = Egyszerusit(nev).Contains(keres) ? Color.LemonChiffon : dgv.DefaultCellStyle.BackColor;
}
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. Sort kifejezések
Írd meg a (a) bs.Sort szövegét: (a) ár szerint csökkenően; (b) kategória növekvően, azon belül név szerint.Megoldás megnyitása
"Ar DESC"; (b) "Kategoria ASC, Nev ASC".
2. Filter kifejezések
Írd meg a szűrőt: (a) raktáron lévő papírok; (b) a név „t”-vel kezdődik; (c) az ár 100 és 500 között. (a) Megoldás megnyitása
"Kategoria = 'Papír' AND Keszlet > 0"; (b) "Nev LIKE 't%'"; (c) "Ar >= 100 AND Ar <= 500".
Közepes szint
3. Szűrés dátumra
A A dátumot DataTable Datum oszlopára szűrsz: az adott hónap sorai. Hogyan írod a kifejezést?Megoldás megnyitása
# jelek közé teszed, tartományként (>= elsőnap AND < következő hónap első napja). A dátum alakját a DataColumn kultúrafüggetlenül (yyyy-MM-dd/MM/dd/yyyy) várja; érdemes kipróbálni a saját gépeden.DateTime elso = new DateTime(2026, 10, 1);
DateTime kovetkezo = elso.AddMonths(1);
bs.Filter = "Datum >= #" + elso.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) + "# AND Datum < #" + kovetkezo.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) + "#";
4. Rendezés számként, nem szövegként
A A szövegek betűrendben rendeződnek (DataTable Ar oszlopa string típusú, ezért a 100 a 20 előtt áll. Miért, és mi a megoldás?Megoldás megnyitása
"100" < "20"). Az oszlop típusa legyen szám (typeof(decimal)); a rendezés típus szerint történik.
Kihívás szint
5. Mentett szűrők
A felhasználó elmentheti a beállított szűrőt névvel (Olcsó papírok), és később visszatöltheti. Mit tárolsz? A szűrő beállításait (szöveg, kategória-index, tartomány, jelölő), nem a kész kifejezést: így a mezők is visszaállíthatók és a kifejezés biztonságosan újraépül. Egy kis Megoldás megnyitása
SzuroBeallitas osztály (név + mezők) listában, szövegként a Settings-ben vagy fájlban (10. fejezet).public class SzuroBeallitas
{
public string Nev = "";
public string Keres = "";
public int KategoriaIndex = 0;
public decimal Min = 0;
public decimal Max = 0;
public bool Raktaron = false;
public override string ToString() { return Nev; }
}
6. Oldalakra bontott találatok
1000 találatot 50-esével jelenítesz meg lapozva. Hogyan számolod az oldal tartalmát LINQ-val? A Megoldás megnyitása
Skip((oldal - 1) * meret).Take(meret) hívással; az oldalak száma (int)Math.Ceiling(osszes / (double)meret).private const int Meret = 50;
private int oldal = 1;
private void OldalMutat(List<Termek> osszes)
{
int oldalak = Math.Max(1, (int)Math.Ceiling(osszes.Count / (double)Meret));
oldal = Math.Max(1, Math.Min(oldal, oldalak));
dgv.DataSource = new BindingList<Termek>(osszes.Skip((oldal - 1) * Meret).Take(Meret).ToList());
lblOldal.Text = oldal + " / " + oldalak + ". oldal";
}
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. Nincs: csak a nézetet változtatják, az adat megmarad. Különben megtöri a kifejezést (kivétel, beszúrás); a Ponttal, Nagy adatnál gépelés közben nem számol minden betű után, csak a szünetben.1. Melyik adatforrásnál rendez a rács magától?
DataTable (DataView) esetén. A List és BindingList nem támogatja.2. Hogyan rendezel listát a magyar ábécé szerint?
string.Compare(a, b, StringComparison.CurrentCultureIgnoreCase) a Sort lambdában.3. Mi a Filter és a Sort hatása az adatra?
4. Miért kell az aposztrófot kettőzni a szűrőben?
'' szó szerinti aposztrófot jelent.5. Hogyan írsz tizedes számot a szűrőbe?
CultureInfo.InvariantCulture segítségével.6. Hogyan lesz a keresés ékezetfüggetlen?
Normalize(FormD), az ékezet-jelek kihagyása és ToLowerInvariant mindkét oldalon.7. Mire jó a késleltetett szűrés?
Mit tudsz már?
- Tudod, mikor rendez a rács magától, és mikor kell kézi rendezés.
- A
BindingSource.SortésFiltertulajdonságot helyes, biztonságos kifejezéssel használod. - LINQ-val szűrsz, és ékezetfüggetlen keresést írsz.
- Kényelmes kereső felületet építesz találatszámmal és üres eredmény kezeléssel.
- Felismered a tipikus hibákat (aposztróf, tizedes, elvesző rendezés).
Következő lecke: CellValidating és adatellenőrzés
A táblázatba írt adat ellenőrzése: érvénytelen érték megakadályozása, hibajelzés a cellán és a soron, a DataError esemény.



