Grafikus C# – Windows Forms tanfolyam › 12.1 lecke

Windows Forms · 12.1 lecke · OOP

Osztályok, objektumok és Formok

Idáig a programjaid nagy része egyetlen Form1 osztályban élt, amelybe minden bekerült. Most egy lépést hátralépünk, és megnézzük, mi az a Form valójában: egy osztály, amelyből objektumokat (példányokat) hozol létre. Ebből következik minden, amit a 12. fejezetben tanulsz: ugyanabból az osztályból tetszőleges számú, egymástól független ablak nyitható; az objektumok referenciákon át érhetők el; a saját osztályaid ugyanúgy működnek, mint a Form. Ez a lecke az alap a rendezett, karbantartható program felé.

  • kb. 100 perc
  • közepes szint
  • osztály és objektum
Anime stílusú fiú és lány egy C# programozási feladatot beszél meg

A lecke végére

  • érted, hogy a Form1 osztály, és a Form1 : Form öröklést jelent;
  • megkülönbözteted az osztályt (terv) és az objektumot (a terv alapján létrehozott példány);
  • ugyanabból a Form osztályból több, független állapotú ablakot nyitasz;
  • érted a referenciákat: két változó ugyanarra az objektumra mutathat; tudod, mi a null;
  • használod a this kulcsszót, a Show és ShowDialog metódust, és kezeled az ablak életciklusát;
  • saját osztályt írsz, és a példány- és static tagok különbségét ismered.

Mielőtt elkezded

Ehhez a leckéhez a 4.x leckék (metódusok), az 5.1 lecke (események) és a 9.8 lecke (Dispose) szükséges. Az osztályokkal már találkoztál (például Alakzat a 9.7 leckében), most rendszerbe foglaljuk.

11.9 Folyamatkijelző →

A Form is osztály

Form1.cs és Program.csC#
// Form1.cs: az osztály (a TERV)
public partial class Form1 : Form // a Form1 a Form leszármazottja: mindent tud, amit a Form, és még többet
{
private int kattintasok = 0; // MEZŐ: minden Form1 objektum saját példánya

public Form1() // KONSTRUKTOR: az objektum létrehozásakor fut
{
InitializeComponent(); // a Designer által generált vezérlők (12.2 lecke)
}

private void btnKatt_Click(object sender, EventArgs e) // METÓDUS
{
kattintasok++;
Text = "Kattintások: " + kattintasok; // a Text a Form tulajdonsága (örökölt)
}
}

// Program.cs: az objektum létrehozása (PÉLDÁNYOSÍTÁS)
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1()); // new: egy Form1 objektum jön létre, az Application.Run megjeleníti
}
Osztály = tervAz osztály leírja, milyen adatokat (mezők) tárol és mit tud csinálni (metódusok) az ilyen típusú dolog. A Form1 osztály egy ablak terve: gombokkal, címkékkel, eseménykezelőkkel.
Objektum = példányA new Form1() a tervből egy tényleges ablakot épít: saját mezőkkel és vezérlőkkel a memóriában. Ugyanabból a tervből több ház is építhető.
Öröklés: Form1 : FormA kettőspont azt jelenti: a Form1 a Form leszármazottja: megörökli a Text, Width, Show(), Close() és az összes többi tagot, és újakat ad hozzá. A partial osztályról a 12.2 lecke szól.
KonstruktorA konstruktor az osztály nevével azonos, visszatérési típus nélküli metódus; az objektum létrehozásakor automatikusan fut, és rendbe teszi a kezdőállapotot. Az InitializeComponent() hívás hozza létre a vezérlőket.

Jósolj!

A program kétszer hívja a new Form1() kifejezést, és mindkét ablakot megjeleníti. Az egyikben háromszor a Katt gombra kattintasz. Mi lesz a másik ablak címsorában?

Jóslat ellenőrzése

A másik ablak nem változik: minden objektumnak saját kattintasok mezője van (példány-szintű tag). Az osztály a terv, az állapot az objektumban él.

Referenciák, null és a this

Form1.csC#
// a változó egy HIVATKOZÁS (referencia) az objektumra, nem maga az objektum
Form2 a = new Form2(); // egy objektum jön létre; az "a" hivatkozik rá
Form2 b = a; // NEM másolat: a "b" ugyanarra az objektumra mutat

