Grafikus C# – Windows Forms tanfolyam › 8.5 lecke

Windows Forms · 8.5 lecke · listák kötése

DataSource, DisplayMember és ValueMember

Az adatbázisokban és a nyilvántartásokban az adatok gyakran azonosítókkal kapcsolódnak: egy feladathoz egy kategória-azonosító (3) tartozik, a felhasználónak viszont a kategória neve (Iskola) kell. A ListBox és a ComboBox kötése pontosan ezt oldja meg: a DisplayMember megmondja, melyik tulajdonságot mutassa, a ValueMember pedig, melyik tulajdonságot adja vissza (az azonosítót). Ebben a leckében a szöveg és az érték szétválasztását, a SelectedValue és SelectedItem különbségét, a Format eseményt és a táblázat ComboBox oszlopát tanulod meg.

  • kb. 100 perc
  • közepes–haladó szint
  • szöveg és érték
Diák C# programozást gyakorol egy tanulósarokban

A lecke végére

  • listát és legördülő listát kötsz egy gyűjteményhez (DataSource);
  • beállítod, mit mutasson (DisplayMember) és mit adjon vissza (ValueMember);
  • megkülönbözteted a SelectedItem (a teljes objektum) és a SelectedValue (az azonosító) használatát;
  • a Format eseménnyel összetett szöveget mutatsz;
  • a DataGridView ComboBox oszlopát kötöd (DataPropertyName), és az azonosítót névként jeleníted meg;
  • kerülöd a tipikus hibákat (Items módosítása kötött listán, kötéskor lefutó események).

Mielőtt elkezded

Ehhez a leckéhez a 8.1 és 8.2 lecke (listák, kijelölés), a 8.3 lecke (DataGridView oszlopok) és a 8.4 lecke (BindingList, BindingSource, tulajdonságok) szükséges.

8.4 BindingList →

Lista kötése: DataSource, DisplayMember, ValueMember

Form1.cs (using System.ComponentModel;)C#
public class Kategoria
{
public int Id { get; set; }
public string Nev { get; set; } = "";
}

private BindingList<Kategoria> kategoriak = new BindingList<Kategoria>();

private void Form1_Load(object sender, EventArgs e)
{
kategoriak.Add(new Kategoria { Id = 1, Nev = "Iskola" });
kategoriak.Add(new Kategoria { Id = 2, Nev = "Otthon" });
kategoriak.Add(new Kategoria { Id = 3, Nev = "Hobbi" });

cmbKategoria.DropDownStyle = ComboBoxStyle.DropDownList;
cmbKategoria.DisplayMember = "Nev"; // ezt látja a felhasználó
cmbKategoria.ValueMember = "Id"; // ezt adja vissza a SelectedValue
cmbKategoria.DataSource = kategoriak; // a forrás: a tulajdonságnevek a DataSource beállítása után is érvényesek
}

private void btnMutat_Click(object sender, EventArgs e)
{
int id = (int)cmbKategoria.SelectedValue; // az azonosító: 1, 2 vagy 3
Kategoria k = (Kategoria)cmbKategoria.SelectedItem; // a teljes objektum

lblInfo.Text = "Id: " + id + ", név: " + k.Nev + ", felirat: " + cmbKategoria.Text;
}
DisplayMemberA tulajdonság neve szövegként, amelyet a lista megjelenít. Ha üres, a ToString() eredménye jelenik meg (8.2 lecke).
ValueMemberA tulajdonság neve, amelynek értéke a SelectedValue. Egyedi azonosító legyen (Id), ne a szöveg.
Items tilosKötött listánál az Items.Add kivételt dob (InvalidOperationException: a lista adatforrásból töltődik). Az adatot a forrásban módosítod (kategoriak.Add(...)), a lista követi (BindingList esetén).
SorrendA DisplayMember és ValueMember beállítását általában a DataSource előtt érdemes megtenni: így a kötés már ezekkel épül fel, és kevesebb felesleges esemény fut.

Jósolj!

A ComboBox kötött (DataSource beállítva), és a program a cmbKategoria.Items.Add("Új"); sort hajtja végre. Mi történik?

Jóslat ellenőrzése

InvalidOperationException: adatforrással kötött lista elemeit közvetlenül nem lehet módosítani. A forrásgyűjteményhez adj hozzá (kategoriak.Add(új)).

