Home > View Post

PropertyListView control

The other day, in my post about the PropertyGrid, I mentioned that I would be posting the outcome of my latest little pet project.

I use the ListView control in my WinForm applications a lot. I mainly use it in Details mode where you get the multiple columns just like you do in Windows Explorer.

Windows Explorer Details View

This is also the reason I use it so much - it's familiar and it looks good too. However, I have to admit that using this control is mostly a royal pain in the ass. First, you have to configure all the column headers and then you have the error prone task of wiring up the actual data and converting it into a ListViewItem. You want sorting on each column you say? Uh oh, you're going to need to create a new IComparer class that has knowledge of the column types and pass this to the ListView's ListViewSorter property. I'm so bored of doing this that I thought there has to be a better way...

The PropertyGrid kindly provided the inspiration for the birth of this pet project when I realised the answer lay with reflection. Most of us are working with domain objects now that represent the 'thing' we would want to add to the list. Maybe it's an apple or maybe it's a pear but whatever it is, we just want to add it to the list and have it's properties displayed. Well now you can with the ProperyListView.

The new control simply inherits from ListView (so all the functionality you know and love is still available) and just adds a couple of extra methods and properties.

public Type Type
{
    get { /* ... */ };
    set { /* ... */ };
}

There's a new get/set property of type Type (called, um, 'Type'). You set this to prepare the PropertyListView to receive objects of a particular type. At this point the control reflects over the specified type for readable (not interested in setters) properties and creates the appropriate columns and you can even specify an interface if you like. Once this property is set you're ready to start adding objects.

public void Add(object item)
{
    /* ... */
}

Which is exactly what the new Add(object item) method on the PropertyListView control is for. The object must be of the type specified in the Type property above (or a subclass or implementation thereof) or you'll have an exception thrown at you. Otherwise, it really is that easy. The object that you passed will also be stored on the Tag property of its ListViewItem so you can easily get it back too.

And you'll have sorting right out of the box, without doing a thing. AND they'll sort on the actual type rather than just the string representation (where the type implements IComparable)!

Now, chances are that your domain objects will have a lot of ugly stuff that you don't want to display in the list. Maybe you want to display something nicer than the actual property name (e.g. "Batch Number" rather than "BatchNumber") or even have the value formatted in a specific way. What about the order of the columns? This is why there's a reasonably rich attribution model provided too.

Here's an example:

public class Apple
{
        // private fields here
    
    [PropertyListColumn(ColumnName = "Batch Number", ColumnOrder=2)]
    public int BatchNumber
    {
        get { return _batchNumber; }
        set { _batchNumber = value; }
    }
    
    [PropertyListColumn(ColumnName = "Picked On", ColumnOrder=1, FormatString="dd/MM/yyyy")]
    public DateTime PickedOn
    {
        get { return _pickedOn; }
        set { _pickedOn = value; }
    }
    
    [PropertyListColumn(Visible = false)]
    public string Nonsense
    {
        get { return _nonsense; }
        set { _nonsense = value; }
    }
    
    // This wouldn't be shown...
    public string SetOnly
    {
        set { _nonsense = value; }
    }
}

Notice the FormatString? If the property's type implements IFormattable (such as Int32, DateTime, Decimal etc) then you can specify a FormatString that's used when the value is rendered. You can specify the IFormatProvider used in this formatting by setting the IFormatProvider property on this PropertyListView control itself (defaults to CurrentCulture).

If you don't want to attribute your domain objects with all this nonsense, then just create a simple wrapper object as described in this post about the PropertyGrid.

I'm sure there are ways of doing this beautifully using DataBinding and Object Data Sources but I just want this for those quick applications I throw together where this will more than suffice.

There's even support for providing the ImageIndex if you want to display icons in the view, but I cover that in a separate post (or have a look inside the example application in the download).

Example application using PropertyListView

Download

Enjoy, I know I will.

Why not give it a try and let us know how you get on. Feedback is always appreciated. Update: Read about how to use images with the PropertyListView control.

Tags: WinForms.NET

 
Josh Post By Josh Twist
12:38 AM
24 Jul 2006

» Next Post: Two assemblies into one does go
« Previous Post: Visual Studio .NET Datasources bug

Comments are closed for this post.

© 2005 - 2017 Josh Twist - All Rights Reserved.