Budowa aplikacji w technologii.net wykład 7 konwersja, walidacja, szablony, widoki

Podobne dokumenty
Programownie w technologii.net wykład 6 Element Binding i Data Binding

Rozwój aplikacji modułowych Paweł Brudnicki. Dodanie modułu

Przewodnik krok po kroku:

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

xmlns:prism= c. <ContentControl prism:regionmanager.regionname="mainregion" />

MVVM Light Toolkit Przewodnik krok po kroku

Zdarzenia i polecenia

Programowanie obiektowe i zdarzeniowe

Programowanie obiektowe i zdarzeniowe wykład 1 Wprowadzenie do programowania zdarzeniowego

Aby nadać jej pożądaną postać należy w pliku Window1.xaml stworzyć definicję swojego stylu modyfikując ręcznie postać zapisu XAML:

Instrukcja laboratoryjna cz.3

Instrukcja laboratoryjna cz.4

Logger. Następnie w klasie Bootstrapper muimy zarejestrować nasz nowy logger:

Rozpoczynając wywód na temat MVVM należy najpierw zadań sobie kilka podstawowych pytań na temat MVVM jako wzorca projektowego :

Programowanie w technologii.net wykład 4 Aplikacja i okna

Wykład 12. Programowanie serwera MS SQL 2005 w C#

1. Wprowadzenie do WPF i XAML. Tworzenie interfejsu użytkownika.

Programowanie w technologii.net wykład 8 Style, listy, drzewa, toolbary, menu

BEAN VALIDATION. Waldemar Korłub. Narzędzia i aplikacje Java EE KASK ETI Politechnika Gdańska

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

Modele zawartości. WPF wykorzystuje 4 modele zawartości kontrolek: ContentControl pojedyncza zawartość

Instrukcja laboratoryjna cz.7

Programowanie Komputerów

- Narzędzie Windows Forms. - Przykładowe aplikacje. Wyższa Metody Szkoła programowania Techniczno Ekonomiczna 1 w Świdnicy

Wykład 2 Wybrane konstrukcje obiektowych języków programowania (1)

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Laboratorium z przedmiotu: Inżynieria Oprogramowania INEK Instrukcja 7

Leszek Stasiak Zastosowanie technologii LINQ w

Wykład 5 Okna MDI i SDI, dziedziczenie

Wyrażenie include(sciezka_do_pliku) pozwala na załadowanie (wnętrza) pliku do skryptu php. Plik ten może zawierać wszystko, co może się znaleźć w

Proxy (pełnomocnik) Cel: Zastosowanie: Dostarczyć zamiennik pewnego obiektu, pozwalający kontrolować dostęp do niego.

Laboratorium 10 - Web Services

Programowanie Obiektowe Ćwiczenie 4

Informatyka II. Laboratorium Aplikacja okienkowa

Programowanie telefonów z Windows Phone 7, cz. 4

Rozdział 3. Zapisywanie stanu aplikacji w ustawieniach lokalnych

ASP.NET MVC. Podstawy. Zaawansowane programowanie internetowe Instrukcja nr 3

Laboratorium programowania urządzeń mobilnych

Zaawansowane aplikacje WWW - laboratorium

Realizacja Aplikacji Internetowych 2013 laboratorium cz. 2 K.M. Ocetkiewicz

Instrukcja laboratoryjna nr.4

Lista, Stos, Kolejka, Tablica Asocjacyjna

POLITECHNIKA POZNAŃSKA. Oprogramowanie dla telefonów z systemem Windows Phone 8 obsługujących technologię NFC do sprawdzania listy obecności.

Platforma.NET laboratorium 4 Aktualizacja: 15/11/2013. Visual Basic.NET dostęp do bazy danych. Baza Microsoft SQL Server Compact

Laboratorium z przedmiotu: Inżynieria Oprogramowania INEK Instrukcja 6

Platformy Programistyczne Podstawy języka Java

Programowanie w środowiskach graficznych. Wykład 3 Język C#

Kurs programowania. Wykład 9. Wojciech Macyna

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Bazy danych dla producenta mebli tapicerowanych. Bartosz Janiak Marcin Sikora Wrocław r.