SelectedValue és SelectedItem

TulajdonságMit ad?Mikor használd?
SelectedItemA teljes objektum (Kategoria).Ha több tulajdonságra van szükség.
SelectedValueA ValueMember tulajdonság értéke (Id), object típusú.Ha az azonosítót kell tárolni (például Feladat.KategoriaId).
TextA megjelenített felirat.Csak kiírásra.
SelectedIndexA sorszám (-1, ha nincs).Lépegetéshez, az első elem beállításához.
Form1.csC#
// beállítás azonosító szerint: a lista a megfelelő elemre áll
cmbKategoria.SelectedValue = 2; // az "Otthon"

// kiolvasás védetten: a SelectedValue null lehet (nincs kijelölés), és kötés közben más típusú is
if (cmbKategoria.SelectedValue is int)
{
int id = (int)cmbKategoria.SelectedValue;
// ... használat ...
}

// a kötés közbeni események elkerülése: jelző (5.5 lecke)
private bool kotes = false;

private void KategoriakKot()
{
kotes = true;
cmbKategoria.DataSource = kategoriak;
kotes = false;
}

private void cmbKategoria_SelectedValueChanged(object sender, EventArgs e)
{
if (kotes || !(cmbKategoria.SelectedValue is int))
{
return;
}

// a felhasználó választására reagálunk
}
SelectedValue típusaA SelectedValue object: a (int) átalakítás kell, és null vagy más típus esetén kivételt dob. Az is int ellenőrzés védi.
Beállítás értékkelA SelectedValue = 2 az azonos típusú azonosítót keresi: a "2" szöveg nem találna int azonosítót. Ha nincs ilyen elem, a kijelölés megszűnik.
Események kötéskorA DataSource beállításakor a SelectedIndexChanged és SelectedValueChanged események lefuthatnak, amikor a SelectedValue még nem érvényes. A jelző vagy az is int ellenőrzés kell.
Mikor SelectedItem?A SelectedItem típusos (as Kategoria) és kényelmesebb, ha több mezőt használsz. Az azonosító tárolásához a SelectedValue a megszokott.

Jósolj!

A kategóriák azonosítója int. A kód: cmb.SelectedValue = "2"; (szöveg). Mit látsz a ComboBoxban?

Jóslat ellenőrzése

A lista nem választ ki semmit (az üres állapot marad): a "2" szöveg nem egyezik az int típusú 2 azonosítóval, a kereső nem talál elemet. Az érték típusa egyezzen az azonosítóéval.

Összetett szöveg: a Format esemény

A DisplayMember egyetlen tulajdonságot mutat. Ha összetett szöveg kell (Iskola (3 feladat)), a Format eseményt használod, amely minden elem megjelenítése előtt lefut, és átírhatja a szöveget (FormattingEnabled = true szükséges):

Form1.csC#
lstKategoria.FormattingEnabled = true;
lstKategoria.Format += lstKategoria_Format;

private void lstKategoria_Format(object sender, ListControlConvertEventArgs e)
{
Kategoria k = e.ListItem as Kategoria; // az e.ListItem az eredeti objektum

if (k != null)
{
int db = 0;

foreach (Feladat f in feladatok)
{
if (f.KategoriaId == k.Id) { db++; }
}

e.Value = k.Nev + " (" + db + " feladat)"; // a megjelenített szöveg
}
}

// a Format kimenete akkor frissül, ha a kötés újraolvas:
bsKategoria.ResetBindings(false);
e.ListItem és e.ValueAz e.ListItem a listaelem (az objektum), az e.Value a megjelenítendő szöveg: ezt írod át. A DisplayMember értéke kezdetben az e.Value.
Sokszor futA Format minden megjelenítéskor lefut, ezért gyors legyen. A darabszám számolása itt nagy listán lassú: érdemes előre kiszámolni (szótárban).
FrissítésA Format csak újrarajzoláskor fut. Ha az adat változik (új feladat), kérd az újrarajzolást (ResetBindings, lst.Refresh()).
AlternatívaEgyszerűbb, ha az osztálynak van egy Felirat tulajdonsága (Nev + " (" + Db + ")"), és azt kötöd DisplayMember-ként. A Format akkor jó, ha a szöveg a felülettől (nyelvtől, nézettől) függ.

Jósolj!

A Format kezelő kiszámolja a feladatok számát, de egy új feladat hozzáadása után a lista felirata nem változik. Miért?

