How to Create a Custom View
One of the most powerful features of ListView is supporting custom views. If built-in views do not apply your scenarios, you can easily write your own. ListView will handle your views the same way with built-in views.
Creating a custom view is pretty simple. ListView control has done quiet a bit of work to make the implementation easy. Here are main steps to follow. Firstly, a class should be created and it should derive from ViewBase directly or indirectly. Then define the style of the view in a resource file. Finally link them together using ComponentResourceKey. In this blog I will show you how to create a custom view named ImageView. ImageView is used to display thumbnail of image files. The snapshot is listed below.
Step 1. Define ImageView class
All you have to do is to subclass ViewBase.
public class ImageView : ViewBase
{
}
Step 2. Define Style for ImageView
Two styles should be defined in a resource file. One is for ListView and the other is for ListViewItem. If you only want to do a little modification on the original one, you can use the following code. It will merge your style into its original style. The magic lies in the keyword “BasedOn”. It means your style definition is based on another style definition.
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource {x:Type ListBox}}">
NOTE: if you forget to define Template in styles, ListView will show nothing.
The following XAML code is digested from the style definitions for ImageView.
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource {x:Type ListBox}}">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="0.5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Name="bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" Margin="{TemplateBinding Margin}">
<ScrollViewer Margin="{TemplateBinding Padding}">
<WrapPanel ItemWidth="150" IsItemsHost="True" MinWidth="100"
Width="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}">
</WrapPanel>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType='{x:Type ListViewItem}' BasedOn='{StaticResource {x:Type ListBoxItem}}'>
<Setter Property='Padding' Value='3'/>
<Setter Property='Margin' Value='5'/>
<Setter Property='HorizontalContentAlignment' Value='Center'/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="White">
<Image Margin="3" Source="{Binding FullName}"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Step 3. Link them together
The link method here is using ComponentResourceKey. Firstly give a key to each style defined before.
<Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type l:ImageView},ResourceId=ImageView}">
</Style>
<Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type l:ImageView},ResourceId=ImageViewItem}"}">
</Style>
Then set DefaltStyleKey and ItemContainerStyleKey in ImageView class.
public class ImageView : ViewBase
{
protected override object DefaultStyleKey
{
get { return new ComponentResourceKey(GetType(), "ImageView"); }
}
protected override object ItemContainerDefaultStyleKey
{
get { return new ComponentResourceKey(GetType(), "ImageViewItem"); }
}
}
Step 4. Use it in ListView
It is used like GridView.
<ListView>
<ListView.View>
<l:ImageView />
</ListView.View>
</ListView>
We’re done!
Comments
- Anonymous
May 10, 2006
Hi, thanks for all the samples so far!! It is a great resource to get info on customizing the list view.
I am trying to reproduce the image view but I want to have a Collection of Images as the ItemsSource of the List View. E.g
public sealed class ImageCollection :
ObservableCollection<Image>
{
public void AddItem(Image item)
{
Add(item);
}
}
Is this possible? And if it is correct, what should I bind the ImageViewItem's Source To?
E.g (You're Example)
<Image Margin="3" Source="{Binding FullPath}"/>
Mine
<Image Margin="3" Source="{Binding Source}"/>
?
Thank you very much. - Anonymous
May 10, 2006
Image is a control. A control is not sharable. I mean that you cannot put a control in different places. So if you want to show images in ListView, please use a list of ImageSource as its ItemsSource. - Anonymous
May 10, 2006
Thank you for the reply, but can you maybe give me an example how to do it?
Thank you. - Anonymous
May 10, 2006
Sorry, the example is not in our schedule. Go ahead to implement it. Feel free to contact us if you meet any other issues. - Anonymous
May 24, 2006
Currently, I am struggling with WinFX and I must admit that I do not like the way how WPF (Windows Presentation... - Anonymous
March 25, 2007
Hello,nice example. Unfortunately the virtualizing feature is no longer available. With own try I it yet did not create.Can you help me to expand your Sample?ThorstenPS: Sorry, i dont't speak english. - Anonymous
March 26, 2007
In this sample, we're using WrapPanel to host the items, it doesn't support Virtualizing.If you want the virtualizing feature, please write a custom panel and inherit from VirtualizingPanel. - Anonymous
November 05, 2007
Hi,Nice example ! I would like to implement the same behaviour in my application, but i would prefer to don't have my view in a separate assembly. Is that possible ?What should i change to do so ? Because i try some things, and it doesn't work (the listview stay invisible).Regards,Jeremy - Anonymous
October 23, 2010
The comment has been removed - Anonymous
December 09, 2011
This one worked great but it the Vertical scroll bar isn't showing up for some reason. - Anonymous
July 24, 2014
cool but it's not virtualized because in this code you use a WrapPanel :s it's works with a few images, but if you have a lot of images displayed in this listbox, huge lost of performance...