Grafikus C# – Windows Forms tanfolyam › 7.7 lecke

Windows Forms · 7.7 lecke · ablakok közti adat

Adatátadás két Form között

Két ablak két különálló objektum: nem látják egymás vezérlőit. Mégis gyakran kell adatot átadni: a főablak odaadja a szerkesztendő személyt a szerkesztőablaknak, az pedig visszaadja a módosított adatot. Ebben a leckében megtanulod az adatátadás módjait (konstruktor, tulajdonság, metódus, esemény), a másolat és a hivatkozás különbségét (amiből az egyik leggyakoribb hiba származik: a Mégse gomb mégis módosít), és azt, melyik módszer mikor való.

  • kb. 100 perc
  • közepes szint
  • adat ablakok között
Diák C# programozást gyakorol egy tanulósarokban

A lecke végére

  • ismered az adatátadás módjait, és kiválasztod a helyzethez illőt;
  • a dialógusnak tulajdonságon át adsz adatot, és olvasol vissza (az OK eredmény után);
  • érted a hivatkozás és a másolat különbségét, és a Mégse gombot helyesen kezeled;
  • osztállyal vagy EventArgs leszármazottal adsz át több adatot;
  • élő előnézetet építesz eseménnyel;
  • tudod, miért kerülendő a nyilvános vezérlő és az Owner típuskényszerítése.

Mielőtt elkezded

Ehhez a leckéhez a 7.5–7.6 lecke (ablakok, ShowDialog), a 3.9 lecke (osztályok, tulajdonságok), az 5.2 lecke (EventArgs) és az 5.7 lecke (feliratkozás) szükséges.

7.6 Új Form és modalitás →

Az adatátadás módjai

MódIrányMikor jó?Megjegyzés
Konstruktor paraméterhívó → ablakKötelező kezdőadat.Sok paraméternél nehézkes (osztályt adj át).
Nyilvános tulajdonságmindkét iránybaDialógus: beállítás nyitás előtt, kiolvasás OK után.A leggyakoribb, ajánlott dialógusokhoz.
Nyilvános metódushívó → ablakNem modális ablak frissítése (Frissit(adat)).A művelet neve megmondja, mit csinál.
Eseményablak → hívóNem modális ablak jelez, élő változás (7.6 lecke).Laza csatolás, az ablak nem ismeri a hívót.
Közös állapot (egy beállítás-objektum, statikus osztály)bárhonnanAz egész programra érvényes adat (beállítások).Óvatosan: rejtett függőségeket teremt.
Owner típuskényszerítése (((Form1)Owner).x)ablak → hívóKerüld.Szoros csatolás: az ablak csak egy főablakkal működik.
Nyilvános vezérlő (Modifiers = Public)bárhonnanKerüld.Az ablak belső szerkezete kiszivárog; a vezérlő megváltoztatása mindenhol törést okoz.
Form1.cs és ReszletekForm.csC#
// 1. konstruktor: kezdőadat
public ReszletekForm(string cim)
{
InitializeComponent();
this.Text = cim;
}

// 2. tulajdonság: oda és vissza (a vezérlők a formon belül maradnak privátak)
public string Nev
{
get { return txtNev.Text.Trim(); }
set { txtNev.Text = value; }
}

// 3. metódus: nem modális ablak frissítése
public void Frissit(int darab)
{
lblDarab.Text = darab + " elem";
}

// a hívás:
using (ReszletekForm ablak = new ReszletekForm("Szerkesztés"))
{
ablak.Nev = lblNev.Text; // oda

if (ablak.ShowDialog(this) == DialogResult.OK)
{
lblNev.Text = ablak.Nev; // vissza (a using blokkon belül!)
}
}
A tulajdonság védi a vezérlőtA txtNev vezérlő privát marad: az ablak tulajdonságot mutat (Nev), így később kicserélheted a vezérlő típusát (ComboBox), a hívó kódja nem változik.
Kiolvasás a using-on belülA using blokk végén az ablak megsemmisül (Dispose), a vezérlők is: a tulajdonság kiolvasása utána hibát dobhat. Olvass az OK ág belsejében, vagy az adatot az ablak a OK kattintáskor tegye mezőbe (lásd lent).
Mit ne tegyélA ((Form1)this.Owner).lblNev.Text = ... működik, de az ablak csak a Form1-gyel használható, és a lblNev nyilvános lesz.
Metódus vagy tulajdonság?Állapotot (adat) tulajdonság, műveletet (frissítés, törlés) metódus fejezzen ki.

