Grafikus C# – Windows Forms tanfolyam › 10.8 lecke

Windows Forms · 10.8 lecke · beállítások

Application Settings

Egy jó program emlékszik: ugyanabban a helyen és méretben nyílik meg, ahol bezártad, megőrzi a témát, a betűméretet és az utolsó mappát. Az ilyen apró, a programhoz és a felhasználóhoz tartozó értékek tárolására a .NET beépített megoldása az Application Settings (Properties.Settings): a Visual Studio szerkesztőjében felveszed a beállításokat, a kódban típusos tulajdonságként éred el, a mentést és az XML-fájl helyét a keretrendszer intézi. Ebben a leckében megtanulod a használatát (Save, Reset, Upgrade), az ablakpozíció helyes mentését (több monitor, kis ablak), a legutóbbi fájlok tárolását, a sérült beállításfájl kezelését, és tudni fogod, mikor nem ez a jó megoldás.

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

A lecke végére

  • felveszel beállítást a Settings szerkesztőben (név, típus, hatókör, alapérték), és típusosan éred el;
  • megkülönbözteted a felhasználói és az alkalmazás hatókört (csak a felhasználói írható);
  • mentesz, visszaállítasz és frissítesz (Save, Reload, Reset, Upgrade);
  • az ablak helyét és méretét helyesen tárolod (RestoreBounds, képernyőn kívüli pozíció kezelése);
  • listát (StringCollection) és színt tárolsz;
  • kezeled a sérült beállításfájlt, és tudod, mi tartozik a beállításokba, és mi nem (jelszó, nagy adat).

Mielőtt elkezded

Ehhez a leckéhez az 5.6 lecke (a Form életciklusa: Load, FormClosing), a 10.1 lecke (adatmappák) és a 10.6 lecke (JSON, a beállítások alternatívájaként) szükséges. A Settings szerkesztő a Visual Studio Solution Explorer → Properties → Settings.settings fájljában érhető el.

10.7 XML →

Beállítások felvétele és elérése

A Settings.settings szerkesztőben táblázatban adod meg a beállításokat: Name (név), Type (típus: string, int, bool, System.Drawing.Color, Size, Point, StringCollection…), Scope (hatókör) és Value (alapérték). A Visual Studio a Properties.Settings.Default osztályba típusos tulajdonságokat generál:

NameTypeScopeValue (alapérték)
HatterSzinSystem.Drawing.ColorUserWhite
BetuMeretintUser11
AblakHelySystem.Drawing.PointUser0, 0
AblakMeretSystem.Drawing.SizeUser800, 600
AblakAllapotstringUserNormal
LegutobbiSystem.Collections.Specialized.StringCollectionUser(üres)
IndulasokSzamaintUser0
FrissitesKellboolUserTrue
SzerverstringApplicationhttps://pelda.hu (csak olvasható)
Form1.csC#
// olvasás: típusos tulajdonságok, nincs konverzió
int meret = Properties.Settings.Default.BetuMeret;
Color hatter = Properties.Settings.Default.HatterSzin;

// írás (csak a User hatókörű): a memóriában azonnal érvényes, a lemezre a Save írja
Properties.Settings.Default.BetuMeret = 14;
Properties.Settings.Default.Save();

// az alkalmazás-hatókörű érték csak olvasható: az írási kísérlet nem fordul le
string szerver = Properties.Settings.Default.Szerver;
User hatókörFelhasználónként külön érték, olvasható és írható futás közben; a user.config fájlba kerül a felhasználó %LocalAppData% mappájában. Ide valók a személyes beállítások (téma, ablakméret, utolsó mappa).
Application hatókörAz egész programra érvényes, csak olvasható futás közben; a program konfigurációs fájljában (*.exe.config) tárolódik. Szerver cím, alapértelmezett limit: olyan érték, amelyet a telepítő vagy az üzemeltető módosít.
TípusosA generált tulajdonság típusa a megadott típus: nem kell int.Parse. A Color, Size, Point, Font is használható (a program XML-szövegként tárolja).
Mikor kerül a lemezre?A Save() hívására. Hívás nélkül a módosítás a program leállásával elvész. Ezért a FormClosing vagy az érték módosítása után kell mentened.

Jósolj!

