'Display Data in Group and Horizontal
Solution 1:[1]
Let us assume that you have created data structures for your catgories and products like this:
public class Category
{
public Category(string name)
{
Name = name;
Products = new ObservableCollection<Product>();
}
public string Name { get; }
public ObservableCollection<Product> Products { get; }
}
public class Product
{
public Product(string name, ImageSource image)
{
Name = name;
Image = image;
}
public string Name { get; }
public ImageSource Image { get; }
}
Each Category has a name and a collection of Products. The collection is an ObservableCollection<T> so you can add, insert or remove products at runtime and the user interface is automatically notified of the changes and adopts them accordingly. If you want the names or the collection itself to be interchangable, you have to implement the INotifyPropertyChanged interface. If your collections never change, a List<T> or a similar type is sufficient. Each Product has a name and an ImageSource that points to the image to be displayed.
The categories are exposed as a property ofObservableCollection<Category> in your view model.
public ObservableCollection<Category> Categories { get; }
Fill the Categories and Products collections with your data, e.g.:
Categories = new ObservableCollection<Category>
{
new Category("First"),
new Category("Second"),
new Category("Third"),
new Category("Fourth"),
// ...other categories.
};
Categories[0].Products.Add(new Product("Product 1.1", new BitmapImage(new Uri(@"pack://application:,,,/Your/Resources/YourImage.png"))));
// ...other products in various categories.
The XAML markup to display the categories and products looks like this:
<Grid Background="Gray">
<ItemsControl ItemsSource="{Binding Categories}"
Margin="0, 20">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="local:Category">
<Border BorderThickness="0, 1, 0, 0"
BorderBrush="Black">
<StackPanel Margin="10, 0">
<TextBlock Text="{Binding Name}"
FontWeight="Bold"
Margin="0, 10"/>
<TextBlock x:Name="NoProductTextBlock"
Text="No product"
Visibility="Collapsed"/>
<ListBox x:Name="ProductsListBox"
ItemsSource="{Binding Products}"
BorderThickness="0"
Background="Transparent"
Margin="0, 0, 0, 10"
Visibility="Visible">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="local:Product">
<StackPanel>
<Image Source="{Binding Image}"/>
<TextBlock Text="{Binding Name}"
Margin="0, 10, 0, 0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Products.Count}" Value="0">
<Setter TargetName="NoProductTextBlock" Property="Visibility" Value="Visible"/>
<Setter TargetName="ProductsListBox" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
What does the markup do to create the user interface you want to achieve?
- There is an outer
Gridthat is only there for showing the background for demo purposes.- An
ItemsControlis the base type for controls showing multiple items of a collection. It does not have any style for states like Mouse Over or Selected, it just displays items. Bind theCategoriesproperty to it, so it displays eachCategoryobject.- A
DataTemplateis created to tell theItemsControlhow to display aCategory.- A
Bordercreates the top horizontal line of each category. - The
StackPanelcontains the elements for the category and the establishes the margin.- A
TextBlockdisplays the name of the category by bindingName. - A
TextBlockdisplays the placeholder text if there are no products. - A
ListBoxdisplays all of theProducts of aCategory. It is bound to theProductsproperty insideCategory. In contrast to anItemsControl, aListBoxhas states for MouseOver, Focused and Selected which is what you want to interact with products.As items panel, a
WrapPanelis used.Positions child elements in sequential position from left to right, breaking content to the next line at the edge of the containing box. Subsequent ordering happens sequentially from top to bottom or from right to left, depending on the value of the
Orientationproperty.Another
DataTemplateis used to tell theListBoxhow to display aProduct. This is simply anImageand aTextBlockstacked vertically.
- A
- A
- A
DataTriggeris used to observe theCountproperty of theProductscollection. If there are no products -Countis zero - we collapse theListBoxand show the placeholderTextBlockinstead.
- A
- An
This is what the result looks like with some dummy data:
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | thatguy |