Jósolj!

A hívó a using blokk után olvassa ki az ablak.Nev tulajdonságot, amely a txtNev.Text értéket adja vissza. Mi történik?

Jóslat ellenőrzése

A bezárt, megsemmisített ablak vezérlőjének elérése ObjectDisposedException kivételt dobhat (vagy üres szöveget adhat). Az adatot a using blokkon belül kell kiolvasni, vagy az ablak őrizze meg mezőben az OK kattintásakor (lásd a mini projektet).

Több adat: osztály az ablakok között

Ha a dialógus tíz mezőt szerkeszt, a tíz tulajdonság és a tíz paraméter kényelmetlen. Egy adatosztály (Szemely) egyben adja át az adatot:

Szemely.csC#
public class Szemely
{
public string Nev = "";
public string Email = "";
public int Kor = 18;
public bool Aktiv = true;

// másolat készítése: a mezők értéke átmásolódik, új objektum jön létre
public Szemely Masol()
{
return (Szemely)this.MemberwiseClone();
}

public override string ToString()
{
return Nev + " (" + Kor + ")" + (Aktiv ? "" : " – inaktív");
}
}
AdatosztályEgyszerű osztály, amely csak adatot hordoz (3.9 lecke). A ToString() felülírása a listában is értelmes szöveget ad.
MemberwiseCloneAz objektum sekély másolatát készíti: az érték típusú mezők (szám, bool, string megváltoztathatatlan) átmásolódnak. Ha az osztály más objektumra (lista) hivatkozik, az megosztott marad: ilyenkor mélyebb másolat kell.
Struct?Az érték típusú struct értékadáskor magától másolódik, de módosítható szerkezetben könnyű hibázni; kezdőként az osztály és a kifejezett Masol() az áttekinthetőbb.
ImmutableHaladó megoldás a megváltoztathatatlan adatosztály (módosításkor új példány jön létre): nincs véletlen módosítás, de több kód kell.

Másolat vagy hivatkozás? A Mégse csapdája

Az osztály hivatkozás típus: két változó ugyanarra az objektumra mutathat. Ha a főablak magát az objektumot adja át a dialógusnak, és az a mezők alapján módosítja, a változás azonnal az eredetit érinti, tehát a Mégse gomb sem állítja vissza:

A hibás megoldásC#
// Form1: az eredeti objektumot adjuk át
Szemely kijelolt = (Szemely)lstSzemelyek.SelectedItem;

using (SzemelyForm ablak = new SzemelyForm())
{
ablak.Adat = kijelolt; // ugyanaz az objektum
ablak.ShowDialog(this); // a dialógus a mezők változásakor kijelolt.Nev = ... sort hajt végre
}
// Mégse esetén is megváltozott a kijelolt objektum!
A helyes megoldás: másolaton dolgozunkC#
// SzemelyForm.cs: a tulajdonság másolatot vesz át, és másolatot ad vissza
private Szemely szemely = new Szemely();

public Szemely Adat
{
get { return szemely.Masol(); } // a hívó másolatot kap
set { szemely = value.Masol(); Betolt(); } // az ablak másolatot tart
}

private void btnOk_Click(object sender, EventArgs e)
{
if (txtNev.Text.Trim().Length == 0)
{
epHiba.SetError(txtNev, "A név kötelező.");
txtNev.Focus();
return; // az ablak nyitva marad
}

szemely = Mezokbol(); // az adat a mezőkből, csak az OK pillanatában
this.DialogResult = DialogResult.OK;
}

