Grafikus C# – Windows Forms tanfolyam › 14.7 lecke Windows Forms · 14.7 lecke · kiadás Fejlesztés közben minden fájl „ott van, ahol a program”: a Fájlok, adatbázisok helye telepítés után
bin mappában. Telepítés után ez megváltozik: a program a Program Files mappába kerül, ahová a felhasználó nem írhat; a beállítások, a mentett adatok, az adatbázis és a naplók másik helyre valók. Aki ezt nem tervezi meg, annak a programja a saját gépén működik, a felhasználónál viszont „Access denied” hibával áll le, vagy a felhasználó adatai eltűnnek frissítéskor. Ebben a leckében megtanulod, melyik adat hová való (ApplicationData, LocalApplicationData, MyDocuments, ProgramData), hogyan kezeld a beállításokat (Settings és saját JSON), hol legyen az SQLite adatbázis és hogyan frissítsd a sémáját, mi az első indítás és a hordozható mód, és hogyan kezeld a jogosultsági hibákat.
A lecke végére
- eldöntöd, hogy melyik adat hová való (program mappa,
ApplicationData,LocalApplicationData,MyDocuments,ProgramData); - az elérési utakat egy központi osztályban kezeled;
- beállításokat mentesz és töltesz (
Settingsés JSON), alapértékekkel és verzióval; - az SQLite adatbázist a megfelelő helyre teszed, és a sémáját verziózod (
user_version); - kezeled az első indítást és a hordozható módot;
- kezeled a jogosultsági hibákat, és megmutatod a felhasználónak, hol vannak az adatai.
Mielőtt elkezded
Ehhez a leckéhez a 13.6 lecke (fájl- és adatbázis-kivételek), a 14.2 lecke (AppContext.BaseDirectory) és a 14.6 lecke (telepítés, eltávolítás) szükséges.
Hová melyik adat való?
| Hely | Tipikus útvonal | Mire való? |
|---|---|---|
Program mappaAppContext.BaseDirectory | C:\Program Files\Program\ | Csak olvasható: a program, alapértelmezett sablonok, képek. Ide nem írunk. |
| ApplicationData (roaming) | C:\Users\Név\AppData\Roaming\ | A felhasználó beállításai és adatai, amelyeknek „követniük” kell (vállalati hálózaton a felhasználóval együtt vándorol). |
| LocalApplicationData | C:\Users\Név\AppData\Local\ | Gépfüggő, nagyobb adatok: adatbázis, gyorsítótár, naplók. |
| MyDocuments | C:\Users\Név\Documents\ | A felhasználó saját fájljai: exportok, dokumentumok, amelyeket ő keres és kezel. |
| CommonApplicationData | C:\ProgramData\ | Minden felhasználó közös adata; az írási jog a mappától függ (telepítéskor kell beállítani). |
| Temp | %TEMP% | Ideiglenes fájlok (Path.GetTempPath()): bármikor törölhetők. |
public static class Utak
{
private const string Program = "Diaknyilvantarto";
// A hordozható mód: ha a program mellett van a "portable.txt", minden adat a program mappájában lesz (pendrive)
public static bool Hordozhato { get { return File.Exists(Path.Combine(AppContext.BaseDirectory, "portable.txt")); } }
private static string Gyoker(Environment.SpecialFolder mappa)
{
return Hordozhato ? Path.Combine(AppContext.BaseDirectory, "Adat") : Path.Combine(Environment.GetFolderPath(mappa), Program);
}
public static string BeallitasMappa { get { return Letrehoz(Gyoker(Environment.SpecialFolder.ApplicationData)); } }
public static string AdatMappa { get { return Letrehoz(Path.Combine(Gyoker(Environment.SpecialFolder.LocalApplicationData), "Adat")); } }
public static string NaploMappa { get { return Letrehoz(Path.Combine(Gyoker(Environment.SpecialFolder.LocalApplicationData), "Naplo")); } }
public static string ExportMappa { get { return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); } }
public static string BeallitasFajl { get { return Path.Combine(BeallitasMappa, "beallitasok.json"); } }
public static string AdatbazisFajl { get { return Path.Combine(AdatMappa, "diakok.db"); } }
private static string Letrehoz(string ut) { Directory.CreateDirectory(ut); return ut; } // létrehozza, ha még nincs
}"C:\\..." sztring, és a hordozható mód vagy a mappacsere egy helyen módosítható. A Form és a szolgáltatások az Utak.AdatbazisFajl értéket kérik, nem építenek útvonalat.ApplicationData) a hálózati profilú gépeken a felhasználót követi: kicsi, fontos adatnak (beállítások) való. A Local (LocalApplicationData) a gépen marad: nagy adatnak (adatbázis, gyorsítótár, napló). Egyszerű otthoni gépen a kettő működésben nem különbözik, de a helyes választás a vállalati környezetben számít.AppData alatt marad: nem akarjuk, hogy a felhasználó ott véletlenül belenyúljon.Jósolj!
A program a naplo.txt fájlt a AppContext.BaseDirectory mappába írja. Fejlesztés közben (a bin mappában) működik. Mi történik telepítés után, a Program Files mappában, normál felhasználóval?
Jóslat ellenőrzése
UnauthorizedAccessException az első naplóíráskor (vagy, ha a naplózó elnyeli, nem lesz napló). A naplónak a LocalApplicationData mappába kell kerülnie. Ez a leggyakoribb „csak a saját gépemen működik” hiba telepítés után.
Beállítások: Settings vagy saját JSON
1. Properties.Settings (beépített)
Visual Studio: Project → Properties → Settings: nevet, típust, hatókört (User) és alapértéket adsz meg; a kód: Properties.Settings.Default.Nev, mentés: Settings.Default.Save(). A fájl (user.config) a %LocalAppData% alatt, verziónként külön mappában él.
2. Saját JSON fájl
Egy Beallitasok osztály, amelyet a System.Text.Json ment az ApplicationData mappába. Átlátható (a felhasználó vagy te megnyithatod), hordozható móddal is működik, és a verzióváltás nem „veszíti el” a beállításokat.
public class Beallitasok
{
public int Verzio { get; set; } = 2; // a fájl sémájának verziója (migrációhoz)
public bool FrissitesEllenorzes { get; set; } = true; // alapérték: ha a fájlban nincs, ez lesz
public string Nyelv { get; set; } = "hu";
public int AblakSzel { get; set; } = 900;
public int AblakMag { get; set; } = 600;
public string UtolsoMappa { get; set; } = "";
public static Beallitasok Betolt()
{
try
{
if (!File.Exists(Utak.BeallitasFajl)) { return new Beallitasok(); } // első indítás: alapértékek
return JsonSerializer.Deserialize<Beallitasok>(File.ReadAllText(Utak.BeallitasFajl)) ?? new Beallitasok();
}
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is JsonException)
{
return new Beallitasok(); // sérült fájl: alapértékekkel indulunk (és naplózunk), nem omlunk össze
}
}
public void Ment()
{
try
{
string tmp = Utak.BeallitasFajl + ".tmp";
File.WriteAllText(tmp, JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true }));
if (File.Exists(Utak.BeallitasFajl)) { File.Delete(Utak.BeallitasFajl); }
File.Move(tmp, Utak.BeallitasFajl); // biztonságos mentés (13.6 lecke)
}
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { /* naplózd; a beállítás mentésének hibája ne állítsa le a programot */ }
}
}
// Form: indításkor betölt, zárásakor ment
private Beallitasok beallitasok;
private void Form1_Load(object s, EventArgs e) { beallitasok = Beallitasok.Betolt(); this.Size = new Size(beallitasok.AblakSzel, beallitasok.AblakMag); }
private void Form1_FormClosing(object s, FormClosingEventArgs e) { beallitasok.AblakSzel = this.Width; beallitasok.AblakMag = this.Height; beallitasok.Ment(); }= true, = "hu") azért fontos, mert egy régebbi beállításfájlból az újabb verzió új beállításai hiányozhatnak: ilyenkor az alapérték marad, és nem lesz hibás (false/null) érték.Verzio mező megmondja, melyik séma szerint mentették: ha a program új beállításokat vezet be, betöltéskor a Verzio alapján átalakítja a régit (például a Nyelv mező átnevezése), majd növeli a verziót.Properties.Settings új programverziónál új mappát használ, ezért az új verzió „üres” beállításokkal indul. A megoldás: egy Upgrade jelző a beállításokban, és induláskor Settings.Default.Upgrade() hívás, ha az még igaz. A JSON-nál ez a gond nincs: a fájl verziófüggetlen.ProtectedData, DPAPI: felhasználóhoz kötött titkosítás), és a legkevesebbet tárold.Jósolj!
Az 1.0-s program Properties.Settings beállításokat használt. A felhasználó frissít 1.1-re, és az összes beállítása visszaáll az alapértékre. Mi történt?
Jóslat ellenőrzése
A Settings a user.config fájlt verziónként külön mappában tárolja, ezért az 1.1 nem találja az 1.0 beállításait. Megoldás: induláskor Settings.Default.Upgrade() (egy „frissítve van-e” jelzővel), vagy a verziófüggetlen saját JSON fájl.
Az adatbázis helye és a séma verziója
public static class Adatbazis
{
private const int AktualisVerzio = 2; // a program által várt séma verziója
public static SqliteConnection Nyit()
{
SqliteConnection kap = new SqliteConnection("Data Source=" + Utak.AdatbazisFajl); // az AppData alatt, nem a program mappájában
kap.Open();
return kap;
}
// INDULÁSKOR: létrehozza vagy frissíti a sémát (migráció)
public static void Inicializal()
{
using (SqliteConnection kap = Nyit())
{
int verzio = Verzio(kap); // PRAGMA user_version: új adatbázisnál 0
using (SqliteTransaction tr = kap.BeginTransaction())
{
if (verzio < 1) { Futtat(kap, tr, "CREATE TABLE diak (id INTEGER PRIMARY KEY, nev TEXT NOT NULL)"); }
if (verzio < 2) { Futtat(kap, tr, "ALTER TABLE diak ADD COLUMN osztaly TEXT NOT NULL DEFAULT ''"); } // 2. verzió: új oszlop
Futtat(kap, tr, "PRAGMA user_version = " + AktualisVerzio);
tr.Commit();
}
}
}
private static int Verzio(SqliteConnection kap)
{
using (SqliteCommand c = kap.CreateCommand()) { c.CommandText = "PRAGMA user_version"; return Convert.ToInt32(c.ExecuteScalar()); }
}
private static void Futtat(SqliteConnection kap, SqliteTransaction tr, string sql)
{
using (SqliteCommand c = kap.CreateCommand()) { c.Transaction = tr; c.CommandText = sql; c.ExecuteNonQuery(); }
}
// BIZTONSÁGI MÁSOLAT migráció előtt
public static void Mentes()
{
if (File.Exists(Utak.AdatbazisFajl)) { File.Copy(Utak.AdatbazisFajl, Utak.AdatbazisFajl + ".bak", true); }
}
}PRAGMA user_version egy egész szám az adatbázisban, amelyet te használhatsz a séma verziójának jelzésére. Új adatbázisnál 0. Induláskor összeveted a program által várt (AktualisVerzio) értékkel, és a hiányzó lépéseket sorban lefuttatod..bak).DROP TABLE): a felhasználó adatai elvesznének. Az új oszlopokhoz ALTER TABLE ... ADD COLUMN és alapérték.ProgramData), az írási jogot a telepítőnek kell beállítania, és az SQLite zárolási korlátai (egyszerre egy író) miatt egy szerver-adatbázis lehet jobb. Egyfelhasználós asztali programnál az AppData a megfelelő hely.Jósolj!
Az 1.0 program az osztaly oszlop nélküli táblát hozta létre. A 1.1 program az új oszloppal számol, de nem migrál: CREATE TABLE IF NOT EXISTS mellett fut. Mi történik a frissített felhasználónál?
Jóslat ellenőrzése
A CREATE TABLE IF NOT EXISTS nem módosítja a már létező táblát: az osztaly oszlop hiányzik, és az első lekérdezés SqliteException (no such column) hibával elszáll. A friss telepítés (új adatbázis) jól működik, a frissített nem: ezt csak „régi adatbázissal” végzett teszt találja meg. A séma verziózott migrációja oldja meg.
Első indítás, hordozható mód, jogosultságok
// INDULÁSKOR: a mappák, adatbázis és beállítások előkészítése
private void Elokeszit()
{
try
{
bool elsoIndulas = !File.Exists(Utak.AdatbazisFajl); // a mappákat az Utak már létrehozza
if (!elsoIndulas) { Adatbazis.Mentes(); } // migráció előtt másolat
Adatbazis.Inicializal();
beallitasok = Beallitasok.Betolt();
if (elsoIndulas) { tsslUzenet.Text = "Üdvözlünk! Az adataid itt vannak: " + Utak.AdatMappa; }
}
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException || ex is SqliteException)
{
MessageBox.Show("A program nem tudja létrehozni vagy megnyitni az adatait itt: " + Utak.AdatMappa + Environment.NewLine + ex.Message + Environment.NewLine + Environment.NewLine + "Ellenőrizd a mappa jogosultságait, vagy a lemezt.", "Adathiba", MessageBoxButtons.OK, MessageBoxIcon.Warning);
Application.Exit(); // adat nélkül nincs értelme tovább futni: kontrolláltan kilépünk
}
}
// MENÜ: Adatmappa megnyitása (a felhasználó lássa, hol vannak az adatai)
private void mnuAdatmappa_Click(object sender, EventArgs e)
{
Process.Start(new ProcessStartInfo(Utak.AdatMappa) { UseShellExecute = true }); // megnyitja a Fájlkezelőben
}CreateDirectory, séma-létrehozás), alapértékekkel, és barátságosan köszönteni. Az első indítás tesztje: töröld az AppData mappát, és indítsd újra a programot.portable.txt fájl jelzi, hogy minden adatot a program melletti Adat mappába kell tenni (pendrive, 14.5 lecke ZIP). A mappának írhatónak kell lennie: ezért hordozható módban a program nem telepíthető a Program Files mappába.%AppData% mappa rejtett a Fájlkezelőben: a menü segít.Jósolj!
A program portable.txt jelenlétében a program mappájába (Adat) ír, de a felhasználó a ZIP-et a Program Files alá csomagolta ki. Mi történik?
Jóslat ellenőrzése
A Program Files alatt a program mappája nem írható: az első adat-létrehozás UnauthorizedAccessException-nel leáll (hordozható módban az Utak létrehozni próbálja az Adat mappát). Megoldás: a README-ben jelezd, hogy a hordozható módot írható helyre (Asztal, pendrive, saját mappa) kell kicsomagolni, és a program adjon érthető hibaüzenetet.
Mit tegyél ide: a Fájlkezelő a %AppData% és %LocalAppData% program-mappáival, és az „Adatmappa megnyitása” menü.Javasolt fájlnév: winforms-14-7-adatmappa.webp · Alt szöveg: A program adatmappái az AppData alatt
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. Access denied telepítés után
A program a saját mappájába ír. Program Files alatt nincs írási jog. A beállítások az Ok és javítás
ApplicationData, az adatok és naplók a LocalApplicationData mappába kerüljenek (az Utak osztályon át).
2. A frissítés után eltűntek a beállítások
Az 1.1 verzió alapértékekkel indul.Ok és javítás
Properties.Settings verziónkénti mappája: Settings.Default.Upgrade(), vagy verziófüggetlen JSON fájl.
3. A frissített felhasználónál no such column
A friss telepítés jó, a frissített nem. Nincs séma-migráció (Ok és javítás
CREATE TABLE IF NOT EXISTS nem módosít). PRAGMA user_version és sorrendben lefuttatott ALTER TABLE lépések; teszteld régi adatbázissal.
4. A sérült beállításfájl miatt nem indul
A program A betöltés nem kezeli a sérült fájlt. JsonException-nel leáll.Ok és javítás
try–catch, és alapértékekkel induljon (a sérült fájlról másolat, és naplózás).
5. A felhasználó nem találja az exportot
A program a rejtett AppData mappába exportált. Amit a felhasználó keres, az a Dokumentumok mappába való (vagy Mentés másként ablak); és jelezd az útvonalat az üzenetben.Ok és javítás
6. Két felhasználó adata összekeveredik
Egy közös gépen mindenki ugyanazt a beállítást látja. A beállítások a Ok és javítás
ProgramData vagy a program mappa alá kerültek. Felhasználónkénti adat az ApplicationData/LocalApplicationData mappába való (minden felhasználónak saját).
Mini projekt: adatkezelés központi Utak osztállyal
Rendezd át egy meglévő programodat (például a 13.10 diáknyilvántartót) úgy, hogy telepítés után is helyesen működjön, és próbáld ki három helyzetben:
- Utak osztály: hozd létre az
Utakosztályt (a leckéből), és cseréld le a programban az összes beégetett elérési utat (C:\...,AppContext.BaseDirectoryírás,Environment.CurrentDirectory). - Beállítások: készíts
BeallitasokJSON osztályt (ablakméret, utolsó mappa, frissítés-ellenőrzés be/ki), alapértékekkel, sérült fájl kezelésével, biztonságos mentéssel. - Adatbázis: az SQLite fájl az
Utak.AdatbazisFajlalatt;Inicializalmigrációval (user_version1 → 2: újosztalyoszlop), biztonsági másolattal. - Napló: a naplózó (13.7 lecke) a
Utak.NaploMappamappába ír. - Export: a CSV-export a Dokumentumok mappába kerül (
Utak.ExportMappa+ almappa), az üzenet kiírja az útvonalat. - Menü: Súgó → Adatmappa megnyitása és Beállítások mappa megnyitása (
Process.Start). - Első indítás próba: töröld az adatmappákat; indítsd a programot; az üdvözlő üzenet jelenjen meg, minden mappa és az adatbázis jöjjön létre.
- Migráció próba: készíts 1-es verziójú adatbázist (az
osztalyoszlop nélkül,user_version = 1, néhány sorral); indítsd az új programot; ellenőrizd, hogy az oszlop megjelent, az adat megmaradt, a.baklétrejött, auser_version2 lett. - Jogosultsági próba: állítsd az adatmappát csak olvashatóra (Tulajdonságok → Csak olvasható, vagy a biztonsági fülön tiltsd az írást), és indítsd a programot: érthető hibaüzenet és kontrollált kilépés legyen, nem összeomlás.
- Hordozható mód: tegyél
portable.txtfájlt a program mellé; az adatok a programAdatmappájában jelenjenek meg (írható helyen); jegyezd fel a viselkedést a README-be.
Megoldás megnyitása (próbáld ki előbb önállóan!)
// Egy 1-es verziójú adatbázis előállítása a próbához (csak a teszthez: ezt futtasd, MIELŐTT az új program indul)
public static void RegiAdatbazis(string ut)
{
if (File.Exists(ut)) { File.Delete(ut); }
using (SqliteConnection kap = new SqliteConnection("Data Source=" + ut))
{
kap.Open();
string[] sql = {
"CREATE TABLE diak (id INTEGER PRIMARY KEY, nev TEXT NOT NULL)",
"INSERT INTO diak (nev) VALUES ('Anna'), ('Béla')",
"PRAGMA user_version = 1"
};
foreach (string s in sql)
{
using (SqliteCommand c = kap.CreateCommand()) { c.CommandText = s; c.ExecuteNonQuery(); }
}
}
}
// Ellenőrzés a migráció után (az új program indulása után)
using (SqliteConnection kap = Adatbazis.Nyit())
using (SqliteCommand c = kap.CreateCommand())
{
c.CommandText = "SELECT nev, osztaly FROM diak"; // az osztaly oszlop már létezik, alapértéke üres
using (SqliteDataReader r = c.ExecuteReader()) { while (r.Read()) { System.Diagnostics.Debug.WriteLine(r.GetString(0) + " / '" + r.GetString(1) + "'"); } }
}Várt tapasztalat: az Anna és Béla sor megmarad, az osztaly mező üres (alapérték); a PRAGMA user_version 2; a diakok.db.bak létrejött. A csak olvasható mappánál a program az UnauthorizedAccessException-t elkapja, kiírja az útvonalat, és kilép. A pontos üzenetek a Windows nyelvétől és verziójától függnek.
Mit tegyél ide: a program menüje az „Adatmappa megnyitása” pontokkal, és a migráció előtti-utáni adatbázis.Javasolt fájlnév: winforms-14-7-kesz.webp · Alt szöveg: A program adatmappái és a migráció eredménye
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. Adatok átvitele
A felhasználó új gépre költözik. Hogyan viheti át az adatait? Az adatmappa (vagy az adatbázis és a beállításfájl) másolása; még jobb egy beépített Biztonsági mentés / Visszaállítás menü (ZIP az adatmappából a Dokumentumok alá), amely ellenőrzi a verziót és a sérülést.Egy lehetséges megoldás
2. Settings Upgrade
Írd meg a A beállításokban egy Settings.Default.Upgrade() hívást úgy, hogy csak az első indításkor (új verziónál) fusson.Egy lehetséges megoldás
bool UpgradeSzukseges (alapérték true); induláskor: if (Settings.Default.UpgradeSzukseges) { Settings.Default.Upgrade(); Settings.Default.UpgradeSzukseges = false; Settings.Default.Save(); }.
3. Titok tárolása
A program egy API-kulcsot tárol. Hol és hogyan? Lehetőleg ne tárold; ha kell, Egy lehetséges megoldás
ProtectedData.Protect (DPAPI, DataProtectionScope.CurrentUser) titkosítva az ApplicationData mappában; a kulcsot a forráskódba és a verziókezelésbe ne tedd.
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. Hová mit?
Hová teszed: (a) a beállításokat; (b) az adatbázist; (c) az exportált CSV-t? (a) Megoldás megnyitása
ApplicationData; (b) LocalApplicationData; (c) MyDocuments (a felhasználó mappája).
2. Írható-e?
Írhat-e a program a Program Files mappába normál felhasználóként? Nem: Megoldás megnyitása
UnauthorizedAccessException; a felhasználói adatot máshová kell tenni.
Közepes szint
3. Roaming vagy local?
Mi a különbség? A roaming a felhasználóval vándorol hálózati profil esetén (kis, fontos adat); a local gépen marad (nagy adat, gyorsítótár).Megoldás megnyitása
4. Alapérték
Miért kell alapérték a beállításokban? Az újabb verzió új beállításai hiányozhatnak a régi fájlból; az alapérték helyes működést ad, nem Megoldás megnyitása
null/false hibát.
Kihívás szint
5. Migráció
Miért nem elég a Nem módosítja a már létező táblát: az új oszlop nem jön létre. Verziózott migráció (CREATE TABLE IF NOT EXISTS a frissítéshez?Megoldás megnyitása
user_version és ALTER TABLE) kell.
6. Teszt régi adattal
Hogyan teszteled, hogy a frissítés megőrzi a felhasználó adatait? Az előző verzióval létrehozott (vagy mentett) adatbázison és beállításfájlon futtatod az új programot, és ellenőrzöd az adatok, a séma és a verzió helyességét; a friss telepítés önmagában nem elég.Megoldás megnyitása
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. Az Az elérési utak egy helyen élnek; a hordozható mód és a mappák cseréje egy helyen módosítható. A fájl sémájának verziója: a migrációhoz. Az SQLite adatbázis általad használt séma-verziószáma. A mappák, az adatbázis és az alapbeállítások létrehozása, ha még nincsenek. Érthető hibaüzenettel és kontrollált kilépéssel (vagy másik hely felajánlásával), nem összeomlással. A 1. Hová ír a program?
AppData mappákba, nem a program mappájába.2. Mi az Utak osztály haszna?
3. Mire jó a Verzio a beállításokban?
4. Mit jelent a user_version?
5. Mi az első indítás?
6. Hogyan kezeled a nem írható mappát?
7. Mi a hordozható mód?
portable.txt jelzi, hogy az adatok a program melletti mappába kerülnek (írható helyen).
Mit tudsz már?
- Eldöntöd, melyik adat hová kerül (program mappa,
ApplicationData,LocalApplicationData,MyDocuments). - Központi
Utakosztállyal kezeled az elérési utakat és a hordozható módot. - Beállításokat mentesz alapértékkel és verzióval, és adatbázist migrálsz
user_versionsegítségével. - Kezeled az első indítást és a jogosultsági hibákat.
Következő lecke: Ikon, verzió, szerző és About
A program arculata és azonosítása: az ikon, a verziószám, a szerzői adatok és a Névjegy ablak.