Algorytmy i Struktury Danych. Anna Paszyńska

Podstawowe kontrolki graficzne. Obsługa plików poprzez kontrolki

Współbieżność w środowisku Java

STWORZENIE MOBILNEJ APLIKACJI,

Systemy Rozproszone. Spis treści. Temat projektu: Regułowy system analizujacy logi. autorzy: Rafał Sadłowski, Sebastian Falkus, Michał Różycki

Programowanie telefonów z Windows Phone 7, cz. 2

using System;... using System.Threading;

Programowanie obiektowe i zdarzeniowe wykład 3 Okna i kontrolki

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Klasy i obiekty cz II

Ćwiczenie 1. Kolejki IBM Message Queue (MQ)

Diagram stanów Laboratorium 9

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Zastosowanie słuchaczy zdarzeń wg

Dawid Gierszewski Adam Hanasko

SWING c.d. przydatne narzędzia: JFileChooser, JOptionPane. drag'n drop, menu kontekstowe.

MVVM i XAML w Visual Studio 2015 / Jacek Matulewski. Gliwice, cop Spis treści

Komputerowe systemy na rynkach finansowych. wykład 5. MQL4 - funkcje operujące na obiektach wykresu

Inżynieria Programowania Laboratorium 6 Pierwsza finalna wersja. Paweł Paduch paduch@tu.kielce.pl

Kurs programowania. Wykład 6. Wojciech Macyna. 7 kwietnia 2016

Wzorce logiki dziedziny

Programowanie obiektowe

Rys. 3. Kod elementów na stronie po dodaniu kontrolek podstawowych.

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Testowanie II. Celem zajęć jest zapoznanie studentów z oceną jakości testów przy wykorzystaniu metryk pokrycia kodu testami (ang. code coverage).

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.

Języki i metodyka programowania. Język C# pętle, sterowanie, wyjątki

Programowanie obiektowe

Programowanie w środowiskach graficznych. Wykład 4 Język C# cd

Metodyki zwinne wytwarzania oprogramowania

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Laboratorium 8 Diagramy aktywności

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)

Podstawy tworzenia aplikacji z wykorzystaniem języka Java ME ćwiczenia 2

1 LINQ. Zaawansowane programowanie internetowe Instrukcja nr 1

Microsoft IT Academy kurs programowania

Wykład 4. Klasa List Kolejki Stosy Słowniki

PHP: bloki kodu, tablice, obiekty i formularze

Laboratorium 1. Wzorce oprogramowania lab1, Zofia Kruczkiewicz

Laboratorium 7 Blog: dodawanie i edycja wpisów

Swing ćwiczenia 2 opis

HttpRequest Aplikacja Czat

Informatyzacja Przedsiębiorstw

Systemy wirtualnej rzeczywistości. Komponenty i serwisy

Programowanie obiektowe

Kurs programowania 2 - listy

Backend Administratora

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania

Transkrypt:

Budowa aplikacji w technologii.net wykład 7 konwersja, walidacja, szablony, widoki 1/85 <Window... Title="Księgarnia"> <Grid>... <ListBox Name="lista" DisplayMemberPath="Title"/> <GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Center"/> <Grid Grid.Column="2" DataContext="Binding ElementName=lista, Path=SelectedItem" >... <Label...>Tytuł:</Label> <TextBox... Text="Binding Path=Title" /> <Label...>Autor:</Label> <TextBox... Text="Binding Path=Author"/> <Label...>Cena:</Label> <TextBox... Text="Binding Path=Price"/> </Grid> </Grid> </Window>

2/85 public class Book public string Title get; set; public string Author get; set; public decimal Price get; set; public Book(string title, string author, decimal price) Title = title; Author = author; Price = price; List<Book> lst = new List<Book>(); lst.add(new Book("Lód", "Jacek Dukaj", 57.99M)); lst.add(new Book("Inne pieśni", "Jacek Dukaj", 48.50M));... lista.itemssource = lst;

3/85