// Form1: az eredményt csak OK esetén alkalmazzuk
if (ablak.ShowDialog(this) == DialogResult.OK)
{
lstSzemelyek.Items[lstSzemelyek.SelectedIndex] = ablak.Adat; // az új objektum cseréli a régit
}
A szabályA dialógus másolaton dolgozik, és az eredetit a hívó cseréli le, de csak OK esetén. A Mégse ilyenkor magától működik: egyszerűen nem csinálunk semmit.
Mezőkből az OK-nálAz adat a mezőkből az OK kattintásakor épül össze (nem minden gépeléskor): az ablak a Mégse esetén sem módosít semmit. A kiolvasható érték így az ablak bezárása után is érvényes (mezőben tárolt).
Ellenőrzés az ablakbanAz ablak csak érvényes adattal ad OK eredményt (6.7 lecke): a hívónak nem kell újra ellenőriznie.
Lista frissítéseA listában az elem cseréjével (Items[i] = új) frissül a megjelenített szöveg (7.2 lecke).

Jósolj!

A dialógus nem másol, hanem az átvett Szemely objektum mezőit írja gépeléskor (szemely.Nev = txtNev.Text). A felhasználó átír egy nevet, majd a Mégse gombot nyomja meg. Mi látszik a főablak listájában?

Jóslat ellenőrzése

Az átírt név (legalábbis amikor a lista újrarajzolja a szöveget): a dialógus az eredeti objektumot módosította, és a Mégse nem vonja vissza. A hiba alattomos, mert azonnal nem látszik: a lista csak a következő frissítéskor mutatja az új szöveget. A megoldás a másolat (Masol()).

Élő előnézet eseménnyel

Ha a főablak a szerkesztés közben is mutatna valamit (előnézet), az ablak eseményt vált ki minden változáskor, a főablak pedig megjeleníti. A másolat elve megmarad: az előnézet átmeneti, az eredeti csak OK után változik:

SzemelyForm.cs és Form1.csC#
public class SzemelyEventArgs : EventArgs
{
public Szemely Adat { get; private set; }

public SzemelyEventArgs(Szemely adat)
{
Adat = adat;
}
}

// SzemelyForm: a mezők közös kezelője
public event EventHandler<SzemelyEventArgs> ElonezetValtozott;
private bool betoltes = false;

private void Valtozas(object sender, EventArgs e)
{
if (betoltes)
{
return; // a kezdőérték betöltése nem „változás”
}

ElonezetValtozott?.Invoke(this, new SzemelyEventArgs(Mezokbol()));
}

// Form1: feliratkozás a dialógus élettartamára
ablak.ElonezetValtozott += (s, ev) => lblElonezet.Text = "Előnézet: " + ev.Adat;
betoltes jelzőA mezők kezdőértékének betöltése is kiváltaná a TextChanged eseményt. A jelző (5.5 lecke) elnyeli ezeket.
Lambda és leiratkozásA lambda a dialógus élettartamára köt, az ablak a using végén megsemmisül, ezért itt nem kell külön leiratkozni (5.7 lecke: rövid élettartamú feliratkozó, rövid élettartamú kibocsátó).
Mit nem csinál az eseményAz előnézet nem módosítja a főablak adatát: az csak az OK után cserélődik. Mégse esetén a főablak az előnézetet törli.
Többféle módszer együttA tulajdonság (kezdő és végső adat), az esemény (élő jelzés) és az OK eredmény (döntés) együtt a teljes párbeszédablak-minta.

Jósolj!

Az Adat tulajdonság set ága feltölti a mezőket (txtNev.Text = ...), de a betoltes jelző nincs bekapcsolva. A főablak már feliratkozott az eseményre. Mit tapasztalsz nyitáskor?

Jóslat ellenőrzése

A mezők betöltése többször kiváltja a TextChanged eseményt, ezért az előnézet feleslegesen (és részleges adatokkal) frissül a nyitáskor, ráadásul a mezők sorrendjétől függően félkész adatokkal. A betoltes jelző kiküszöböli. Ha a feliratkozás a tulajdonság beállítása után történik, ez nem látszik, de a megoldás ettől még a jelző.

📷 Képernyőkép helye

