数据绑定 ListView






4.60/5 (26投票s)
对继承 ListView 和实现设计时数据绑定功能进行概述。
引言
Microsoft 提供的 ListView
控件不支持设计时数据绑定。本文将提供一个基本概述,帮助您开始实现此功能。文中还将介绍如何隐藏基类的属性以及在 ListView 被排序时对 Currency Manager 进行排序。
背景
我正在紧迫的时间内构建一个系统;因此,我想使用数据绑定来实现快速开发。然而,我发现 ListView
控件无法在设计时绑定到 DataSource。和你们大多数开发人员一样,在 Google 搜索一番后,我决定发布一篇关于此主题的文章。本文的讲解非常基础,但旨在帮助您入门。源代码可以进行许多修改和更改,因为它并不完美。因此,我将在向控件添加有用功能时更新文章。
免责声明
请注意,下面未列出 Visual Studio 生成的代码。您可以在上面的源代码中找到完整的代码。此外,代码并不完美,但可以正常工作。它以零散的形式呈现,仅为了说明要点。本文实现的 C# 代码使用了 SQL Server 2000 的 NorthWind 数据库中的 Customer 表。
入门
在运行代码之前,请确保将 sqlConnection1
对象的 ConnectionString
属性更改为指向您的数据库。您可以修改下面的字符串,并在设计器中替换 ConnectionString
属性。
sqlConnection1.ConnectionString = "workstation id=YOUR_WORKSTATION_ID;packet size=4096;" + "integrated security=SSPI;data source=YOUR_SQL_SERVER;" + "persist security info=True;initial catalog=Northwind”
替换上述字符串后,您应该能够运行代码片段。
首先,列出了必需的命名空间,以及我们继承自 ListView
控件的事实。
using System;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
public class MyListView : System.Windows.Forms.ListView
类变量
我们定义了两个类变量。一个 CurrencyManager cm
用于跟踪当前选定的记录,另一个 DataView dv
用于在 CurrencyManager
上对列进行排序。
CurrencyManager <CODE>cm = null;
DataView dv
= null;
构造函数
构造函数很简单。我们添加了两个事件处理程序。一个用于 selected-index-changed 事件,另一个用于 column-header-click 事件。
public MyListView()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
base.SelectedIndexChanged +=new EventHandler(
MyListView_SelectedIndexChanged);
base.ColumnClick +=new ColumnClickEventHandler(
MyListView_ColumnClick);
}
属性
我们将 DataSource 属性添加为 Object
类型。然后,我们将 Bindable
属性设置为 true
,这会强制属性网格在 DataBindings 集合下显示此成员。TypeConverter
属性设置为 “System.Windows.Forms.Design.DataSourceConverter, System.Design”
。现在,DataSource 属性会在设计时显示属性网格中的所有可用数据源。最后,Category 属性将该属性归类到 Data 类别下。
private Object source;
[Bindable(true)]
[TypeConverter("System.Windows.Forms.Design.DataSourceConverter,
System.Design")]
[Category("Data")]
public Object DataSource
{
get
{
return source;
}
set
{
source = value;
}
}
接下来,我们将 DataMember
属性添加为 String
类型,用于存储要在 ListView
中显示字段的名称。我们再次将 Bindable
属性设置为 true
,并将 Category 设置为 Data。然后,将 Editor
属性设置为 “System.Windows.Forms.Design.DataMemberFieldEditor, System.Design”
,它会显示与 DataSource 关联的列。RefreshProperties
属性设置为重新查询所有属性并刷新视图。最后,在设置 DataMember
属性时,我们调用 bind()
方法来负责填充 ListView
。
private String data;
[Bindable(true)]
[Category("Data")]
[Editor("System.Windows.Forms.Design.DataMemberFieldEditor,
System.Design", "System.Drawing.Design.UITypeEditor,
System.Drawing")]
[RefreshProperties(RefreshProperties.All)]
public String DataMember
{
get
{
return data;
}
set
{
data = value;
bind();
}
}
然后,我们通过重新定义具有精确签名的 Sorting
属性并将其 browsable
属性设置为 false
,来从属性网格中隐藏基类的 Sorting
属性。这会在设计时隐藏 Sorting
属性,但仍可通过代码访问。请注意:此属性不需要隐藏。您可以在启动时编写额外代码,根据设计时选择对列表进行排序。
[Browsable(false)]
public new SortOrder Sorting
{
get
{
return base.Sorting;
}
set
{
base.Sorting = value;
}
}
方法
最后,这是最关键的部分。bind()
方法从 DataSource 中提取 DataRowCollection 并填充 ListView
。
private void bind()
{
//Clear the existing list
Items.Clear();
//This implementation assumes the DataSource is a DataSet
if(source is DataSet)
{
DataSet ds = source as DataSet;
DataTable dt = ds.Tables[0];
if(dt!=null)
{
//get the Binding Context for the Form
cm = (CurrencyManager)BindingContext[ds,
ds.Tables[0].TableName];
//add an event handler for the Currency Manager
cm.CurrentChanged +=new EventHandler(cm_CurrentChanged);
//Get the Currency Manager Collection as a DataView
dv = (DataView)cm.List;
//Create the column header based on the DataMember
Columns.Add(DataMember, ClientRectangle.Width - 17,
HorizontalAlignment.Left);
//Add each Row as a ListViewItem
foreach(DataRow dr in dt.Rows)
{
ListViewItem lvi = new ListViewItem(
dr[DataMember].ToString());
lvi.Tag = dr;
Items.Add(lvi);
}
//Set the Sorting property as Ascending
Sorting = SortOrder.Ascending;
//Sort the DataView on the DataMember
dv.Sort = this.Columns[0].Text + " ASC";
}
}
else
{
//If no source is defined, Currency Manager is null
cm = null;
}
}
事件
我为此控件编写了三个基本事件。
- Selected-Index-Changed 事件处理程序负责更新 Currency Manager 上的
Position
属性,这会强制其他绑定的控件更新到新选定的记录。private void MyListView_SelectedIndexChanged(object sender, EventArgs e) { if(this.SelectedIndices.Count>0) { if(cm!=null) { cm.Position = base.SelectedIndices[0]; } } }
- Column-Click 事件处理程序用于同步对
ListView
和DataView
进行排序,以及 Currency Manager 的列表。private void MyListView_ColumnClick(object sender, ColumnClickEventArgs e) { if(Sorting==SortOrder.None || Sorting == SortOrder.Descending) { Sorting = SortOrder.Ascending; dv.Sort = this.Columns[0].Text + " ASC"; } else if(Sorting==SortOrder.Ascending) { Sorting = SortOrder.Descending; dv.Sort = this.Columns[0].Text + " DESC"; } }
- Currency Manager 的 position change 事件处理程序会在
ListView
中选择相应的项。private void cm_CurrentChanged(object sender, EventArgs e) { this.Items[cm.Position].Selected = true; }
瞧!我们现在已经成功地将数据绑定实现到了 ListView
控件。上述绑定功能有限,但您可以进一步扩展该控件以增强基本功能。
关注点
在编写此控件时,我发现可以为绑定自定义控件编写一个通用类。这将允许非常快速地将绑定实现到新控件,而无需大量编码。有机会我会提交一篇关于它的文章。
历史
- 2005年4月2日
提交了原始文章