Jóslat ellenőrzése

A lista nem tudja, hogy a megjelenített szöveg függ a feladatok számától: nem rajzolja újra magát. Újrarajzolásra kell kérni (bsKategoria.ResetBindings(false)), a feladat hozzáadása után.

ComboBox oszlop a táblázatban

A leggyakoribb alkalmazás: a táblázat sorai azonosítót tárolnak (Feladat.KategoriaId), de a felhasználó a nevet látja, és legördülő listából választ. A DataGridViewComboBoxColumn pont ezt tudja: a DataPropertyName kapcsolja a sor adatának tulajdonságához, a DataSource, DisplayMember, ValueMember pedig a kategóriák listájához:

Form1.csC#
public class Feladat
{
public string Cim { get; set; } = "";
public int KategoriaId { get; set; } = 1;
public bool Kesz { get; set; }
}

private BindingList<Feladat> feladatok = new BindingList<Feladat>();

private void TablaBeallit()
{
dgv.AutoGenerateColumns = false;

dgv.Columns.Add(new DataGridViewTextBoxColumn { Name = "colCim", HeaderText = "Feladat", DataPropertyName = "Cim", AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill });

DataGridViewComboBoxColumn kat = new DataGridViewComboBoxColumn();
kat.Name = "colKat";
kat.HeaderText = "Kategória";
kat.DataPropertyName = "KategoriaId"; // a sor adatának tulajdonsága (az azonosító)
kat.DataSource = kategoriak; // a választék
kat.DisplayMember = "Nev"; // amit a felhasználó lát
kat.ValueMember = "Id"; // amit a cella tárol
kat.Width = 140;
dgv.Columns.Add(kat);

dgv.Columns.Add(new DataGridViewCheckBoxColumn { Name = "colKesz", HeaderText = "Kész", DataPropertyName = "Kesz", Width = 60 });

dgv.DataSource = feladatok; // a sorok adata
}
DataPropertyNameEz köti az oszlopot a sorobjektum tulajdonságához. AutoGenerateColumns = false mellett minden oszlopnak meg kell adni, különben üres marad.
Az azonosító és a névA cella értéke az azonosító (3), a megjelenítés a névre fordítja (Hobbi). A felhasználó választása visszaírja az azonosítót a Feladat.KategoriaId tulajdonságba.
Érvénytelen azonosítóHa egy feladat KategoriaId értéke nincs a kategóriák között (törölt kategória), a DataGridView DataError eseményt vált ki (8.3 lecke). Ezért az érték törlése előtt ellenőrizni kell a hivatkozásokat.
Egy forrás, több helyA kategóriák ugyanaz a BindingList a ComboBox-ban, a táblában és a ListBox-ban: egy módosítás mindenhol látszik.

Jósolj!

Egy feladat KategoriaId értéke 9, de a kategóriák azonosítói 1, 2, 3. Mit tapasztalsz a tábla megjelenítésekor?

Jóslat ellenőrzése

A cella hibát jelez (alapból felugró „a legördülő cella értéke érvénytelen” üzenet, DataError esemény). A javítás: DataError kezelő, és az érvényes hivatkozások biztosítása (alapértelmezett kategória, törlés előtti ellenőrzés).

📷 Képernyőkép helye

Mit tegyél ide: a feladattábla Kategória legördülő oszloppal (kinyitva), mellette a kategóriák listája a darabszámokkal.Javasolt fájlnév: winforms-8-5-combooszlop.webp · Alt szöveg: Táblázat ComboBox oszloppal

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 lista a típus nevét mutatja

A ComboBox elemei Kategoria-ként jelennek meg.

Ok és javítás

A DisplayMember nincs beállítva (vagy elírt), és a ToString() az osztály nevét adja. Állítsd DisplayMember = "Nev"-re, vagy írd felül a ToString() metódust.

2. InvalidOperationException az Items.Add-nál

cmb.DataSource = kategoriak;
cmb.Items.Add("Új"); // kötött listához nem lehet
Hiba és javítás

Az elemet a forrásba add: kategoriak.Add(new Kategoria { ... }).

3. InvalidCastException a SelectedValue-nál

A (int)cmb.SelectedValue a kötés közben hibázik.

Ok és javítás

A DataSource beállításakor az események lefutnak, amikor a SelectedValue még nem int. Védd is int ellenőrzéssel vagy jelzővel.

