Grafikus C# – Windows Forms tanfolyam › 12.2 lecke Windows Forms · 12.2 lecke · Designer Amikor a Toolboxból gombot húzol a Formra, a Visual Studio kódot ír helyetted. Ez a kód egy külön fájlban él, a partial class és a Designer generált kódja
Form1.Designer.cs-ben, és ugyanannak az osztálynak a másik fele, mint a Form1.cs. A két fájlt a partial kulcsszó köti össze. Aki érti, mi van a Designer fájlban, az tudja, mit szabad kézzel módosítani, hogyan javítja ki a „furcsa” hibákat (például egy törölt eseménykezelő miatti fordítási hibát), és hogyan oszt fel egy túl nagy Formot átláthatóbb fájlokra.
A lecke végére
- elmagyarázod, mit jelent a
partial class, és hogy a fordító a darabokat egyetlen osztállyá egyesíti; - elolvasod és értelmezed a
Form1.Designer.cstartalmát (InitializeComponent, mezők,Dispose); - tudod, mit szabad és mit nem szabad szerkeszteni a generált fájlban;
- javítod az eltört eseménykezelő-bekötések hibáit;
- egy nagy Formot partial fájlokra osztasz, és tudod, hol a korlátja;
- a felületet kódból is felépíted, ahogy a Designer teszi.
Mielőtt elkezded
Ehhez a leckéhez a 12.1 lecke (osztály, objektum, konstruktor) és az 5.1 lecke (események) szükséges.
A partial class: egy osztály, két fájl
// Form1.cs: a TE kódod (eseménykezelők, logika)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent(); // ez a metódus a MÁSIK fájlban van
}
private void btnMent_Click(object sender, EventArgs e) { /* ... */ }
}
// Form1.Designer.cs: a Visual Studio generálja
partial class Form1
{
private System.ComponentModel.IContainer components = null;
private Button btnMent; // a vezérlők mezői
private void InitializeComponent() { /* vezérlők létrehozása és beállítása */ }
}partial jelzi: az osztály több fájlban van leírva. A fordító a darabokat egyetlen Form1 osztállyá egyesíti: a két fájl tagjai látják egymást (a btnMent mezőt a te kódod is eléri).partial, azonos névtérben és névvel. A hozzáférési szint (public) elég az egyik darabnál. Az ősosztályt (: Form) elég egyszer megadni.Jósolj!
A Form1.cs fájlból kitörlöd a partial szót. Mi történik a fordításkor?
Jóslat ellenőrzése
Fordítási hiba (CS0260: hiányzik a partial módosító; és CS0101: a névtér már tartalmaz ilyen nevű osztályt): a két Form1 kettős definíciónak számít.
A Form1.Designer.cs tartalma
partial class Form1
{
private IContainer components = null;
protected override void Dispose(bool disposing) // a nem látható komponensek (Timer) felszabadítása
{
if (disposing && components != null) { components.Dispose(); }
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.btnMent = new System.Windows.Forms.Button(); // 1. létrehozás
this.SuspendLayout();
this.btnMent.Location = new System.Drawing.Point(24, 20); // 2. tulajdonságok (a Properties ablak értékei)
this.btnMent.Name = "btnMent";
this.btnMent.Size = new System.Drawing.Size(96, 32);
this.btnMent.Text = "Mentés";
this.btnMent.Click += new System.EventHandler(this.btnMent_Click); // 3. eseménykezelő bekötése
this.ClientSize = new System.Drawing.Size(320, 200);
this.Controls.Add(this.btnMent); // 4. a Formra helyezés
this.Name = "Form1";
this.ResumeLayout(false);
}
#endregion
}| Mit teszel a Designerben | Mit ír a Designer a fájlba |
|---|---|
| Gombot húzol a Formra | új mező (private Button btnMent;) és new Button() az InitializeComponent-ben |
Átírod a Text tulajdonságot | this.btnMent.Text = "Mentés"; |
| Dupla kattintás a gombon | a Click += sor a Designerben és az üres kezelő a Form1.cs-ben |
| Törölsz egy vezérlőt | a mező, a létrehozás és a tulajdonságsorok eltűnnek; az eseménykezelő metódusa a te fájlodban megmarad |
Átnevezed (Name) | a mező és minden hivatkozás átíródik a Designerben (a te kódodban is, ha a Designer-ből nevezed át) |
Click += sor olyan metódusra mutat, amely már nincs): ilyenkor törölheted ezt az egy sort. A művelet után a Designer újra működik.InitializeComponent() után: public Form1() { InitializeComponent(); sajatBeallitas(); }. Itt állítod be, amit a Properties nem tud (listák feltöltése, kezdőértékek).Form1.resx a Form erőforrásait (képek, szövegek) tartalmazza; a Program.cs a belépési pont. Mindhármat a Visual Studio kezeli.Jósolj!
A Designerben kitörlöd a btnMent gombot, de a btnMent_Click metódus a Form1.cs-ben megmarad. Hibás lesz-e a program?
Jóslat ellenőrzése
Nem: az üres metódus árván marad, de nem hibás (felesleges kód). Fordított esetben (a metódust törlöd, a Designer sorát nem) fordítási hiba lesz.
Nagy Form felosztása partial fájlokra
// Form1.cs: konstruktor, életciklus
public partial class Form1 : Form { public Form1() { InitializeComponent(); } }
// Form1.Fajlok.cs: csak a fájlkezeléssel kapcsolatos kezelők és metódusok
public partial class Form1
{
private void btnMegnyit_Click(object sender, EventArgs e) { /* ... */ }
private void MentFajlba(string ut) { /* ... */ }
}
// Form1.Rajz.cs: a rajzolás
public partial class Form1
{
private void panel1_Paint(object sender, PaintEventArgs e) { /* ... */ }
}Form1.cs helyett téma szerinti fájlok. A fájlnév tükrözi a tartalmat (Form1.Fajlok.cs); a Solution Explorerben a Form1.cs alá csoportosulnak.partial felosztás legfeljebb átmeneti lépés.Jósolj!
A Form1.Fajlok.cs-ben egy private metódust írsz. Hívható-e a Form1.Rajz.cs-ből?
Jóslat ellenőrzése
Igen: a private az osztályra vonatkozik, és a két fájl ugyanaz az osztály. Pont ezért nem ad a partial valódi elkülönítést.
Mit tegyél ide: a Solution Explorer a Form1.cs, Form1.Designer.cs, Form1.resx és a partial fájlokkal.Javasolt fájlnév: winforms-12-2-fajlok.webp · Alt szöveg: A Form fájljai a Solution Explorerben
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. CS1061: nincs ilyen metódus
A Törölted az eseménykezelő metódusát, de a Designer még bekötötte. Add vissza a metódust, vagy töröld a Form1.Designer.cs: Form1 does not contain a definition for btnMent_Click.Ok és javítás
Click += sort (vagy a Properties/Events ablakban töröld a kezelő nevét).
2. A Designer nem nyílik meg
A tervező nézet hibát jelez (The designer could not be shown). Gyakori ok: a konstruktor vagy a Ok és javítás
Load kód olyasmit tesz, ami tervezési időben hibát ad (adatbázis, fájl). Védd: if (DesignMode) { return; }, vagy a futásidejű kódot a Load-ba / Shown-ba tedd. Másik ok: kézzel elrontott Designer fájl.
3. Eltűnt a beállításom
A Designer fájlba kézzel írt sor megszűnt. A Designer újraírta a fájlt. Az egyedi beállítást a konstruktorba, az Ok és javítás
InitializeComponent() hívás után írd.
4. A kód a konstruktorban nem hat
public Form1()
{
lblCim.Text = "Üdv"; // a vezérlő még nincs létrehozva
InitializeComponent();
}Hiba és javítás
A vezérlők az InitializeComponent() hívásban jönnek létre: előtte NullReferenceException. A hívás legyen az első sor.
5. CS0101: kettős definíció
Új fájlba bemásoltad a Minden darabon Form1 osztályt partial nélkül.Ok és javítás
partial kell, azonos névtérben és névvel.
6. Átnevezés után fordítási hibák
A vezérlőt a Designer fájlban kézzel nevezted át. A Ok és javítás
Name tulajdonságot a Properties ablakban (vagy Rename refaktorálással, Ctrl+R, R) módosítsd, így minden hivatkozás átíródik.
Mini projekt: Designer-felfedező
Értsd meg a Designer munkáját úgy, hogy te magad építesz fel egy Formot kódból:
- Elemzés: készíts Designerrel egy egyszerű Formot (címke, szövegmező, gomb), nyisd meg a
.Designer.csfájlt, és írd meg a naplódba: melyik sor mit csinál (mezők,new, tulajdonságok,Controls.Add, eseménybekötés). - Kódból épített Form: új osztály
NevjegyForm : FormDesigner nélkül; a konstruktornewhívásokkal létrehozza aLabel,TextBox,Buttonvezérlőket, beállítja a tulajdonságaikat, és hozzáadja aControlsgyűjteményhez. - Elrendezés: egy
TableLayoutPanelkétoszlopos rácsa (címke–mező), nem fix pozíciók;Dock/Anchor. - Eseménykezelő: a gomb
Clickeseménye+=operátorral, névtelen metódussal vagy névvel; az OK a mezőket egyMessageBox-ban mutatja. - Felszabadítás: a
Dispose(bool)felülírása a sajátTimerésFonterőforrásokhoz (9.8 lecke). - Felosztás: a nagy
Form1-et (a 11.9 mappa-elemző) oszd három partial fájlra (.cs,.Munka.cs,.Kijelzes.cs), és állapítsd meg: mi lett jobb, és mi maradt ugyanaz. - Teszteld: a kódból épített Form megjelenése, átméretezése, a Tab sorrend (
TabIndex), a fájlok felosztása utáni fordítás, a törölt kezelő hibájának javítása.
Megoldás megnyitása (próbáld ki előbb önállóan!)
public class NevjegyForm : Form
{
private TextBox txtNev, txtEmail;
private Button btnOk;
private Font kiemeltBetu = new Font("Segoe UI", 11, FontStyle.Bold);
public NevjegyForm()
{
// ugyanazt csináljuk, mint az InitializeComponent: létrehozás, beállítás, elhelyezés, események
Text = "Névjegy";
ClientSize = new Size(360, 150);
StartPosition = FormStartPosition.CenterScreen;
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
TableLayoutPanel tabla = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 3, Padding = new Padding(12) };
tabla.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 80));
tabla.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
txtNev = new TextBox { Dock = DockStyle.Fill, Name = "txtNev", TabIndex = 0 };
txtEmail = new TextBox { Dock = DockStyle.Fill, Name = "txtEmail", TabIndex = 1 };
btnOk = new Button { Text = "OK", Name = "btnOk", TabIndex = 2, Font = kiemeltBetu, AutoSize = true };
tabla.Controls.Add(new Label { Text = "Név:", AutoSize = true, Anchor = AnchorStyles.Left }, 0, 0);
tabla.Controls.Add(txtNev, 1, 0);
tabla.Controls.Add(new Label { Text = "E-mail:", AutoSize = true, Anchor = AnchorStyles.Left }, 0, 1);
tabla.Controls.Add(txtEmail, 1, 1);
tabla.Controls.Add(btnOk, 1, 2);
btnOk.Click += (s, e) => MessageBox.Show(this, txtNev.Text + " <" + txtEmail.Text + ">", "Névjegy"); // eseménybekötés kódból
Controls.Add(tabla);
AcceptButton = btnOk;
}
protected override void Dispose(bool disposing) // mint a Designer Dispose-a, kiegészítve a saját erőforrással
{
if (disposing) { kiemeltBetu.Dispose(); }
base.Dispose(disposing);
}
}
// hívás: using (NevjegyForm f = new NevjegyForm()) { f.ShowDialog(this); }Mit tegyél ide: a kódból épített névjegy-ablak és mellette a Designer fájl megfelelő sorai.Javasolt fájlnév: winforms-12-2-kesz.webp · Alt szöveg: A kódból épített Form
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. Dinamikus vezérlők
Egy gombnyomásra hozz létre kódból öt gombot egy Ciklusban FlowLayoutPanel-ben. Hogyan?Egy lehetséges megoldás
new Button { Text = i.ToString() }, btn.Click += ... bekötés, flow.Controls.Add(btn). Bezáráskor a gombokat nem kell külön felszabadítani, a szülő Dispose metódusa megteszi; a törölt vezérlőt viszont Controls.Remove után Dispose() hívással szabadítod fel.
2. Tervezési mód védelme
A konstruktor adatbázist hív, és a Designer nem nyílik meg. Mit teszel? A Egy lehetséges megoldás
DesignMode tulajdonságot ellenőrzöd (konstruktorban nem megbízható: a Load-ban vagy a LicenseManager.UsageMode alapján), a hívást az OnLoad/Shown eseménybe teszed.
3. Régi kezelő eltávolítása
Egy esemény bekötését kell kikapcsolnod futás közben. Hogyan? A Egy lehetséges megoldás
-= operátor: btn.Click -= btn_Click; (névvel megadott kezelő kell; a névtelen lambda nem vehető ki).
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. Mit jelent a partial?
Fogalmazd meg egy mondatban. Az osztály több fájlban van leírva, a fordító egyetlen osztállyá egyesíti.Megoldás megnyitása
2. Hol a kódod?
Melyik fájlba írod az eseménykezelőt, és melyikben a Designer a vezérlőt? A kezelő a Megoldás megnyitása
Form1.cs-be; a vezérlő létrehozása a Form1.Designer.cs InitializeComponent metódusába kerül.
Közepes szint
3. Hova tennéd?
Egy A konstruktorba az ComboBox feltöltése kezdéskor: hova írod?Megoldás megnyitása
InitializeComponent() után, vagy a Load eseménybe (nem a Designer fájlba).
4. InitializeComponent
Mit csinál az Létrehozza és beállítja a vezérlőket; előtte a mezők InitializeComponent, és miért az első a konstruktorban?Megoldás megnyitása
null értékűek.
Kihívás szint
5. Több Form, közös elrendezés
Két Formnak azonos eszköztára van. Mit tehetsz Designer nélkül? Közös Megoldás megnyitása
UserControl (újrahasználható vezérlő), vagy közös ősosztály (AlapForm : Form), amelyből mindkét Form örököl.
6. A Dispose szerepe
Mikor kell felülírni a Ha a Form saját Dispose(bool) metódust?Megoldás megnyitása
IDisposable erőforrást tart (Font, Pen, Bitmap, folyam): a disposing ágban felszabadítod, majd a base.Dispose(disposing) hívást meghívod. Kézzel írt változatot ne a Designer fájlba tedd, hanem a Form1.cs-be (a Designer fájl már tartalmaz egyet; ott helyezd el a hívást, vagy mozgasd át).
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. A generált és a kézi kód szétválasztására: a Designer a sajátját újraírhatja. A vezérlők létrehozását, tulajdonságait, eseménybekötéseit és a Általában ne; vészhelyzetben egy-egy sor (törött kezelő) igen. A konstruktorba az A Designer olyan kezelőt köt be, amely már nincs. Nem: az osztály egy marad; külön osztályok kellenek. A 1. Miért két fájl a Form?
2. Mit tartalmaz az InitializeComponent?
Controls.Add hívásokat.3. Szerkeszthető a Designer fájl?
4. Hova kerül az egyedi beállítás?
InitializeComponent() után.5. Mi a CS1061 oka?
6. Megoldja-e a partial felosztás a rossz szerkezetet?
7. Hogyan kapcsolsz ki egy eseménykezelőt?
-= operátorral.
Mit tudsz már?
- Érted a
partial classműködését és a Designer fájl szerepét. - Tudod, mit szabad és mit nem szabad a generált kódban szerkeszteni.
- Javítod a törött eseménykezelő-bekötéseket.
- A felületet kódból is felépíted, és a nagy Formot partial fájlokra osztod.
Következő lecke: Mezők, propertyk és metódusok
Az osztály építőkövei: mezők, tulajdonságok (get/set), metódusok és a köztük lévő munkamegosztás.