Mit tegyél ide: a személylista a főablakban, mellette a szerkesztő dialógus és az „Előnézet: …” felirat a főablakban.Javasolt fájlnév: winforms-7-7-elonezet.webp · Alt szöveg: Szerkesztő dialógus élő előnézettel

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 Mégse is módosítja az adatot

A dialógusban átírtad a nevet, a Mégse után mégis az új név látszik.

Ok és javítás

A dialógus az eredeti objektumot módosította (hivatkozás). Dolgozz másolaton (Masol()), és az eredetit csak OK esetén cseréld le.

2. ObjectDisposedException az adat kiolvasásakor

SzemelyForm ablak;
using (ablak = new SzemelyForm()) { ablak.ShowDialog(this); }
lblNev.Text = ablak.Nev; // a using után: az ablak megsemmisült
Hiba és javítás

A megsemmisített ablak vezérlőjének elérése hibás. Olvasd ki az adatot a using blokkon belül (az OK ágban), vagy az ablak őrizze meg mezőben az OK kattintáskor (Adat tulajdonság).

3. Az ablak nem látja a főablak adatát

A dialógus üresen nyílik, pedig a főablakban kijelölt egy személy.

Ok és javítás

Az adatot nyitás előtt át kell adni (tulajdonság vagy konstruktor): ablak.Adat = kijelolt;. Az ablak nem „lát” a főablakba.

4. Az előnézet a nyitáskor villog

Az események a kezdőérték betöltésekor is lefutnak.

Ok és javítás

Használj betoltes jelzőt: a mezők feltöltése közben az eseménykezelő ne váltson ki eseményt (5.5 lecke).

5. A főablak vezérlői nyilvánosak

A tervezőben mindent Public-ra állítottál, hogy a dialógus elérje.

Ok és javítás

Az ablak belső szerkezete kiszivárgott. Állítsd vissza Private-ra, és használj tulajdonságot, metódust vagy eseményt.

6. Az egyik ablak módosítja a másik mezőjét, és hurok keletkezik

Két ablak egymás eseményére iratkozott, és végtelenül frissítik egymást.

Ok és javítás

Kölcsönös frissítésnél használj jelzőt (5.5 lecke), vagy csak az egyik irányt engedd: az adat egy „forrása” legyen (egy közös adatobjektum), az ablakok azt mutatják.

Mini projekt: névjegyzék szerkesztő

Készíts névjegyzék programot, amelyben a szerkesztés külön ablakban történik:

  1. Főablak: lstSzemelyek (ListBox), gombok: Új, Szerkesztés (dupla kattintás is), Törlés; egy lblElonezet az élő előnézethez; lblInfo (a darabszám).
  2. Szemely osztály (Nev, Email, Kor, Aktiv, Masol(), ToString()).
  3. SzemelyForm: txtNev, txtEmail, nudKor (0–120), chkAktiv, OK, Mégse, epHiba; párbeszédablak-beállítások (7.6 lecke); Adat tulajdonság (másolatot vesz át és ad vissza); az OK ellenőrzi a nevet (legalább 3 karakter) és az e-mailt (@), hibánál nyitva marad; az ElonezetValtozott esemény a mezők minden változásakor.
  4. Az Új egy üres Szemely objektummal nyitja az ablakot; az eredmény OK esetén bekerül a listába. A Szerkesztés a kijelölt elem másolatát adja át; OK esetén a lista elemét az új objektum cseréli.
  5. A Törlés megerősítést kér (7.4 lecke, Button2 alapértelmezett).
  6. A főablak lblElonezet címkéje a szerkesztés alatt az aktuális mezők alapján frissül, a bezárás után törlődik.
  7. Teszteld: új elem, szerkesztés OK-val és Mégse-vel (a lista nem változhat), érvénytelen adat, az előnézet, a törlés megerősítése, a dupla kattintás.
Megoldás megnyitása (próbáld ki előbb önállóan!)

A szerkesztés közös metódusa (Szerkeszt) mind az Új, mind a Szerkesztés gomb mögött áll. A dialógus Adat tulajdonsága másolatot kezel, ezért a főablak sosem kap „félig módosított” objektumot.

