Grafikus C# – Windows Forms tanfolyam › 8.6 lecke

Windows Forms · 8.6 lecke · adatkötés

Adatkötés (data binding) alapok

Eddig a vezérlők és az adatok közti másolást kézzel írtad: txtNev.Text = szemely.Nev;, majd visszafelé szemely.Nev = txtNev.Text;. Az adatkötés (data binding) ezt a keretrendszerre bízza: egyszer megmondod, hogy a vezérlő melyik tulajdonsága melyik adattulajdonsághoz tartozik, és a két oldal szinkronban marad. Ebben a leckében megtanulod a DataBindings.Add használatát, az irányok és frissítési módok szabályait, az INotifyPropertyChanged szerepét, a formázást és visszaalakítást, valamint a BindingSource alapú navigációt.

  • kb. 110 perc
  • közepes szint
  • adatkötés
Diáklány C# programot készít laptopon

A lecke végére

  • vezérlő-tulajdonságot adattulajdonsághoz kötsz (DataBindings.Add);
  • tudod, mikor frissül az adat (DataSourceUpdateMode) és mikor a felület (INotifyPropertyChanged);
  • megvalósítod az INotifyPropertyChanged felületet számított tulajdonságokkal;
  • formázást és visszaalakítást adsz a kötéshez (FormatString, Format, Parse);
  • a BindingSource aktuális elemét és navigációját használod;
  • felismered a tipikus hibákat (nem frissülő felület, késleltetett visszaírás, kötés üres forrással).

Mielőtt elkezded

Ehhez a leckéhez a 8.4 lecke (BindingList, BindingSource), a 8.5 lecke (DataSource, DisplayMember) és a 3.9 lecke (osztály, tulajdonság) szükséges, valamint az 5.1 lecke (események).

8.5 DataSource, DisplayMember →

Az első kötés: DataBindings.Add

Termek.cs és Form1.csC#
public class Termek
{
public string Nev { get; set; } = "";
public int Keszlet { get; set; }
public bool Aktiv { get; set; } = true;
}

// Form1.cs
private Termek termek = new Termek { Nev = "Füzet", Keszlet = 40 };

private void Form1_Load(object sender, EventArgs e)
{
// vezérlő tulajdonsága, adatforrás, adat tulajdonsága
txtNev.DataBindings.Add("Text", termek, "Nev");
nudKeszlet.DataBindings.Add("Value", termek, "Keszlet");
chkAktiv.DataBindings.Add("Checked", termek, "Aktiv");
}

private void btnMutat_Click(object sender, EventArgs e)
{
// a felhasználó átírta a mezőket: az objektum már az új értékeket tartalmazza
MessageBox.Show(termek.Nev + ": " + termek.Keszlet + " db, aktív: " + termek.Aktiv);
}
Három paraméterAz első a vezérlő tulajdonságának neve ("Text"), a második az adatforrás (objektum, lista vagy BindingSource), a harmadik az adat tulajdonságának neve ("Nev"). A tulajdonságnevek szövegek: elgépelés csak futáskor derül ki.
Melyik tulajdonság?A szövegmezőnél Text, a NumericUpDownnál Value, a CheckBoxnál Checked, a DateTimePickernél Value, a ComboBoxnál SelectedValue (8.5 lecke). Bármely nyilvános tulajdonság köthető.
Mi változikA kötés az adatot betölti a vezérlőbe a kötés létrehozásakor, és a felhasználó módosítását visszaírja az objektumba. Nincs szükség TextChanged kezelőre a másoláshoz.
Csak tulajdonságKötni tulajdonságot lehet, mezőt (public int Keszlet;) nem. A { get; set; } alakú automatikus tulajdonság megfelel.

Jósolj!

A Termek osztályban a Keszlet nem tulajdonság, hanem nyilvános mező (public int Keszlet;). Mi történik a nudKeszlet.DataBindings.Add("Value", termek, "Keszlet") hívásakor?

Jóslat ellenőrzése

ArgumentException kivétel (a kötés nem találja a tulajdonságot): az adatkötés tulajdonságokat használ (reflexióval), mezőt nem lát. A mező { get; set; } tulajdonságra cserélése megoldja.

