Why do I want to databind a ListView-control and not use the DataGrid-control? Well, I think that the ListView-control is more suitable for displaying readonly data and the look and feel is also customizable (see
previous post). I regret that DataBinding is not possible for the base ListView-control ...
.NET allows us to create custom controls by using inheritance. In my example I will inherit from the ListView-control and add functionality to this base control to create a
custom databound ListView-control.
In the form above a listView is used for displaying all data (stored in a dataset "MyDataSet") and Textboxes are set for updating the data. Binding Textboxes to a dataset is simple :
//DataBinding for TextBoxes
this.txtFirstName.DataBindings.Add("Text", this.myDataSet.Names, "FirstName");
this.txtLastName.DataBindings.Add("Text", this.myDataSet.Names, "LastName");
Binding more complex controls is done via the DataSource property :
//DataBinding for DataGrid
this.myDataGrid.DataSource = myDataSet.Names;
So for building a Databound ListView we need to implement a custom DataSource Property [+ DataMember for name of DataTable] and focus on the interaction with the DataSource to retrieve the data for display (DataBinding) in the listView.
I've created a separate project for storing the new databound ListView. In the constructor some defaults are already set for my ListView and I've also created two Properties (DataSource and DataMember).
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
namespace DataBoundListView
{
public class MyListView : ListView
{
//Variables
private string dataMember;
private DataSet dataSource;
private int columnWidth = 100;
private CurrencyManager cm;
//Constructor
public MyListView()
{
//set default settings for listView
this.View = View.Details;
this.FullRowSelect = true;
this.MultiSelect = false;
this.BackColor = Color.Wheat;
this.ForeColor = Color.Brown;
this.HideSelection = false;
this.SelectedIndexChanged += new EventHandler(MyListView_SelectedIndexChanged);
}
//Properties
public string DataMember
{
get { return this.dataMember; }
set { this.dataMember = value; }
}
public DataSet DataSource
{
get { return this.dataSource; }
set
{
this.dataSource = value;
this.dataBindControl();
this.setCurrencyManager();
}
}
//Methods
private void setCurrencyManager()
{
//Assign CurrencyManager [from BindingContext]
this.cm = (CurrencyManager) this.BindingContext[this.dataSource.Tables[dataMember]];
}
private void dataBindControl()
{
this.Clear();
ListViewItem newItem;
//Add columns to ListView
foreach (DataColumn col in this.dataSource.Tables[dataMember].Columns)
{
base.Columns.Add(col.ColumnName, columnWidth, HorizontalAlignment.Left);
}
for (int i=0; i < this.dataSource.Tables[dataMember].Rows.Count; i++)
{
newItem = new ListViewItem();
//First Column
newItem.Text = this.dataSource.Tables[dataMember].Rows[i].ItemArray[0].ToString();
//SubItems
for (int subItems=1; subItems < base.Columns.Count; subItems++)
{
newItem.SubItems.Add(this.dataSource.Tables[dataMember].Rows[i].ItemArray[subItems].ToString());
}
this.Items.Add(newItem);
}
}
private void MyListView_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.SelectedItems.Count > 0)
{
//set Position of CurrencyManager to selectedIndex of ListView
cm.Position = this.SelectedItems[0].Index;
}
}
}
}
In the method "dataBindControl", the databinding is set for the dataSet. First, the columns are added to the listView and afterwards, the rows (item + subItems) are added. This method is called each time the "DataSource" Property is set. "setCurrencyManager" assigns the CurrencyManager and the EventHandler "MyListView_SelectedIndexChanged" sets the position of the CurrencyManager so that other controls bound to myDataSet can be updated.
That's all for coding the custom ListView. The control is now ready to use in a new project ...
//Using the custom control
this.myListView = new MyListView();
this.myListView.DataMember = "Names";
this.myListView.DataSource = this.myDataSet;
The EventHandlers of the textBoxes are looking after the DataBinding with myDataSet and so for updating the ListView.
private void txtFirstName_Validated(object sender, System.EventArgs e)
{
this.renewDataBinding();
}
private void txtLastName_Validated(object sender, System.EventArgs e)
{
this.renewDataBinding();
}
private void renewDataBinding()
{
this.myListView.DataSource = this.myDataSet;
}
Useful links