4/85 Konwersja danych Odpowiada za konwertowanie źródłowych danych, zanim zostaną wyświetlone (np. z niskopoziomowej reprezentacji w postać czytelną dla użytkownika) oraz konwersję nowych wartości, nim zostaną zapamiętane. Używana jest do: formatowania danych (np. konwersja liczby na string), tworzenia obiektów WPF (np. przy wyświetlaniu obrazków), warunkowej modyfikacji pewnych własności elementów interfejsu.

Value Converter [ValueConversion(typeof(decimal), typeof(string))] public class PriceConverter : IValueConverter public object Convert(object value, Type targettype, object parameter, CultureInfo culture) decimal price = (decimal)value; return price.tostring("c", culture); public object ConvertBack(object value, Type targettype, object parameter, CultureInfo culture) string price = value.tostring(); decimal result; if (Decimal.TryParse(price, NumberStyles.Any, culture, out result)) return result; return value; 5/85

6/85 Value Converter Ustawienia języka: <Window... xmlns:local="clr-namespace:wpfapp1" Language="pl-PL"> Wybór konwertera: <Label Grid.Row="2" Margin="3">Cena:</Label> <TextBox Grid.Column="1" Grid.Row="2" Margin="3"> <TextBox.Text> <Binding Path="Price"> <Binding.Converter> <local:priceconverter/> </Binding.Converter> </Binding> </TextBox.Text> </TextBox>

7/85 Value Converter Konwerter w zasobach: <Window.Resources> <local:priceconverter x:key="priceconverter" /> </Window.Resources> Korzystanie: <TextBox Grid.Column="1" Grid.Row="2" Margin="3" Text="Binding Path=Price, Converter=StaticResource PriceConverter"/>

Value Converter 8/85

9/85 Tworzenie obiektów z Value Converterem Baza danych może przechowywać dane binarne reprezentujące obraz produktu. Konwerter pozwala skonwertować tablicę bajtów na obiekt klasy BitmapImage: tworzymy obiekt BitmapImage, odczytujemy dane obrazka w MemoryStream, wywołujemy BitmapImage.BeginInit(), ustawiamy własność StreamSource na nasz MemoryStream, wywołujemy EndInit() aby zakończyć ładowanie obrazka. Prostszy przykład: pole ImagePath przechowuje ścieżkę, a obrazki są zapisane na dysku.

Tworzenie obiektów z Value Converterem public class ImagePathConverter : IValueConverter private string imagedirectory = Directory.GetCurrentDirectory(); public string ImageDirectory get return imagedirectory; set imagedirectory = value; public object Convert(...) string imagepath = System.IO.Path.Combine(ImageDirectory, (string)value); return new BitmapImage(new Uri(imagePath)); public object ConvertBack(...) throw new NotSupportedException(); obrazek można odczytać też ze zdalnej lokacji: return new BitmapImage(new Uri( (string)value, UriKind.Absolute)); 10/85

11/85 Tworzenie obiektów z Value Converterem Wykorzystanie: <Window.Resources> <local:imagepathconverter x:key="imagepathconverter" /> </Window.Resources> <Image Margin="3" Grid.Row="3" Grid.Column="1" Stretch="Uniform" HorizontalAlignment="Center" Source="Binding Path=ImagePath, Converter=StaticResource ImagePathConverter"> W wypadku braku obrazka możemy łapać wyjątek w metodzie Convert() i np. zwracać Binding.DoNothing lub jakiś obrazek domyślny.

Tworzenie obiektów z Value Converterem 12/85

13/85 Formatowanie warunkowe public class PriceToBackgroundConverter : IValueConverter public decimal MaximumPriceToHighlight get; set; public Brush HighlightBrush get; set; public Brush DefaultBrush get; set; public object Convert(...) decimal price = (decimal)value; if (price <= MaximumPriceToHighlight) return HighlightBrush; else return DefaultBrush; public object ConvertBack(...) throw new NotSupportedException();

14/85 Formatowanie warunkowe <Window.Resources>... <local:pricetobackgroundconverter x:key="pricetobackgroundconverter" DefaultBrush="x:Null" HighlightBrush="GreenYellow" MaximumPriceToHighlight="29.99"/> </Window.Resources> <Grid DataContext="Binding ElementName=lista, Path=SelectedItem" Grid.Column="2" Background="Binding Path=Price, Converter=StaticResource PriceToBackgroundConverter">... </Grid>

Formatowanie warunkowe 15/85

16/85 MultiConverter Pozwala kilka własności skonwertować na jedną wartość. <Window.Resources> <local:pricevatconverter x:key="pricevatconverter" /> </Window.Resources> <TextBox Grid.Column="1" Grid.Row="2" Margin="3"> <TextBox.Text> <MultiBinding Converter="StaticResource PriceVatConverter"> <Binding Path="Price"></Binding> <Binding Path="VAT"></Binding> </MultiBinding> </TextBox.Text> </TextBox>

17/85 MultiConverter Wartości w tablicy values są w tej samej kolejności, co Bindingi w definicji w XAMLu. public class PriceVatConverter : IMultiValueConverter public object Convert(object[] values,...) try decimal price = (decimal)values[0]; decimal vat = (decimal)values[1]; return (price * (1 + vat)).tostring("c", culture); catch return Binding.DoNothing; public object[] ConvertBack(object value, Type[] t,...) throw new NotSupportedException();

MultiConverter 18/85

19/85 Walidacja Pozwala kontrolować poprawność danych przy przesyłaniu ich z elementu docelowego do źródła. Rzucanie wyjątku: private decimal price; public decimal Price get return price; set if (value <= 0) throw new ArgumentException( "Cena musi być większa od 0."); price = value;

20/85 Walidacja Wyjątki wiązania danych są ignorowane, dlatego potrzebujemy jeszcze reguły walidacji: <TextBox Grid.Column="1" Grid.Row="2" Margin="3"> <TextBox.Text> <Binding Path="Price"> <Binding.Converter> <StaticResource ResourceKey="PriceConverter"/> </Binding.Converter> <Binding.ValidationRules> <ExceptionValidationRule/> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox>

Walidacja 21/85

22/85 Walidacja W wypadku nieudanej walidacji WPF: ustawia własność dołączoną Validation.HasError na true, tworzy ValidationError zawierający szczegóły błędu, jeśli ustawiono Binding.NotifyOnValidationError na true, podnosi zdarzenie Validation.Error. Zmienia się również wygląd kontrolki (wykorzystanie szablonu Validation.ErrorTemplate).

23/85 Walidacja Niekiedy nie chcemy rzucać wyjątków przy każdym błędzie użytkownika: public class Book : IDataErrorInfo... private decimal price; public decimal Price get return price; set price = value;

24/85 Walidacja public class Book : IDataErrorInfo... public string this[string columnname] get if (columnname == "Price") if (price <= 0) return "Cena musi być większa od 0."; return null; public string Error get return null;

25/85 Walidacja Inny przykład: public string this[string columnname] get if (propertyname == "Code") bool valid = true; foreach (char c in Code) if (!Char.IsLetterOrDigit(c)) valid = false; break; if (!valid) return "Może zawierać tylko cyfry i litery."; return null;

26/85 Walidacja <TextBox Grid.Column="1" Grid.Row="2" Margin="3"> <TextBox.Text> <Binding Path="Price"> <Binding.Converter> <StaticResource ResourceKey="PriceConverter"/> </Binding.Converter> <Binding.ValidationRules> <DataErrorValidationRule/> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> Możliwe jest łączenie obu podejść. Możemy skorzystać ze skrótu zamiast dodawać ExceptionValidationRule i DataErrorValidationRule, ustawiamy na true: Binding.ValidatesOnExceptions Binding.ValidatesOnDataErrors

Walidacja 27/85

28/85 Walidacja Własne reguły walidacji. public class PositivePriceRule : ValidationRule private decimal min = 0; private decimal max = Decimal.MaxValue; public decimal Min get return min; set min = value; public decimal Max get return max; set max = value;

29/85 Walidacja public class PositivePriceRule : ValidationRule... public override ValidationResult Validate(object value, CultureInfo culture) decimal price = 0; try if (((string)value).length > 0) price = Decimal.Parse((string)value, NumberStyles.Any, culture); catch return new ValidationResult(false, "Illegal characters.");