4. A SelectedValue beállítása nem választ ki semmit

cmb.SelectedValue = "2";   // az azonosító int
Hiba és javítás

Az azonosító típusa nem egyezik: használd 2-t (int), vagy alakítsd át az értéket.

5. A tábla ComboBox oszlopa hibát jelez

A cellák az „érvénytelen érték” üzenetet adják.

Ok és javítás

A sor azonosítója nincs a választékban, vagy a DataPropertyName/ValueMember típusa eltér. Ellenőrizd az értékeket, és kezeld a DataError eseményt.

6. A lista felirata nem frissül új adatnál

A Format kezelő számolja a darabszámot, de az nem változik.

Ok és javítás

A Format csak újrarajzoláskor fut. Kérd a frissítést: bs.ResetBindings(false) a feladat hozzáadása után.

Mini projekt: feladatkezelő kategóriákkal

Készíts programot, amely feladatokat kategóriákhoz rendel:

  1. Az osztályok: Kategoria (Id, Nev), Feladat (Cim, KategoriaId, Kesz), mindkettő tulajdonságokkal; két BindingList.
  2. A cmbUjKat (DropDownList, DisplayMember Nev, ValueMember Id) az új feladat kategóriája; a txtCim és az Új feladat gomb (vagy Enter) új feladatot ad a kiválasztott kategória azonosítójával.
  3. A dgv oszlopai: Feladat (szöveg), Kategória (ComboBox oszlop DataPropertyName = "KategoriaId"), Kész (jelölőnégyzet). A kategória a táblában is átállítható.
  4. A lstKategoria (ListBox) a kategóriák nevét mutatja a feladatok számával (Iskola (3 feladat), Format esemény), és a kijelölt kategória feladatainak számát frissen tartja (ResetBindings).
  5. Az Új kategória mező és gomb új kategóriát ad a forrásgyűjteményhez (ismétlés nélkül, Id = legnagyobb + 1), amely a három helyen azonnal megjelenik.
  6. A kategória törlése csak akkor lehet, ha nincs hozzá feladat (különben üzenet, 7.4 lecke).
  7. Teszteld: új feladat, kategóriaváltás a táblában, új kategória (a ComboBox oszlopban is), törlés használt és használatlan kategóriára, a darabszámok frissülése, a DataError kezelése.
Megoldás megnyitása (próbáld ki előbb önállóan!)

A kategóriák BindingSource-on át kötődnek a ListBox-hoz (a ResetBindings miatt), a ComboBox oszlop és a ComboBox ugyanazt a BindingList-et használja.

Form1.cs (using System.ComponentModel;)C#
public class Kategoria { public int Id { get; set; } public string Nev { get; set; } = ""; }
public class Feladat { public string Cim { get; set; } = ""; public int KategoriaId { get; set; } = 1; public bool Kesz { get; set; } }

private BindingList<Kategoria> kategoriak = new BindingList<Kategoria>();
private BindingList<Feladat> feladatok = new BindingList<Feladat>();
private BindingSource bsKat = new BindingSource();

private void Form1_Load(object sender, EventArgs e)
{
kategoriak.Add(new Kategoria { Id = 1, Nev = "Iskola" });
kategoriak.Add(new Kategoria { Id = 2, Nev = "Otthon" });
kategoriak.Add(new Kategoria { Id = 3, Nev = "Hobbi" });

cmbUjKat.DropDownStyle = ComboBoxStyle.DropDownList;
cmbUjKat.DisplayMember = "Nev";
cmbUjKat.ValueMember = "Id";
cmbUjKat.DataSource = kategoriak;

bsKat.DataSource = kategoriak;
lstKategoria.DisplayMember = "Nev";
lstKategoria.ValueMember = "Id";
lstKategoria.FormattingEnabled = true;
lstKategoria.Format += lstKategoria_Format;
lstKategoria.DataSource = bsKat;

TablaBeallit();
dgv.DataError += dgv_DataError;
}

