• Nie Znaleziono Wyników

Własności klasy ItemsControl:

ItemsSource – źródło danych (kolekcja lub DataView)

DisplayMemberPath – wskazuje, którą własność elementu wyświetlić

ItemTemplate – szablon elementu

ItemTemplateSelector – klasa dokonująca wyboru szablonu elementu

ItemContainerStyle – styl kontenera otaczającego pojedynczy element

ItemContainerStyleSelector

ItemsPanel – panel, który przechowuje wszystkie elementy listy (zazwyczaj:

pionowy StackPanel)

GroupStyle – styl formatowania grupy

GroupStyleSelector

Klasa Selector

◦ dodaje możliwość wybierania elementu (ToolBar czy Menu tego nie mają)

własności: SelectedItem, SelectedIndex, SelectedValue (własność Value wybranego obiektu danych, zgodnie z SelectedValuePath)

selector nie daje obsługi wielokrotnego wyboru – to jest dodane w ListBox, przez SelectionMode i SelectedItems

zdarzenie SelectionChanged

• TreeView też pozwala wybierać elementy, ale (z powodu hierarchicznej struktury) działa to inaczej, choć własności nazywają się tak samo: SelectedItem,

SelectedValue, SelectedValue path properties. Do tego zdarzenie SelectedItemChanged.

ComboBox

• Składa się z dwóch części: okna wyboru (ukazuje aktualny wybór) i listy rozwijalnej (wszystkie możliwe wybory).

• Ustawienie IsEditable na true zmienia działanie:

◦ w okienku wyboru wyświetlany jest jedynie tekst zwrócony przez ToString

◦ użytkownik może wpisać tu jakąś wartość

◦ autouzupełnianie

<ComboBox IsEditable="True" ... />

ListView

Umożliwia wyświetlanie różnych widoków do tych samych danych.

• Zwłaszcza przydaje się do tworzenia widoku wielokolumnowego.

• Dziedziczy z ListBox, dodając jedną własność: View.

• Widok to obiekt dziedziczący z ViewBase – klasy przechowującej wskazanie na style: styl kontrolki listy (DefaultStyleKey) i styl elementu listy

(ItemContainerDefaultStyleKey).

Wydzielenie informacji o widoku daje lepszą organizację, pozwala np.

wykorzystywać ten sam widok w różnych listach lub używać zamienni kilku widoków w jednej liście.

• WPF dostarcza jeden gotowy widok: GridView. Mamy też możliwość tworzenia własnych.

• Dodawanie kolumn: kolekcja GridView.Columns. Header to nagłówek kolumny, a DisplayMemberBinding – wiązanie obiektem danych.

<ListView Name="lstBooks" Margin="3">

<ListView.View>

<GridView>

</ListView.View>

</ListView>

Oczywiście wszystkie rzeczy, które działały dla list (konwertery, szablony) mogą być tu stosowane.

Użytkownik ma możliwość zmiany kolejności kolumn i zmiany ich rozmiaru (domyślnie rozmiar jest ustalany na podstawie zawartości, o ile nie określimy ręcznie własności Width).

Szablony komórek

• Podobnie jak szablony danych dla ListBoxa, ale działa tylko dla jednej kolumny.

<GridViewColumn Header="Tytuł" Width="150">

<GridViewColumn.CellTemplate>

<DataTemplate>

<TextBlock Text="{Binding Path=Title}"

TextWrapping="Wrap"></TextBlock>

</DataTemplate>

</GridViewColumn.CellTemplate>

</GridViewColumn>

W ten sam sposób możemy umieścić w kolumnach dowolne elementy, np. obrazek z poprzedniego wykładu (ImagePathConverter).

Ponieważ szablony kolumn nie mogą być używane w innym miejscu, przeważnie definiuje się je inline.

• GridViewColumn.CellTemplateSelector pozwala na ustawienie selectora szablonu.

• GridViewColumn.Header pozwala na zdefiniowanie wyglądu nagłówka;

GridViewColumn.HeaderTemplate pozwala na wybór szablonu dla nagłówka lub GridView.ColumnHeaderTemplate na wybór jednego szablonu dla wszystkich.

DataGrid

• Oferuje wielokolumnowy widok z edycją.

• Przeznaczony do wyświetlania całych tabel danych.

• Podstawowe wykorzystanie jest bardzo proste:

<DataGrid Name="data"/>

• I w kodzie:

data.ItemsSource = books;

RowDetailsTemplate pozwala na prezentację dodatkowych informacji w wierszu:

<DataGrid Name="data" SelectionMode="Single">

<DataGrid.RowDetailsTemplate>

<DataTemplate>

<TextBlock Margin="10" FontWeight="Bold"

Text="{Binding Price}"/>

</DataTemplate>

</DataGrid.RowDetailsTemplate>

</DataGrid>

Wypełnienie kolekcji DataGrid.Columns pozwala na własne definicje kolumn:

<DataGrid Name="data" SelectionMode="Single"

AutoGenerateColumns="False">

<DataGrid.Columns>

<DataGridTextColumn Header="Title"

Binding="{Binding Title}"/>

<DataGridTextColumn Header="Author"

Binding="{Binding Author}"/>

</DataGrid.Columns>

</DataGrid>

TreeView

• Wspiera wiązanie danych.

• TreeView to specjalizowana kontrolka listy, która zawiera elementy TreeViewItem.

• TreeViewItem to nie kontrolka zawartości, ale kolejna kontrolka listy, która może zawierać kolejne elementy TreeViewItem.

• TreeViewItem dziedziczy z HeaderedItemsControl, która dodaje własność Header.

• Prosty przykład ręcznej definicji drzewa:

<TreeView>

<TreeViewItem Header="Filmy">

<TreeViewItem Header="Komedie"/>

<TreeViewItem Header="Dramaty"/>

<TreeViewItem Header="Seriale"/>

</TreeViewItem>

<TreeViewItem Header="Książki">

<TreeViewItem Header="Fantasy"/>

<TreeViewItem Header="Science fiction"/>

<TreeViewItem Header="Horror"/>

</TreeViewItem>

</TreeView>

Podobnie, jak w wypadku ListBox, nie musimy budować drzewa z elementów TreeViewItem. Jednak przeważnie najlepiej jest opakowywać swoje obiekty w TreeViewItem, a zawartość do wyświetlenia udostępniać przez

TreeViewItem.Header.

TreeView i wiązanie danych

• Podobnie, jak wypadku pozostałych kontrolek listy, wystarczy ustawić własność ItemsSource.

• Wypełnia to jednak tylko pierwszy poziom drzewa:

public class Category {

public string Name { get; set; } public Category(string name) {

Name = name;

} }

<Grid>

<TreeView Name="drzewo" DisplayMemberPath="Name" />

</Grid>

private void Window_Loaded(object sender, RoutedEventArgs e) {

List<Category> lst = new List<Category>();

lst.Add(new Category("Fantasy"));

lst.Add(new Category("Science fiction"));

lst.Add(new Category("Horror"));

drzewo.ItemsSource = lst;

}

• Dodajmy książki do kategorii:

public class Category {

public string Name { get; set; } public Category(string name) {

Name = name;

books = new List<Book>();

}

private List<Book> books;

public List<Book> Books {

get { return books; } }

}

private void Window_Loaded(object sender, RoutedEventArgs e) {

...

lst[0].Books.Add(new Book("Gra o tron",

"George R.R. Martin", 45M));

lst[0].Books.Add(new Book("Straż nocna",

"Terry Pratchett", 27.5M));

lst[0].Books.Add(new Book("Czarnoksiężnik z Archipelagu", "Ursula K. Le Guin", 19.9M));

...

}

• Aby wyświetlić zawartość kategorii, potrzebny jest szablon, który może obsłużyć dane hierarchiczne:

<TreeView Name="drzewo">

<TreeView.ItemTemplate>

<HierarchicalDataTemplate>

<TextBlock Text="{Binding Path=Name}" />

</HierarchicalDataTemplate>

</TreeView.ItemTemplate>

</TreeView>

• To wyświetli tylko nazwę kategorii.

• HierarchicalDataTemplate może zawierać kolejny szablon – a kolekcja elementów z pierwszego poziomu może być przekazana do kolejnego poziomu.

Własność ItemsSource określa własność, która zawiera elementy dzieci.

<TreeView Name="drzewo">

<TreeView.ItemTemplate>

<HierarchicalDataTemplate

ItemsSource="{Binding Path=Books}">

<TextBlock Text="{Binding Path=Name}" />

<HierarchicalDataTemplate.ItemTemplate >

<DataTemplate>

<TextBlock Text="{Binding Path=Title}" />

</DataTemplate>

</HierarchicalDataTemplate.ItemTemplate>

</HierarchicalDataTemplate>

</TreeView.ItemTemplate>

</TreeView>

• Drzewo posługuje się teraz dwoma osobnymi szablonami dla pierwszego i drugiego poziomu.

