通用WinForms ListView(关于标记)

通用WinForms ListView(关于标记),winforms,listview,tags,generics,typed,Winforms,Listview,Tags,Generics,Typed,我试图改进Winforms项目,其中datatable行存储在ListViewItems的标记属性中。当datatable被重构为List(或者实际上是包含List的类)时,如果我可以使用ListView的子类使标记属性成为泛型的,那将非常有帮助 在最好的情况下,我希望将Tag属性替换为一个公共的T标记{get;set;},它包装base.Tag并强制转换它。 第二个最好的方法是淘汰标签,并提供一个像TypedTag这样的新属性,它可以像上面那样工作 我认为这将涉及至少ListView、List

我试图改进Winforms项目,其中datatable行存储在ListViewItems的标记属性中。当datatable被重构为List(或者实际上是包含List的类)时,如果我可以使用ListView的子类使标记属性成为泛型的,那将非常有帮助

在最好的情况下,我希望将Tag属性替换为一个公共的T标记{get;set;},它包装base.Tag并强制转换它。 第二个最好的方法是淘汰标签,并提供一个像TypedTag这样的新属性,它可以像上面那样工作

我认为这将涉及至少ListView、ListViewItemCollection、SelectedListViewItemCollection和ListViewItem的子类化或复合聚合,我不确定如何做到这一点

简言之:

ListView<Employee> lvwEmployees;
并为此提供一个编译错误:

DataRow selected = lvwEmployees.SelectedItems[0].TypedTag;
可能吗?已经完成了吗? 这个项目是Dotnet2.0,但我想如果它有助于解决这个问题,我会尝试升级它

编辑:事实证明,所有者构造函数参数是某个集合连接到内部集合所需的全部参数。因此,开展了以下工作:

ListView a = new ListView();
a.Items.Add("Hello");
Assert.AreEqual(1, new ListView.ListViewItemCollection(a).Count);
这使得创建一般标记的ListView变得相当容易。稍后我将发布完整的解决方案。:)

EDIT2:以下是解决方案:

EDIT3:对于设计器支持,只需添加一个非泛型子类并使用它。 示例:如果要在表单中使用ListView,请在另一个文件中创建ListViewEmployee:ListView,然后在表单中使用ListViewEmployee


添加这些列表视图中的一个最简单的方法是在表单中添加一个普通的列表视图,然后在源文件中更改它的类型。(如果您不知道它在哪里声明或实例化,请查找或使用普通的listview。)

您将错误的类设置为泛型。SelectedItems[0]是ListView项,而不是ListView

您无法更改项目的类型和SelectedItems属性。您当然可以从ListViewItem派生自己的类,只需添加要存储的属性。不需要另一个标记属性。添加它们不会有问题,但从Selected/Items集合中检索它们时,需要将其转换回派生类

通常,通过仅将ListView用作模型的视图来避免此类代码。然后,ListViewItem.Index应该始终能够从您的模型中获取类型安全引用。

以下是解决方案:

享受:)


/Carl

VS Designer根本无法处理抽象或通用控件()

绕过该限制的一种方法是围绕标准的
ListView
编写类型安全包装

大概是这样的:

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
}
公共类类型列表视图,其中T:class
{
公共类型对象ListView(ListView lv){
this.lv=lv;
}
私有ListView lv;
公共虚拟T选择对象{
获取{return(T)this.lv.SelectedItems[0].Tag;}
}
//更多方法/属性
}
您可以在Designer中创建一个普通的ListView,然后当您想要访问它时,您可以创建并使用适配器。像这样:

var typedListView = new TypedListView<Employee>(this.listView1);
Employee selectedEmployee = typedListView.SelectedObject;
var typedListView=新的typedListView(this.listView1);
Employee selectedEmployee=typedListView.SelectedObject;
您需要提供要使用的每个
ListView
属性或方法的键入版本


该项目采用这种方法创建了一个
TypedObjectListView
,它完全满足了您的要求。

在我想创建一个完整的类链,而不仅仅是ListViewItem上也讨论了一个类似的主题。构造结构没有问题,但是ListViewItem的私有(或未实现)项的构造和分配问题更大。只要它们来自ListViewItem。否则,无法将它们添加到ListView的项集合中。ListViewItem中有一些私有成员是让Windows满意所必需的。是的,但ListView的项集合不是泛型的,因此需要重写它。是的,但正如我在回答中所指出的,您不能重写Items属性。它不是虚拟的。是的,我知道。这就是为什么OP中提到了聚合这个词。不过,我想我现在已经基本上解决了这个问题。:)此解决方案的主要问题是无法在设计器中使用通用ListView。因此,除非您打算手工编写所有的UI代码(或对Designer.cs进行后期编辑),否则此解决方案不是很有用。啊,感谢您的注意并让我知道!我得调查一下看来设计师的问题真的不是问题。我所需要做的就是再次继承到一个非泛型类中并使用它。哇,ObjectListView看起来真不错。我得调查一下。谢谢!顺便说一句,我喜欢适配器的想法,但它并不理想,因为它很容易遍历普通变量,这样就有带有其他类型“标记”的行。
var typedListView = new TypedListView<Employee>(this.listView1);
Employee selectedEmployee = typedListView.SelectedObject;