开发者

Generic WinForms ListView (with regards to Tag)

I'm trying to improve on a Winforms project where datatable rows are stored in the Tag property of ListViewItems. When the datatable is refactored to List<T> (or actually classes containing lists) it would help immensely if I could make the Tag property generic by using a subclass of ListView.

In the best of worlds, I'd want the Tag property to be replaced by a public T Tag{get; set;} that wraps base.Tag and casts it. Second best would be Obsoleting Tag and providing a new property like TypedTag working like above.

I think this would involve subclassing or composite aggregation of at least ListView, ListViewItemCollection, SelectedListViewItemCollection and ListViewItem, and I'm not sure how to do it.

In short:

ListView<Employee> lvwEmployees;

should result in this being possible:

Employee selected = lvwEmployees.SelectedItems[0].TypedTag;

And give a compilation error for this:

DataRow selected = lvwEmployees.SelectedItems[0].TypedTag;

Is it possible? Is it already done? Project is dotnet 2.0 but I think I'll try to have it upgraded if it helps this matter.

EDIT: It turns out that the owner constructor argument is all a certain collection needs to hook up to the inner collection. Hence the following works:

ListView a = new ListView();
a.Items.Add("Hello");
Assert.AreEqual(1, new ListView.ListViewItemCollection(a).Count);

This makes it rather easy to create a generic ta开发者_如何学运维gged ListView. I'll post a complete solution later. :)

EDIT2: Here's the solution: http://thecarlr.blogspot.com/2010/11/generic-listview.html

EDIT3: For designer support, just add a non generic subclass and use that. Example: If you intended to use ListView<Employee> in the form, create a ListViewEmployee : ListView<Employee> in another file, and use ListViewEmployee in the form.

The easiest way to add one of theese listviews would be to add a normal listview to the form, and then change it's type in the source files. (And if you don't know where it's declared or instantiated, find out or use the normal listview instead.)


You made the wrong class generic. SelectedItems[0] is a ListViewItem, not a ListView.

There isn't anything you can do to change the type of the Items and SelectedItems properties. You can certainly derive your own class from ListViewItem and just add the property you want to store. No need for another Tag property. You'll have no trouble adding them but you'll need to cast back to your derived class when you retrieve them back from the Selected/Items collection.

In general, avoid this kind of code by using the ListView only as a view of your model. The ListViewItem.Index should then always be good to get a typesafe reference back from your model.


Here's the solution: http://thecarlr.blogspot.com/2010/11/generic-listview.html

Enjoy :)

/Carl


VS Designer simply cannot handle abstract or generic controls (not for want of asking).

One way around that limitation is to write a type safe wrapper around a standard ListView.

Something like this:

public class TypedListView<T> where T : class
{
    public TypedObjectListView(ListView lv) {
        this.lv = lv;
    }
    private ListView lv;

    public virtual T SelectedObject {
        get { return (T)this.lv.SelectedItems[0].Tag; }
    }

    // Lots more methods/properties
}

You create a normal ListView in Designer, and then when you wanted to access it, you create and use your adapter instead. Like this:

var typedListView = new TypedListView<Employee>(this.listView1);
Employee selectedEmployee = typedListView.SelectedObject;

You would need to provide a typed version of every ListView properties or method you wanted to use.

The ObjectListView project takes this approach to create a TypedObjectListView which does exactly what are you asking for.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