It turned out it wasn't so difficult. Here's the source:
/// <summary>
/// Typed ListViewItem v1.1 by Carl Ribbegårdh
/// </summary>
/// <typeparam name="T">The type of the Tag object</typeparam>
public class ListViewItem<T> : ListViewItem where T : class
{
public ListViewItem() : base()
{}
public ListViewItem(string text) : base(text)
{}
public ListViewItem(string text, int imageIndex) : base(text, imageIndex)
{}
public ListViewItem(string text, string imageKey) : base(text, imageKey)
{}
public new T Tag
{
get { return base.Tag as T; }
set { base.Tag = value; }
}
}
/// <summary>
/// Typed ListView v1.1 by Carl Ribbegårdh
/// </summary>
/// <typeparam name="T">The type of the Tag object</typeparam>
public class ListView<T> : ListView where T : class
{
public ListView() : base()
{}
public new class ListViewItemCollection : ListView.ListViewItemCollection
{
private ListView m_owner;
public ListViewItemCollection(ListView<T> owner) : base(owner)
{
m_owner = owner;
}
public new ListViewItem<T> this[int index]
{
get
{
return (ListViewItem<T>)base[index];
}
set
{
base[index] = value;
}
}
public new ListViewItem<T> this[string key]
{
get
{
return (ListViewItem<T>)base[key];
}
}
public ListViewItem<T> Add(ListViewItem<T> value)
{
return (ListViewItem<T>)base.Add(value);
}
[Obsolete("Please use the generic Add instead.", true)]
public new ListViewItem Add(ListViewItem value)
{
throw new NotSupportedException("Please use the generic Add instead.");
}
public new ListViewItem<T> Add(string text)
{
return (ListViewItem<T>)base.Add(new ListViewItem<T>(text));
}
public new ListViewItem<T>[] Find(string key, bool searchAllSubItems)
{
List<ListViewItem<T>> result = new List<ListViewItem<T>>();
foreach (var item in base.Find(key, searchAllSubItems))
{
result.Add((ListViewItem<T>)item);
}
return result.ToArray();
}
public new IEnumerator<ListViewItem<T>> GetEnumerator()
{
IEnumerator baseEnumerator = base.GetEnumerator();
while (baseEnumerator.MoveNext())
{
yield return (ListViewItem<T>)baseEnumerator.Current;
}
}
[Obsolete("Please use the generic Insert instead.", true)]
public new ListViewItem<T> Insert(int index, ListViewItem item)
{
throw new NotSupportedException("Please use the generic Insert instead.");
}
public ListViewItem<T> Insert(int index, ListViewItem<T> item)
{
return (ListViewItem<T>)base.Insert(index, item);
}
public new ListViewItem<T> Insert(int index, string text)
{
return (ListViewItem<T>)base.Insert(index, new ListViewItem<T>(text));
}
public new ListViewItem<T> Insert(int index, string text, int imageIndex)
{
return (ListViewItem<T>)base.Insert(index, new ListViewItem<T>(text, imageIndex));
}
public new ListViewItem<T> Insert(int index, string text, string imageKey)
{
return (ListViewItem<T>)base.Insert(index, new ListViewItem<T>(text, imageKey));
}
public new ListViewItem<T> Insert(int index, string key, string text, int imageIndex)
{
ListViewItem<T> item = new ListViewItem<T>(text, imageIndex);
item.Name = key;
return (ListViewItem<T>)base.Insert(index, item);
}
public new ListViewItem<T> Insert(int index, string key, string text, string imageKey)
{
ListViewItem<T> item = new ListViewItem<T>(text, imageKey);
item.Name = key;
return (ListViewItem<T>)base.Insert(index, item);
}
}
public new class SelectedListViewItemCollection : ListView.SelectedListViewItemCollection
{
public SelectedListViewItemCollection(ListView<T> owner) : base(owner)
{}
public new ListViewItem<T> this[int index]
{
get { return base[index] as ListViewItem<T>; }
}
public virtual new ListViewItem<T> this[string key]
{
get { return base[key] as ListViewItem<T>; }
}
}
public new class CheckedListViewItemCollection : ListView.CheckedListViewItemCollection
{
public CheckedListViewItemCollection(ListView<T> owner) : base(owner)
{}
public new ListViewItem<T> this[int index]
{
get { return base[index] as ListViewItem<T>; }
}
public virtual new ListViewItem<T> this[string key]
{
get { return base[key] as ListViewItem<T>; }
}
}
public new ListView<T>.ListViewItemCollection Items
{
get
{
return new ListView<T>.ListViewItemCollection(this);
}
}
public new ListView<T>.SelectedListViewItemCollection SelectedItems
{
get
{
return new ListView<T>.SelectedListViewItemCollection(this);
}
}
public new ListView<T>.CheckedListViewItemCollection CheckedItems
{
get
{
return new ListView<T>.CheckedListViewItemCollection(this);
}
}
}
Let's say it's in BSD license. :)
It could use some more constructors, and a couple more collections implemented. I'll update the source if that happens.
There's no unit tests for it, so I'll be happy for any bug fixes or bug reports.
The code I just used it for works. ;)
/Carl
Here's where it started earlier today:
http://stackoverflow.com/questions/4207279/generic-winforms-listview-with-regards-to-tag