Marek Tabędzki – Programowanie obiektowe i zdarzeniowe 1/34
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 2/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 3/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 4/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 5/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 6/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 7/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 8/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 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(); 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 10/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 11/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 12/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 13/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 14/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 15/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 16/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 17/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 18/34
Klient – wersja z listą:
class Konto { ... public int Numer { get; set; } } 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; } }
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 19/34
Klient – wersja z listą:
class Konto { ... public int Numer { get; set; } } 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); } }
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
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 21/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 22/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 23/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 24/34
Inny przykład: <StackPanel Margin="3"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <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 25/34
Marek Tabędzki – Programowanie obiektowe i zdarzeniowe 26/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 27/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 28/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 29/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 30/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 31/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 32/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"/> <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>
Marek Tabędzki – Programowanie obiektowe i zdarzeniowe 33/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 34/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); } }