Két irány: mikor frissül az adat, mikor a felület?

Felület → adat

A DataSourceUpdateMode határozza meg: alapértelmezetten OnValidation, vagyis amikor a vezérlő elveszti a fókuszt (érvényesítés). OnPropertyChanged: minden változásnál (betűnként), Never: soha (kézi WriteValue).

Adat → felület

A kötés csak akkor értesül az adat változásáról, ha az adatosztály INotifyPropertyChanged felületet valósít meg, és a tulajdonság beállításakor kiváltja a PropertyChanged eseményt. Különben a vezérlő a régi értéket mutatja.

Termek.cs (using System.ComponentModel; using System.Runtime.CompilerServices;)C#
public class Termek : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

private void Valtozott([CallerMemberName] string nev = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nev));
}

private decimal netto;
private int afa = 27;

public decimal Netto
{
get { return netto; }
set
{
if (netto != value)
{
netto = value;
Valtozott(); // a „Netto” tulajdonság változott
Valtozott("Brutto"); // a számított tulajdonság is
}
}
}

public int AfaSzazalek
{
get { return afa; }
set
{
if (afa != value)
{
afa = value;
Valtozott();
Valtozott("Brutto");
}
}
}

// számított, csak olvasható tulajdonság
public decimal Brutto
{
get { return Math.Round(netto * (100 + afa) / 100m); }
}
}
CallerMemberNameA [CallerMemberName] a fordítóval automatikusan beírja a hívó tulajdonság nevét: nem kell szövegként kézzel megadni, így elgépelés sem lehet.
Csak változáskorAz if (netto != value) vizsgálat nem vált ki felesleges eseményt (és hurkot sem, ha a kötés visszaírja ugyanazt az értéket).
Számított tulajdonságA Brutto a nettóból és az áfából származik: amikor azok változnak, a Brutto változását is jelezni kell (Valtozott("Brutto")), különben a hozzá kötött címke nem frissül.
Frissítési módHa a bruttó árnak azonnal követnie kell a nettó mezőbe gépelést, a nettó mező kötésénél DataSourceUpdateMode.OnPropertyChanged kell: txtNetto.DataBindings.Add("Text", termek, "Netto", true, DataSourceUpdateMode.OnPropertyChanged).

Jósolj!

A Termek osztály nem valósítja meg az INotifyPropertyChanged felületet. A kódban a gombnyomás termek.Nev = "Toll"; sort hajt végre. Mit mutat a txtNev mező?

Jóslat ellenőrzése

A régi nevet (Füzet): az adat megváltozott, de a kötés nem értesült róla. Megoldás: az osztály valósítsa meg az INotifyPropertyChanged felületet, vagy a kód hívja meg a BindingSource.ResetBindings(false) metódust a frissítéshez (8.4 lecke).

Formázás és visszaalakítás

Az adat és a megjelenített szöveg gyakran eltér: az ár 12500 helyett 12 500 Ft, a dátum 2026. 10. 28. formában látszik. Ezt a formázó kötés oldja meg (a negyedik paraméter true):

Form1.csC#
// 1. egyszerű formátum sztringgel
Binding ar = new Binding("Text", termek, "Brutto", true);
ar.FormatString = "N0"; // ezres tagolás, tizedes nélkül: 12 500
lblBrutto.DataBindings.Add(ar);

// 2. saját Format és Parse esemény: egyedi szöveg és visszaalakítás
Binding netto = new Binding("Text", termek, "Netto", true);

netto.Format += (s, e) =>
{
if (e.Value is decimal ertek)
{
e.Value = ertek.ToString("N0") + " Ft"; // adat → megjelenítés
}
};

netto.Parse += (s, e) =>
{
string szoveg = (e.Value as string ?? "").Replace("Ft", "").Replace(" ", "").Trim();
decimal szam;

if (decimal.TryParse(szoveg, out szam))
{
e.Value = szam; // megjelenítés → adat
}
else
{
e.Value = DBNull.Value; // érvénytelen: a kötés hibát jelez
}
};

txtNetto.DataBindings.Add(netto);
FormattingEnabledA negyedik paraméter (true) bekapcsolja a formázást és az automatikus típusátalakítást (decimal ↔ szöveg). Nélküle a szöveg–szám átalakítás nem mindig működik.
FormatStringA szokásos .NET formátum: N0 (ezres tagolás), C0 (pénznem), 0.00 (két tizedes), d (rövid dátum), yyyy. MM. dd. (saját dátum).
Format és ParseA Format az adatból a szöveget, a Parse a szövegből az adatot állítja elő. Egyedi megjelenésnél (12 500 Ft) mindkettő kell: a visszaalakítás nélkül a „Ft” miatt a szám nem értelmezhető.
KultúraA formázás a gép kultúráját használja (tizedesvessző vagy pont). A Binding.FormatInfo (CultureInfo) rögzíthető, ha kell.

Jósolj!

A kötés Format eseménye "12 500 Ft" szöveget ad, de nincs Parse kezelő. A felhasználó a mezőbe belép, egy betűt sem módosít, és továbblép. Mi történik?

Jóslat ellenőrzése

Ha az érték nem változott, a visszaírás gyakran elmarad, de a szöveg módosításakor a rendszer a „12 500 Ft” szöveget decimal számmá próbálja alakítani, ami hibát (FormatException) okoz, a kötés pedig érvényesítési hibát jelez, és a mezőből nem lehet kilépni. Ezért a Format mellé mindig kell Parse.

BindingSource: aktuális elem és navigáció

Egyetlen objektumnál a kötés egyszerű. Lista esetén a vezérlők mindig a lista aktuális elemét mutatják. A BindingSource (8.4 lecke) tartja nyilván az aktuális elemet (Position), és a hozzá kötött összes vezérlő együtt vált:

Form1.cs (using System.ComponentModel;)C#
private BindingList<Termek> lista = new BindingList<Termek>();
private BindingSource bs = new BindingSource();

private void Form1_Load(object sender, EventArgs e)
{
lista.Add(new Termek { Nev = "Füzet", Netto = 300, Keszlet = 40 });
lista.Add(new Termek { Nev = "Toll", Netto = 150, Keszlet = 120 });
lista.Add(new Termek { Nev = "Radír", Netto = 90, Keszlet = 0 });

bs.DataSource = lista;

// a vezérlők a BindingSource-hoz kötődnek, nem a listához
txtNev.DataBindings.Add("Text", bs, "Nev", true, DataSourceUpdateMode.OnPropertyChanged);
nudKeszlet.DataBindings.Add("Value", bs, "Keszlet", true);
lblBrutto.DataBindings.Add("Text", bs, "Brutto", true, DataSourceUpdateMode.Never, "", "N0");

bs.CurrentChanged += (s, ev) => PozFrissit();
PozFrissit();
}

private void PozFrissit()
{
lblPoz.Text = bs.Count == 0 ? "nincs adat" : (bs.Position + 1) + " / " + bs.Count;
}

private void btnKovetkezo_Click(object sender, EventArgs e) { bs.MoveNext(); }
private void btnElozo_Click(object sender, EventArgs e) { bs.MovePrevious(); }
private void btnUj_Click(object sender, EventArgs e) { bs.AddNew(); bs.MoveLast(); txtNev.Focus(); }
private void btnTorol_Click(object sender, EventArgs e) { if (bs.Count > 0) { bs.RemoveCurrent(); } }
Position és CurrentA Position az aktuális elem sorszáma (0-tól), a Current maga az objektum ((Termek)bs.Current), a Count az elemek száma. A MoveNext, MovePrevious, MoveFirst, MoveLast lépked.
Közös aktuális elemMinden, ugyanahhoz a BindingSource-hoz kötött vezérlő ugyanazt az elemet mutatja, ezért a DataGridView kijelölése és az adatlap egyszerre követi egymást (ha mindkettő a bs-hez kötött).
AddNew és RemoveCurrentAz AddNew() új elemet vesz fel (paraméter nélküli konstruktorral), a RemoveCurrent() törli az aktuálisat. Üres lista esetén a kötött vezérlők üresek, érdemes letiltani őket.
Csak olvasható kötésA DataSourceUpdateMode.Never mellett a vezérlő csak megjelenít (a számított bruttó ár nem írható vissza). A számított tulajdonságnak nincs is set ága.

