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!

CustomView.zip


Comments (11)

  1. CodeDjinn says:

    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.

  2. ATC Avalon Team says:

    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.

  3. CodeDjinn says:

    Thank you for the reply, but can you maybe give me an example how to do it?

    Thank you.

  4. ATC Avalon Team says:

    Sorry, the example is not in our schedule. Go ahead to implement it. Feel free to contact us if you meet any other issues.

  5. Currently, I am struggling with WinFX and I must admit that I do not like the way how WPF (Windows Presentation…

  6. eclere says:

    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?

    Thorsten

    PS: Sorry, i dont’t speak english.

  7. ATC Avalon Team says:

    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.

  8. JeremyFr says:

    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

  9. sazzad says:

    ******************************** ATTENTION**************************************

    a major thing is not mentioned in this article is that ComponentResourceKey  does not usually work if it is defined in a resourceDictionary or in the same XAML file as the controls are.

    for this line to work

    get { return new ComponentResourceKey(GetType(), "ImageView");

    you must define the imageView in a dictionary path like this : Themes/Generic.xaml.

    again if you define those styles in a ResourceDictionary this is not going to work.

    for help see this article

    social.msdn.microsoft.com/…/e1979a4c-c4e7-4386-8d66-d989cb035fb6

  10. Hebertpa says:

    This one worked great but it the Vertical scroll bar isn't showing up for some reason.

  11. seb cbien says:

    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…