b.Text = "Közös ablak";
// az a.Text is "Közös ablak": egyetlen objektum, két név

bool ugyanaz = object.ReferenceEquals(a, b); // igaz

// NULL: a változó nem hivatkozik semmire
Form2 c = null;

if (c != null) { c.Show(); } // ellenőrzés nélkül: NullReferenceException
c?.Show(); // rövidítés: csak akkor hívja, ha nem null

// this: az aktuális objektum (maga a Form, amelyben a kód fut)
private void btnMasik_Click(object sender, EventArgs e)
{
Form2 uj = new Form2(this); // átadjuk a SAJÁT objektumunkat az új ablaknak
uj.Show(this); // tulajdonos: a Form1 (az új ablak vele együtt zárul/minimalizálódik)
}

// a this a névütközést is feloldja: a konstruktor paramétere és a mező neve azonos lehet
public Form2(Form1 szulo)
{
InitializeComponent();
this.szulo = szulo; // bal oldal: a mező, jobb oldal: a paraméter
}
Referencia-típusAz osztályok referencia-típusok: a változó csak az objektum címét tárolja. A hozzárendelés (b = a) a címet másolja, nem az objektumot. Két változó így ugyanazt az objektumot módosítja.
nullA null azt jelenti: nincs objektum. Egy null változón metódust hívni NullReferenceException kivételt dob, a leggyakoribb kezdő hiba. Ellenőrizd (!= null), vagy használd a ?. operátort.
Másolat vs. hivatkozásAz egyszerű típusok (int, double, bool) érték-típusok: a hozzárendelés másol. Az osztályok referencia-típusok: a hozzárendelés a hivatkozást másolja. Ez a különbség okozza a legtöbb „miért változott meg?” meglepetést.
thisA this az aktuális objektum: az a példány, amelyen a kód épp fut. Átadhatod más objektumnak (new Form2(this)), és megkülönbözteti a mezőt a hasonló nevű paramétertől.

Jósolj!

A Form2 a = new Form2(); Form2 b = a; b.Close(); sorok után az a.Visible értéke mi?

Jóslat ellenőrzése

Az ablak bezáródik (és az a is bezártat mutat): az a és a b ugyanarra az objektumra hivatkozik. Bezárás után a Visible hamis, és az objektum felszabadított (IsDisposed igaz): az a.Show() ObjectDisposedException kivételt dobna.

Több ablak: példányok és életciklus

Form1.csC#
// több független ablak ugyanabból az osztályból; a példányokat lista tartja számon
private readonly List<JegyzetForm> nyitottak = new List<JegyzetForm>();

private void btnUj_Click(object sender, EventArgs e)
{
JegyzetForm ablak = new JegyzetForm(nyitottak.Count + 1);

ablak.FormClosed += (s, ev) => nyitottak.Remove(ablak); // bezáráskor kivesszük a listából

nyitottak.Add(ablak);
ablak.Show(this); // NEM modális: a főablak közben használható
}

// ShowDialog: MODÁLIS, a hívó kód megáll, amíg az ablak be nem zárul; az eredmény DialogResult
private void btnBeallitas_Click(object sender, EventArgs e)
{
using (BeallitasForm f = new BeallitasForm()) // ShowDialog után a Form NEM szabadul fel magától: using vagy Dispose kell
{
if (f.ShowDialog(this) == DialogResult.OK)
{
szin = f.ValasztottSzin; // az eredményt a bezárt ablak tulajdonságából olvassuk
}
}
}

// EGYETLEN PÉLDÁNY: ha már nyitva van, azt hozzuk előre, nem nyitunk újat
private SugoForm sugo;

private void btnSugo_Click(object sender, EventArgs e)
{
if (sugo == null || sugo.IsDisposed)
{
sugo = new SugoForm();
sugo.Show(this);
}
else
{
sugo.Activate(); // előre hozza; ha minimalizált: sugo.WindowState = FormWindowState.Normal;
}
}
Show és ShowDialogA Show() megnyitja az ablakot, és azonnal visszatér: mindkét ablak használható. A ShowDialog() modális: a hívó ablak le van tiltva, a kód addig áll, amíg a párbeszédablak be nem zárul, az eredmény a DialogResult.
FelszabadításA Show() alapú ablak bezáráskor automatikusan megsemmisül (Dispose). A ShowDialog() ablak nem: csak elrejtőzik, hogy a hívó kiolvashassa az eredményt, ezért a using blokk (vagy Dispose()) a te dolgod.
ÉletciklusEgy Form eseményei sorban: Load (első megjelenés előtt), Shown (megjelenés után), FormClosing (bezárás előtt, megakadályozható), FormClosed (bezárás után). A kezelőket mindig a példány bezárásakor kell takarítani (nyilvántartásból kivenni).
NyilvántartásHa több ablakot nyitsz, egy lista tárolja a referenciákat; a FormClosed esemény kiveszi a bezártat. Ugyanez a minta egy mezőben egyetlen ablakra (sugo == null || sugo.IsDisposed).

Jósolj!

A sugo ablak már be van zárva. A btnSugo_Click csak a sugo == null feltételt ellenőrzi. Mi történik a következő kattintáskor?

Jóslat ellenőrzése

A sugo nem null (a referencia megmaradt a bezárt objektumra), a kód az else ágra lép, és a sugo.Activate() ObjectDisposedException kivételt dob. Kell az IsDisposed ellenőrzés, vagy a FormClosed-ben a mező nullázása.

Saját osztály és a static tagok

Jegyzet.cs (új osztály: Project → Add Class)C#
public class Jegyzet
{
// STATIC: az egész osztályé, nem a példányé (egyetlen közös érték)
private static int kovetkezoAzonosito = 1;
public static int Letrehozott { get { return kovetkezoAzonosito - 1; } }

// PÉLDÁNY-mezők: minden Jegyzet objektumnak saját
public int Azonosito;
public string Cim;
public string Szoveg = "";
public DateTime Letrehozva;

public Jegyzet(string cim)
{
Azonosito = kovetkezoAzonosito++; // minden új objektum következő számot kap
Cim = cim;
Letrehozva = DateTime.Now;
}

public int SzavakSzama() // példány-metódus: a SAJÁT mezőkkel dolgozik
{
return Szoveg.Split(new char[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries).Length;
}

public static string Biztonsagos(string cim) // static metódus: nincs példány, nincs this
{
return string.IsNullOrWhiteSpace(cim) ? "Névtelen" : cim.Trim();
}
}

// használat
Jegyzet j1 = new Jegyzet(Jegyzet.Biztonsagos(" Teendők "));
Jegyzet j2 = new Jegyzet("Ötletek");

j1.Szoveg = "tejet venni kenyeret";
MessageBox.Show(j1.SzavakSzama() + " szó, azonosító: " + j1.Azonosito + ", létrehozva: " + Jegyzet.Letrehozott); // 3 szó, 1, 2
Példány-tagA példány-mező és -metódus objektumonként más: a j1.Cim és a j2.Cim független. A metódus a this objektum mezőivel dolgozik.
static tagA static mező az osztályé: egyetlen közös érték, bármelyik objektum nélkül elérhető az osztály nevén át (Jegyzet.Letrehozott). Számlálóra, segédmetódusra jó; közös, módosítható állapotra óvatosan (szálbiztonság, tesztelhetőség).
KonstruktorA Jegyzet(string cim) kötelezi: nincs cim nélküli objektum. A konstruktor biztosítja, hogy az objektum létrehozás után érvényes állapotú legyen (a 12.4 lecke részletezi).
Miért saját osztály?A jegyzet adatai és műveletei (SzavakSzama) összetartoznak: egy helyen vannak, nem szétszórt változók és metódusok a Form kódjában. A Form csak megjeleníti. Ez a 12. fejezet vezérgondolata.

Jósolj!

A fenti kódban három new Jegyzet(...) hívás után mi a Jegyzet.Letrehozott értéke, és mi a harmadik objektum Azonosito mezője?

Jóslat ellenőrzése

A Letrehozott 3 (a közös számláló), a harmadik objektum Azonosito értéke 3 (a létrehozáskori számláló), az elsőé 1, a másodiké 2: minden objektum saját mezője más, a static érték közös.

📷 Képernyőkép helye

Mit tegyél ide: az ablakkezelő-labor: a főablak és több független jegyzetablak, az állapotukkal.Javasolt fájlnév: winforms-12-1-ablakkezelo.webp · Alt szöveg: Az ablakkezelő-labor program

Hibakeresés: te vagy a hibadetektív

Mi a baj, és hogyan javítod?

Gondold végig az okot, és csak utána nyisd le a megoldást.

1. NullReferenceException

Jegyzet j;
lblCim.Text = j.Cim; // a j értéke null
Hiba és javítás

A változó nem hivatkozik objektumra. Hozz létre példányt (new), vagy ellenőrizd a null értéket (if (j != null), j?.Cim).

2. A két ablak ugyanazt mutatja

JegyzetForm a = new JegyzetForm();
JegyzetForm b = a; // „második” ablak?
b.Show();
Hiba és javítás

Nincs második objektum: b ugyanarra mutat. Új ablakhoz új new JegyzetForm() kell.

3. A bezárt ablak előhozása kivételt dob

if (sugo == null) { sugo = new SugoForm(); sugo.Show(); }
else { sugo.Activate(); }
Hiba és javítás

A bezárt ablak referenciája nem lett null. Ellenőrizd az IsDisposed értéket is: sugo == null || sugo.IsDisposed.

4. A párbeszédablak memóriát szivárogtat

BeallitasForm f = new BeallitasForm();
f.ShowDialog(); // nincs Dispose
Hiba és javítás

A ShowDialog után a Form nem szabadul fel magától. Használj using blokkot.

5. A mező nem látható a másik osztályból

A CS0122 hiba: a mező védett szintje miatt nem érhető el.

Ok és javítás

A private mező csak a saját osztályban látszik. Tegyél hozzá public tulajdonságot (12.3, 12.5 lecke), ne a mezőt tedd nyilvánossá.

6. A static számláló újraindításkor nullázódik

A program újraindításakor az azonosítók újra 1-től indulnak.

Ok és javítás

A static mező csak a program futása alatt él. A tartós értékhez fájlba (10. fejezet) vagy adatbázisba mentés kell.

Mini projekt: ablakkezelő-labor

Készíts programot, amely több független jegyzetablakot kezel, és az osztály–objektum–referencia fogalmakat gyakorolja:

  1. Jegyzet osztály: Azonosito (statikus számlálóból), Cim, Szoveg, Letrehozva, Modositva; konstruktor a címmel; SzavakSzama(); static Biztonsagos(cim); static Letrehozott.
  2. JegyzetForm: konstruktora egy Jegyzet objektumot kap; a Text a Jegyzet #3: Teendők; txtSzoveg (többsoros), lblSzavak (szavak száma, élőben), chkKiemel (háttérszín); a modositott jelző; a FormClosing módosított tartalomnál rákérdez (Mented?).
  3. Főablak: Új jegyzet (címet kér, új JegyzetForm nyílik, Show(this)), a lstAblakok felsorolja a nyitott ablakokat (#3 Teendők, 4 szó), dupla kattintás előre hozza az ablakot (Activate).
  4. Nyilvántartás: List<JegyzetForm>; a FormClosed kiveszi; a lista és az állapotsor (Nyitva: 3, létrehozott összesen: 5) frissül.
  5. Egyetlen példány: Súgó gomb: egyszer nyílik, újabb kattintásra előre hozza (IsDisposed védelem).
  6. Modális ablak: Beállítás...: BeallitasForm (ShowDialog + using), amely az alapértelmezett kiemelő színt adja vissza; OK / Mégse a DialogResult szerint.
  7. Referencia-kísérlet: Két név, egy objektum gomb: JegyzetForm a = nyitottak[0]; JegyzetForm b = a;, a b.Text módosítása látszik az a-n is, és a ReferenceEquals eredménye a naplóban; a null eset (nincs nyitott ablak) érthető üzenettel.
  8. Összes bezárása: a Mind bezár gomb végigmegy a lista másolatán (ToList()), mert a bezárás módosítja az eredeti listát.
  9. Teszteld: több ablak független állapota, a bezárás sorrendje, a súgó kétszeri kattintása bezárás után, a módosított jegyzet bezárása (Igen/Nem/Mégse), a lista frissülése, üres lista.
Megoldás megnyitása (próbáld ki előbb önállóan!)

A Jegyzet osztályt a 4. lépés kódja adja; itt a két Form kulcsrésze.

JegyzetForm.cs és Form1.cs (using System.Collections.Generic; using System.Linq;)C#
// ---- JegyzetForm.cs ----
public partial class JegyzetForm : Form
{
private readonly Jegyzet jegyzet;
private bool modositott = false;

public Jegyzet Adat { get { return jegyzet; } }

public JegyzetForm(Jegyzet j)
{
InitializeComponent();

jegyzet = j; // a hivatkozás: ugyanaz az objektum, amit a főablak is ismer
Text = "Jegyzet #" + j.Azonosito + ": " + j.Cim;
txtSzoveg.Text = j.Szoveg;
Frissit();
modositott = false;
}

private void Frissit()
{
jegyzet.Szoveg = txtSzoveg.Text;
lblSzavak.Text = jegyzet.SzavakSzama() + " szó";
modositott = true;
}

private void txtSzoveg_TextChanged(object sender, EventArgs e) { Frissit(); }

private void chkKiemel_CheckedChanged(object sender, EventArgs e)
{
BackColor = chkKiemel.Checked ? Color.LemonChiffon : SystemColors.Control;
}

private void JegyzetForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (modositott && e.CloseReason == CloseReason.UserClosing)
{
DialogResult v = MessageBox.Show(this, "Mented a módosításokat?", Text, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

if (v == DialogResult.Cancel) { e.Cancel = true; return; }
if (v == DialogResult.Yes) { jegyzet.Modositva = DateTime.Now; }
}
}
}

// ---- Form1.cs (főablak) ----
private readonly List<JegyzetForm> nyitottak = new List<JegyzetForm>();
private SugoForm sugo;
private Color kiemeloSzin = Color.LemonChiffon;

private void btnUj_Click(object sender, EventArgs e)
{
string cim = Jegyzet.Biztonsagos(Microsoft.VisualBasic.Interaction.InputBox("A jegyzet címe:", "Új jegyzet", ""));
JegyzetForm ablak = new JegyzetForm(new Jegyzet(cim));

ablak.FormClosed += (s, ev) => { nyitottak.Remove(ablak); ListaFrissit(); };

nyitottak.Add(ablak);
ablak.Show(this);
ListaFrissit();
}

private void ListaFrissit()
{
lstAblakok.Items.Clear();

foreach (JegyzetForm f in nyitottak)
{
lstAblakok.Items.Add("#" + f.Adat.Azonosito + " " + f.Adat.Cim + ", " + f.Adat.SzavakSzama() + " szó");
}

tsslUzenet.Text = "Nyitva: " + nyitottak.Count + ", létrehozott összesen: " + Jegyzet.Letrehozott;
}

private void lstAblakok_DoubleClick(object sender, EventArgs e)
{
int i = lstAblakok.SelectedIndex;

if (i >= 0 && i < nyitottak.Count)
{
if (nyitottak[i].WindowState == FormWindowState.Minimized) { nyitottak[i].WindowState = FormWindowState.Normal; }

nyitottak[i].Activate();
}
}

private void btnSugo_Click(object sender, EventArgs e)
{
if (sugo == null || sugo.IsDisposed) { sugo = new SugoForm(); sugo.Show(this); }
else { sugo.Activate(); }
}

private void btnBeallitas_Click(object sender, EventArgs e)
{
using (BeallitasForm f = new BeallitasForm(kiemeloSzin))
{
if (f.ShowDialog(this) == DialogResult.OK) { kiemeloSzin = f.ValasztottSzin; }
}
}

private void btnReferencia_Click(object sender, EventArgs e)
{
if (nyitottak.Count == 0) { tsslUzenet.Text = "Nincs nyitott jegyzet."; return; }

JegyzetForm a = nyitottak[0];
JegyzetForm b = a; // nem másolat

b.Text = "(átnevezve b-n keresztül)";
lstNaplo.Items.Add("a.Text = " + a.Text + "; ReferenceEquals: " + object.ReferenceEquals(a, b));
}

private void btnMindBezar_Click(object sender, EventArgs e)
{
foreach (JegyzetForm f in nyitottak.ToList()) { f.Close(); } // másolaton megyünk végig: a bezárás módosítja a listát
}
📷 Képernyőkép helye

Mit tegyél ide: a kész ablakkezelő-labor több nyitott jegyzetablakkal.Javasolt fájlnév: winforms-12-1-kesz.webp · Alt szöveg: A kész ablakkezelő-labor

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. Számláló osztály

Írj Szamlalo osztályt Novel(), Nulláz() metódussal és Ertek mezővel, majd hozz létre kettőt.

Egy lehetséges megoldás

Két new Szamlalo() két független Ertek mezőt ad: az egyik növelése nem hat a másikra. Ha az értéket static mezőbe teszed, közös lesz: ez a különbség lényege.

2. Modális választó

Egy ShowDialog ablakban a felhasználó kiválaszt egy színt. Hogyan jut az eredmény a hívóhoz?

Egy lehetséges megoldás

Az ablak nyilvános tulajdonsága (ValasztottSzin), amelyet az OK gomb a DialogResult.OK beállítása előtt kitölt; a hívó using blokkban olvassa ki.

3. Másolat

Hogyan készítesz valódi másolatot egy Jegyzet objektumról?

Egy lehetséges megoldás

Új objektumot hozol létre, és átmásolod a mezőket (Jegyzet masolat = new Jegyzet(eredeti.Cim) { Szoveg = eredeti.Szoveg };), esetleg egy Masol() metódusba téve. A b = a nem másol.

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. Osztály vagy objektum?

Melyik az osztály, melyik az objektum: Form1; new Form1()?

Megoldás megnyitása

A Form1 az osztály (terv); a new Form1() egy objektumot (példányt) hoz létre.

2. Mi a this?

Fogalmazd meg egy mondatban.

Megoldás megnyitása

Az aktuális objektum: az a példány, amelyen a kód éppen fut.

Közepes szint

3. Mit ír ki?

Jegyzet a = new Jegyzet("x"); Jegyzet b = a; b.Cim = "y"; MessageBox.Show(a.Cim);

Megoldás megnyitása

y: egyetlen objektum két névvel.

4. Show vagy ShowDialog?

Melyiket választod: (a) súgó; (b) mentés előtti megerősítés?

Megoldás megnyitása

(a) Show: a főablak közben használható; (b) ShowDialog: választ kell adni, mielőtt továbblépsz.

Kihívás szint

5. Szivárgás

Egy program 1000-szer megnyit és bezár egy ShowDialog ablakot using nélkül. Mi a gond?

Megoldás megnyitása

Az ablak nem szabadul fel (a ShowDialog után csak elrejtőzik): a fogantyúk és a memória nőnek (9.8 lecke). using vagy Dispose() kell.

6. Lista bejárása bezáráskor

Miért hibás a foreach (var f in nyitottak) f.Close();, ha a FormClosed kiveszi az elemet?

Megoldás megnyitása

A foreach közben módosul a lista: InvalidOperationException. A lista másolatán (nyitottak.ToList()) kell végigmenni.

Gyors önellenőrzés

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

1. Mi a különbség az osztály és az objektum között?

Az osztály a terv, az objektum a belőle létrehozott példány saját állapottal.

2. Mit jelent a Form1 : Form?

A Form1 a Form leszármazottja: örökli a tagjait.

3. Mit másol a b = a?

A hivatkozást, nem az objektumot: két név, egy objektum.

4. Mi a null?

Nincs objektum; a használata NullReferenceException.

5. Mi a különbség a Show és a ShowDialog között?

A Show azonnal visszatér; a ShowDialog modális, megvárja a bezárást, és DialogResult-ot ad.

6. Mikor kell felszabadítani a Formot?

ShowDialog után (using/Dispose); a Show ablak bezáráskor magától.

7. Mi a static tag?

Az osztályé, egyetlen közös érték, példány nélkül elérhető.

Mit tudsz már?

  • Érted, hogy a Form osztály, és példányokból több független ablak nyitható.
  • Kezeled a referenciákat, a null értéket és a this kulcsszót.
  • Helyesen használod a Show és ShowDialog metódust, és kezeled az ablakok életciklusát.
  • Saját osztályt írsz példány- és static tagokkal.

Következő lecke: partial class és a Designer generált kódja

Mit rejt a Form1.Designer.cs, hogyan kapcsolódik a két fájl, és mit szabad (és mit nem) szerkeszteni.