Introduction
In this article, I will explain how to generate a ListViewItem
from an object. The basic idea is to have a class with a method where we can throw in any object and get a ListViewItem
as result.
Getting started
So let's get some code done.
public class MyListViewItem : System.Windows.Forms.ListViewItem
{
public MyListViewItem() { }
public MyListViewItem CreateItem(object obj) { return this; }
}
This will be our little class. We only need one method called CreateItem
which is supposed to return us a ListViewItem
.
Using reflection to get information about the object?
Since we know nothing about the object passed into our CreateItem
method, we really can't do much with the object, can we?
Let's assume, our object we pass into CreateItem
is created from the following class:
public class ClassA
{
private string author;
public ClassA()
{
}
public string Author
{
get { return this.author; }
set { this.author = value; }
}
public int Number(int nr)
{
return 2*nr;
}
}
The first attempt would be to simply fill the ListViewItem
according to all properties our object exposes. But what if we are only interested in some of the properties? We need to specify which data we expect to be included in our ListViewItem
and where our CreateItem
method can find this information.
We use an XML file to specify this information. Our file will look something like this:
We need some XML
="1.0" ="utf-8"
<ListViewItem>
<item Name="Author" Type="Property" Parameter=""></item>
<item Name="Number" Type="Method" Parameter="2"></item>
<item Name="Number" Type="Method" Parameter="4"></item>
</ListViewItem>
Let's extend our class so we can make use of this information.
Our little helper class
First, we create a little helper class which can contain the information from the XML file.
private class MethodInformation
{
private string name;
private string type;
private string parameter;
public MethodInformation()
{
}
public string Name
{
get{return this.name;}
set{this.name = value;}
}
public string Type
{
get{return this.type;}
set{this.type = value;}
}
public string Parameter
{
get{return this.parameter;}
set{this.parameter = value;}
}
}
Let's make use of it
Now, let's make use of the helper class and the info from the XML file. We put the following code in the constructor of our MyListViewItem
class:
_methodInformation = new ArrayList();
DataSet ds = new DataSet();
ds.ReadXml("item.xml");
foreach(DataRow dr in ds.Tables["item"].Rows)
{
MethodInformation mi = new MethodInformation();
mi.Name = dr["Name"].ToString();
mi.Type = dr["Type"].ToString();
mi.Parameter = new object[] {dr["Parameter"].ToString()};
_methodInformation.Add(mi);
}
Now, our CreateItem
method can make use of this information, and via reflection call the methods to create a ListViewItem
.
The CreateItem Method using Reflection and XML information
public MyListViewItem CreateItem(object obj)
{
int itemCounter=0;
string methodName;
Type myType = obj.GetType();
foreach(MethodInformation itemInfo in _methodInformation)
{
if(itemInfo.Type=="Property")
{
methodName = "get_"+itemInfo.Name;
}
else if(itemInfo.Type=="Method")
{
methodName = itemInfo.Name;
}
else
{
throw new Exception("Unkown Type." +
" Only Method or Property are valids type");
}
MethodInfo mi = myType.GetMethod(methodName);
object[] parameter = null;
if(itemInfo.Parameter != "")
{
ParameterInfo[] pi = mi.GetParameters();
Type parType = pi[0].ParameterType;
parameter = new Object[1];
TypeConverter tc = TypeDescriptor.GetConverter(parType);
parameter[0] = tc.ConvertFromString(itemInfo.Parameter);
}
if(itemCounter==0)
{
this.Text = System.Convert.ToString(mi.Invoke(obj,parameter));
itemCounter++;
}
else
{
this.SubItems.Add(System.Convert.ToString(mi.Invoke(obj,parameter)));
}
}
return this;
}
Final Note
I am using this approach in several projects and it saved me quite a lot of work. Please leave your comments about it. Thank you!
History
- 20.06.04 Version 1.0
- 24.06.04 Version 1.1 - update to handle non String parameters (thx to mav.northwind)