65.9K
CodeProject is changing. Read more.
Home

Using reflection to fill ListViews with arbritary objects

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.50/5 (5 votes)

Jan 22, 2004

2 min read

viewsIcon

36934

downloadIcon

501

How to make the ListView to display objects regardless of type.

Sample Image - listviewadapter.gif

Introduction

An often recurring task is to visualize collections of objects. This article explains how to use an adapter class to fill a ListView control with completely arbitrary objects.

Using the ListViewAdapter

The ListViewAdapter must get some basic information about which properties it should display:

adapter.AddBinding("Name","The name",100);
adapter.AddBinding("Comment","Comments?",100);
adapter.Fill(myListView,myCollection);

This is enough to get the adapter to display your objects. You could throw an object at it that doesn't have any of the properties Name and Comment. It would work, but a blank row will just look silly, so please don't.

The myCollection object must implement the interface IEnumerable. Most collections do, so this shouldn't be a problem.

How it works

What makes this piece of magic work is - as most of you probably have figured out - reflection. Reflection is used to discover type information runtime to handle objects that are unknown when you wrote the code.

The first step when the adapter fills a ListView with objects is to remove existing columns and ListViewItems. Secondly, it iterates through the bindings and creates the columns. Then it starts filling the ListView with items:

  Type t=obj.GetType();
  ListViewItem item=new ListViewItem();
  bool first=true;

  foreach(ColumnBinding b in bindings)
  {
    PropertyInfo p=t.GetProperty(b.Property);

    string text=string.Empty;
    if(p!=null)
    {
      //Fetch the value of the property of the object
      object val=p.GetValue(obj,null);

    //Parse the object
    if(val!=null)
    {
      text=b.Parser.Parse(val);
    }
  }

  //The first column gets its text from the Text property.
  //Thats why we must store the result of the first binding
  //in item.Text and the subsequent in subitems.
  if(first)
    item.Text=text;
  else
    item.SubItems.Add(text);
  first=false;
}

This is the part of the code that builds the actual ListViewItem. It is pretty straightforward. It loops through the column bindings and tries to get the value, as an object, of the property that is bound to the column. Then it sends the object to the parser, which I will explain later, and adds the string returned from the parser to the ListViewItem.

There is some additional code which handles images. But if you get the principles of this part of the code, you'll understand how it works when you look at it.

The Parser

The Parser arose from the need to display information that was interpreted in some way. It is not always desirable to display the result of a .ToString() call. A Parser object doesn't do anything else than return the result of .ToString(). But it can be extended to allow more creative interpretations.

An example of a class that extends Parser is the CustomParser class. The custom parser overrides the Parse method of its base class and replaces it with a method that uses a delegate to parse the object. So if you don't feel like writing a new class just to parse an object, you can just use the custom parser and provide it with a suitable delegate to do the job.