Szemely.cs, SzemelyForm.cs, Form1.csC#
// SzemelyForm.cs
public class SzemelyEventArgs : EventArgs
{
public Szemely Adat { get; private set; }

public SzemelyEventArgs(Szemely adat) { Adat = adat; }
}

public partial class SzemelyForm : Form
{
public event EventHandler<SzemelyEventArgs> ElonezetValtozott;

private Szemely szemely = new Szemely();
private bool betoltes = false;

public SzemelyForm()
{
InitializeComponent();
}

public Szemely Adat
{
get { return szemely.Masol(); }
set { szemely = value.Masol(); Betolt(); }
}

private void Betolt()
{
betoltes = true;

txtNev.Text = szemely.Nev;
txtEmail.Text = szemely.Email;
nudKor.Value = Math.Max(nudKor.Minimum, Math.Min(nudKor.Maximum, szemely.Kor));
chkAktiv.Checked = szemely.Aktiv;

betoltes = false;
}

private Szemely Mezokbol()
{
Szemely s = new Szemely();

s.Nev = txtNev.Text.Trim();
s.Email = txtEmail.Text.Trim();
s.Kor = (int)nudKor.Value;
s.Aktiv = chkAktiv.Checked;

return s;
}

private void Valtozas(object sender, EventArgs e)
{
if (!betoltes)
{
ElonezetValtozott?.Invoke(this, new SzemelyEventArgs(Mezokbol()));
}
}

private void btnOk_Click(object sender, EventArgs e)
{
bool nevOk = txtNev.Text.Trim().Length >= 3;
bool emailOk = txtEmail.Text.Contains("@");

epHiba.SetError(txtNev, nevOk ? "" : "A név legalább 3 karakter legyen.");
epHiba.SetError(txtEmail, emailOk ? "" : "Az e-mail címnek tartalmaznia kell a @ jelet.");

if (!nevOk)
{
txtNev.Focus();
return;
}

if (!emailOk)
{
txtEmail.Focus();
return;
}

szemely = Mezokbol();
this.DialogResult = DialogResult.OK;
}
}

// Form1.cs
private void Szerkeszt(Szemely kezdo, bool uj)
{
using (SzemelyForm ablak = new SzemelyForm())
{
ablak.Text = uj ? "Új személy" : "Személy szerkesztése";
ablak.Adat = kezdo;
ablak.ElonezetValtozott += (s, ev) => lblElonezet.Text = "Előnézet: " + ev.Adat;

if (ablak.ShowDialog(this) == DialogResult.OK)
{
if (uj)
{
lstSzemelyek.Items.Add(ablak.Adat);
}
else
{
lstSzemelyek.Items[lstSzemelyek.SelectedIndex] = ablak.Adat;
}
}

lblElonezet.Text = "";
}

lblInfo.Text = lstSzemelyek.Items.Count + " személy";
}

private void btnUj_Click(object sender, EventArgs e)
{
Szerkeszt(new Szemely(), true);
}

private void btnSzerkeszt_Click(object sender, EventArgs e)
{
Szemely kijelolt = lstSzemelyek.SelectedItem as Szemely;

if (kijelolt != null)
{
Szerkeszt(kijelolt, false); // a dialógus a másolatot kapja
}
}

private void lstSzemelyek_DoubleClick(object sender, EventArgs e)
{
btnSzerkeszt.PerformClick();
}