private void TablaBeallit()
{
dgv.AutoGenerateColumns = false;
dgv.Columns.Add(new DataGridViewTextBoxColumn { Name = "colCim", HeaderText = "Feladat", DataPropertyName = "Cim", AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill });

DataGridViewComboBoxColumn kat = new DataGridViewComboBoxColumn { Name = "colKat", HeaderText = "Kategória", DataPropertyName = "KategoriaId", DataSource = kategoriak, DisplayMember = "Nev", ValueMember = "Id", Width = 140 };
dgv.Columns.Add(kat);

dgv.Columns.Add(new DataGridViewCheckBoxColumn { Name = "colKesz", HeaderText = "Kész", DataPropertyName = "Kesz", Width = 60 });

dgv.AllowUserToAddRows = false;
dgv.DataSource = feladatok;
dgv.CellValueChanged += (s, ev) => bsKat.ResetBindings(false); // a kategóriaváltás a számokat is érinti
}

private int Darab(int kategoriaId)
{
int db = 0;

foreach (Feladat f in feladatok)
{
if (f.KategoriaId == kategoriaId) { db++; }
}

return db;
}

private void lstKategoria_Format(object sender, ListControlConvertEventArgs e)
{
Kategoria k = e.ListItem as Kategoria;

if (k != null)
{
e.Value = k.Nev + " (" + Darab(k.Id) + " feladat)";
}
}

private void UjFeladat()
{
if (txtCim.Text.Trim().Length == 0 || !(cmbUjKat.SelectedValue is int)) { return; }

feladatok.Add(new Feladat { Cim = txtCim.Text.Trim(), KategoriaId = (int)cmbUjKat.SelectedValue });
txtCim.Clear();
txtCim.Focus();
bsKat.ResetBindings(false);
}

private void btnUjFeladat_Click(object sender, EventArgs e) { UjFeladat(); }

private void txtCim_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter) { e.SuppressKeyPress = true; UjFeladat(); }
}

private void btnUjKat_Click(object sender, EventArgs e)
{
string nev = txtUjKat.Text.Trim();

if (nev.Length == 0) { return; }

foreach (Kategoria k in kategoriak)
{
if (k.Nev.Equals(nev, StringComparison.CurrentCultureIgnoreCase))
{
lblInfo.Text = "Ilyen kategória már van.";
return;
}
}

int max = 0;

foreach (Kategoria k in kategoriak) { max = Math.Max(max, k.Id); }

kategoriak.Add(new Kategoria { Id = max + 1, Nev = nev });
txtUjKat.Clear();
}

private void btnTorolKat_Click(object sender, EventArgs e)
{
Kategoria k = bsKat.Current as Kategoria;

if (k == null) { return; }

if (Darab(k.Id) > 0)
{
MessageBox.Show(this, "A kategóriához feladatok tartoznak, ezért nem törölhető.", "Törlés", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}

bsKat.RemoveCurrent(); // a ComboBoxok és az oszlop is követi
}

private void dgv_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
e.ThrowException = false;
lblInfo.Text = "Érvénytelen kategória a(z) " + (e.RowIndex + 1) + ". sorban.";
}

Három önálló gyakorlófeladat

Egyszerre csak egyet csinálj, és csak utána nyisd ki a megoldást.

1. Név és azonosító kiírása

Egy kötött ListBox kijelölt elemének nevét és azonosítóját írd ki egy címkébe. Melyik tulajdonságokat használod?

Egy lehetséges megoldás

A SelectedItem típusos olvasásával (as Kategoria) mindkettő elérhető.

Form1.csC#
Kategoria k = lst.SelectedItem as Kategoria;

lblInfo.Text = k == null ? "Nincs kijelölés." : k.Nev + " (azonosító: " + k.Id + ")";

2. A felirat tulajdonságként

A Kategoria osztály kapjon Felirat tulajdonságot (Id. Nev), amelyet a lista DisplayMember-ként mutat. Mi az előnye a Format eseménnyel szemben?

Egy lehetséges megoldás

Egyszerűbb (nincs eseménykezelő), és a rendezéshez, kereséshez is használható. A Format akkor jobb, ha a szöveg a felülettől függ.

Kategoria.csC#
public string Felirat { get { return Id + ". " + Nev; } }

// lst.DisplayMember = "Felirat";

3. Kezdőérték a kategóriához

A program indításkor az utolsó használt kategóriát jelöli ki a ComboBoxban (a Settings-ből, azonosító szerint). Hogyan állítod be?

Egy lehetséges megoldás

A SelectedValue = azonosító beállítással; ha nincs ilyen elem (törölt kategória), az első elemet jelölöd ki.