30/85 Walidacja... if ((price < Min) (price > Max)) return new ValidationResult(false, "Not in the range " + Min + " to " + Max + "."); else return new ValidationResult(true, null);

31/85 Walidacja <TextBox Grid.Column="1" Grid.Row="2" Margin="3"> <TextBox.Text> <Binding Path="Price"> <Binding.Converter> <StaticResource ResourceKey="PriceConverter"/> </Binding.Converter> <Binding.ValidationRules> <local:positivepricerule Min="0.01" Max="999.99" /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> Uwaga: możemy dodać dowolną liczbę reguł walidacji.

Walidacja 32/85

33/85 Walidacja Reakcja na błędy walidacji: flaga NotifyOnValidationError: <Binding Path="Price" NotifyOnValidationError="True">... </Binding> zdarzenie: <Grid Validation.Error="validationError"> obsługa: private void validationerror(object sender,...) if (e.action == ValidationErrorEventAction.Added) MessageBox.Show(e.Error.ErrorContent.ToString());

Walidacja 34/85

35/85 Walidacja Lista błędów walidacji: private void cmdok_click(object sender, RoutedEventArgs e) string message; if (FormHasErrors(out message)) // Errors still exist. MessageBox.Show(message); else //...

36/85 Walidacja private bool FormHasErrors(out string message) StringBuilder sb = new StringBuilder(); GetErrors(sb, gridproductdetails); message = sb.tostring(); return message!= "";

Walidacja private void GetErrors(StringBuilder sb, DependencyObject obj) foreach (object child in LogicalTreeHelper.GetChildren(obj)) TextBox element = child as TextBox; if (element == null) continue; if (Validation.GetHasError(element)) sb.append(element.text + " has errors:\r\n"); foreach (ValidationError error in Validation.GetErrors(element)) sb.append(" " + error.errorcontent.tostring()); sb.append("\r\n"); // sprawdź dzieci GetErrors(sb, element); 37/85

38/85 Walidacja Własne style powiadomienia: <TextBox Grid.Column="1" Grid.Row="2" Margin="3,3,20,3"> <Validation.ErrorTemplate> <ControlTemplate> <DockPanel LastChildFill="True"> <TextBlock DockPanel.Dock="Right" Foreground="Red" FontSize="14" FontWeight="Bold">*</TextBlock> <Border BorderBrush="Green" BorderThickness="1"> <AdornedElementPlaceholder /> </Border> </DockPanel> </ControlTemplate> </Validation.ErrorTemplate> <TextBox.Text>... </TextBox.Text> </TextBox>

Walidacja 39/85

40/85 Walidacja <TextBlock... ToolTip="Binding ElementName=adornerPlaceholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent">*</TextBlock>... <AdornedElementPlaceholder Name="adornerPlaceholder" />

41/85 Szablony danych Fragment kodu XAMLa, który mówi w jaki sposób ma być wyświetlany dowiązany obiekt danych: kontrolki zawartości obsługują to poprzez własność ContentTemplate kontrolki list poprzez ItemTemplate (stosowane do każdego obiektu kolekcji) Pozwala zastąpić to: <ListBox Name="lista" Margin="5" DisplayMemberPath="Title"/> Tym: <ListBox Name="lista" Margin="5"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="Binding Path=Title"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox>

Szablony danych 42/85

43/85 Szablony danych <ListBox Name="lista" Margin="5" HorizontalContentAlignment="Stretch"> <ListBox.ItemTemplate> <DataTemplate> <Border Margin="5" BorderThickness="1" BorderBrush="SteelBlue" CornerRadius="4"> <Grid Margin="3"> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <TextBlock FontWeight="Bold" Text="Binding Path=Title"></TextBlock> <TextBlock Grid.Row="1" Text="Binding Path=Author"></TextBlock> </Grid> </Border> </DataTemplate> </ListBox.ItemTemplate> </ListBox>

Szablony danych 44/85

