65.9K
CodeProject 正在变化。 阅读更多。
Home

数据绑定 ListView

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (26投票s)

2005 年 4 月 2 日

CPOL

4分钟阅读

viewsIcon

540292

downloadIcon

11852

对继承 ListView 和实现设计时数据绑定功能进行概述。

Sample Image - ListView_DataBinding.jpg

引言

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;                                        
    }
}

事件

我为此控件编写了三个基本事件。

  1. 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];
            }
        }
    }
  2. Column-Click 事件处理程序用于同步对 ListViewDataView 进行排序,以及 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";
        }
    }
  3. Currency Manager 的 position change 事件处理程序会在 ListView 中选择相应的项。
    private void cm_CurrentChanged(object sender, EventArgs e)
    {
        this.Items[cm.Position].Selected = true;
    }

瞧!我们现在已经成功地将数据绑定实现到了 ListView 控件。上述绑定功能有限,但您可以进一步扩展该控件以增强基本功能。

关注点

在编写此控件时,我发现可以为绑定自定义控件编写一个通用类。这将允许非常快速地将绑定实现到新控件,而无需大量编码。有机会我会提交一篇关于它的文章。

历史

  • 2005年4月2日

    提交了原始文章

© . All rights reserved.