PRB: "Index Was Out of Range" Error Message from the DataGrid While Paging (813832)



The information in this article applies to:

  • Microsoft ASP.NET (included with the .NET Framework) 1.0
  • Microsoft Visual Basic .NET (2002)
  • Microsoft Visual C# .NET (2002)
  • Microsoft ASP.NET (included with the .NET Framework 1.1)
  • Microsoft Visual C# .NET (2003)
  • Microsoft Visual Basic .NET (2003)

SYMPTOMS

To trap the record that is being accessed in a DataGrid Web server control, you use the DataKeys collection of DataGrid on an ItemCommand event, and then pass the ItemIndex property as a key to the DataKey collection. When you click a link to move to the next page (or to a new page) in the DataGrid, you may receive the following error message:
Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

CAUSE

When you click a link to move to the next page (or to a new page) in the DataGrid, the ItemCommand event is invoked. The value of the ItemIndex property is -1 in the ItemCommand event. You may receive an error when you pass the ItemIndex property as a key to retrieve the value from the DataKey collection because the DataKey collection is zero bound.

WORKAROUND

To work around this problem, retrieve a value from the DataKey collection only when the value of the ItemIndex property is greater than or equal to 0. The following ItemCommand event sample code demonstrates how to do this.

Visual C# .NET Sample Code
private void DataGrid1_ItemCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
 // If Not navigating to Next Page, show the CategoryID in the text box.
  if (e.Item.ItemIndex > -1)
  {
  // Get the CategoryID of the Row Selected in the DataGrid.
  TextBox1.Text = DataGrid1.DataKeys[e.Item.ItemIndex].ToString();
  }
}
Visual Basic .NET code
   Private Sub DataGrid1_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles DataGrid1.ItemCommand
      ' If Not navigating to Next Page, show the CategoryID in the text box.
      If e.Item.ItemIndex > -1 Then
         ' Get the CategoryID of the Row Selected in the DataGrid.
         TextBox1.Text = DataGrid1.DataKeys(e.Item.ItemIndex)
      End If
   End Sub

STATUS

This behavior is by design.

MORE INFORMATION

