I have a DataGrid bound to an ArrayList. When I delete a 'row' from the
ArrayList the DataGrid throws an IndexOutOfRangeException exception. I
constructed a very simple sample app that reproduces the problem (code
below). This sample simply populates the grid from the array (see Form1
constructor). When you click the button it deletes the current row (see
button1_click). At that point the exception is thrown.
If anyone could suggest what I'm doing wrong I'd appreciate it.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace WindowsApplication1
{
public class Form1 : System.Windows.Forms.Form
{
private ArrayList m_oArrayList=new ArrayList();
private System.Windows.Forms.DataGrid m_oDataGrid;
private System.Windows.Forms.Button button1;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
m_oArrayList.Add(new NameValuePair("NameOne","ValueOne"));
m_oArrayList.Add(new NameValuePair("NameTwo","ValueTwo"));
m_oArrayList.Add(new NameValuePair("NameThree","ValueThree"));
m_oArrayList.Add(new NameValuePair("NameFour","ValueFour"));
m_oArrayList.Add(new NameValuePair("NameFive","ValueFive"));
m_oArrayList.Add(new NameValuePair("NameSix","ValueSix"));
m_oArrayList.Add(new NameValuePair("NameSeven","ValueSeven"));
m_oDataGrid.SetDataBinding(m_oArrayList,"");
}
private void button1_Click(object sender, System.EventArgs e)
{
m_oArrayList.RemoveAt(m_oDataGrid.CurrentRowIndex);
m_oDataGrid.Refresh();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.m_oDataGrid = new System.Windows.Forms.DataGrid();
this.button1 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.m_oDataGrid)).BeginInit();
this.SuspendLayout();
this.m_oDataGrid.DataMember = "";
this.m_oDataGrid.HeaderForeColor =
System.Drawing.SystemColors.ControlText;
this.m_oDataGrid.Location = new System.Drawing.Point(16, 40);
this.m_oDataGrid.Name = "m_oDataGrid";
this.m_oDataGrid.Size = new System.Drawing.Size(264, 176);
this.m_oDataGrid.TabIndex = 0;
this.button1.Location = new System.Drawing.Point(80, 8);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(64, 24);
this.button1.TabIndex = 1;
this.button1.Text = "delete";
this.button1.Click += new System.EventHandler(this.button1_Click);
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 229);
this.Controls.Add(this.button1);
this.Controls.Add(this.m_oDataGrid);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.m_oDataGrid)).EndInit();
this.ResumeLayout(false);
}
[STAThread] static void Main()
{
Application.Run(new Form1());
}
}
public class NameValuePair
{
private string m_strName=string.Empty;
public string Name{get{return m_strName;} set{m_strName=value;}}
private string m_strValue=string.Empty;
public string Value{get{return m_strValue;} set{m_strValue=value;}}
public NameValuePair(string strName,string strValue)
{
m_strName = strName;
m_strValue =strValue;
}
}
}

Exception deleting a row from DataGrid bound to an ArrayList
Basic Veteran
I have found refreshing the grid via the CurrencyManager to be reliable:
private void button1_Click(object sender, System.EventArgs e)
{
m_oArrayList.RemoveAt(m_oDataGrid.CurrentRowIndex);
((CurrencyManager)m_oDataGrid.BindingContex[m_oDataGrid.DataSource]).Refresh();
}
iping
Hi!
DataGrid.Refresh() simply redraw content of the window, it doesn't understand changes in list.
DataGrid thinks that DataSource must provide IBindingList interface to notify about changes in list, so grid will update it's content. ArrayList do not implement such interface. To correctly delete you must implement IBindingList on your class that wrap array list.
But I think it's easier to create DataTable and use it instead of ArrayList.
Timbo
DataTable implements IListSource that is another interface to support data binding. In fact DataTable return it's default DataView for binding, which is implementing IBindingList. So you can use it.
One thing you must understand with DataTable - it do not displayed in data source, but it's DataView. So index in grid will refer to DataRowView in DataView, not the row in table itself.
IBindingList is not necessary for data binding (simple immutable datasource case), but it required in case like yours - when list changes must be noticed by grid (IBindingList.ListChanged event).
BTW, why you think grid aware of changes
If you use .NET 2.0 - use BindingSource and DataGridView, they are more suitable than DataGrid.
Paul_P
Thanks for taking the time to reply.
However, I'm confused by your response. DataTable doesn't implement IBindingList, and IBindingList isn't listed as an interface necessary to qualify as a data source for DataGrid.
Stepping through the code with the debugger I can see that the grid is aware that the array has changed.