A program Properties.Settings.Default.BetuMeret = 14; értéket állít be, de a Save() hívás kimarad. A felhasználó bezárja és újra megnyitja a programot. Mekkora a betűméret?

Jóslat ellenőrzése

11 (az utoljára mentett vagy az alapérték): a módosítás csak a memóriában élt, és a program bezárásakor elveszett. A Save() nélkül nincs tartós változás.

Mentés, Reload, Reset és Upgrade

Form1.cs (using System.Collections.Specialized;)C#
private void Form1_Load(object sender, EventArgs e)
{
Properties.Settings be = Properties.Settings.Default;

// a program új verziója új user.config mappát kap: az előző verzió beállításait át kell hozni
if (be.FrissitesKell)
{
be.Upgrade(); // az előző verzió értékeit betölti
be.FrissitesKell = false; // az új verzió fájljában már hamis
be.Save();
}

be.IndulasokSzama++;

if (be.Legutobbi == null) { be.Legutobbi = new StringCollection(); } // a gyűjtemény alapból null lehet

this.BackColor = be.HatterSzin;
this.Font = new Font(this.Font.FontFamily, be.BetuMeret);
}

private void btnAlaphelyzet_Click(object sender, EventArgs e)
{
if (MessageBox.Show(this, "Visszaállítod a beállításokat az alapértékekre?", "Beállítások", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
Properties.Settings.Default.Reset(); // minden User érték az alapérték (a Save-ig csak a memóriában)
Properties.Settings.Default.Save();
}
}

// a módosítás elvetése: a legutóbb mentett állapot visszatöltése
Properties.Settings.Default.Reload();
ResetA Reset() a felhasználói beállításokat az alapértékekre állítja. A fájlt a Save() írja; mentés nélkül csak a memóriában változik.
ReloadA Reload() a lemezről újratölti a mentett értékeket (a nem mentett módosítást elveti): „Mégse” gombhoz ideális.
UpgradeA beállítások helye a program verziójához kötött mappa. Új verziónál (vagy a program útvonalának változásánál) a program üres beállításokkal indulna. A FrissitesKell jelző mintája: az első indításnál Upgrade() átveszi az előző verzió értékeit, majd a jelzőt hamisra állítja és menti.
GyűjteményA StringCollection alapértéke üres beállításnál null lehet. Használat előtt ellenőrizd és hozd létre. A gyűjtemény elemeinek módosítása után is hívj Save() metódust.

Jósolj!

A program új változata (1.1) kijön, a felhasználó telepíti. A programban nincs Upgrade() hívás. Mit tapasztal a felhasználó?

Jóslat ellenőrzése

Hogy a program elfelejtett mindent: az új verzió új beállítás-mappát használ, és üres (alapértékű) beállításokkal indul. Az Upgrade() az előző verzió user.config fájljából hozza át az értékeket.

Az ablak helyének és méretének tárolása

Form1.cs (using System.Linq;)C#
// visszaállítás indításkor
private void AblakVisszaallit()
{
Properties.Settings be = Properties.Settings.Default;

Size meret = be.AblakMeret;
Point hely = be.AblakHely;

// ellenőrzés: elég nagy-e a méret, és az ablak látszik-e valamelyik (még meglévő) képernyőn?
if (meret.Width < this.MinimumSize.Width || meret.Height < this.MinimumSize.Height) { return; } // érvénytelen, marad az alap

Rectangle kert = new Rectangle(hely, meret);
bool latszik = Screen.AllScreens.Any(s => s.WorkingArea.IntersectsWith(kert) && Rectangle.Intersect(s.WorkingArea, kert).Width >= 100);

if (!latszik) { return; } // a monitor megszűnt (kihúzott kijelző): a program az alapértelmezett helyen nyílik

this.StartPosition = FormStartPosition.Manual;
this.Location = hely;
this.Size = meret;

if (be.AblakAllapot == "Maximized") { this.WindowState = FormWindowState.Maximized; }
}

// mentés bezáráskor
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Properties.Settings be = Properties.Settings.Default;

if (this.WindowState == FormWindowState.Normal)
{
be.AblakHely = this.Location;
be.AblakMeret = this.Size;
be.AblakAllapot = "Normal";
}
else
{
be.AblakHely = this.RestoreBounds.Location; // a maximalizált/kis méretű ablaknál a visszaállítandó méret
be.AblakMeret = this.RestoreBounds.Size;
be.AblakAllapot = this.WindowState == FormWindowState.Maximized ? "Maximized" : "Normal"; // minimalizálva nem indítunk
}

try { be.Save(); }
catch (System.Configuration.ConfigurationErrorsException) { } // a beállítás mentése nem akadályozhatja a kilépést
}
RestoreBoundsHa az ablak maximalizált vagy minimalizált, a Location és Size az ideiglenes értéket (teljes képernyő, a tálca melletti pont) adja. A RestoreBounds a normál állapot helyét és méretét: ezt kell menteni.
Minimalizált állapotA minimalizált ablakkal induló program zavaró: a minimalizált állapotot normálként mentjük.
Képernyő-ellenőrzésA felhasználó a második monitoron dolgozott, majd kihúzta a kijelzőt: a mentett hely ekkor a képernyőn kívül esik, és az ablak „eltűnik”. A Screen.AllScreens alapján ellenőrizd, hogy az ablak legalább egy része (itt 100 képpont szélesen) látszik.
FormClosingA mentés a FormClosing (vagy FormClosed) eseményben történik (5.6 lecke). A mentés hibája nem akadályozhatja meg a kilépést.

