Thursday, November 13, 2008

Using WPF ListView to display Complex Data Structure

I was ask @ work today, to display in a WPF List View, a list of items and within each item there are other list of items (subclass within a class).

There are lots of examples on the net to display to simple class.
But in the real world there is no simple data structure, only complex data structure.

I wrote is example to demonstrate the point.
Imagine that you have a list of movies, and each movie has a movie id, a title, a list (subclass) of images and descriptions for the movie, a list (subclass) of cast in the movie and a list (subclass) of movie recommendations.




Code:
A list of Movies

public List<Movie> MovieData

And each Movie has

public class Movie
{
public int MovieId { get; set; }
public string Title { get; set; }
public IList<MovieInfos> Infos { get; set; }
public IList<Cast> Cast { get; set; }
public IList<string> Recommendations { get; set; }
}

MovieInfos is a subclass in the Movie class

public class MovieInfos
{
public string Description { get; set; }
public ImageSource MovieImage { get; set; }
}

Xaml:
Bind the list of movies to the WPF List View

<ListView ItemsSource="{Binding Path=MovieData}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=MovieId}" Header="Movie Id" />
<GridViewColumn DisplayMemberBinding="{Binding Path=Title}" Header="Title" />
<!-- Can Bind to complex subclass -->
<GridViewColumn Header="Movie(s)">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=Infos}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image ToolTip="{Binding Path=Description}"
Source="{Binding Path=MovieImage}"
Margin="3,0,3,0"
Height="125" Width="75" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!-- Binding with data triggers -->
<GridViewColumn Header="Cast">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=Cast}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="tbName" Text="{Binding Path=Name}"/>
<Image x:Name="imgStar"
Visibility="Collapsed"
Source="{Binding Source={x:Static constants:ImageConstants.STAR}}"
Height="16" Width="16" Margin="3,0,0,0" />
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=MainCharacter}" Value="True">
<Setter TargetName="tbName" Property="Foreground" Value="Red" />
<Setter TargetName="imgStar" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!-- Simple binding -->
<GridViewColumn Header="Recommendations">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=Recommendations}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>

This sample demonstrates the power of WPF List View.

Using Items Control in WPF List View

Please let me know if this helps you.