• Drugi szablon wykorzystuje wybrany element pierwszego, jako źródło danych.

• Szablony możemy też przenieść do zasobów i wybierać na podstawie typów, a nie zagnieżdżenia:

<Window.Resources>

<HierarchicalDataTemplate

DataType="{x:Type local:Category}"

ItemsSource="{Binding Path=Books}">

<TextBlock Text="{Binding Path=Name}"/>

</HierarchicalDataTemplate>

<HierarchicalDataTemplate

DataType="{x:Type local:Book}">

<TextBlock Text="{Binding Path=Title}" />

</HierarchicalDataTemplate>

</Window.Resources>

<Grid>

<TreeView Name="drzewo"> </TreeView>

</Grid>

• Pozwala to również na kolejne zagnieżdżenia elementów w drzewie. Np. tak:

public class Category {

public string Name { get; set; } public Category(string name) {

Name = name;

books = new List<object>();

}

private List<object> books;

public List<object> Books {

get { return books; } }

}

...

lst[1].Books.Add(new Category("podkategoria"));

((Category)lst[1].Books[3]).Books.Add(new Book(...));

((Category)lst[1].Books[3]).Books.Add(new Book(...));

Tworzenie gałęzi na żądanie:

Jeśli drzewo zawiera dużą ilość danych, możemy nie wypełniać od razu wszystkich podkategorii, a odwlec to do czasu rozwinięcia gałezi przez użytkownika.

TreeViewItem odpala zdarzenia Expanded i Collapsed, które na o tym informują. Można to wykorzystać, by wypełnić listę danymi.

Początkowo, każda kategoria powinna zawierać jakiś wypełniacz, aby wyświetlony został plus, który umożliwi jej rozwinięcie.

◦ W obsłudze zdarzenia Expanded możemy wczytać potrzebne dane i wypełnić

Menu

Mamy dostępne dwie kontrolki: Menu (menu aplikacji) i ContextMenu (menu kontekstowe).

• Menu:

◦ Podlega zwyczajnym regułom rozmieszczania elementów (przeważnie jest na szczycie DockPanela lub w pierwszym wierszu Grida).

◦ Można dodać dowolną liczbę menu.

◦ Własność IsMainMenu ustawiona na true powoduje, że menu dostanie focusa po naciśnięciu klawisza Alt lub F10.

◦ Menu zachowało wszelkie cechy kontrolek listy (wiązanie danych, szablony danych, grupowanie, style itemów, etc.)

MenuItem

Menu składa się z obiektów klas MenuItem oraz Separator.

Klasa MenuItem dziedziczy z HeaderedItemsControl.

• Separator to po prostu pozioma linia, nie reagująca na wejście użytkownika.

Menu możemy (teoretycznie) wypełniać dowolnymi elementami (ale lepiej nie przesadzać).

<Menu DockPanel.Dock="Top">

<MenuItem Header="File">

<MenuItem Header="New"></MenuItem>

<MenuItem Header="Open"></MenuItem>

<MenuItem Header="Save"></MenuItem>

<Separator></Separator>

<MenuItem Header="Exit"></MenuItem>

</MenuItem>

<MenuItem Header="Edit">

<MenuItem Header="Undo"></MenuItem>

<MenuItem Header="Redo"></MenuItem>

<Separator></Separator>

<MenuItem Header="Cut"></MenuItem>

<MenuItem Header="Copy"></MenuItem>

<MenuItem Header="Paste"></MenuItem>

</MenuItem>

</Menu>

Można używać znaku podkreślenia, aby oznaczyć skrót z Altem.

• Reakcja na kliknięcie w element Menu:

◦ zdarzenie MenuItem.Click (osobno dla każdego elementu lub jeden handler w korzeniu),

• MenuItem wyświetla:

tekst z własności Header,

ikonę: MenuItem.Icon (przyjmuje dowolny obiekt, co pozwala na dołączenie również grafiki wektorowej),

checkmark: własność MenuItem.IsChecked; jeśli ustawimy dodatkowo IsCheckable, kliknięcie na menu zmieni ten stan (niestety, nie ma automatycznej obsługi grup),

◦ skrót klawiaturowy: można go wyświetlić podając

MenuItem.InputGestureText (to jest tylko tekst, nie daje żadnej obsługi – tu lepiej polegać na Commands, jeśli nie chcemy robić tego ręcznie).

<MenuItem Command="Open"></MenuItem>

MenuItem pozwala na sprawdzenie stanu: IsChecked, IsHighlighted, IsPressed, IsSubmenuOpen. Możemy wykorzystać to np. w triggerach.