Jósolj!

A felhasználó a program ablakát maximalizálva zárja be. A FormClosing a this.Location és this.Size értéket menti. Legközelebb a program normál állapotban indul. Hol és mekkora lesz az ablak?

Jóslat ellenőrzése

Gyakran a teljes képernyő méretében (vagy a képernyő szélén, negatív koordinátával): a maximalizált ablak Location és Size értéke a képernyőhöz igazodik, nem az előző normál mérethez. A RestoreBounds a helyes.

Sérült beállításfájl és a Settings korlátai

Program.cs (using System.Configuration;)C#
// A sérült user.config az első Properties.Settings.Default eléréskor ConfigurationErrorsException kivételt dob.
// Ezért az első elérést védjük, és szükség esetén töröljük a hibás fájlt.
private static void BeallitasokEllenorzese()
{
try
{
int proba = Properties.Settings.Default.BetuMeret; // az első elérés tölti be a fájlt
}
catch (ConfigurationErrorsException ex)
{
string fajl = ex.Filename;

if (string.IsNullOrEmpty(fajl) && ex.InnerException is ConfigurationErrorsException) { fajl = ((ConfigurationErrorsException)ex.InnerException).Filename; }

DialogResult v = MessageBox.Show("A beállításfájl sérült, ezért nem tölthető be. Alaphelyzetbe állítsam a beállításokat?", "Beállítások", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

if (v == DialogResult.Yes && fajl != null && File.Exists(fajl))
{
File.Move(fajl, fajl + ".hibas"); // nem törlünk: a hibás fájl megmarad a vizsgálathoz
}
else { Environment.Exit(0); }
}
}

// Main elején: BeallitasokEllenorzese(); Application.Run(new Form1());
AdatApplication Settings?Miért?
Téma, betűméret, ablakméret, utolsó mappaIgenKicsi, felhasználónkénti, nem érzékeny.
Legutóbbi fájlok (néhány elem)IgenStringCollection, kicsi.
Jelszó, API-kulcs, tokenNEMTitkosítatlan XML-fájl: jelszót ne tárolj. Használj védett tárolót (Windows Credential Manager, ProtectedData).
A felhasználó dokumentumai, névjegyek, jegyzetekNEMSaját fájl (JSON, 10.6 lecke): megosztható, mentésbe vonható, nagyobb.
Hordozható program (pendrive-on)NEMA beállítások a gép felhasználói mappájában vannak: saját beallitasok.json a program mellett.
Több profil, több ablakNEMEgyetlen user.config: profilokhoz saját fájl.

Jósolj!

A program a felhasználó e-mail-jelszavát egy User hatókörű Jelszo beállításban tárolja, hogy ne kelljen mindig beírni. Ki olvashatja el?

Jóslat ellenőrzése

Bárki, aki hozzáfér a felhasználó mappájához (más program, a gép másik használója rendszergazdaként, egy biztonsági mentés): a user.config szöveges XML, a jelszó olvasható benne. Jelszót nem tárolunk a beállításokban; ha feltétlenül kell, a Windows védett tárolóját használd.

📷 Képernyőkép helye

Mit tegyél ide: a Settings szerkesztő a felvett beállításokkal, mellette a kész beállításkezelő program.Javasolt fájlnév: winforms-10-8-beallitasok.webp · Alt szöveg: A Settings szerkesztő és a beállításkezelő

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 beállítás nem marad meg

Properties.Settings.Default.HatterSzin = Color.Gold;   // nincs Save()
Hiba és javítás

A Save() hívás hiányzik. Mentsd a módosítás után (vagy a FormClosing-ben).

2. A fordító hibát jelez az írásnál

Properties.Settings.Default.Szerver = "masik.hu";   // Application hatókör
Hiba és javítás

Az Application hatókörű érték csak olvasható. Ha a program módosítja, a hatókörnek Usernek kell lennie.

3. Új verzió után minden beállítás elveszett

A frissítés utáni induláskor a program alapértékekkel indul.

Ok és javítás

Hiányzik az Upgrade(). Használd a FrissitesKell jelző mintáját az első indításnál.

4. NullReferenceException a Legutobbi gyűjteménynél

Properties.Settings.Default.Legutobbi.Add(ut);   // az első indításkor null
Hiba és javítás

A StringCollection alapból null lehet. Ellenőrizd és hozd létre: if (Legutobbi == null) Legutobbi = new StringCollection();.

5. Az ablak a képernyőn kívül nyílik meg

A második monitor eltávolítása után a program „eltűnik”.

Ok és javítás

A mentett hely nincs ellenőrizve. Ellenőrizd a Screen.AllScreens alapján, hogy a hely látszik-e; ha nem, az alapértelmezett pozíciót használd.

6. A program összeomlik az indulásnál

Az indulásnál ConfigurationErrorsException jön.

Ok és javítás

A user.config sérült (kézi szerkesztés, megszakadt mentés). Kezeld az első elérést, és ajánlj alaphelyzetet (a hibás fájl átnevezése).

Mini projekt: beállításkezelő

Készíts programot, amely emlékszik a felhasználó beállításaira:

  1. Settings: a lecke táblázata szerinti beállítások (HatterSzin, BetuMeret, AblakHely, AblakMeret, AblakAllapot, Legutobbi, IndulasokSzama, FrissitesKell), kiegészítve: ElsoIndulas (bool, True), UtolsoMappa (string), Tema (string, Vilagos).
  2. Felület: txtSzoveg (próbaszöveg), beállító panel: cmbTema (Világos, Sötét, Magas kontraszt), btnHatter (Háttérszín..., ColorDialog), nudBetu (8–32), lblIndulas (Ez a(z) 17. indítás), lstLegutobbi; gombok: Alaphelyzet, Beállítások exportálása..., Importálás...; állapotsor: a beállítások helye (%LocalAppData%).
  3. Indulás: BeallitasokEllenorzese (sérült fájl kezelése), Upgrade a jelzővel, az ablak visszaállítása (RestoreBounds, képernyő-ellenőrzés), a téma és a betűméret alkalmazása, az indítások számának növelése.
  4. Első indítás: az ElsoIndulas igaz esetén üdvözlő ablak (Köszöntelek!) rövid bemutatóval, utána a jelző hamis.
  5. Élő előnézet: a beállítások módosítása azonnal látszik; a Mégse a Reload(), az OK a Save() (egy Alkalmaz / Megse gombpár).
  6. Érvényesítés betöltéskor: a BetuMeret 8–32 közé szorítva (Math.Max, Math.Min); ismeretlen téma esetén az alap; a háttérszín és a szövegszín kontrasztja ellenőrizve (a magas kontraszt téma kényszeríti).
  7. Exportálás és importálás: a beállítások (a téma, a betűméret, a háttérszín) JSON-ba (10.6 lecke, a szín #RRGGBB szövegként); importálásnál az értékek ellenőrzése, hibás fájl jelentése; így a beállítások átvihetők másik gépre.
  8. Legutóbbi fájlok: a StringCollection (legfeljebb 8, duplikátum nélkül, az új elöl); a Fájl megnyitása gomb az utolsó mappából indul (10.4 lecke).
  9. Hibatűrés: a Save() hibája (ConfigurationErrorsException, IOException, UnauthorizedAccessException) az állapotsorban jelenik meg, a program nem omlik össze.
  10. Teszteld: első indítás, újraindítás (ablak helye, mérete, maximalizált állapot), a második monitor eltávolítása (ha van), alaphelyzet, a user.config szándékos elrontása (egy < jel hozzáadása), nagy betűméret, a Mégse és az OK, export–import, 10 egymás utáni indítás (számláló).
Megoldás megnyitása (próbáld ki előbb önállóan!)

A központi rész az indulás sorrendje (ellenőrzés → upgrade → ablak → téma) és a mentés a bezáráskor.

Form1.cs (using System.Collections.Specialized; using System.Configuration; using System.Linq; using System.IO; using System.Text.Json;)C#
private Properties.Settings be { get { return Properties.Settings.Default; } }

private void Form1_Load(object sender, EventArgs e)
{
if (be.FrissitesKell) { be.Upgrade(); be.FrissitesKell = false; be.Save(); }

if (be.Legutobbi == null) { be.Legutobbi = new StringCollection(); }

be.BetuMeret = Math.Max(8, Math.Min(32, be.BetuMeret)); // érvényesítés

cmbTema.Items.AddRange(new object[] { "Világos", "Sötét", "Magas kontraszt" });
cmbTema.SelectedItem = cmbTema.Items.Contains(be.Tema) ? be.Tema : "Világos";

AblakVisszaallit();
Alkalmaz();

be.IndulasokSzama++;
lblIndulas.Text = "Ez a(z) " + be.IndulasokSzama + ". indítás.";

foreach (string ut in be.Legutobbi) { lstLegutobbi.Items.Add(ut); }

if (be.ElsoIndulas)
{
MessageBox.Show(this, "Köszöntelek! A beállításaidat a program megjegyzi.", "Üdv", MessageBoxButtons.OK, MessageBoxIcon.Information);
be.ElsoIndulas = false;
}

tsslHely.Text = "Beállítások: %LocalAppData%";
}

private void Alkalmaz()
{
Color hatter = be.HatterSzin, szoveg = Color.Black;

switch (cmbTema.SelectedItem as string)
{
case "Sötét": hatter = Color.FromArgb(32, 32, 36); szoveg = Color.WhiteSmoke; break;
case "Magas kontraszt": hatter = Color.Black; szoveg = Color.Yellow; break; // a kontraszt kikényszerítve
}

txtSzoveg.BackColor = hatter;
txtSzoveg.ForeColor = szoveg;

// az új betű létrehozása, a régi felszabadítása a csere UTÁN

Font uj = new Font(txtSzoveg.Font.FontFamily, be.BetuMeret);
Font elozo = txtSzoveg.Font;

txtSzoveg.Font = uj;
elozo.Dispose(); // a TextBox a beállított betűt nem szabadítja fel (9.8 lecke)
}

private void AblakVisszaallit()
{
Size meret = be.AblakMeret;
Point hely = be.AblakHely;

if (meret.Width < this.MinimumSize.Width || meret.Height < this.MinimumSize.Height) { return; }

Rectangle kert = new Rectangle(hely, meret);
bool latszik = Screen.AllScreens.Any(s => Rectangle.Intersect(s.WorkingArea, kert).Width >= 100 && Rectangle.Intersect(s.WorkingArea, kert).Height >= 50);

if (!latszik) { return; }

this.StartPosition = FormStartPosition.Manual;
this.Location = hely;
this.Size = meret;

if (be.AblakAllapot == "Maximized") { this.WindowState = FormWindowState.Maximized; }
}

private void btnAlkalmaz_Click(object sender, EventArgs e)
{
be.Tema = (string)cmbTema.SelectedItem;
be.BetuMeret = (int)nudBetu.Value;
Alkalmaz();
Ment();
}

private void btnMegse_Click(object sender, EventArgs e)
{
be.Reload(); // a nem mentett módosítás elvetése
nudBetu.Value = be.BetuMeret;
Alkalmaz();
}

private void btnAlaphelyzet_Click(object sender, EventArgs e)
{
if (MessageBox.Show(this, "Visszaállítod az összes beállítást az alapértékre?", "Alaphelyzet", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) != DialogResult.Yes) { return; }

be.Reset();
be.FrissitesKell = false;
be.ElsoIndulas = false;
nudBetu.Value = be.BetuMeret;
Alkalmaz();
Ment();
}

private void Ment()
{
try { be.Save(); tsslUzenet.Text = "A beállítások mentve."; }
catch (ConfigurationErrorsException ex) { tsslUzenet.Text = "A mentés nem sikerült: " + ex.Message; }
catch (IOException ex) { tsslUzenet.Text = "A mentés nem sikerült: " + ex.Message; }
catch (UnauthorizedAccessException) { tsslUzenet.Text = "Nincs jogosultság a beállítások mentéséhez."; }
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (this.WindowState == FormWindowState.Normal) { be.AblakHely = this.Location; be.AblakMeret = this.Size; be.AblakAllapot = "Normal"; }
else { be.AblakHely = this.RestoreBounds.Location; be.AblakMeret = this.RestoreBounds.Size; be.AblakAllapot = this.WindowState == FormWindowState.Maximized ? "Maximized" : "Normal"; }

Ment();
}

// export: csak a hordozható értékek, a szín #RRGGBB szövegként (10.6 lecke)
private void btnExport_Click(object sender, EventArgs e)
{
int idx;
string ut = FajlValaszto.Ment(this, "Beállítások (*.json)|*.json", be.UtolsoMappa, "beallitasok", out idx);

if (ut == null) { return; }

var adat = new { tema = be.Tema, betuMeret = be.BetuMeret, hatterSzin = ColorTranslator.ToHtml(be.HatterSzin) };

try { File.WriteAllText(ut, JsonSerializer.Serialize(adat, new JsonSerializerOptions { WriteIndented = true })); }
catch (IOException ex) { MessageBox.Show(this, ex.Message, "Exportálás", MessageBoxButtons.OK, MessageBoxIcon.Error); }
}

private void btnImport_Click(object sender, EventArgs e)
{
string ut = FajlValaszto.Megnyit(this, "Beállítások (*.json)|*.json", be.UtolsoMappa);

if (ut == null) { return; }

try
{
using (JsonDocument dok = JsonDocument.Parse(File.ReadAllText(ut)))
{
JsonElement gy = dok.RootElement, v;
int meret;

if (gy.TryGetProperty("betuMeret", out v) && v.TryGetInt32(out meret) && meret >= 8 && meret <= 32) { be.BetuMeret = meret; }
if (gy.TryGetProperty("tema", out v) && cmbTema.Items.Contains(v.GetString())) { be.Tema = v.GetString(); }
if (gy.TryGetProperty("hatterSzin", out v)) { try { be.HatterSzin = ColorTranslator.FromHtml(v.GetString()); } catch (Exception) { } }
}

Alkalmaz();
Ment();
}
catch (JsonException ex) { MessageBox.Show(this, "Hibás beállításfájl: " + ex.Message, "Importálás", MessageBoxButtons.OK, MessageBoxIcon.Warning); }
catch (IOException ex) { MessageBox.Show(this, ex.Message, "Importálás", MessageBoxButtons.OK, MessageBoxIcon.Error); }
}
📷 Képernyőkép helye

Mit tegyél ide: a kész beállításkezelő a témaválasztóval és az indítások számával.Javasolt fájlnév: winforms-10-8-kesz.webp · Alt szöveg: A kész beállításkezelő

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. Utolsó splitter-pozíció

Egy SplitContainer elválasztójának helyét tárold. Melyik beállítás típusát használod, és mikor állítod vissza?

Egy lehetséges megoldás

Egy int beállítás (SplitHely); a Load-ban a SplitterDistance beállítása érvényesítéssel (a Panel1MinSize és az ablakméret határain belül), a FormClosing-ben a mentés.

2. Indítás számláló és köszöntés

A program a 10., 50., 100. indításnál „kerek” indításra gratulál. Hol számolsz?

Egy lehetséges megoldás

A Load-ban az IndulasokSzama++ után; az int beállítást ellenőrzöd (szam % 50 == 0 vagy tömb). Az indítás számát a Save menti, ezért a számláló megbízhatósága a menthetőségtől függ.

3. Beállítások két ablakban

A program két ablakot nyit meg (főablak és beállítóablak), mindkettő a Settings.Default osztályt használja. Szükséges-e átadni a beállításokat?

Egy lehetséges megoldás

Nem: a Settings.Default egyetlen példány (singleton), mindenhol ugyanaz. A beállítóablak módosít és Save-et hív; a főablaknak értesítés kell (esemény vagy PropertyChanged), hogy újraalkalmazza az értékeket (7.6 lecke eseménye).

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 hatókör?

Válaszd ki a hatókört: (a) a felhasználó témája; (b) a szerver címe, amelyet az üzemeltető állít be.

Megoldás megnyitása

(a) User (olvasható és írható); (b) Application (csak olvasható).

2. Mi hiányzik?

A felhasználó módosítja a témát, de újraindítás után a régi téma tér vissza. Mi a hiba?

Megoldás megnyitása

A Save() hívás hiányzik (vagy a mentés kivételt dobott, amelyet elnyelt).

Közepes szint

3. Kontraszt-ellenőrzés

Hogyan ellenőrzöd, hogy a betöltött háttér- és szövegszín kontrasztja megfelelő?

Megoldás megnyitása

A relatív fényesség arányából (6.9 lecke): ha 4,5 alatt van, a program az alap színeket vagy a magas kontraszt témát alkalmazza.

4. Hordozható mód

A program a beállításait a saját mappájában lévő beallitasok.json fájlba is mentheti (pendrive). Hogyan döntöd el, melyiket használod?

Megoldás megnyitása

Ha a program mellett van portable.txt jelzőfájl (és a mappa írható), akkor a JSON; különben a Settings. A beállítás-réteg egy közös felület mögött (IBeallitasok) lehet.

Kihívás szint

5. SettingsSaving esemény

Mentés előtt a program ellenőrzi az értékeket, és szükség esetén megakadályozza a mentést. Mit használsz?

Megoldás megnyitása

A Properties.Settings.Default.SettingsSaving esemény (CancelEventArgs): az e.Cancel = true megállítja a mentést. Az ellenőrzés egy helyen van, bárhonnan hívják a Save() metódust.

6. Titkosított érték

Egy API-kulcsot mégis tárolni kell. Hogyan teszed biztonságosabbá?

Megoldás megnyitása

A ProtectedData.Protect (DataProtectionScope.CurrentUser) a felhasználó Windows-fiókjához köti a titkosítást; a titkosított bájtokat Base64 szövegként tárolod. Jobb a Windows Credential Manager. Titkosított értéket sem naplózol, és nem írsz ki.

Gyors önellenőrzés

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

1. Mi a különbség a User és az Application hatókör között?

A User felhasználónként külön és írható; az Application az egész programra érvényes és futás közben csak olvasható.

2. Mikor kerül lemezre a beállítás?

A Save() hívásra.

3. Mire való az Upgrade?

Az új verzió az előző verzió beállításait átveszi.

4. Miért a RestoreBounds-t mentjük?

Maximalizált vagy minimalizált ablaknál a Location/Size félrevezető; a RestoreBounds a normál állapot.

5. Miért ellenőrizzük az ablak helyét indításkor?

A monitor megszűnhetett: az ablak a képernyőn kívül „eltűnne”.

6. Mit ne tárolj a Settings-ben?

Jelszót és más érzékeny adatot, a felhasználó dokumentumait és nagy adatot.

7. Mit teszel sérült user.config esetén?

Kezeled a ConfigurationErrorsException kivételt, a fájlt átnevezed (nem törlöd), és alaphelyzetben indulsz.

Mit tudsz már?

  • Beállításokat veszel fel és használsz típusosan, a hatókör ismeretében.
  • Mentesz, visszaállítasz és frissítesz (Save, Reload, Reset, Upgrade).
  • Az ablak helyét és méretét helyesen, több monitor mellett is kezeled.
  • Kezeled a sérült beállításfájlt.
  • Tudod, mi való a Settings osztályba, és mi nem.

Következő lecke: mentési hibák, fájlzárak és kivételkezelés

Megbízható mentés: ideiglenes fájl és csere, biztonsági másolat, újrapróbálkozás zárolt fájlnál, a tipikus IOException okok és az érthető hibaüzenetek.