Jósolj!

A lista üres (bs.Count == 0), de a felhasználó rákattint a Törlés gombra, amely a RemoveCurrent() metódust hívja Count vizsgálat nélkül. Mi történik?

Jóslat ellenőrzése

A RemoveCurrent() üres forrásnál kivételt dobhat (nincs aktuális elem). A Count és a Current != null ellenőrzés védi a kódot. A letiltott gomb (Enabled = bs.Count > 0) a felhasználónak is jelzi, hogy nincs mit törölni.

📷 Képernyőkép helye

Mit tegyél ide: a termék adatlap a mezőkkel, a bruttó árral, a „2 / 3” pozíció-jelzéssel és a lapozó gombokkal.Javasolt fájlnév: winforms-8-6-adatlap.webp · Alt szöveg: Termék adatlap adatkötéssel

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 kódból módosított adat nem jelenik meg

A termek.Nev = "Toll"; után a szövegmező a régi nevet mutatja.

Ok és javítás

Az adatosztály nem valósítja meg az INotifyPropertyChanged felületet. Valósítsd meg, és a tulajdonság set ágában válts ki PropertyChanged eseményt.

2. A bruttó ár nem frissül a nettó változásakor

A nettó mező módosítása után a bruttó címke változatlan.

Ok és javítás

Két ok lehet: (1) a nettó mező kötése OnValidation módú, ezért csak fókuszvesztéskor ír vissza (állítsd OnPropertyChanged módra); (2) a Netto set ága nem jelzi a Brutto változását (Valtozott("Brutto")).

3. ArgumentException a DataBindings.Add hívásakor

txtNev.DataBindings.Add("Text", termek, "nev");    // a tulajdonság neve Nev
nudKeszlet.DataBindings.Add("Value", termek, "Keszlet"); // a Keszlet mező, nem tulajdonság
Hiba és javítás

A tulajdonságnév (kisbetű/nagybetű) pontos, és csak tulajdonság köthető. Javítsd a nevet, és a mezőt alakítsd { get; set; } tulajdonsággá.

4. A mező nem enged kilépni

A felhasználó rossz értéket ír be, a fókusz nem lép tovább.

Ok és javítás

A visszaalakítás (Parse vagy típusátalakítás) hibát ad, és a kötés érvényesítése megakadályozza a kilépést. Kezeld a hibás bevitelt a Parse eseményben (DBNull/hibajelzés), vagy az ErrorProvider segítségével jelezd (8.8 lecke).

5. A vezérlők nem váltanak együtt

A lapozás csak az egyik mezőt mozgatja.

Ok és javítás

A vezérlők különböző adatforráshoz vannak kötve (az egyik a listához, a másik a BindingSource-hoz). Minden kötés ugyanazt a BindingSource-ot használja.

6. Üres lista, hibás kötött vezérlők

Az adatlap üres lista esetén is szerkeszthető, de nincs mit módosítani.

Ok és javítás

Az Enabled értékét a bs.Count > 0 alapján állítsd (a ListChanged vagy CurrentChanged eseményben).

Mini projekt: termék adatlap

Készíts adatlap-programot, amelyben a mezők adatkötéssel követik a lista aktuális elemét:

  1. Termek osztály (INotifyPropertyChanged): Nev, Netto (decimal), AfaSzazalek (int, alap 27), Keszlet (int), Aktiv (bool), számított Brutto. Minden módosítás PropertyChanged eseményt vált ki, a Brutto is.
  2. Felület: txtNev, txtNetto (formátum: 12 500 Ft, Format és Parse), nudAfa (0–100), nudKeszlet, chkAktiv, lblBrutto (csak olvasható, N0 formátum), lblPoz (2 / 5), lblOsszKeszlet (az összes készlet).
  3. A BindingList<Termek> egy BindingSource-ba kerül, és minden vezérlő ahhoz kötődik; a nettó, a név és az áfa mezők OnPropertyChanged módúak (a bruttó azonnal követi a gépelést).
  4. Gombok: Előző, Következő, Első, Utolsó, Új, Törlés (megerősítéssel, 7.4 lecke). Üres listánál az adatlap és a lapozás letiltott.
  5. A ListChanged és CurrentChanged események frissítik a pozíciót és az összkészletet.
  6. Egy DataGridView ugyanahhoz a BindingSource-hoz kötődik (kijelölés és adatlap együtt mozog).
  7. Teszteld: lapozás, gépelés közben a bruttó ár, érvénytelen nettó (betűk), új és törölt elem, üres lista, az összkészlet frissülése, a rács és az adatlap együtt mozgása.