45/85 Szablony danych Umieszczanie szablonów w zasobach: <Window.Resources>... <DataTemplate x:key="bookdatatemplate"> <Border Margin="5" BorderThickness="1" BorderBrush="SteelBlue" CornerRadius="4"> <Grid Margin="3"> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <TextBlock FontWeight="Bold" Text="Binding Path=Title"></TextBlock> <TextBlock Grid.Row="1" Text="Binding Path=Author"></TextBlock> </Grid> </Border> </DataTemplate> </Window.Resources>

46/85 Szablony danych Korzystanie z szablonów umieszczonych w zasobach: <ListBox Name="lista" Margin="5" HorizontalContentAlignment="Stretch" ItemTemplate="StaticResource BookDataTemplate"/>

Szablony danych <DataTemplate x:key="bookdatatemplate"> <Border...> <Grid Margin="3"> <Grid.RowDefinitions> <RowDefinition/><RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto" SharedSizeGroup="ikona"></ColumnDefinition> <ColumnDefinition ></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock Grid.Column="1" FontWeight="Bold" Text="Binding Path=Title"></TextBlock> <TextBlock Grid.Column="1" Grid.Row="1" Text="Binding Path=Author"></TextBlock> <Image Grid.RowSpan="2" MaxHeight="64" Source="Binding Path=ImagePath, Converter=StaticResource ImagePathConverter"> </Image> </Grid> </Border> </DataTemplate> 47/85

48/85... <Grid Name="gridProductDetails" Grid.IsSharedSizeScope="True"> <ListBox Name="lista" Margin="5" HorizontalContentAlignment="Stretch" ItemTemplate="StaticResource BookDataTemplate"/>

Szablony danych 49/85

50/85 Szablony danych <DataTemplate x:key="bookdatatemplate">... <Button Click="cmdDoKoszyka" Tag="Binding Path=ProductID">Do koszyka...</button> </DataTemplate> private void cmddokoszyka(object sender, RoutedEventArgs e) Button cmd = (Button)sender; int productid = (int)cmd.tag; //...

51/85 Szablony danych Inne rozwiązanie: <DataTemplate x:key="bookdatatemplate">... <Button Click="cmdDoKoszyka" Tag="Binding"> Do koszyka...</button> </DataTemplate> private void cmddokoszyka(object sender, RoutedEventArgs e) Button cmd = (Button)sender; Book book = (Book)cmd.Tag; lista.selecteditem = book; //...

Szablony danych 52/85

53/85 Szablony danych Różnicowanie szablonów danych: <DataTemplate x:key="bookdatatemplate"> <Border... Background="Binding Path=Price, Converter=StaticResource PriceToBackgroundConverter">... </Border> </DataTemplate>

Szablony danych 54/85

Szablony danych Wybór szablonów: public class BookTemplateSelector : DataTemplateSelector public override DataTemplate SelectTemplate(object item, DependencyObject container) Book product = (Book)item; Window window = Application.Current.MainWindow; if (product.categoryname == "Horror") return (DataTemplate)window.FindResource("HorrorBookTemplate"); else return (DataTemplate)window.FindResource("DefaultBookTemplate"); 55/85

56/85 Szablony danych <Window.Resources> <DataTemplate x:key="defaultbooktemplate">... </DataTemplate> <DataTemplate x:key="horrorbooktemplate"> <Border Margin="5" BorderThickness="2" BorderBrush="Red" CornerRadius="4" Background="Black" TextBlock.Foreground="White">... </Border> </DataTemplate> </Window.Resources> <ListBox Name="lista" Margin="5" HorizontalContentAlignment="Stretch"> <ListBox.ItemTemplateSelector> <local:booktemplateselector/> </ListBox.ItemTemplateSelector> </ListBox>

Szablony danych 57/85

58/85 Szablony danych Lepsze (bardziej uniwersalne) rozwiązanie: public class SingleCriteriaHighlightTemplateSelector : DataTemplateSelector public DataTemplate DefaultTemplate get; set; public DataTemplate HighlightTemplate get; set; public string PropertyToEvaluate get; set; public string PropertyValueToHighlight get; set; public override DataTemplate SelectTemplate(object item, DependencyObject container) Product product = (Product)item; Type type = product.gettype(); PropertyInfo property = type.getproperty(propertytoevaluate);

