Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych Obiekty reprezentują pewne pojęcia, przedmioty, elementy rzeczywistości. Obiekty udostępniają swoje usługi: metody operacje, które możemy na nich wykonać, zadania, które możemy im zlecić. Klasa to przepis na obiekt. Każdy obiekt klasy jest odrębną strukturą. Metoda jest funkcją wywoływaną z konkretnego obiektu. Specjalnie rodzaje metod: o konstruktory o ToString Marek Tabędzki Programowanie obiektowe i zdarzeniowe 1/34
class Drzwi private int licz; public Drzwi() licz = 0; public void wejdź() licz++; public void wyjdź() if (licz > 0) licz--; else Console.WriteLine("W środku nikogo nie ma!"); public override string ToString() return String.Format("Liczba osób w środku: 0.", licz);... Drzwi drzwi = new Drzwi(); drzwi.wyjdź(); drzwi.wejdź(); drzwi.wejdź(); drzwi.wejdź(); drzwi.wyjdź(); Console.WriteLine(drzwi); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 2/34
<Window x:class="wpfapplication1.mainwindow"... Title="Okno" SizeToContent="WidthAndHeight"> <Grid Name="grid"> <Button Margin="5" Padding="5" Click="OnClick"> Click me! </Button> </Grid> </Window>... public partial class MainWindow : Window private void OnClick(object sender, RoutedEventArgs e) grid.fontsize += 5; Marek Tabędzki Programowanie obiektowe i zdarzeniowe 3/34
Publiczne zmienne składowe: // deklaracja: class Osoba public string imię; // użycie: Osoba osoba = new Osoba(); osoba.imię = "Jan"; Console.WriteLine(osoba.imię); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 4/34
Metody dostępowe: // deklaracja: class Osoba private string imię; public void setimię(string imię) this.imię = imię; public string getimię() return imię; // użycie: Osoba osoba = new Osoba(); osoba.setimię("jan"); Console.WriteLine(osoba.getImię()); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 5/34
Właściwości (properties): // deklaracja: class Osoba private string imię; public string Imię get return imię; set imię = value; // użycie: Osoba osoba = new Osoba(); osoba.imię = "Jan"; Console.WriteLine(osoba.Imię); // właściwości można inicjować w trakcie tworzenia obiektu: Osoba osoba2 = new Osoba Imię = "Piotr" ; Marek Tabędzki Programowanie obiektowe i zdarzeniowe 6/34
Właściwości automatyczne (auto-properties): // deklaracja: class Osoba public string Imię get; set; // użycie: Osoba osoba = new Osoba(); osoba.imię = "Jan"; Console.WriteLine(osoba.Imię); // lub: Osoba osoba2 = new Osoba Imię = "Piotr" ; Marek Tabędzki Programowanie obiektowe i zdarzeniowe 7/34
Kompozycja Kompozycja określa relację zawierania się obiektów. Niekiedy wyróżnia się dwa warianty kompozycji: o Kompozycja właściwa o Agregacja Kompozycją określa się sytuację, kiedy kompozyt (i czasem komponent) nie mogą istnieć oddzielnie a liczność komponentów nie zmienia się, związek między obiektami jest bardzo silny (np. Klient i DaneOsobowe) Agregacją określa się sytuację, kiedy kompozyt i komponent mogą istnieć bez siebie, liczność komponentów może się zmieniać dynamicznie, a związek między obiektami jest o wiele słabszy niż w kompozycji właściwej (np. Klient i Konto) Marek Tabędzki Programowanie obiektowe i zdarzeniowe 8/34
Kompozycja właściwa: class DaneOsobowe public string Imię get; set; public string Nazwisko get; set; public string Adres get; set; class Klient public long ID get; set; public DaneOsobowe DaneOsobowe get; set; // i teraz: Klient klient = new Klient(); klient.id = 1; klient.daneosobowe = new DaneOsobowe(); klient.daneosobowe.imię = "Jan"; klient.daneosobowe.nazwisko = "Kowalski"; klient.daneosobowe.adres = "Wiejska 45A"; Marek Tabędzki Programowanie obiektowe i zdarzeniowe 9/34
Kompozycja właściwa: class DaneOsobowe public string Imię get; set; public string Nazwisko get; set; public string Adres get; set; class Klient public long ID get; set; public DaneOsobowe DaneOsobowe get; set; // i teraz: Klient klient = new Klient ID = 1, DaneOsobowe = new DaneOsobowe Imię = "Jan", Nazwisko = "Kowalski", Adres = "Wiejska 45A" ; Marek Tabędzki Programowanie obiektowe i zdarzeniowe 10/34
A co z kontem? class Konto private double suma; public void Wpłać(double kwota) suma += kwota; public void Wypłać(double kwota) suma -= kwota; public double Saldo() return suma; Marek Tabędzki Programowanie obiektowe i zdarzeniowe 11/34
Jeden klient jedno konto: class Klient public Konto Konto get; set; // i teraz: Klient klient = new Klient(); klient.konto = new Konto(); klient.konto.wpłać(100.0); klient.konto.wypłać(50); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 12/34
Przypomnienie konstruktory: class Klient public Konto Konto get; private set; public Klient() Konto = new Konto(); // i teraz: Klient klient = new Klient(); klient.konto = new Konto(); klient.konto.wpłać(100.0); klient.konto.wypłać(50); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 13/34
A jeśli chcemy więcej kont tablica? class Klient private Konto[] konta; public Klient() konta = new Konto[10]; public Konto Konto(int nr) return konta[nr]; public void Załóż(int nr) konta[nr] = new Konto(); // i teraz: Klient klient = new Klient(); klient.załóż(0); klient.załóż(1); klient.konto(0).wpłać(100); klient.konto(1).wpłać(50); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 14/34
Kolekcje (lepsze rozwiązanie od tablic) lista, gdzie każdy element ma swój indeks (może być traktowana jako dynamiczna tablica): List<Element> słownik pewnej wartości klucza przyporządkowują pewną wartość (mogą być traktowane jako uogólnienie tablic): Dictionary<Klucz, Wartość> Tworząc kolekcję określamy rodzaj przechowywanego elementu. List<int> lista1 = new List<int>(); List<string> lista2 = new List<string>(); List<Konto> konta1 = new List<Konto>(); Dictionary<string, int> dic1 = new Dictionary<string, int>(); Dictionary<int, string> dic2 = new Dictionary<int, string>(); Dictionary<int, Konto> konta2 = new Dictionary<int, Konto>(); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 15/34
Posługiwanie się listami: List<string> lista = new List<string>(); Dodawanie elementów. lista.add("a"); // [a] lista.add("b"); // [a, b] lista.add("c"); // [a, b, c] lista.insert(1, "x"); // [a, x, b, c] Przeszukiwanie listy. Console.WriteLine(lista.Contains("b")); // True Console.WriteLine(lista.IndexOf("d")); // -1 Usuwanie elementów. lista.remove("a"); // [x, b, c] lista.removeat(0); // [b, c] Przeglądanie listy. foreach (string str in lista) Console.WriteLine(str); Dostęp do elementów. Console.WriteLine(lista.Count); // 2 Console.WriteLine(lista[1]); // "c" Opróżnianie listy. lista.clear(); // [] Marek Tabędzki Programowanie obiektowe i zdarzeniowe 16/34
Posługiwanie się słownikami: Dictionary<string, string> słownik = new Dictionary<string, string>(); Umieszczanie wartości w słowniku. słownik.add("jeden", "one"); słownik.add("dwa", "two"); słownik.add("trzy", "three"); // "jeden":"one", "dwa":"two", "trzy":"three" Usuwanie wpisów ze słownika. słownik.remove("dwa"); Sprawdzanie, czy pod kluczem jest jakaś wartość. Console.WriteLine(słownik.ContainsKey("jeden")); // True Dostęp do wpisów w słowniku. Console.WriteLine(słownik["trzy"]); // "three" Opróżnianie słownika. słownik.clear(); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 17/34
Klient wersja z listą: class Konto... public int Numer get; set; Klient klient = new Klient(); klient.załóż(10); klient.załóż(20); klient.konto(10).wpłać(100); klient.konto(20).wpłać(50); class Klient private List<Konto> konta = new List<Konto>(); public void Załóż(int nr) konta.add(new Konto Numer = nr ); public Konto Konto(int nr) foreach (Konto konto in konta) if (konto.numer == nr) return konto; return null; Marek Tabędzki Programowanie obiektowe i zdarzeniowe 18/34
Klient wersja z listą: class Konto... public int Numer get; set; Klient klient = new Klient(); klient.załóż(10); klient.załóż(20); klient.konto(10).wpłać(100); klient.konto(20).wpłać(50); class Klient private List<Konto> konta = new List<Konto>(); public void Załóż(int nr) konta.add(new Konto Numer = nr ); public Konto Konto(int nr) return konta.find(konto => konto.numer == nr); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 19/34
Klient wersja ze słownikiem: class Klient private Dictionary<int, Konto> konta; public Klient() konta = new Dictionary<int, Konto>(); public void Załóż(int nr) konta.add(nr, new Konto Numer = nr ); // ale Numer z Konta możemy równie dobrze usunąć public Konto Konto(int nr) return konta[nr]; // interfejs się nie zmienił // zmieniła się implementacja Klient klient = new Klient(); klient.załóż(10); klient.załóż(20); klient.konto(10).wpłać(100); klient.konto(20).wpłać(50); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 20/34
Wiązanie danych (Binding) Mechanizm, który pozwala wydobyć pewne informacje z obiektu źródłowego i zapisać je w pewnym obiekcie docelowym. Obiektem docelowym przeważnie jest jakaś własność w kontrolce WPF (wiązanie danych służy głównie obsłudze interfejsu użytkownika). Obiektem źródłowym może być cokolwiek: inne kontrolki WPF, własne obiekty dowolnych klas, ich własności, kolekcje obiektów, dane XML. Klasyczne podejście polegałoby na obsłudze odpowiednich zdarzeń i ręcznym ustawianiu własności elementów (w kodzie). Wiązanie danych tworzy łącznik między interfejsem graficznym a źródłem danych, odpowiedzialny za ich pobieranie i wyświetlanie. Wiązanie danych w większości dotyczyć będzie wiązania elementów interfejsu użytkownika z przechowywanymi danymi. W momencie zmiany własności obiektu źródłowego, następuje automatyczne powiadomienie i aktualizacja obiektu docelowego. Marek Tabędzki Programowanie obiektowe i zdarzeniowe 21/34
Rozwiązanie przy użyciu zdarzeń: <StackPanel Margin="5"> <Slider Margin="5" Minimum="10" Maximum="50" Value="12" TickFrequency="5" TickPlacement="BottomRight" ValueChanged="slide"/> <Label HorizontalAlignment="Center"> To jest test slidera. </Label> </StackPanel> private void slide(object sender, RoutedPropertyChangedEventArgs<double> e) this.fontsize = e.newvalue; Marek Tabędzki Programowanie obiektowe i zdarzeniowe 22/34
Rozwiązanie przy użyciu wiązania: <StackPanel Margin="5"> <Slider Margin="5" Minimum="10" Maximum="50" Value="12" TickFrequency="5" TickPlacement="BottomRight" Name="slider"/> <Label HorizontalAlignment="Center" FontSize="Binding ElementName=slider, Path=Value"> To jest test slidera. </Label> </StackPanel> Ten sam efekt zero kodu. ElementName wskazujemy na źródło wiązania (skąd pobierzemy wartość) Path wskazuje, którą własność odczytamy z obiektu źródłowego i użyjemy jako wartość naszej własności. Marek Tabędzki Programowanie obiektowe i zdarzeniowe 23/34
Inny przykład: <StackPanel Margin="3"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <Grid.RowDefinitions> <ColumnDefinition/> </Grid.ColumnDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Label Margin="3">Rozmiar</Label> <Label Grid.Row="1" Margin="3">Zawartość</Label> <Label Grid.Row="2" Margin="3">Kolor</Label> <Slider Grid.Column="1" Name="rozmiar" Margin="3" Minimum="12" Maximum="50" TickFrequency="2" Value="18" TickPlacement="TopLeft"/> <TextBox VerticalAlignment="Center" Margin="3" Grid.Row="1" Grid.Column="1" Name="zawartosc">Wpisz zawartość</textbox> <ComboBox VerticalAlignment="Center" Margin="3" Grid.Row="2" Grid.Column="1" Name="kolor"> <ComboBoxItem IsSelected="True">Red</ComboBoxItem> <ComboBoxItem>Green</ComboBoxItem> <ComboBoxItem>Blue</ComboBoxItem> </ComboBox> </Grid> <TextBlock Name="text" Margin="8" HorizontalAlignment="Center" Foreground="Binding ElementName=kolor, Path=SelectedValue.Content" Text="Binding ElementName=zawartosc, Path=Text, UpdateSourceTrigger=PropertyChanged" FontSize="Binding ElementName=rozmiar, Path=Value"/> </StackPanel> Marek Tabędzki Programowanie obiektowe i zdarzeniowe 24/34
Marek Tabędzki Programowanie obiektowe i zdarzeniowe 25/34
Wiązanie do obiektów: <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Label Margin="3">Imię</Label> <Label Margin="3" Grid.Row="1">Nazwisko</Label> <TextBox Margin="3" Grid.Column="1"/> <TextBox Margin="3" Grid.Row="1" Grid.Column="1"/> <Button Margin="3" Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Right" Padding="10,3"> OK </Button> </Grid> Marek Tabędzki Programowanie obiektowe i zdarzeniowe 26/34
public class Osoba public string Imie get; set; public string Nazwisko get; set; public partial class MainWindow : Window private Osoba os = new Osoba Imie = "Jan", Nazwisko = "Kowalski" ;... Marek Tabędzki Programowanie obiektowe i zdarzeniowe 27/34
Rozwiązanie przy użyciu zdarzeń i właściwości: <Window x:class="wpfapplication1.mainwindow" Loaded="WindowLoaded"> <Grid>... <TextBox Name="imię".../> <TextBox Name="nazwisko".../> <Button Click="OnOK"...>OK</Button> </Grid> </Window> Marek Tabędzki Programowanie obiektowe i zdarzeniowe 28/34
public partial class MainWindow : Window private Osoba os = new Osoba Imie = "Jan", Nazwisko = "Kowalski" ; private void WindowLoaded(object sender, RoutedEventArgs e) imię.text = os.imie; nazwisko.text = os.nazwisko; private void OnOK(object sender, RoutedEventArgs e) os.imie = imię.text; os.nazwisko = nazwisko.text; MessageBox.Show(os.Nazwisko + " " + os.imie); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 29/34
Rozwiązanie przy użyciu wiązania danych: <Window x:class="wpfapplication1.mainwindow" Loaded="WindowLoaded"> <Grid>... <TextBox Text="Binding Path=Imie".../> <TextBox Text="Binding Path=Nazwisko".../> <Button Click="OnOK"...>OK</Button> </Grid> </Window> Marek Tabędzki Programowanie obiektowe i zdarzeniowe 30/34
public partial class MainWindow : Window private Osoba os = new Osoba("Jan", "Kowalski"); private void WindowLoaded(object sender, RoutedEventArgs e) this.datacontext = os; private void OnOK(object sender, RoutedEventArgs e) MessageBox.Show(os.Nazwisko + " " + os.imie); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 31/34
Wiązanie z kolekcją obiektów: <Window x:class="wpfapplication1.mainwindow"... Loaded="WindowLoaded"> <DockPanel> <ToolBar DockPanel.Dock="Top"> <Button Click="Dodaj">Dodaj</Button> <Button Click="Usuń">Usuń</Button> </ToolBar> <Grid Margin="3"> <Grid.ColumnDefinitions> <ColumnDefinition Width="2*" /> <ColumnDefinition Width="auto" /> <ColumnDefinition Width="3*" /> </Grid.ColumnDefinitions> <ListBox Margin="3"/> <GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Center"/> <Grid Grid.Column="2"> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Label Margin="3">Imię</Label> <Label Grid.Row="1" Margin="3">Nazwisko</Label> <TextBox Grid.Column="1" Margin="3/> <TextBox Grid.Column="1" Grid.Row="1" Margin="3"/> </Grid> </Grid> </DockPanel> </Window> <RowDefinition Height="auto"/> Marek Tabędzki Programowanie obiektowe i zdarzeniowe 32/34
Przygotowanie okna: <ListBox Name="lista" DisplayMemberPath="Nazwisko"/> <Grid DataContext="Binding ElementName=lista, Path=SelectedItem"> <TextBox Text="Binding Path=Imie".../> <TextBox Text="Binding Path=Nazwisko".../> </Grid> Marek Tabędzki Programowanie obiektowe i zdarzeniowe 33/34
Od strony kodu: public partial class MainWindow : Window private ObservableCollection<Osoba> osoby = new ObservableCollection<Osoba>(); private void WindowLoaded(object sender, RoutedEventArgs e) lista.itemssource = osoby; private void Dodaj(object sender, RoutedEventArgs e) Osoba osoba = new Osoba(); osoby.add(osoba); lista.selecteditem = osoba; private void Usuń(object sender, RoutedEventArgs e) osoby.remove(lista.selecteditem as Osoba); Marek Tabędzki Programowanie obiektowe i zdarzeniowe 34/34