private void btnTorol_Click(object sender, EventArgs e)
{
Szemely kijelolt = lstSzemelyek.SelectedItem as Szemely;

if (kijelolt != null && MessageBox.Show(this, "Törlöd: " + kijelolt.Nev + "?", "Törlés", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
lstSzemelyek.Items.Remove(kijelolt);
lblInfo.Text = lstSzemelyek.Items.Count + " személy";
}
}
📷 Képernyőkép helye

Mit tegyél ide: a kész névjegyzék: a lista, a szerkesztő dialógus és az előnézet felirat.Javasolt fájlnév: winforms-7-7-kesz.webp · Alt szöveg: A névjegyzék szerkesztő 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. Beállítások átadása

A főablak egy Beallitasok objektumot (betűméret, tördelés, téma) ad át a BeallitasokForm ablaknak, amely OK esetén visszaadja a módosítottat. Hogyan akadályozod meg, hogy a Mégse módosítson?

Egy lehetséges megoldás

A dialógus másolatot kap, és másolatot ad vissza. A főablak az eredeti mezőjét csak OK esetén cseréli le.

Form1.csC#
private Beallitasok beallitasok = new Beallitasok();

private void miBeallitasok_Click(object sender, EventArgs e)
{
using (BeallitasokForm ablak = new BeallitasokForm())
{
ablak.Adat = beallitasok; // a tulajdonság másolatot vesz át

if (ablak.ShowDialog(this) == DialogResult.OK)
{
beallitasok = ablak.Adat;
Alkalmaz();
}
}
}

2. Frissülő segédablak

Egy nem modális StatisztikaForm a főablakban lévő lista elemeinek számát mutatja, és a lista minden változásakor frissül. Melyik adatátadási módot választod, és miért?

Egy lehetséges megoldás

Nyilvános metódus (Frissit(int)) a főablaktól az ablak felé: a főablak hívja minden változáskor. Esemény fordított irányban nem kell. A főablak a szerkesztő ablak IsDisposed értékét ellenőrzi.

Form1.csC#
private void StatFrissit(){
if (statisztika != null && !statisztika.IsDisposed)
{
statisztika.Frissit(lstSzemelyek.Items.Count);
}
}

3. Visszaadott érték a statikus segédmetódussal

Írj SzemelyForm.Szerkeszt(IWin32Window tulajdonos, Szemely kezdo) statikus metódust, amely a szerkesztett Szemely példányt adja vissza (vagy null Mégse esetén). Mi az előnye a hívónak?

Egy lehetséges megoldás

A hívó egyetlen sorban használja, a using, a ShowDialog és az adatátvétel az ablak osztályában van egy helyen.

SzemelyForm.csC#
public static Szemely Szerkeszt(IWin32Window tulajdonos, Szemely kezdo){
using (SzemelyForm ablak = new SzemelyForm())
{
ablak.Adat = kezdo;

return ablak.ShowDialog(tulajdonos) == DialogResult.OK ? ablak.Adat : null;
}
}

// használat:
Szemely uj = SzemelyForm.Szerkeszt(this, kijelolt);

if (uj != null)
{
lstSzemelyek.Items[lstSzemelyek.SelectedIndex] = uj;
}

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. Melyik módszer?

Adatátadási mód: (a) a dialógus kezdőszövege; (b) a kereső jelzi a főablaknak, hogy keresni kell; (c) a beállítás visszaadása OK után; (d) a statisztika ablak frissítése.

Megoldás megnyitása

(a) konstruktor vagy tulajdonság; (b) esemény; (c) tulajdonság (OK után); (d) nyilvános metódus.

2. Hivatkozás vagy érték?

Mi történik: Szemely a = new Szemely(); a.Nev = "Anna"; Szemely b = a; b.Nev = "Béla"; — mi az a.Nev?

Megoldás megnyitása

Béla: az osztály hivatkozás típus, a és b ugyanarra az objektumra mutat. Másolathoz Szemely b = a.Masol(); kell.

Közepes szint

3. Visszaadott lista

A dialógus egy List<string> listát szerkeszt. Mire kell vigyáznod a másolásnál (sekély másolat)?

Megoldás megnyitása

A MemberwiseClone a listára mutató hivatkozást másolja, nem a lista elemeit: a két objektum ugyanazt a listát használja. Mélyebb másolat kell: new List<string>(eredeti).

Szemely.csC#
public List<string> Cimkek = new List<string>();

public Szemely Masol()
{
Szemely m = (Szemely)this.MemberwiseClone();
m.Cimkek = new List<string>(this.Cimkek); // mélyebb másolat a listáról
return m;
}

4. Konstruktor és tulajdonság

Mikor jobb a konstruktor, és mikor a tulajdonság a dialógus kezdőadatához?

Megoldás megnyitása

A konstruktor, ha az adat nélkül az ablak nem értelmezhető (kötelező). A tulajdonság, ha az adat választható vagy az ablakot a tervező is létrehozza (a tervező paraméter nélküli konstruktort kell, hogy találjon).

Kihívás szint

5. Közös adatmodell

A főablak és a statisztika ablak ugyanazt a BindingList<Szemely> listát használja. Miért nem kell az adatot külön átadogatni?

Megoldás megnyitása

Mindkét ablak ugyanarra a gyűjteményre mutat, és a lista változásakor eseményt vált ki (ListChanged): a statisztika ablak feliratkozik, és maga frissül. Az adatmodellt a 8. és 12. fejezet részletezi.

StatisztikaForm.csC#
private readonly BindingList<Szemely> lista;

public StatisztikaForm(BindingList<Szemely> lista)
{
InitializeComponent();
this.lista = lista;
lista.ListChanged += Lista_ListChanged;
Frissit();
}

private void Lista_ListChanged(object sender, ListChangedEventArgs e)
{
Frissit();
}

private void Frissit()
{
lblDarab.Text = lista.Count + " személy";
}

private void StatisztikaForm_FormClosed(object sender, FormClosedEventArgs e)
{
lista.ListChanged -= Lista_ListChanged; // a hosszabb életű lista nem tarthatja vissza az ablakot (5.7)
}

6. Visszavonható módosítás

A főablak megőrzi a szerkesztés előtti állapotot, és a Szerkesztés visszavonása menüpont visszaállítja. Hogyan használod a Masol() metódust?

Megoldás megnyitása

A cserekor a régi objektumot egy Stack<Szemely> veremre teszed (a pozícióval együtt), a visszavonás kiveszi, és visszaírja. Ez a másolat–csere mintára épül.

Form1.csC#
private readonly Stack<KeyValuePair<int, Szemely>> elozo = new Stack<KeyValuePair<int, Szemely>>();

private void Csere(int index, Szemely uj)
{
elozo.Push(new KeyValuePair<int, Szemely>(index, (Szemely)lstSzemelyek.Items[index]));
lstSzemelyek.Items[index] = uj;
}

private void miVisszavon_Click(object sender, EventArgs e)
{
if (elozo.Count > 0)
{
KeyValuePair<int, Szemely> tetel = elozo.Pop();
lstSzemelyek.Items[tetel.Key] = tetel.Value;
}
}

Gyors önellenőrzés

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

1. Hogyan adsz kezdőadatot a dialógusnak?

Konstruktor paraméterrel vagy nyilvános tulajdonsággal, a ShowDialog előtt.

2. Hol olvasod ki az eredményt?

A using blokkon belül, OK eredmény esetén (vagy az ablak őrizze mezőben).

3. Mi a hivatkozás típus veszélye?

Két változó ugyanarra az objektumra mutat: a dialógus módosítása az eredetit is módosítja, a Mégse nem vonja vissza.

4. Hogyan oldod meg a Mégse problémát?

Másolaton dolgozol (Masol()), és az eredetit csak OK esetén cseréled le.

5. Mikor használj eseményt?

Ha az ablak jelezni akar a hívónak (nem modális ablak, élő változás), és nem szeretné ismerni a hívót (laza csatolás).

6. Miért ne legyen nyilvános a vezérlő?

Az ablak belső szerkezete kiszivárog, és a vezérlő megváltoztatása mindenhol törést okoz. Használj tulajdonságot.

7. Mit csinál a MemberwiseClone?

Sekély másolatot készít: az érték típusú mezők másolódnak, a hivatkozások ugyanarra az objektumra mutatnak.

Mit tudsz már?

  • Ismered az adatátadás módjait, és kiválasztod a helyzethez illőt.
  • A dialógus adatait tulajdonsággal adod át és olvasod vissza.
  • Érted a hivatkozás és a másolat különbségét, és a Mégse gombot helyesen kezeled.
  • Élő előnézetet építesz eseménnyel.
  • Elkerülöd a szoros csatolást és a nyilvános vezérlőket.

Következő lecke: OpenFileDialog, SaveFileDialog és FolderBrowserDialog

A beépített fájl- és mappaválasztó ablakok: szűrők, kezdőmappa, többes kijelölés, felülírás-védelem és a hibák kezelése.