Megoldás megnyitása (próbáld ki előbb önállóan!)

A Termek osztályt a lecke 2. része mutatja (egészítsd ki a Nev, Keszlet, Aktiv tulajdonságokkal ugyanazzal a Valtozott() mintával). Az összkészlet a lista elemeinek összege, a ListChanged eseményre frissítve; a BindingList csak akkor jelzi az elemek tulajdonság-változását is, ha az elem megvalósítja az INotifyPropertyChanged felületet.

Form1.csC#
private BindingList<Termek> lista = new BindingList<Termek>();
private BindingSource bs = new BindingSource();

private void Form1_Load(object sender, EventArgs e)
{
lista.Add(new Termek { Nev = "Füzet", Netto = 300, Keszlet = 40 });
lista.Add(new Termek { Nev = "Toll", Netto = 150, Keszlet = 120 });
lista.Add(new Termek { Nev = "Radír", Netto = 90, Keszlet = 0 });

bs.DataSource = lista;
dgv.DataSource = bs;

txtNev.DataBindings.Add("Text", bs, "Nev", true, DataSourceUpdateMode.OnPropertyChanged);

Binding netto = new Binding("Text", bs, "Netto", true, DataSourceUpdateMode.OnPropertyChanged);

netto.Format += (s, ev) =>
{
if (ev.Value is decimal d) { ev.Value = d.ToString("N0") + " Ft"; }
};

netto.Parse += (s, ev) =>
{
string szoveg = (ev.Value as string ?? "").Replace("Ft", "").Replace(" ", "").Trim();
decimal szam;

ev.Value = decimal.TryParse(szoveg, out szam) ? (object)szam : DBNull.Value;
};

txtNetto.DataBindings.Add(netto);
nudAfa.DataBindings.Add("Value", bs, "AfaSzazalek", true, DataSourceUpdateMode.OnPropertyChanged);
nudKeszlet.DataBindings.Add("Value", bs, "Keszlet", true, DataSourceUpdateMode.OnPropertyChanged);
chkAktiv.DataBindings.Add("Checked", bs, "Aktiv", true, DataSourceUpdateMode.OnPropertyChanged);
lblBrutto.DataBindings.Add("Text", bs, "Brutto", true, DataSourceUpdateMode.Never, "", "N0");

bs.CurrentChanged += (s, ev) => Frissit();
bs.ListChanged += (s, ev) => Frissit();
Frissit();
}

private void Frissit()
{
bool van = bs.Count > 0;

pnlAdat.Enabled = van;
btnElozo.Enabled = btnKovetkezo.Enabled = btnElso.Enabled = btnUtolso.Enabled = van;
btnTorol.Enabled = van;

lblPoz.Text = van ? (bs.Position + 1) + " / " + bs.Count : "nincs adat";

int ossz = 0;

foreach (Termek t in lista)
{
ossz += t.Keszlet;
}

lblOsszKeszlet.Text = "Összes készlet: " + ossz + " db";
}

private void btnElozo_Click(object sender, EventArgs e) { bs.MovePrevious(); }
private void btnKovetkezo_Click(object sender, EventArgs e) { bs.MoveNext(); }
private void btnElso_Click(object sender, EventArgs e) { bs.MoveFirst(); }
private void btnUtolso_Click(object sender, EventArgs e) { bs.MoveLast(); }

private void btnUj_Click(object sender, EventArgs e)
{
bs.AddNew();
bs.MoveLast();
txtNev.Focus();
}