ContextMenu

• Podobnie jak Menu, przechowuje kolekcję obiektów MenuItem.

• Jedyna różnica – nie może być umieszczone w oknie.

• Służy do ustawienia własności ContextMenu innych elementów (pokazuje się na prawy przycisk myszy lub Shift+F10):

<TreeView ...>

<TreeView.ContextMenu>

<ContextMenu>

<MenuItem Command="Undo"/>

<MenuItem Command="Redo"/>

</ContextMenu>

</TreeView.ContextMenu>

</TreeView>

• Menu kontekstowe domyślnie nie pokazuje się, jeśli element jest wyszarzony (isEnabled równe False), ale można to zmienić ustawiając

ContextMenuService.ShowOnDisabled na True.

Separator

• Służy do dzielenia elementów na grupy.

• Zawartość separatora można zmieniać przy pomocy szablonów – pozwala to definiować własne, nieklikalne elementy menu (nawet jeśli dodamy do menu wrzucimy element nie będący MenuItem, to będzie się zachowywał jak one;

Separator nie – np. nie jest podświetlany).

<Separator>

<Separator.Template>

<ControlTemplate>

</Separator.Template>

</Separator>

Niestety, Separator to nie kontrolka zawartości, zatem nie można oddzielić zawartości od formatowania i zawartość musi siedzieć w szablonie.

Toolbar i StatusBar

• Standardowo pasek narzędzi przechowuje przyciski, a pasek statusu – tekst i kontrolki, z ktorymi użytkownik nie wchodzi w interakcję (np. pasek postępu).

• Nie ma elementów przeznaczonych specjalnie dla paska narzędzi czy statusu – można w nim umieszczać wszelkie podstawowe elementy WPF.

ToolBar

• Przeważnie zawiera obiekty typu Button, ComboBox, CheckBox, RadioButton i Separator.

• Button w toolbarze wygląda inaczej niż w oknie, gdyż toolbar nadpisuje domyślny styl przycisku.

• Własność Orientation pozwala na stworzenie pionowego toolbara.

<ToolBar DockPanel.Dock="Top">

<CheckBox FontWeight="Bold">Bold</CheckBox>

<CheckBox FontStyle="Italic">Italic</CheckBox>

<CheckBox>

<TextBlock TextDecorations="Underline">

Underline </TextBlock>

</CheckBox>

<Separator></Separator>

<ComboBox SelectedIndex="1">

<ComboBoxItem>120%</ComboBoxItem>

<ComboBoxItem>100%</ComboBoxItem>

<ComboBoxItem>80%</ComboBoxItem>

</ComboBox>

<Separator></Separator>

• Gdy wszystkie elementy paska narzędzi nie mieszczą się w oknie, zostają przeniesione do rozwijalnego menu.

• Elementy trafiają automatycznie, ale możemy wskazać (przy pomocy własności dołączonej ToolBar.OverflowMode), jakie elementy nie powinny tam trafić

(OverflowMode.Never), a jakie powinny być tam zawsze (OverflowMode.Always)

ToolBarTray

• Przechowuje kolekcję toolbarów (własność ToolBars) i daje możliwość ich przemieszczania przez użytkownika (o ile nie ustawiliśmy ToolBarTray.IsLocked na true).

• ToolBar przy pomocy własności Band może określić swoje położenie w ToolBarTray.

<ToolBarTray DockPanel.Dock="Top">

<ToolBar>

<Button>One</Button> <Button>Two</Button>

<Button>Three</Button>

</ToolBar>

<ToolBar>

<Button>A</Button> <Button>B</Button>

<Button>C</Button>

</ToolBar>

<ToolBar Band="1">

<Button>Red</Button>

<Button>Blue</Button>

<Button>Green</Button>

<Button>Black</Button>

</ToolBar>

StatusBar

• Może przechowywać dowolną zawartość (która zostaje automatycznie opakowana przez StatusBarItem).

• Nadpisuje domyślne style niektórych elementów.

• Używany głównie do wyświetlania statycznej informacji.

• Domyślnie rozmieszcza elementy od lewej do prawej. Można podmienić mu panel, aby rozmieszczać w inny sposób.

<StatusBar DockPanel.Dock="Bottom">

<StatusBar.ItemsPanel>

<ItemsPanelTemplate>

</StatusBar.ItemsPanel>

<TextBlock>2/10</TextBlock>

<StatusBarItem Grid.Column="1">

<TextBlock>120%</TextBlock>

</StatusBarItem>

Powiązane dokumenty