Form1.csC#
cmbUjKat.SelectedValue = Properties.Settings.Default.UtolsoKat;

if (cmbUjKat.SelectedIndex < 0 && cmbUjKat.Items.Count > 0)
{
cmbUjKat.SelectedIndex = 0;
}

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. Mit tesz a DisplayMember?

Mit mutat a lista, ha a DisplayMember üres?

Megoldás megnyitása

Az objektum ToString() eredményét (alapból az osztály nevét).

2. SelectedItem vagy SelectedValue?

Melyiket használod, ha az azonosítót kell eltárolni?

Megoldás megnyitása

A SelectedValue-t (a ValueMember értékét), is int védelemmel.

Közepes szint

3. Kötés ismétlődés nélkül

Hogyan akadályozod meg, hogy kötéskor a SelectedIndexChanged kezelő összeomoljon?

Megoldás megnyitása

Jelző (kotes = true a kötés alatt), vagy ellenőrzés a kezelő elején: if (!(cmb.SelectedValue is int)) return;.

4. Szótár a darabszámokhoz

A Format eseményben gyorsítsd a darabszámlálást: előre számold ki egy Dictionary<int,int> szótárba. Mikor frissíted?

Megoldás megnyitása

Minden feladatváltozás után újraszámolod (egy menet), a Format csak kiolvassa.

Form1.csC#
private Dictionary<int, int> darabok = new Dictionary<int, int>();

private void Szamol()
{
darabok.Clear();

foreach (Feladat f in feladatok)
{
int db;
darabok.TryGetValue(f.KategoriaId, out db);
darabok[f.KategoriaId] = db + 1;
}

bsKat.ResetBindings(false);
}

// a Format kezelőben: int db; darabok.TryGetValue(k.Id, out db);

Kihívás szint

5. Két összefüggő ComboBox

Az Ország kiválasztása után a Város listája az adott ország városait mutatja. Hogyan kötöd?

Megoldás megnyitása

Az első lista SelectedValueChanged eseményében a második DataSource-át a szűrt gyűjteményre cseréled (új List a megfelelő városokkal).

Form1.csC#
private void cmbOrszag_SelectedValueChanged(object sender, EventArgs e)
{
if (!(cmbOrszag.SelectedValue is int)) { return; }

int orszagId = (int)cmbOrszag.SelectedValue;
List<Varos> szurt = varosok.FindAll(v => v.OrszagId == orszagId);

cmbVaros.DisplayMember = "Nev";
cmbVaros.ValueMember = "Id";
cmbVaros.DataSource = szurt;
}

6. Törlés védelme

Hogyan akadályozod meg, hogy egy használt kategória törlése DataError-t okozzon?

Megoldás megnyitása

Törlés előtt ellenőrzöd, hogy tartozik-e hozzá feladat (ahogy a mini projektben): ha igen, üzenet és nincs törlés. A másik lehetőség az áthelyezés egy alapértelmezett kategóriába.

Gyors önellenőrzés

1. Mi a DisplayMember?

A tulajdonság neve, amelynek értékét a lista megjeleníti.

2. Mi a ValueMember?

A tulajdonság neve, amelynek értéke a SelectedValue (általában az azonosító).

3. Mi a különbség a SelectedItem és a SelectedValue között?

A SelectedItem a teljes objektum, a SelectedValue a ValueMember értéke.

4. Miért nem működik az Items.Add kötött listán?

Az elemek az adatforrásból jönnek: a forrást módosítsd.

5. Mire való a Format esemény?

Összetett megjelenített szöveg előállítása az objektumból, a FormattingEnabled = true mellett.

6. Mit köt a DataPropertyName?

A táblázat oszlopát a sorobjektum tulajdonságához.

7. Mit ad a SelectedValue kötés közben?

Lehet null vagy nem a várt típus: ellenőrizd (is int) vagy jelzővel védd.

Mit tudsz már?

  • Listát és legördülő listát kötsz: mit mutasson, és mit adjon vissza.
  • Megkülönbözteted és védetten használod a SelectedItem és SelectedValue tulajdonságot.
  • Összetett szöveget mutatsz a Format eseménnyel.
  • A táblázatban az azonosítót névként jeleníted meg ComboBox oszloppal.

Következő lecke: Adatkötés alapjai

Szövegmezők és más vezérlők kötése az aktuális elemhez: két irányú kötés, formázás, frissítés.