59/85 if (property.getvalue(product, null).tostring() == PropertyValueToHighlight) return HighlightTemplate; else return DefaultTemplate;

60/85 Szablony danych <ListBox Name="lista" HorizontalContentAlignment="Stretch"> <ListBox.ItemTemplateSelector> <local:singlecriteriahighlighttemplateselector DefaultTemplate="StaticResource DefaultBookTemplate" HighlightTemplate="StaticResource HorrorBookTemplate" PropertyToEvaluate="CategoryName" PropertyValueToHighlight="Horror" > </local:singlecriteriahighlighttemplateselector> </ListBox.ItemTemplateSelector> </ListBox>"> Uwaga: wybór szablonu następuje raz, w momencie tworzenia dowiązania. Jeśli zmiana stanu obiektu może wymagać wyboru innego szablonu, możemy wymusić to ręcznie (np. w PropertyChanged): DataTemplateSelector selector = lista.itemtemplateselector; lista.itemtemplateselector = null; lista.itemtemplateselector = selector;

61/85 Zmiana układu listy Możemy zastąpić domyślny kontener listy: <ListBox Name="lista" Margin="5" ScrollViewer.HorizontalScrollBarVisibility="Disabled"> <ListBox.ItemTemplateSelector> <local:booktemplateselector/> </ListBox.ItemTemplateSelector> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel></WrapPanel> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox>

Zmiana układu listy 62/85

63/85 Widoki danych Data Views Widok znajduje się pomiędzy źródłem danych a powiązaną kontrolką. To widok śledzi aktualny element listy, udostępnia sortowanie, filtrowanie, grupowanie. Widok jest typu: BindingListCollectionView jeśli źródło danych jest typu IbindingList, ListCollectionView jeśli źródło nie jest typu IbindingList, ale Ilist CollectionView jeśli nie jest ani IbindingList, ani Ilist, a tylko Ienumerable. Dostęp do widoku: ICollectionView view = CollectionViewSource.GetDefaultView(lista.ItemsSource);

64/85 Widoki danych filtrowanie Pozwala pokazać jedynie podzbiór rekordów listy spełniających pewne warunki. ListCollectionView view = (ListCollectionView)CollectionViewSource.GetDefaultView(lista.ItemsSource); view.filter = FilterBook; public bool FilterBook(Object item) Book product = (Book)item; return (product.price> 100); albo: view.filter = delegate(object item) Book product = (Book)item; return (product.price > 30); ;

Widoki danych filtrowanie 65/85

Widoki danych filtrowanie public class ProductByPriceFilter public decimal MinimumPrice get; set; public ProductByPriceFilter(decimal minimumprice) MinimumPrice = minimumprice; public bool FilterItem(Object item) Book product = item as Book; if (product!= null) return (product.price > MinimumPrice); return false; 66/85

67/85 Widoki danych filtrowanie private void cmdfilter_click(object sender,...) decimal minimumprice; if (Decimal.TryParse(txtMinPrice.Text, out minimumprice)) ListCollectionView view = CollectionViewSource.GetDefaultView(lista.ItemsSource) as ListCollectionView; if (view!= null) ProductByPriceFilter filter = new ProductByPriceFilter(minimumPrice); view.filter = filter.filteritem; Usunięcie filtra: view.filter = null;

68/85 Widoki danych filtrowanie Uwaga: nie można łączyć kilku filtrów należy raczej zaprojektować filtr z wieloma warunkami.

69/85 Widoki danych sortowanie Sortowanie na podstawie wskazanej własności danych: ListCollectionView view = (ListCollectionView)CollectionViewSource.GetDefaultView(lista.ItemsSource); view.sortdescriptions.add(new SortDescription("Title", ListSortDirection.Ascending));

Widoki danych sortowanie 70/85

