Vizuális programozás 1. A gyakorlat célja A gyakorlat célja a Könyvtár alkalmazás folytatása az előző gyakorlaton elkészített grafikus felület felhasználásával. Elsőként lemásoljuk az előző gyakorlat eredményeként elkészült http://johanyak.hu/files/u1/segedlet/vizualis_programozas/gyak_fel_08_Konyvtar.zip projektet, majd a 7. gyakorlaton megismerteknek megfelelően létrehozzuk az adatbázist a lokális SQLEXPRESS szerveren. Ezt követően megnyitjuk a Konyvtar_FF nevű WPF alkalmazást. A gyakorlat során az alábbi ábrán látható négy entitáshoz kapcsolódó adatbevitelt fogjuk megoldani.
2. A feladatot megvalósító kód A középpontban a könyvek felvitele áll, a többi entitást ehhez kapcsolódóan fogjuk megadni.
2.1. Mentés és kilépés A feladatokat megoldó két eseménykezelő metódust a wndFoablak.xaml.cs állományban hozzuk létre. A mentés feladata az 1
entitáshalmazokon végrehajtott módosítások lementése az adatbázisba. private void miMentés_Click(object sender, RoutedEventArgs e) { conKonyvtar.SaveChanges(); } private void miKilépés_Click(object sender, RoutedEventArgs e) { Application.Current.Shutdown(); }
2.2. Könyvadatok rögzítése Elsőként meg kell jelenítenünk a főablakon belül a feladatot megoldó űrlapot. Ezt a menüponthoz kapcsolódó eseménykezelőben tesszük meg. private void miKönyvRögzít_Click(object sender, RoutedEventArgs e) { ucKönyvRögzít.Visibility = Visibility.Visible; }
Létrehozzuk az entitáskonténer objektumot, majd tároljuk a konténer objektum referenciáját az alkalmazás tulajdonságai között, így az minden ablakból/user control-ból elérhető lesz. /// <summary> /// Az entitáskonténer objektum. /// private conKonyvtar conKönyvtár; /// <summary> /// Az ablak konstruktora. /// public wndFőablak() { InitializeComponent(); // Létrehozzuk az entitáskonténer objektumot. conKönyvtár = new conKonyvtar(); // Tároljuk a konténer objektum referenciáját az alkalmazás // tulajdonságai között, így az minden ablakból/user control-ból // elérhető lesz. Application.Current.Properties["conKönyvtár"] = conKönyvtár; }
Az űrlap megvalósításánál alapkoncepciónk az, hogy csak akkor történik adatrögzítés a memóriában levő entitáshalmazok valamelyikébe, ha a felhasználó kattint a Rögzít gombon, ezért kezdetben az 2
entitáshalmazon kívül kell ideiglenesen tárolnunk az újonnan felvitt kiadókat, szerzőket és könyveket. Emellett a könyvhöz tartozó szerzők és kiadók esetében tárolnunk kell, hogy ők új szerzők/kiadók-e. Az adatrögzítést szolgáló UserControl osztályában (ucKonyvRogzit.xaml.cs) először létrehozzuk a feladat megoldásához szükséges adattagokat. /// <summary> /// Az entitáskonténer objektum. /// private conKonyvtar conKönyvtár; /// <summary> /// Az aktuális könyv objektum. /// private Konyv Könyv; /// <summary> /// A könyv kiadója egy új kiadó-e, vagy már szerepel az adatbázisban. /// private bool ÚjKiadó; /// <summary> /// A könyv szerzői egy új szerzők-e, vagy már szerepelnek az adatbázisban. /// private List
ÚjSzerző;
Alapértelmezésben feltételezzük, hogy úgy a kiadó, mint a szerzők már szerepelnek az adatbázisban. /// <summary> /// A usercontrol konstruktora. /// public ucKönyvRögzít() { InitializeComponent(); // Alapértelmezésben feltételezzük, hogy úgy a kiadó mint a szerzők már szerepelnek az // adatbázisban. ÚjKiadó = false; ÚjSzerző=new List(); }
Amikor az űrlap láthatóvá válik, kiolvassuk az alkalmazás tulajdonságai közül az entitáskonténer objektum referenciáját, létrehozunk egy könyv objektumot kezdőértékekkel, és az űrlap adatforrásaként megadjuk a könyv objektumot. A felület elkészítésekor definiált adatkötések tesztelése érdekében a könyv objektumot inicializálással hozzuk létre, úgy, hogy kezdőértékeket adunk a kapcsolódó objektumok számára is. /// <summary> /// Az űrlap láthatóvá válik. /// private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { 3
// Az entitás objektum referenciájának kiolvasása és eltárolása egy adattagban. conKönyvtár = Application.Current.Properties["conKönyvtár"] as conKonyvtar; // Könyv objektum létrehozása. Könyv = new Konyv() // Az alábbi inicializálás csak tesztelési célt szolgál. { Kiado = new Kiado {Név = "Springer", Székhely = "New York"}, Ár = 27106,Cím = "Artificial Immune Systems",KiadásiÉv = 2011, KonyvPeldanyok = new EntityCollection{ new KonyvPeldany{KönyvtáriAzonosító = "15687"}}, Szerzok = new EntityCollection<Szerzo>{new Szerzo{Vezetéknév ="Lió",Utónév = "Pietro"}} }; // Az űrlap adatforrásaként megadjuk a könyv objektumot. DataContext = Könyv; }
Amennyiben minden adat megjelenik helyesen, töröljük az inicializálást a kódból. Az adatrögzítés funkcionalitás megvalósítását a megoldandó feladatok szerint négy csoportba bontva tekintjük át. 2.2.1. Cím, Kiadási év és Ár A Cím, Kiadási év és Ár mezők egyszerűen kitölthetőek, és a felületet leíró XAML kódban már kötve lettek a megfelelő adattagokhoz.
4
Ellenőrzés Az ellenőrzést végző kóddal azt szeretnénk elérni, hogy amikor a felhasználó érvénytelen értéket ír be, akkor az adott szövegmező piros kerettel jelenjen meg. Továbbá a Rögzít gombon történő kattintáskor az érvénytelen szövegmező kapja meg az input fókuszt, és a gyorstippben jelenjen meg a hibaüzenet az alábbi mintáknak megfelelően.
A cím, kiadási év és ár adatok ellenőrzéséhez létrehozunk három validációs szabályt. Ehhez definiálunk három leszármazott osztályt (vrCím, vrÉv és vrÁr) a ValidationRules osztályhoz, majd átdefiniáljuk bennük a Validate virtuális metódust.
5
public class vrCím:ValidationRule { /// <summary> /// Ellenőrzi a Cím szerkesztőmezőbe beírt értéket. /// /// <param name="value">A szerkesztőmező tartalma. /// <param name="cultureInfo">The culture to use in this rule. /// Egy <see cref="T:System.Windows.Controls.ValidationResult"/> objektum, ami jelzi /// az érvényességet (true/false), és tartalmazza a hibaüzenetet. 6
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { string Cím=value as string; // A cím mező nem állhat üresen. return Cím==null || Cím.Length==0 ? new ValidationResult(false, "A cím megadása kötelező") : new ValidationResult(true, null); } }
class vrÉv:ValidationRule { /// <summary> /// Ellenőrzi az Év szerkesztőmezőbe beírt értéket. /// /// <param name="value">A szerkesztőmező tartalma. /// <param name="cultureInfo">The culture to use in this rule. /// Egy <see cref="T:System.Windows.Controls.ValidationResult"/> objektum, ami jelzi /// az érvényességet (true/false) és tartalmazza a hibaüzenetet. public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { string sÉv = value as string; // Az év megadása kötelező. if (sÉv == null) return new ValidationResult(false, "A kiadási év megadása kötelező!"); // Az év pozitív egész kell legyen és kisebb vagy egyenlő mint az aktuális év. Int16 Év; bool siker = Int16.TryParse(sÉv, out Év) && Év >= 1 && Év <= DateTime.Now.Year; if (!siker) return new ValidationResult(false, "Az év 1 és " + DateTime.Now.Year + " közötti pozitív érték kell legyen!"); // A megadott érték érvényes. return new ValidationResult(true, null); } }
class vrÁr:ValidationRule { /// <summary> /// Ellenőrzi az Ár szerkesztőmezőbe beírt értéket. /// /// <param name="value">A szerkesztőmező tartalma. /// <param name="cultureInfo">The culture to use in this rule. /// Egy <see cref="T:System.Windows.Controls.ValidationResult"/> objektum, ami jelzi /// az érvényességet (true/false) és tartalmazza a hibaüzenetet. public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { 7
string sÁr = value as string; // Az ár megadása kötelező. if(sÁr==null) return new ValidationResult(false,"Ár megadása kötelező!"); // Az ár pozitív egész kell legyen. Int16 Ár; bool siker = Int16.TryParse(sÁr, out Ár)&& Ár>=0; if(!siker) return new ValidationResult(false,"Az ár 0 és "+Int16.MaxValue+ " közötti pozitív érték kell legyen!"); // A megadott érték érvényes. return new ValidationResult(true,null); } }
A szabályok végrehajtása (kiértékelése) érdekében néhány apróbb módosítás szükséges a UserControl XAML kódjában. Először a gyökértagben felvesszük a projektünk névterét, így lehetőségünk lesz arra, hogy hivatkozzunk a validációs szabály osztályokra.
Következő lépésként átalakítjuk a három szövegmezőre vonatkozó részt úgy, hogy az adatkötés definíciójába beépítjük a validációs szabályok hivatkozását is. … 8
… 2.2.2. Példány hozzáadása A példány hozzáadása gombon történő kattintás engedélyezi a Könyvtári azonosító szövegmezőt és az alatta levő gombot, ahol a felhasználó felvihet egy újabb azonosítót, azaz könyvpéldányt. A gombon kattintva a példány azonosítója felhasználásával egy új KonyvPeldany objektumot hozunk létre, amit felveszünk a könyv objektum által hivatkozott KonyvPeldanyok gyűjteménybe. Az adatkötésnek köszönhetően az azonosító megjelenik a bal oldali listadobozban. A feladatot megvalósító két eseménykezelő (érintett nyomógombok eseménykezelői) az alábbiak. /// <summary> /// Kattintás a Példány hozzáadása gombon. /// /// <param name="sender">A nyomógomb objektum. /// <param name="e"> private void btKrPéldányHozzáadása_Click(object sender, RoutedEventArgs e) { // A jobb oldali StackPanel engedélyezése. spKrKönyvtáriAzonosító.IsEnabled = true; // A Példány hozzáadása gomb tiltása. 9
btKrPéldányHozzáadása.IsEnabled = false; // A könyvtári azonosító bevitelére szolgáló szövegmező ürítése. tbKrKönyvtáriAzonosító.Text = ""; }
/// <summary> /// Kattintás a Példányt rögzít gombon. /// /// <param name="sender">A nyomógomb objektum. /// <param name="e"> private void btKrKaRögzít_Click(object sender, RoutedEventArgs e) { // A jobb oldali StackPanel tiltása. spKrKönyvtáriAzonosító.IsEnabled = false; // A Példány hozzáadása gomb engedélyezése. btKrPéldányHozzáadása.IsEnabled = true; // Új könyvpéldány hozzáadása a KonyvPeldanyok gyűjteményhez. Könyv.KonyvPeldanyok.Add( new KonyvPeldany { KönyvtáriAzonosító = tbKrKönyvtáriAzonosító.Text }); } 2.2.3. Kiadó megadása A USerControlon szereplő kiadó szövegmező (tbKrKiadó) csak olvasható. A Kiadó megadása/kiválasztása gombon kattintva először létrehozzuk a párbeszédablak objektumot. Ha a felhasználó a Rögzít nyomógombbal zárta be a párbeszédablakot, akkor kiolvassuk, hogy a megadott kiadó egy új kiadó-e (még nem szerepel az adatbázisban), kiolvassuk a felhasználó által megadott adatokból létrehozott kiadó objektum referenciáját, és gondoskodunk a kiadói adatok megjelenítéséről.
/// <summary> /// Kattintás a Kiadó megadása/kiválasztása gombon. /// /// <param name="sender">A nyomógomb objektum. /// <param name="e"> private void btKrKiadóMegadása_Click(object sender, RoutedEventArgs e) { // Párbeszédablak objektum létrehozása. var wndKiadó = new wndKiadó(); // Párbeszédablak megjelenítése. var er = wndKiadó.ShowDialog(); // Kilépés, ha a felhasználó a Mégse gombbal zárta be a párbeszédablakot. if (er != true) return; // Kiolvassuk, hogy a megadott kiadó egy új kiadó-e (még nem szerepel az adatbázisban). ÚjKiadó = wndKiadó.ÚjKiadó; 10
// A felhasználó által megadott adatokból létrehozott kiadó objektum. Könyv.Kiado = wndKiadó.Kiadó; // A kiadói adatok megjelenítése. tbKrKiadó.Text = Könyv.KiadóLeírás; }
A párbeszédablak osztályában egy adattagra és két tulajdonságra lesz szükségünk. /// <summary> /// Az entitáskonténer objektum. /// private conKonyvtar conKönyvtár; /// <summary> /// A kiadó objektum. /// public Kiado Kiadó { get; private set; } /// <summary> /// A megadott kiadó egy új kiadó-e (még nem szerepel az adatbázisban)? /// public bool ÚjKiadó { get; private set; }
Mindkét tulajdonság automatikus tulajdonság, a private megkötéssel azt érjük el, hogy csak az osztályon belül állítható be az értéke. A párbeszédablak konstruktorában kiolvassuk az entitás objektum referenciáját és eltároljuk azt egy adattagban. A párbeszédablakban egy legördülő listából választhatunk az adatbázisban szereplő kiadók közül. Ehhez a konstruktorban adatforrásként meg kell adnunk a kiadók entitáshalmazát. public wndKiadó() { InitializeComponent(); // Az entitás konténer objektum referenciájának kiolvasása és eltárolása egy adattagban. conKönyvtár = Application.Current.Properties["conKönyvtár"] as conKonyvtar; // Adatforrás megadása a legördülő listához. cbKiadók.ItemsSource = conKönyvtár.Kiadok; // Alapértelmezés szerint a kiadó már szerepel az adatbázisban. ÚjKiadó = false; }
11
Amennyiben a felhasználó az Új kiadó megadása gombon kattint, akkor engedélyeznünk kell az új kiadó nevének és székhelyének megadását lehetővé tevő StackPanel-t. /// <summary> /// Kattintás az Új kiadó gombon. /// /// <param name="sender">A nyomógomb objektum. /// <param name="e"> private void btÚjKiadó_Click(object sender, RoutedEventArgs e) { // Az új kiadó nevének és székhelyének megadását lehetővé tevő StackPanel engedélyezése. spKiadóAdatok.IsEnabled = true; }
Amennyiben a felhasználó a rögzít gombon kattint, a StackPanel engedélyezettségi állapotától függően beállítjuk az ÚjKiadó logikai tulajdonság értékét, valamint vagy létrehozunk egy új kiadó objektumot a szerkesztőmezőkben levő értékek alapján vagy eltároljuk a kiválasztott kiadó objektum referenciáját. Végül bezárjuk a párbeszédablakot. /// <summary> /// Kattintás a Rögzít gombon. /// /// <param name="sender">A nyomógomb objektum. /// <param name="e"> private void btKRögzít_Click(object sender, RoutedEventArgs e) { if(spKiadóAdatok.IsEnabled) { // Ha új kiadót adtunk meg, akkor létrehozunk hozzá egy új objektumot inicializálással. Kiadó=new Kiado{Név = tbKiadóNév.Text,Székhely = tbSzékhely.Text}; ÚjKiadó = true; } else { // Ha egy létező kiadót választottunk, akkor tároljuk objektumának referenciáját. Kiadó = cbKiadók.SelectedItem as Kiado; 12
ÚjKiadó = false; } // Párbeszédablak bezárása. DialogResult = true; } 2.2.4. Szerzők megadása A szerzők megadása sok tekintetben a kiadók megadásához hasonlóan történik. A könyv szerzőit egyenként adhatjuk meg. Szerző megadása… gombon történő kattintás egy új ablak megjelenését idézi elő. A kiadó esetéhez képest itt az az eltérés, hogy úgy a szerző objektumok referenciáit, mint az új jellegükre vonatkozó információt itt egy-egy gyűjteményben tároljuk. /// <summary> /// Kattintás a Szerző megadása/kiválasztása gombon. /// /// <param name="sender">A nyomógomb objektum /// <param name="e"> private void btKrSzerzőMegadása_Click(object sender, RoutedEventArgs e) { // Párbeszédablak objektum létrehozása. var wndSzerző = new wndSzerző(); // Párbeszédablak megjelenítése. var er = wndSzerző.ShowDialog(); // Kilépés, ha a felhasználó a Mégse gombbal zárta be a párbeszédablakot. if (er != true) return; // Kiolvassuk, hogy a megadott szerző egy új szerző-e (még nem szerepel az // adatbázisban), és tároljuk a logikai gyűjteményben. ÚjSzerző.Add(wndSzerző.ÚjSzerző); // A szerző objektumot hozzáadjuk a könyv szerzőinek gyűjteményéhez. Könyv.Szerzok.Add(wndSzerző.Szerző); }
A szerző megadására szolgáló párbeszédablak osztályában egy adattagra és két tulajdonságra lesz szükségünk. /// <summary> /// Az entitáskonténer objektum. /// private conKonyvtar conKönyvtár; /// <summary> /// A szerző objektum. /// public Szerzo Szerző { get; private set; } /// <summary> /// A megadott szerző egy új szerző-e (még nem szerepel az adatbázisban)? /// public bool ÚjSzerző { get; private set; } 13
Mindkét tulajdonság automatikus tulajdonság, a private megkötéssel azt érjük el, hogy csak az osztályon belül állítható be az értéke. A párbeszédablak konstruktorában kiolvassuk az entitás objektum referenciáját és eltároljuk azt egy adattagban. A párbeszédablakban egy legördülő listából választhatunk az adatbázisban szereplő szerzők közül. Ehhez a konstruktorban adatforrásként meg kell adnunk a kiadók entitáshalmazát. /// <summary> /// A párbeszédablak konstruktora. /// public wndSzerző() { InitializeComponent(); // Az entitás konténer objektum referenciájának kiolvasása és eltárolása egy adattagban. conKönyvtár = Application.Current.Properties["conKönyvtár"] as conKonyvtar; // Adatforrás megadása a legördülő listához. cbSzerzők.ItemsSource = conKönyvtár.Szerzok; // Alapértelmezés szerint a kiadó már szerepel az adatbázisban. ÚjSzerző = false; }
Amennyiben a felhasználó az Új szerző megadása gombon kattint, akkor engedélyeznünk kell az új kiadó nevének és székhelyének megadását lehetővé tevő StackPanel-t. /// <summary> /// Kattintás az Új szerző gombon. /// /// <param name="sender">A nyomógomb objektum. /// <param name="e"> private void btÚjKiadó_Click(object sender, RoutedEventArgs e) { // Az új szerző adatainak megadását lehetővé tevő StackPanel engedélyezése. spSzerződatok.IsEnabled = true; } 14
Amennyiben a felhasználó a rögzít gombon kattint, a StackPanel engedélyezettségi állapotától függően beállítjuk az ÚjSzerző logikai tulajdonság értékét, valamint vagy létrehozunk egy új szerző objektumot a szerkesztőmezőkben levő értékek alapján vagy eltároljuk a kiválasztott szerző objektum referenciáját. Végül bezárjuk a párbeszédablakot. /// <summary> /// Kattintás a Rögzít gombon. /// /// <param name="sender">A nyomógomb objektum. /// <param name="e"> private void btSzRögzít_Click(object sender, RoutedEventArgs e) { // Ha új szerzőt adtunk meg, akkor létrehozunk hozzá egy új objektumot inicializálással. if(spSzerződatok.IsEnabled) { Szerző=new Szerzo{Vezetéknév = tbVezetéknév.Text, Utónév = tbUtónév.Text}; ÚjSzerző = true; } else { // Ha egy létező szerzőt választottunk, akkor tároljuk objektumának referenciáját. Szerző = cbSzerzők.SelectedItem as Szerzo; ÚjSzerző = false; } // Párbeszédablak bezárása. DialogResult = true; }
Az adatkötésnek köszönhetően a főablakban a szerzők táblázatában megjelenik az új szerző.
2.2.5. Az űrlap mégse nyomógombja A Mégse nyomógombon történő kattintással azt jelzi a felhasználó, hogy nem kívánja megőrizni a felvitt adatokat. Ezért ekkor elrejtjük az űrlapot. /// <summary> /// Kattintás a mégse nyomógombon. /// /// <param name="sender">A nyomógomb objektum. /// <param name="e"> 15
private void btKrMégse_Click(object sender, RoutedEventArgs e) { // Az űrlap elrejtése. Visibility = Visibility.Hidden; } 2.2.5. Az űrlap rögzít nyomógombja A rögzít gombon történő kattintáskor először leellenőrizzük a cím kiadási és ár szövegmezőket. Hiba esetén jelzünk a felhasználónak, lehetőséget adva a javításra. Kiadó megadása kötelező, ennek hiányában, az input fókuszt a megfelelő nyomógombra helyezzük. Amennyiben vannak könyvpéldányok, akkor felvisszük azokat a könyvpéldányok entitás halmazába. A könyvet felvesszük a könyvek entitás halmazába. A kiadónál beállítjuk az aktuális könyvet. Ha ez egy új kiadó, akkor felvesszük a kiadók entitás halmazába. Sorra vesszük a szerzőket, és az aktuális szerzőnél beállítjuk az aktuális könyvet. Ha ez egy új szerző, akkor felvesszük a szerzők entitás halmazába. Végül elrejtjük az űrlapot. /// <summary> /// Kattintás Rögzít gombon. /// /// <param name="sender">A nyomógomb objektum. /// <param name="e"> private void btKrRögzít_Click(object sender, RoutedEventArgs e) { // Ellenőrizzük a cím, kiadási év és ár adatokat. if (!Érvényes(tbKrCím) || !Érvényes(tbKrKiadásiÉv) || !Érvényes(tbKrÁr)) return; // Kiadó megadása kötelező. if (Könyv.Kiado==null) { // Input fókusz a nyomógombra. btKrKiadóMegadása.Focus(); // Hibaüzenet gyorstippben! btKrKiadóMegadása.ToolTip = "Kiadó megadása kötelező!"; return; } // Amennyiben vannak könyvpéldányok, akkor felvisszük azokat a könyvpéldányok // entitás halmazába. foreach (var x in Könyv.KonyvPeldanyok) { conKönyvtár.KonyvPeldanyok.AddObject(x); } // A könyvet felvesszük a könyvek entitás halmazába. conKönyvtár.Konyvek.AddObject(Könyv); // A kiadónál beállítjuk az aktuális könyvet. Könyv.Kiado.Konyvek.Add(Könyv); // Ha ez egy új kiadó, akkor felvesszük a kiadók entitás halmazába. if (ÚjKiadó) conKönyvtár.Kiadok.AddObject(Könyv.Kiado); // Sorra vesszük a szerzőket. Ha nincs megadva szerző, akkor a Count értéke 0. for (int i = 0; i < Könyv.Szerzok.Count; i++) 16
{ // Az aktuális szerzőnél beállítjuk az aktuális könyvet. Könyv.Szerzok.ElementAt(i).Konyvek.Add(Könyv); // Ha ez egy új szerző, akkor felvesszük a szerzők entitás halmazába. if (ÚjSzerző[i]) conKönyvtár.Szerzok.AddObject(Könyv.Szerzok.ElementAt(i)); } // Az űrlap elrejtése. Visibility = Visibility.Hidden; }
/// <summary> /// Ellenőrzi a UserControl-on megadott adatok érvényességét. /// /// true, ha minden adat érvényes, és false egyébként. /// <param name="tb">Az ellenőrzött TextBox. private bool Érvényes(TextBox tb) { // Mivel a szövegmezőkben úgy is lehet érvénytelen adat, ha a felhasználó // be se lépett az adott mezőbe, ezért először kikényszerítjük az ellenőrző // szabály kiértékelését. tb.GetBindingExpression(TextBox.TextProperty).UpdateSource(); // Ha volt hiba if (tb.GetBindingExpression(TextBox.TextProperty).HasError) { // A szövegmező gyorstippjébe tesszük a hibaüzenetet. tb.ToolTip = tb.GetBindingExpression(TextBox.TextProperty).ValidationError.ErrorContent; // Az input fókuszt a szövegmezőre tesszük. tb.Focus(); // Hamis visszatérési értékkel jelezzük, hogy hiba volt. return false; } // Nem volt hiba, a megadott adat érvényes. return true; }
3. További feladat A két párbeszédablaknál az ellenőrzés megvalósítása.
17