private void btnTorol_Click(object sender, EventArgs e)
{
Termek t = bs.Current as Termek;

if (t != null && MessageBox.Show(this, "Törlöd: " + t.Nev + "?", "Törlés", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
bs.RemoveCurrent();
}
}
📷 Képernyőkép helye

Mit tegyél ide: az adatlap (bal) és a táblázat (jobb) együtt mozogva, az összkészlet felirattal.Javasolt fájlnév: winforms-8-6-kesz.webp · Alt szöveg: Termék adatlap és táblázat közös adatkötéssel

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. Dátum és ComboBox kötése

A Termek kapjon Datum (DateTime) és Kategoria (string) tulajdonságot, és kösd őket egy DateTimePickerhez és egy ComboBoxhoz. Melyik vezérlő-tulajdonságot köted?

Egy lehetséges megoldás

A DateTimePicker.Value tulajdonságot, a ComboBoxnál (ha DropDownList és a lista szövegei a kategóriák) a SelectedItem vagy a Text tulajdonságot (8.5 lecke).

Form1.csC#
dtpDatum.DataBindings.Add("Value", bs, "Datum", true);

cmbKategoria.Items.AddRange(new object[] { "Irodaszer", "Papír", "Technika" });
cmbKategoria.DataBindings.Add("SelectedItem", bs, "Kategoria", true, DataSourceUpdateMode.OnPropertyChanged);

2. Állapotfüggő szín kötéssel

A készlet címke piros, ha a készlet nulla, egyébként zöld. Hogyan oldod meg a Format eseménnyel egy ForeColor kötésen?

Egy lehetséges megoldás

A ForeColor tulajdonságot a Keszlet adathoz kötöd, és a Format esemény a számból színt állít elő (az adat és a megjelenített típus eltérhet).

Form1.csC#
Binding szin = new Binding("ForeColor", bs, "Keszlet", true);

szin.Format += (s, ev) =>
{
int keszlet = ev.Value is int i ? i : 0;
ev.Value = keszlet == 0 ? Color.Firebrick : Color.SeaGreen;
};

lblKeszlet.DataBindings.Add(szin);

3. Kötések törlése és újra létrehozása

A program két adatlapot (Termek, Vevo) vált egy panelen. Mit kell tenned a vezérlők kötésével váltáskor?

Egy lehetséges megoldás

A régi kötéseket törölni kell (DataBindings.Clear()), különben a vezérlő a régi forráshoz is kötve marad (és hibát okozhat); utána jön az új kötés.

Form1.csC#
private void TermekNezet()
{
txtNev.DataBindings.Clear();
txtNev.DataBindings.Add("Text", bsTermek, "Nev", true);
}

private void VevoNezet()
{
txtNev.DataBindings.Clear();
txtNev.DataBindings.Add("Text", bsVevo, "Nev", true);
}

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. Köthető tulajdonságok

Melyik vezérlő-tulajdonságot köted: (a) TextBox szövegét; (b) CheckBox jelölését; (c) NumericUpDown számát?

Megoldás megnyitása

(a) Text; (b) Checked; (c) Value.

2. Frissítési módok

Melyik DataSourceUpdateMode: (a) az adat fókuszvesztéskor frissül; (b) minden betűnél; (c) csak megjelenítés?

Megoldás megnyitása

(a) OnValidation (alap); (b) OnPropertyChanged; (c) Never.

Közepes szint

3. Két adatlap, egy lista

Két külön Panel mezői ugyanahhoz a BindingSource-hoz kötődnek. Mi történik, ha az egyik panelen módosítasz?

Megoldás megnyitása

Az adat megváltozik, és (INotifyPropertyChanged esetén) a másik panel is frissül: egy forrás, több nézet. Ez az adatkötés egyik nagy előnye.

4. Dátum formátum

A TextBox a Datum tulajdonságot 2026. 10. 28. formában mutassa, és fogadja vissza. Elég-e a FormatString?

Megoldás megnyitása

Megjelenítésre igen (binding.FormatString = "yyyy. MM. dd."), visszaalakításra a rendszer a gép kultúrájának dátumformátumát használja (a kötés megpróbálja értelmezni a szöveget). Biztosabb a Parse eseményben DateTime.TryParseExact hívás.

Form1.csC#
Binding b = new Binding("Text", bs, "Datum", true);
b.FormatString = "yyyy. MM. dd.";

b.Parse += (s, ev) =>
{
DateTime d;

ev.Value = DateTime.TryParseExact((ev.Value as string ?? "").Trim(), "yyyy. MM. dd.", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out d) ? (object)d : DBNull.Value;
};

txtDatum.DataBindings.Add(b);

Kihívás szint

5. Módosítás jelzés

Az adatlap címe * jelet kapjon, ha valamelyik elem módosult. Honnan tudsz a módosításról?

Megoldás megnyitása

A BindingList.ListChanged eseménye (ItemChanged típus) jelzi az elemek tulajdonság-változását, ha az elemek megvalósítják az INotifyPropertyChanged felületet.

Form1.csC#
private bool modosult = false;

lista.ListChanged += (s, ev) =>
{
if (ev.ListChangedType == ListChangedType.ItemChanged || ev.ListChangedType == ListChangedType.ItemAdded || ev.ListChangedType == ListChangedType.ItemDeleted)
{
modosult = true;
this.Text = "Termékek*";
}
};

6. Összetett kötés kódból

Készíts általános segédmetódust (Kot(Control, string tulajdonsag, object forras, string adat)), amely kitörli a vezérlő korábbi kötéseit, majd OnPropertyChanged módú formázó kötést hoz létre. Mi az előnye?

Megoldás megnyitása

Egy helyen van a szabály (formázás, frissítési mód), kevesebb az ismétlés és a hiba, és a kötések újraépítése egyszerű.

Form1.csC#
private void Kot(Control vezerlo, string tulajdonsag, object forras, string adat){
vezerlo.DataBindings.Clear();
vezerlo.DataBindings.Add(tulajdonsag, forras, adat, true, DataSourceUpdateMode.OnPropertyChanged);
}

// használat:
Kot(txtNev, "Text", bs, "Nev");
Kot(nudKeszlet, "Value", bs, "Keszlet");

Gyors önellenőrzés

Válaszolj fejben, és csak utána nyisd le a választ.

1. Mit ad meg a DataBindings.Add három paramétere?

A vezérlő tulajdonságának nevét, az adatforrást és az adat tulajdonságának nevét.

2. Mikor frissül alapból az adat a felületről?

OnValidation: amikor a vezérlő elveszti a fókuszt. OnPropertyChanged módban minden változásnál.

3. Mi kell ahhoz, hogy az adat változása a felületen megjelenjen?

Az adatosztály valósítsa meg az INotifyPropertyChanged felületet, és váltsa ki a PropertyChanged eseményt.

4. Miért kell jelezni a számított tulajdonság változását is?

Mert a hozzá kötött vezérlő csak az ő PropertyChanged eseményére frissül.

5. Mi a Format és a Parse?

A Format az adatból megjelenítendő szöveget, a Parse a szövegből az adatot állítja elő; egyedi formátumnál mindkettő kell.

6. Mire való a BindingSource.Position?

Az aktuális elem sorszáma; a hozzá kötött vezérlők mind az aktuális elemet mutatják.

7. Mit tegyél kötés előtt a régi kötésekkel?

Töröld a vezérlő régi kötéseit (DataBindings.Clear()), különben a régi forráshoz is kötve marad.

Mit tudsz már?

  • Vezérlő-tulajdonságot adattulajdonsághoz kötsz, és ismered a frissítési módokat.
  • Megvalósítod az INotifyPropertyChanged felületet számított tulajdonsággal.
  • Formázó kötést készítesz FormatString, Format és Parse segítségével.
  • A BindingSource aktuális elemét és navigációját használod.
  • Felismered a tipikus kötési hibákat.

Következő lecke: Rendezés, keresés és szűrés

A táblázat fejlécre kattintva rendezhető, a lista szűrhető és kereshető: DataView, RowFilter, LINQ és érthető keresőmező.