Steps to Reproduce the Behavior

  1. Start Visual Studio .NET. On the File menu, point to New, and then click Project.
  2. In the New Project dialog box, under Project Types, click Visual C# Projects or Visual Basic Projects. Under Templates, click ASP.NET Web Application.
  3. In the Location text box, type MyDatagridTest, and then click OK. By default, WebForm1.aspx is created.
  4. Drag a DataGrid control from the toolbox to WebForm1.
  5. In Design view of WebForm1, right-click the DataGrid control, and then click Property Builder.
  6. Click Paging, and then click to select the Allow Paging check box. In Page size textbox, type 4.
    Note Verify for more than four records in the database.
  7. Click Columns. In the Available columns list, expand Button Column.
  8. Click the Select column, and then click the right arrow (>) to add the Select column to the Selected Columns list.
  9. In the Textfield text box, type CategoryID.
  10. Under Button Type, click LinkButton, and then click OK.
  11. Drag a TextBox control from the toolbox to WebForm1.
  12. Double-click anywhere on WebForm1 to view the code for WebForm1.aspx. Replace the existing code with the following sample code:

    Visual C# .NET Sample Code
    using System;
    using System.Data;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.HtmlControls;
    using System.Data.SqlClient;
    
    namespace MyDatagridTest
    {
    	/// <summary>
    	/// Summary description for WebForm1.
    	/// </summary>
    	public class WebForm1 : System.Web.UI.Page
    	{
    		protected System.Web.UI.WebControls.DataGrid DataGrid1;
    		protected System.Web.UI.WebControls.TextBox TextBox1;
    	
    		private void Page_Load(object sender, System.EventArgs e)
    		{
    			// Open a connection to the database.
    			SqlConnection cn ;
    			cn = new SqlConnection("data source=10.150.144.141;initial catalog=Northwind;User ID = sa;"+				"Password = sa; persist security info=False");
    
    			// Create a DataAdaptor for gaining access to data.
    			SqlDataAdapter da ;
    			da = new SqlDataAdapter("SELECT CategoryID, CategoryName, Description FROM Categories", cn);
    
    			//  Populate the DataSet with data.
    			DataSet ds = new DataSet();
    			da.Fill(ds, "Categories"); 
    
    			//  Bind the Table to the DataGrid.
    			DataGrid1.DataSource = ds.Tables["Categories"].DefaultView;
    
    			//  Specify the Column for DataKey.
    			DataGrid1.DataKeyField = "CategoryID";
    			DataGrid1.DataBind();
    		}
    		
    
    		#region Web Form Designer generated code
    		override protected void OnInit(EventArgs e)
    		{
    			//
    			// CODEGEN: ASP.NET Web Form Designer requires this call.
    			//
    			InitializeComponent();
    			base.OnInit(e);
    		}
    		
    		/// <summary>
    		/// Required method for Designer support - do not change
    		/// the contents of this method by using the code editor.
    		/// </summary>
    		private void InitializeComponent()
    		{    
    			this.DataGrid1.ItemCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.DataGrid1_ItemCommand);
    			this.DataGrid1.PageIndexChanged += new System.Web.UI.WebControls.DataGridPageChangedEventHandler(this.DataGrid1_PageIndexChanged);
    			this.Load += new System.EventHandler(this.Page_Load);
    
    		}
    		#endregion
    		
    		private void DataGrid1_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
    		{
    			// Move to Next Page.
    			DataGrid1.CurrentPageIndex = e.NewPageIndex;
    			DataGrid1.DataBind();
    		}
    
    
    		private void DataGrid1_ItemCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e)
    		{
    		
    				// Get the CategoryID of the Row Selected in the DataGrid.
    				TextBox1.Text = DataGrid1.DataKeys[e.Item.ItemIndex].ToString();
    	        
    		}
    
    	}
    }
    
    Visual Basic .NET code
    Imports System.Data.SqlClient
    
    Public Class WebForm1
       Inherits System.Web.UI.Page
       Protected WithEvents TextBox1 As System.Web.UI.WebControls.TextBox
       Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
    
    #Region " Web Form Designer Generated Code "
    
       'The Web Form Designer requires this call.
       <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
    
       End Sub
    
       Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
          'CODEGEN: The Web Form Designer requires this method call.
          'Do not change it by using the code editor.
          InitializeComponent()
       End Sub
    
    #End Region
    
       Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
          ' Open a connection to the database.
          Dim cn As SqlConnection
          cn = New SqlConnection("data source=10.150.144.131;initial catalog=Northwind;User ID = sa; persist security info=False")
    
          ' Create a DataAdaptor for gaining access to data.
          Dim da As SqlDataAdapter
          da = New System.Data.SqlClient.SqlDataAdapter("SELECT CategoryID, CategoryName, Description FROM Categories", cn)
    
          ' Populate the DataSet with data.
          Dim ds As New DataSet()
          da.Fill(ds, "Categories")
    
          ' Bind the Table to the DataGrid.
          DataGrid1.DataSource = ds.Tables("Categories").DefaultView
          ' Specify the Column for DataKey
          DataGrid1.DataKeyField = "CategoryID"
          DataGrid1.DataBind()
       End Sub
    
    
       Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
          ' Move to Next Page.
          DataGrid1.CurrentPageIndex = e.NewPageIndex
          DataGrid1.DataBind()
       End Sub
    
       Private Sub DataGrid1_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles DataGrid1.ItemCommand
          ' Get the CategoryID of the Row Selected in the DataGrid.
          TextBox1.Text = DataGrid1.DataKeys(e.Item.ItemIndex)
       End Sub
    
    End Class
  13. On the Debug menu, click Start to run the application.
  14. Click any record link, for example, 2. The value 2 appears in the text box.
  15. Click the right arrow (>) to move to the next page of records. The error message mentioned in the "Symptoms" section appears.

REFERENCES

For more information about creating and populating a DataGrid control, visit the following Microsoft Web site: For additional information, click the following article number to view the article in the Microsoft Knowledge Base:

318131 HOW TO: Page Through a Query Result for Better Performance


Modification Type:MinorLast Reviewed:4/30/2003
Keywords:kbWebForms kbweb kberrmsg kbEvent kbDataAdapter kbDataBinding kbServerControls kbprb KB813832 kbAudDeveloper