71/85 Widoki danych sortowanie Własna procedura sortowaniea (tylko dla ListCollectionView). public class SortByNameLength : System.Collections.IComparer public int Compare(object x, object y) Book bookx = (Book)x; Book booky = (Book)y; return bookx.title.length.compareto(booky.title.length); view.customsort = new SortByNameLength();

Widoki danych sortowanie 72/85

73/85 Widoki danych grupowanie Jest zbliżone do sortowania: view.groupdescriptions.add(new PropertyGroupDescription("Author"));

Widoki danych grupowanie 74/85

75/85 Widoki danych grupowanie A na czym polega różnica? Czyli: jak rozróżnić grupy? ItemsControl.GroupStyle: ContainerStyle styl dla każdego elementu grupy ContainerStyleSelector HeaderTemplate nagłówek dla grupy HeaderTemplateSelector Panel wybór panelu przechowującego grupę

76/85 Widoki danych grupowanie <ListBox...> <ListBox.GroupStyle> <GroupStyle> <GroupStyle.HeaderTemplate> <DataTemplate> <TextBlock Text="Binding Path=Name" FontWeight="Bold" Foreground="White" Background="LightGreen" Margin="0,5,0,0" Padding="3"/> </DataTemplate> </GroupStyle.HeaderTemplate> </GroupStyle> </ListBox.GroupStyle> </ListBox> Uwaga: nie dowiązujemy do obiektu danych, ale do PropertyGroupDescription, stąd własność Name.

Widoki danych grupowanie 77/85

78/85 Widoki danych grupowanie Grupowanie przedziałami: public class PriceRangeProductGrouper : IValueConverter public int GroupInterval get; set; public object Convert(object value, Type targettype, object parameter, CultureInfo culture) decimal price = (decimal)value;

79/85 if (price < GroupInterval) return String.Format(culture, "Mniej niż 0:C", GroupInterval); else int interval = (int)price / GroupInterval; int lowerlimit = interval * GroupInterval; int upperlimit = (interval + 1) * GroupInterval; return String.Format(culture, "0:C 1:C", lowerlimit, upperlimit); public object ConvertBack(...) throw new NotSupportedException( "This converter is for grouping only.");

80/85 Widoki danych grupowanie view.sortdescriptions.add(new SortDescription("Price", ListSortDirection.Ascending)); PriceRangeProductGrouper grouper = new PriceRangeProductGrouper(); grouper.groupinterval = 10; view.groupdescriptions.add(new PropertyGroupDescription("Price", grouper));

Widoki danych grupowanie 81/85

82/85 Widoki danych nawigacja Widok udostępnia metody i własności służące do nawigacji, np. Count, CurrentItem, CurrentPosition, MoveCurrentToFirst(), MoveCurrentToLast(), MoveCurrentToNext(), MoveCurrentToPrevious(), MoveCurrentToPosition(). Można to robić nawet bez listy: <Window...>... <Grid>... <Label...>Tytuł:</Label> <TextBox...Text="Binding Path=Title" /> <Label...>Autor:</Label> <TextBox...Text="Binding Path=Author"/>... <Button Name="cmdPrev"...><</Button> <TextBlock Name="lblPosition".../> <Button Name="cmdNext"...>></Button> </Grid> </Window>

83/85 Widoki danych nawigacja W klasie okna zadeklarujmy referencję na widok: private ListCollectionView view; W momencie ładowania okna stwórzmy lub załądujmy listę danych i pobierzmy widok: List<Book> lst = new List<Book>(); lst.add(...);... this.datacontext = lst; view = (ListCollectionView)CollectionViewSource.GetDefaultView(this. DataContext); view.currentchanged += view_currentchanged;

84/85 Widoki danych nawigacja private void view_currentchanged(object sender, EventArgs e) lblposition.text = "Pozycja " + (view.currentposition+1).tostring() + " z " + view.count.tostring(); cmdprev.isenabled = view.currentposition > 0; cmdnext.isenabled = view.currentposition < view.count-1; private void cmdprev_click(object sender, RoutedEventArgs e) view.movecurrenttoprevious(); private void cmdnext_click(object sender, RoutedEventArgs e) view.movecurrenttonext();

Widoki danych nawigacja 85/85