programozás iii
DESCRIPTION
Programozás III. Automatikus állapotértesítés adatkötéskor (…Changed, INofityPropertyChanged, ObservableCollection) Adatformázások Adatkonverziók Erőforrások. Példa. Cél: a személy neve legyen kiírva (adatkötés DataContext állítással), a gombbal lehessen változtatni - PowerPoint PPT PresentationTRANSCRIPT
V 1.0
Programozás III.
Automatikus állapotértesítés adatkötéskor(…Changed, INofityPropertyChanged, ObservableCollection<T>, DataTemplate)
Adatformázások
V 1.0 ÓE-NIK, 2014
Példa
• Cél: a személy neve legyen kiírva (adatkötés DataContext állítással), a gombbal lehessen változtatni
• Adatkötés a XAML-ben:
2
public MainWindow(){ InitializeComponent(); aktualisSzemely = new Szemely("Piros Péter"); this.DataContext = aktualisSzemely;}
<Label Content="{Binding Nev}"/>
V 1.0 ÓE-NIK, 2014
Példa folytatás
• A gomb Click eseménykezelője:
• A konzol kiírás szerint megtörtént a változtatás…
• … az adatkötésben semmi sem látszik!3
private void Button_Click(object sender, RoutedEventArgs e){ aktualisSzemely.Nev = "Kék Péter"; Console.WriteLine(aktualisSzemely.Nev); }
V 1.0 ÓE-NIK, 2014
Automatikus állapotértesítés adatkötéskor• Ahhoz, hogy az adatkötések működjenek, a kötés
céljának értesítést kell kapnia a forrás adott tulajdonságának a megváltozásáról– Eddigi kötéseinkben többnyire keretrendszeri osztályok
tulajdonságai voltak a források…• Pl. a Slider Value tulajdonsága volt a forrás, és a Label Content-je a cél• Ezekben meg van oldva, hogy az adatkötés célját értesíteni tudják
– … vagy pedig saját objektum volt a forrás, de csak az adatkötésen keresztül változtattuk benne az adatot
• Pl. a lejátszási listás példaprogramban a Szám típusú objektumok Megjegyzés tulajdonsága volt a forrás, ezt változtatgattuk az adatkötésen keresztül
• Saját objektumaink alapesetben nem küldenek értesítést a változásukról!
4
V 1.0 ÓE-NIK, 2014
Automatikus állapotértesítés adatkötéskor• Módszerek:
1. A függőségi tulajdonságok képesek arra, hogy megváltozásukról automatikus értesítést küldjenek. Megoldás: a forrástulajdonság ne sima, hanem függőségi tulajdonság legyen! (nem tárgyaljuk)
2. …Changed esemény kiváltása a tulajdonság változásakor3. INotifyPropertyChanged interfész implementálása
5
V 1.0 ÓE-NIK, 2014
Állapotértesítés – …Changed esemény• A tulajdonság értékének változásakor tüzeljen egy …
Changed esemény (…=tulajdonság neve)• Az eseményre való feliratkozás az adatkötéskor
automatikus
6
public event EventHandler NevChanged;public string Nev{ get { return nev; } set { nev = value; EventHandler nevChanged = NevChanged; if (nevChanged != null) nevChanged(this, EventArgs.Empty); }}
V 1.0 ÓE-NIK, 2014
Állapotértesítés – INotifyPropertyChanged• A tulajdonságot deklaráló osztály implementálja az
INotifyPropertyChanged interfészt (System.ComponentModel)• Ebben egyetlen esemény van
– public event PropertyChangedEventHandler PropertyChanged;• Ez tüzeljen a tulajdonság értékének változtatásakor, az
EventArgs paramétere a tulajdonság neve legyen– string.Empty vagy null, ha az összes tulajdonság megváltozott
7
public string Nev{ get { return nev; } set { nev = value; PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs("Nev")); }}
V 1.0 ÓE-NIK, 2014
Állapotértesítés – INotifyPropertyChanged• Előny az előzőhöz képest: nem kell annyi esemény• Gyakran egynél több tulajdonságnál akarják használni:
OnPropertyChanged()
8
private void OnPropertyChanged(string propertyName){ PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));}
public string Nev{ get { return nev; } set { nev = value; OnPropertyChanged("Nev"); }}
V 1.0 ÓE-NIK, 2014
Állapotértesítés – INotifyPropertyChanged• OnPropertyChanged(), a .NET4.5- ben
9
private void OnPropertyChanged([CallerMemberName] string propertyName=""){ PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));}
public string Nev{ get { return nev; } set { nev = value; OnPropertyChanged(); }}
V 1.0 ÓE-NIK, 2014
Állapotértesítés – Problémák gyűjteményekkel• Gyűjtemény típusú forrástulajdonságnál az
adatkötött GUI-elem (pl. ListBox) a forrásgyűjtemény lecserélését detektálja csak, ha az OnPropertyChanged()-et a setterben hívjuk
• Ez nem detektálja:– Ha a gyűjtemény valamelyik elemét lecseréljük– Add()/Remove()/Insert()…– Ha a gyűjtemény valamelyik elemének egy tulajdonságát
módosítjuk 10
public List<HirlevelFeliratkozas> HirlevelFeliratkozasok{ get { return hirlevelFeliratkozasok; } set { hirlevelFeliratkozasok = value; OnPropertyChanged("HirlevelFeliratkozasok"); //??? }}
V 1.0 ÓE-NIK, 2014
Állapotértesítés – Problémák gyűjteményekkel
11
List<HirlevelFeliratkozas> uj = new List<HirlevelFeliratkozas>();uj.Add(new HirlevelFeliratkozas("gyereknevelés", true));aktualisSzemely.HirlevelFeliratkozasok = uj; //jó aktualisSzemely.HirlevelFeliratkozasok[0] = new HirlevelFeliratkozas("gyereknevelés", true); //nem jóaktualisSzemely.HirlevelFeliratkozasok.Add( new HirlevelFeliratkozas("gyereknevelés", true)); //nem jó
aktualisSzemely.HirlevelFeliratkozasok[0].Aktiv = false; //nem jó
V 1.0 ÓE-NIK, 2014
Állapotértesítés – ObservableCollection<T>• List<T>-hez hasonlóan kell használni
– System.Collections.ObjectModel
• Értesítést küld:– Ha a gyűjtemény valamelyik elemét lecseréljük– Add()/Remove()/Insert()– Elem tulajdonságának módosításakor NEM!
• INotifyCollectionChanged interfészt implementál• Saját osztályaink számára is implementálható, de akkor a fenti esetekre
mind gondolni kell
12
private ObservableCollection<HirlevelFeliratkozas> hirlevelFeliratkozasok;public ObservableCollection<HirlevelFeliratkozas> HirlevelFeliratkozasok{ get { return hirlevelFeliratkozasok; } set { hirlevelFeliratkozasok = value; OnPropertyChanged("HirlevelFeliratkozasok"); //??? }}
V 1.0 ÓE-NIK, 2014
Állapotértesítés – ObservableCollection<T>
13
ObservableCollection<HirlevelFeliratkozas> uj = new ObservableCollection<HirlevelFeliratkozas>();uj.Add(new HirlevelFeliratkozas("gyereknevelés", true));aktualisSzemely.HirlevelFeliratkozasok = uj; //jó aktualisSzemely.HirlevelFeliratkozasok[0] = new HirlevelFeliratkozas("gyereknevelés", true); //jóaktualisSzemely.HirlevelFeliratkozasok.Add( new HirlevelFeliratkozas("gyereknevelés", true)); //jó
aktualisSzemely.HirlevelFeliratkozasok[0].Aktiv = false; //nem jó!
V 1.0 ÓE-NIK, 2014
Állapotértesítés – Fennmaradó problémák• ToString()-es kiírásaink sohasem frissülnek…
– Lehetőleg elkerüljük a használatát!– Helyette: ha Contentben akarjuk kiíratni a „teljes
objektumot” (=több tulajdonság), a Contentbe tartalommenedzsert és abba több vezérlőt teszünk, és ezekhez egyenként adatkötés
– Esetleg ha több vezérlőnél kell, akkor DataTemplate– Vagy ha ListBoxban akarjuk kilistázni az objektumokat, akkor
DataTemplate vagy saját vezérlő…
14
V 1.0 ÓE-NIK, 2014
Állapotértesítés – Fennmaradó problémák• Tulajdonság tulajdonságának változása
– Tulajdonságot pl. tartalommenedzser vagy DataTemplate DataContextjéhez rendelik, altulajdonságokat az abban lévő UI-elemek mutatják
– Vagy komplex Path (pl: {Binding HaziAllat.Harap}) – Vagy gyakran pl. saját vezérlő…
• Gyűjtemény elemének tulajdonságváltozása– Gyakran DataTemplate-ekkel, saját vezérlővel…
• Minden korrekt megoldáshoz kell:– INotifyPropertyChanged implementálása az adatkötésben
felhasznált összes osztályban – ObservableCollection<T> a többi gyűjtemény helyett
15
V 1.0 ÓE-NIK, 2014
Állapotértesítés – Tulajdonság tulajdonságának változása
• Tartalmazó Window DataContext-je a Szemely példány
16
<Label Content="{Binding Nev}"/><Grid DataContext="{Binding Allat}"> <Label Content="{Binding Nev}"/> <Label Content="{Binding Harap}"/></Grid>
class Szemely : INotifyPropertyChanged { … private Allat allat; public Allat Allat { get { return allat; } set { allat = value; OnPropertyChanged("Allat"); } }}
V 1.0 ÓE-NIK, 2014
Állapotértesítés – Gyűjtemény elemének tulajdonságváltozása – DataTemplate példa
17
class Szemely : INotifyPropertyChanged{ … private ObservableCollection<HirlevelFeliratkozas> hirlevelFeliratkozasok; public ObservableCollection<HirlevelFeliratkozas> HirlevelFeliratkozasok { get { return hirlevelFeliratkozasok; } set { hirlevelFeliratkozasok = value; OnPropertyChanged("HirlevelFeliratkozasok"); } } //+HirlevelFeliratkozas osztályban is implementálvafy-} //van az INotifyPropertyChanged<ListBox ItemsSource="{Binding HirlevelFeliratkozasok}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <Label Content="{Binding Tema}"/> <Label Content="{Binding Aktiv}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate></ListBox>
Az ItemsControloknak az ItemTemplate, a ContentControloknak a ContentTemplate tulajdonságába mehet ilyen DataTemplate, Gridnél CellTemplate… stb.
V 1.0 ÓE-NIK, 2014
Feladat
• HF: az összeállított pizza ListBox-ba való helyezése• HF: Az összeállított pizzák file-ba történő elmentése,
illetve betöltése
18
V 1.0 ÓE-NIK, 2014
Feladat
19