Controls that are able to display collections derive from the ItemsControl:
Object └─DependencyObject └─UIElement └─FrameworkElement └─Control ├─ContentControl │ └─SelectorItem (non-instantiable) │ ├─ComboBoxItem │ ├─FlipViewItem │ ├─GridViewItem │ ├─ListBoxItem │ └─ListViewItem └─ItemsControl - no concept of selection, no scrolling └─Selector (non-instantiable) - selection logic ├─ComboBox ├─FlipView ├─ListBox └─ListViewBase (non-instantiable) ├─GridView └─ListView
Properties of the ItemsControl used with data binding:
Properties of the ItemsControl used with styles:
Properties of the ItemsControl related to grouping:
Example: Snippets showing the use of the ItemsControl's properties:
<ItemsControl> <ItemsControl.ItemTemplate> <DataTemplate> ... </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
<ItemsControl> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl>
<ItemsControl> <ItemsControl.GroupStyle> <GroupStyle> <GroupStyle.HeaderTemplate> <DataTemplate> ... </DataTemplate> </GroupStyle.HeaderTemplate> <GroupStyle.Panel> <ItemsPanelTemplate> <VariableSizedWrapGrid Orientation="Vertical" /> </ItemsPanelTemplate> </GroupStyle.Panel> </GroupStyle> </ItemsControl.GroupStyle> </ItemsControl>
Example: Display items in an ItemsControl:
<!-- without a DataTemplate --> <ItemsControl> <x:String>AAA</x:String> <x:String>BBB</x:String> <x:String>CCC</x:String> </ItemsControl> <!-- with a DataTemplate --> <ItemsControl> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}" FontSize="24" Foreground="Green" /> </DataTemplate> </ItemsControl.ItemTemplate> <x:String>AAA</x:String> <x:String>BBB</x:String> <x:String>CCC</x:String> </ItemsControl>
Example: Wrap an ItemsControl into a ScrollViewer. This adds scrolling functionality to the ItemsControl:
<Grid Background="Beige" Width="300" Height="200"> <ScrollViewer Margin="4"> <ItemsControl> <x:String>One</x:String> <x:String>Two</x:String> <x:String>Three</x:String> <x:String>Four</x:String> <x:String>Five</x:String> <x:String>Six</x:String> <x:String>Seven</x:String> <x:String>Eight</x:String> <x:String>Nine</x:String> <x:String>Ten</x:String> </ItemsControl> </ScrollViewer> </Grid>
Example: Define the ItemsPanelTemplate of an ItemsControl:
<Grid Background="Beige" Width="300" Height="200"> <ItemsControl HorizontalAlignment="Center"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock FontSize="40" Foreground="Black" Text="{Binding}" /> </DataTemplate> </ItemsControl.ItemTemplate> <x:Int32>1</x:Int32> <x:Int32>2</x:Int32> <x:Int32>3</x:Int32> </ItemsControl> </Grid>
<Grid Background="Beige" Width="300" Height="300"> <ItemsControl> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapGrid ItemHeight="100" ItemWidth="100" MaximumRowsOrColumns="2" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.Items> <Rectangle Fill="Blue" Width="50" Height="50" /> <Rectangle Fill="Green" Width="50" Height="50" /> <Rectangle Fill="Red" Width="50" Height="50" /> <Rectangle Fill="Magenta" Width="50" Height="50" /> <Rectangle Fill="Yellow" Width="50" Height="50" /> <Rectangle Fill="Orange" Width="50" Height="50" /> </ItemsControl.Items> </ItemsControl> </Grid>
<Grid Background="Beige"> <ItemsControl> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapGrid ItemHeight="100" ItemWidth="100" MaximumRowsOrColumns="2" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.Items> <!-- fit into ItemHeight and ItemWidth --> <Ellipse Fill="Blue" Width="100" Height="50" /> <Ellipse Fill="Green" Width="100" Height="100" /> <Ellipse Fill="Red" Width="100" Height="100" /> <!-- oversized and clipped; do not fit into ItemHeight and ItemWidth --> <Ellipse Fill="Orange" Width="120" Height="120" /> <Ellipse Fill="Yellow" Width="200" Height="100" /> <Ellipse Fill="Magenta" Width="300" Height="200" /> </ItemsControl.Items> </ItemsControl> </Grid>
ItemsWrapGrid is similar to WrapGrid but implements virtualization:
<Grid> <ItemsControl> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <ItemsWrapGrid ItemHeight="100" ItemWidth="100" MaximumRowsOrColumns="2" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.Items> ... </ItemsControl.Items> </ItemsControl> </Grid>
The Selector class defines the SelectionChanged event. This event is raised whenever the user selects an item from the collection.
Properties of the Selector used with the item selection logic:
Set the selected item in Selector-derived controls with the SelectedItem or SelectedIndex property.
Set an inital item in Selector-derived controls by setting their SelectedIndex property e.g., SelectedIndex=“0”
Example: Display Book items in a ComboBox:
<ComboBox ItemsSource="{Binding Books}" ItemTemplate="{StaticResource BookTemplate}" SelectedItem="{Binding SelectedBook, Mode=TwoWay}" SelectionChanged="BookComboBox_SelectionChanged" />
private void BookComboBox_SelectionChanged(object sender, SelectionChangedEventArgs args) { if (args.AddedItems.Count > 0) { Book book = args.AddedItems[0] as Book; // ... } }
Example: Define ComboBox's items in XAML:
<ComboBox Header="Select a name" SelectedIndex="0" SelectionChanged="ComboBox_SelectionChanged"> <ComboBoxItem Content="John" /> <ComboBoxItem Content="Mike" /> <ComboBoxItem Content="Sophia" /> <ComboBoxItem Content="Derek" /> </ComboBox>
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs args) { var comboBox = sender as ComboBox; string name = (comboBox.SelectedItem as ComboBoxItem).Content as string; Debug.WriteLine(name); }
ComboBox supports the PlaceholderText property.
Example: Placeholder text in a ComboBox and a PasswordBox:
<StackPanel> <PasswordBox Header="Password" PlaceholderText="Enter your password" /> <ComboBox Header="Unusual mammals" PlaceholderText="Pick a mammal"> <x:String>Platypus</x:String> <x:String>Echidna</x:String> <x:String>Aardvark</x:String> <x:String>Hyrax</x:String> </ComboBox> </StackPanel>
Example: A simple FlipView:
<Page x:Class="TestApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:TestApp"> <Grid> <FlipView ItemsSource="{x:Bind Glaciers}"> <FlipView.ItemTemplate> <DataTemplate x:DataType="local:Glacier"> <Grid> <Image Source="{x:Bind ImageUri}" Stretch="UniformToFill" /> <Border Background="#A5000000" Height="80" VerticalAlignment="Bottom"> <TextBlock Text="{x:Bind Title}" FontSize="27" Padding="20" Foreground="White" /> </Border> </Grid> </DataTemplate> </FlipView.ItemTemplate> </FlipView> </Grid> </Page>
using System.Collections.ObjectModel; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace TestApp { public sealed partial class MainPage : Page { public ObservableCollection<Glacier> Glaciers { get; private set; } public MainPage() { this.InitializeComponent(); Glaciers = new ObservableCollection<Glacier>(); Loaded += MainPage_Loaded; } private void MainPage_Loaded(object sender, RoutedEventArgs e) { Glaciers.Clear(); Glaciers.Add(new Glacier { ImageUri = "/Assets/glacier1.jpg", Title = "Glacier #1" }); Glaciers.Add(new Glacier { ImageUri = "/Assets/glacier2.jpg", Title = "Glacier #2" }); Glaciers.Add(new Glacier { ImageUri = "/Assets/glacier3.jpg", Title = "Glacier #3" }); } } public class Glacier { public string ImageUri { get; set; } public string Title { get; set; } } }
Example: A FlipView with a custom ItemContainerStyle and a SelectionChanged event handler:
<FlipView ItemsSource="{x:Bind Data}" SelectionChanged="FlipView_SelectionChanged"> <FlipView.ItemContainerStyle> <Style TargetType="FlipViewItem"> <Setter Property="Margin" Value="80,0,0,0"/> </Style> </FlipView.ItemContainerStyle> <FlipView.ItemTemplate> <DataTemplate> ... </DataTemplate> </FlipView.ItemTemplate> </FlipView>
private void FlipView_SelectionChanged(object sender, SelectionChangedEventArgs e) { // ... }
Frequently used properties of GridView and ListView derived from ListViewBase:
Working with GridView / ListView:
Events related to Drag & Drop:
If the data source of a GridView / ListView uses an ObservableCollection the re-ordering of its items is reflected in the data source. It is achieved by setting the following properties to True:
Examples of customizing ItemContainerStyle:
<ListView> <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Stretch"/> <Setter Property="Padding" Value="0" /> </Style> </ListView.ItemContainerStyle> </ListView>
<GridView> <GridView.ItemContainerStyle> <Style TargetType="GridViewItem"> <Setter Property="HorizontalContentAlignment" Value="Center" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="Margin" Value="4" /> </Style> </GridView.ItemContainerStyle> </GridView>
Example: Stretch ListView's items over the entire width of a container:
<Page x:Class="TestApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:TestApp"> <Grid> <ListView ItemsSource="{x:Bind Books}"> <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Stretch"/> <Setter Property="Padding" Value="0"/> </Style> </ListView.ItemContainerStyle> <ListView.ItemTemplate> <DataTemplate x:DataType="local:Book"> <StackPanel> <TextBlock Text="{x:Bind Title}" FontWeight="Bold" /> <TextBlock Text="{x:Bind Author}" FontStyle="Italic" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> </Grid> </Page>
Example: Respond to the ItemClick event using a ListView. The same code would be for a GridView:
<Page x:Class="TestApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:TestApp"> <Grid> <ListView ItemsSource="{x:Bind Books}" SelectionMode="None" IsSwipeEnabled="False" IsItemClickEnabled="True" ItemClick="ListView_ItemClick"> <ListView.ItemTemplate> <DataTemplate x:DataType="local:Book"> <StackPanel> <TextBlock Text="{x:Bind Title}" FontWeight="Bold" /> <TextBlock Text="{x:Bind Author}" FontStyle="Italic" /> <Rectangle Height="2" Fill="Gray" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> </Grid> </Page>
using System.Collections.ObjectModel; using System.Diagnostics; using Windows.UI.Xaml.Controls; namespace TestApp { public sealed partial class MainPage : Page { public ObservableCollection<Book> Books { get; private set; } public MainPage() { this.InitializeComponent(); Books = new ObservableCollection<Book>(); Loaded += (sender, args) => { Books.Add(new Book { Title = "AAA", Author = "Author1" }); Books.Add(new Book { Title = "BBB", Author = "Author2" }); Books.Add(new Book { Title = "CCC", Author = "Author3" }); }; } private void ListView_ItemClick(object sender, ItemClickEventArgs args) { Book selectedBook = args.ClickedItem as Book; if (selectedBook != null) { Debug.WriteLine(selectedBook.ToString()); } } } public class Book { public string Title { get; set; } public string Author { get; set; } public override string ToString() { return $"Book: Title = \"{Title}\", Author = {Author}"; } } }
Example: Grouping in a ListView:
<Page x:Class="TestApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:TestApp"> <Page.Resources> <CollectionViewSource x:Name="BookCollectionViewSource" IsSourceGrouped="true" /> </Page.Resources> <ListView ItemsSource="{Binding Source={StaticResource BookCollectionViewSource}}"> <ListView.ItemTemplate> <DataTemplate x:DataType="local:Book"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{x:Bind Title, Mode=OneWay}" /> <TextBlock Text="-" Padding="8,0,8,0" /> <TextBlock Text="{x:Bind Author}" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> <ListView.GroupStyle> <GroupStyle> <GroupStyle.HeaderTemplate> <DataTemplate x:DataType="local:BooksByCategory"> <TextBlock Text="{x:Bind Category}" FontWeight="Bold" /> </DataTemplate> </GroupStyle.HeaderTemplate> </GroupStyle> </ListView.GroupStyle> </ListView> </Page>
using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace TestApp { public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); Loaded += (sender, args) => { BookCollectionViewSource.Source = BookRepository.GroupedBooks; }; } } }
This is the BookRepository class used in the above example:
using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; namespace TestApp { public class Book : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string title; public string Title { get { return title; } set { if (value != title) { title = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Title")); } } } public string Author { get; set; } public string Category { get; set; } public override string ToString() { return $"Selected book: Title = \"{Title}\", Author = {Author}, Category = {Category}"; } } public class BooksByCategory : ObservableCollection<Book> { public string Category { get; set; } } public static class BookRepository { public static ObservableCollection<BooksByCategory> GroupedBooks { get; private set; } static BookRepository() { var books = new List<Book>(); books.Add(new Book { Title = "AAA", Author = "Author1", Category = "1" }); books.Add(new Book { Title = "BBB", Author = "Author2", Category = "2" }); books.Add(new Book { Title = "CCC", Author = "Author3", Category = "1" }); books.Add(new Book { Title = "DDD", Author = "Author4", Category = "3" }); books.Add(new Book { Title = "EEE", Author = "Author5", Category = "1" }); books.Add(new Book { Title = "FFF", Author = "Author6", Category = "1" }); books.Add(new Book { Title = "GGG", Author = "Author7", Category = "2" }); books.Add(new Book { Title = "HHH", Author = "Author8", Category = "1" }); books.Add(new Book { Title = "III", Author = "Author9", Category = "3" }); books.Add(new Book { Title = "JJJ", Author = "Author10", Category = "3" }); GroupedBooks = new ObservableCollection<BooksByCategory>(); var query = from book in books orderby book.Category group book by book.Category; foreach (var group in query) { BooksByCategory booksByCategory = new BooksByCategory(); booksByCategory.Category = group.Key; foreach (Book book in group) booksByCategory.Add(book); GroupedBooks.Add(booksByCategory); } } } }
The GroupedBooks collection uses as nested ObservableCollection. It means that you can add new items and they will be automatically reflected in the UI:
BookRepository.GroupedBooks[2].Add(new Book { Title = "ZZZ", Author = "Author100", Category = "2" });
You can also update the item's properties if they support INotifyPropertyChanged:
BookRepository.GroupedBooks[0][2].Title = "NEW BOOK";
Provide a GridView or a ListView for the ZoomedOutView and the ZoomedInView sections.
<SemanticZoom x:Name="SemanticZoom1" ScrollViewer.HorizontalScrollMode="Disabled" VerticalContentAlignment="Stretch"> <ZoomedOutView> <ListView ...> </ZoomedOutView> <ZoomedInView> <GridView ScrollViewer.IsHorizontalScrollChainingEnabled="False" ...> </ZoomedInView> </SemanticZoom>
// Populate the items in the zoom-out view. (SemanticZoom1.ZoomedOutView as ListViewBase).ItemsSource = collection; // Set the selected item. (SemanticZoom1.ZoomedOutView as ListViewBase).SelectedItem = null;
Example: Go back to the zoom-in view if we are in the zoom-out view:
if (!SemanticZoom1.IsZoomedInViewActive) { SemanticZoom1.ViewChangeStarted -= ServiceCallsSemanticZoom_ViewChangeStarted; SemanticZoom1.ToggleActiveView(); SemanticZoom1.ViewChangeStarted += ServiceCallsSemanticZoom_ViewChangeStarted; }
Win10 Update: The default action to switch between the zoomed-in view and the zoomed-out view is to tap on a group header in the zoomed-in view. This is a change from Windows 8.1, which used the pinch gesture to zoom. To change views using pinch-to-zoom, set ScrollViewer.ZoomMode=“Enabled” on the SemanticZoom's internal ScrollViewer.
MSDN: