打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Data binding a ListView

Data binding a ListView

By , 9 Apr 2005
 
Is your email address OK? You are signed up for our newsletters but your email address is either unconfirmed, or has not been reconfirmed in a long time. Please click here to have a confirmation email sent so we can confirm your email address and start sending you newsletters again. Alternatively, you can update your subscriptions.

Introduction

The ListView control provided by Microsoft does not allow design-time data binding. This article gives a basic overview to get you started in implementing this functionality. It will also show you how to hide the base class’ properties and to sort the currency manager when the list view is sorted.

Background

I am in the process of architecting a system under strict time constraints; hence I wanted to use Databinding for rapid development. However, I discovered that the ListView control cannot be bound to a DataSource at design-time. And just like most of you developers out there, after GOOGLING around I decided to post an article on this topic. What I am explaining in this article is quite basic, but it is meant to get you started. There are many modifications and changes that can be made to the source as it is not perfect. Hence, I will update the article as I add useful functionality to the control.

Disclaimer

Please note that the Visual Studio Generated Code is not listed below. You will find the code in its entirety in the source-code above. In addition, the code is not perfect, but it works. It is in bits-n-pieces to just get the point across. The code implemented for this article uses the Customer table from the NorthWind database in SQL Server 2000.

Getting Started

Before you run the code, make sure to change the ConnectionString property of the sqlConnection1 object to point to your database. You can modify the string below and replace the ConnectionString property in the designer.

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”

Once you replace the above string, you should be able to run the code snippet.

First and foremost, the required namespaces are listed below and also the fact that we inherit from the ListView control.

using System;using System.ComponentModel;using System.Data;using System.Windows.Forms;public class MyListView : System.Windows.Forms.ListView

Class Variables

We define two class variables. A CurrencyManager cm to track the current selected record and a DataView dv to sort the columns on the CurrencyManager.

CurrencyManager <CODE>cm</CODE> = null;DataView <CODE>dv</CODE> = null;

Constructor

The constructor is straight-forward. We add two event-handlers. One for the selected-index-changed event and the other for the column-header-click event.

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

Properties

We add the DataSource property as an Object type. Then, we set the Bindable attribute to true which forces the property grid to display this member under the DataBindings collection. The TypeConverter attribute is set to “System.Windows.Forms.Design.DataSourceConverter, System.Design”. Now, the DataSource property shows all the available data sources at design-time in the property-grid. Finally, the Category attribute categorizes the property under the Data Category.

private Object source;[Bindable(true)][TypeConverter("System.Windows.Forms.Design.DataSourceConverter,                                            System.Design")][Category("Data")]public Object DataSource{    get    {        return source;    }    set    {        source = value;    }}

Next we add the DataMember property as a String type to store the Name of the field to be displayed in the ListView. Once again we set the Bindable attribute to true and Category to Data. Next, the Editor attribute is set to “System.Windows.Forms.Design.DataMemberFieldEditor, System.Design”, which shows us the columns associated with the DataSource. The RefreshProperties attribute is set to re-query all the properties and the refresh the view. Finally, on setting the DataMember property, we call the bind() method which takes care of populating the 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();    }}

Then, we hide the base class' Sorting property from the property grid by re-defining the Sorting property with the exact signature and setting its browsable attribute to false. This hides the Sorting property at design-time, but it is still accessible through the code. Please note: this property does not need to be hidden. You can write additional code at startup to sort the list based on the design-time selection.

[Browsable(false)]public new SortOrder Sorting{    get    {        return base.Sorting;    }    set    {        base.Sorting = value;    }}

Methods

Finally, this is where the rubber meets the road. The method bind() pulls out a DataRowCollection from the DataSource and populates the 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;                                            }}

Events

There are three basic events that I have written for this control.

  1. Selected-Index-Changed event handler is in charge of updating the Position property on the Currency Manager, which forces other bound controls to update to the newly selected record.
    private void MyListView_SelectedIndexChanged(object sender, EventArgs e){    if(this.SelectedIndices.Count>0)    {                       if(cm!=null)        {             cm.Position = base.SelectedIndices[0];        }    }}
  2. A Column-Click event handler to sort the ListView and the DataView in sync with the Currency Manager’s list.
    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’s position change event handler selects the appropriate item in the ListView.
    private void cm_CurrentChanged(object sender, EventArgs e){    this.Items[cm.Position].Selected = true;}

Voila! We have now successfully implemented Data-Binding to a ListView control. The binding explained above is quite limited in its features, but you can further expand on the control to enhance the basic features.

Points of Interest

While writing this control, I discovered that a generic class can be written for binding custom controls. This would allow implementing binding on new controls really fast without much coding. I will submit an article about it when I get a chance.

History

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Excel VBA 学习总结
C# linq查询 动态OrderBy
A Sortable GridView (I mean ListView) Control in WPF
WPF自定义控件与样式(7)
无废话WPF系列9: Binding的源
《深入浅出WPF》学习笔记之深入浅出话Binding
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服