locked
Gridview Row Updating Problem - Index was out of range RRS feed

  • Question

  • User-1501204699 posted

    Hello there,

    I have a gridview as follows


    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" AllowSorting="True"
                                CssClass="datatable" CellPadding="0" BorderWidth="0px" GridLines="None" OnRowDeleting="GridView1_RowDeleting"
                                OnRowEditing="GridView1_RowEditing" OnRowUpdating="GridView1_RowUpdating" OnRowCancelingEdit="GridView1_RowCancelingEdit">
                                <PagerStyle CssClass="pager-row" />
                                <RowStyle CssClass="row" />
                                <PagerSettings Mode="NumericFirstLast" PageButtonCount="7" FirstPageText="&#171;"
                                    LastPageText="&#187;" />
                                <Columns>
                                    <asp:BoundField DataField="ID" HeaderText="ID" ReadOnly="True">
                                        <HeaderStyle HorizontalAlign="Left" />
                                    </asp:BoundField>
                                    <asp:BoundField DataField="Name" HeaderText="Name" ReadOnly="True">
                                        <HeaderStyle HorizontalAlign="Left" />
                                    </asp:BoundField>
                                    <asp:BoundField DataField="Price" HeaderText="Price" ReadOnly="True">
                                        <HeaderStyle HorizontalAlign="Left" />
                                    </asp:BoundField>
                                    <asp:BoundField DataField="Quantity" HeaderText="Quantity">
                                        <HeaderStyle HorizontalAlign="Left" />
                                    </asp:BoundField>
                                    <asp:BoundField DataField="Total" HeaderText="Total" ReadOnly="True">
                                        <HeaderStyle HorizontalAlign="Left" />
                                    </asp:BoundField>
                                    <asp:CommandField EditText="Change" ShowDeleteButton="True" ShowEditButton="True">
                                        <ItemStyle BorderStyle="None" />
                                        <HeaderStyle BorderStyle="None" />
                                    </asp:CommandField>
                                </Columns>
                                <EmptyDataTemplate>
                                    <p>
                                        Your Shopping Cart is empty.</p>
                                </EmptyDataTemplate>
                            </asp:GridView>


    and the code behind is


    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            CheckTimeStamps()
            If Session("cart") Is Nothing Then
                Cart = New ShoppingCart()
                Session("cart") = Cart
            Else
                Cart = Session("cart")
            End If
            GridView1.DataSource = Cart.GetItems()
            If Not IsPostBack Then
                GridView1.DataBind()
            End If
            btnCheckOut.Enabled = (Cart.Count > 0)
        End Sub


    Protected Sub GridView1_RowCancelingEdit(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCancelEditEventArgs) Handles GridView1.RowCancelingEdit
            e.Cancel = True
            GridView1.EditIndex = -1
            GridView1.DataBind()
        End Sub

        Protected Sub GridView1_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting
            cart.DeleteItem(e.RowIndex)
            GridView1.DataBind()
        End Sub

        Protected Sub GridView1_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles GridView1.RowEditing
            GridView1.EditIndex = e.NewEditIndex
            GridView1.DataBind()
        End Sub

        Protected Sub GridView1_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles GridView1.RowUpdating
            Dim cell As DataControlFieldCell
            cell = GridView1.Rows(e.RowIndex).Controls(3)
            Dim t As TextBox = cell.Controls(0)
            Try
                Dim q As Integer
                q = Integer.Parse(t.Text)
                cart.UpdateQuantity(e.RowIndex, q)
            Catch ex As FormatException
                e.Cancel = True
            End Try
            GridView1.EditIndex = -1
            GridView1.DataBind()
        End Sub


    But whenever i try to delete  or  update items i get an "Specified argument was out of range of valid values.Parameter name: index" and "Index was out of range. Must be non negative and less than the size of the collection. Parameter name: index". I dont know how to solve this.

    Thanks in advance.




    Saturday, July 18, 2009 6:47 PM

Answers

  • User232384818 posted

    well, keep the previous changes I asked you to make. In addition, you also have erratically wired the event handlers for gridview ItemUpdating,ItemDeleting, RowCancelingEdit, RowEditing..... all these event handlers you have registered two times.

    So this means, everytime you click the delete button for example, the ItemDeleting will fire 2 times. This is the main cause for your Index out of range error as the delete, update is performed 2 times for each postback.

    Please note how you use the Handles clause eg : 

    Protected Sub GridView1_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting
            cart.DeleteItem(e.RowIndex)
            GridView1.DataBind()
        End Sub

    note that the handles clause registers the event handler once. But you register it a second time declaratively, look here :

    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" AllowSorting="True"
                                CssClass="datatable" CellPadding="0" BorderWidth="0px" GridLines="None" OnRowDeleting="GridView1_RowDeleting"
                                OnRowEditing="GridView1_RowEditing" OnRowUpdating="GridView1_RowUpdating" OnRowCancelingEdit="GridView1_RowCancelingEdit">


    you pretty much do this for all your event handlers. Also in your page_load you use the handles clause, remove that since by default, AutoEventWireup="true" for your page. This means, all you need to do is add a method Page_Load eg :

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) <strike>Handles Me.Load</strike>
    End sub

    and the framework will do the rest.

    Remove the handles clause for the rest of your event handlers as you have already wired the event handlers declaratively. And your code should just work :-)

    Unfortunately, c# is my main language and i was a bit slow to catch this mistake in your code.  Undecided

    have a good weekend.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, July 19, 2009 10:04 AM

All replies

  • User232384818 posted

    hi, please note the erratic behavior of your application eg :

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            CheckTimeStamps()
            If Session("cart") Is Nothing Then
                Cart = New ShoppingCart()
                Session("cart") = Cart
            Else
                Cart = Session("cart")
            End If
            GridView1.DataSource = Cart.GetItems()
            If Not IsPostBack Then
                GridView1.DataBind()
            End If
            btnCheckOut.Enabled = (Cart.Count > 0)
        End Sub

    do you see how in page_load you are setting the datasource, specifically this line :
    GridView1.DataSource = Cart.GetItems()

    ok, you set the datasource early in page_load, for a while this is fine.

    But later on, during a delete operation for example :

    Protected Sub GridView1_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting
            cart.DeleteItem(e.RowIndex)
            GridView1.DataBind()
        End Sub

    note again the line :
    cart.DeleteItem(e.RowIndex)

    yoa are deleting an item. However in the next line when you databind, you bind stale data. Because page_load fires prior to the postback events and this is true for paging/deleting cancelling etc.

    so instead you want to delete, then get fresh data and pass that to your gridviews datasource and then only bind. Or you end up with a record that was already deleted, which could result in the index was out of range behavior :-)

    so try to make those changes and report back. More specifically, try to be more explicit, an extra line won't hurt your code eg :
        <strike>GridView1.DataSource = Cart.GetItems()</strike>
            If Not IsPostBack Then
                GridView1.DataSource = Cart.GetItems()
                GridView1.DataBind()

            End If


    eg :

    Protected Sub GridView1_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting
            cart.DeleteItem(e.RowIndex)
            GridView1.DataSource = Cart.GetItems()
            GridView1.DataBind()

        End Sub

    and so on.

    Apart from this, i note nothing out of the ordinary Undecided

    Saturday, July 18, 2009 7:44 PM
  • User-1501204699 posted

    Thanks a lot alessandro for a very nice explanation. But i am still not able to solve my problems..

    I tried your suggestion in the row deleting event but when i did , it just didnt delete.

    and when i do it the way i was doing it throws  error at this line in my VB Class Shopping Cart. Whose code i have pasted below.

    Index was out of range. Must be non-negative and less than the size of the collection.
    Parameter name: index


    Line 31:     End Sub
    Line 32: Public Sub DeleteItem(ByVal index As Integer)
    Line 33: _cart.RemoveAt(index)
    Line 34: End Sub
    Line 35: Public ReadOnly Property Count() As Integer


    And i am still getting this error when i update

    Specified argument was out of the range of valid values.
    Parameter name: index


    Line 40:         Dim cell As DataControlFieldCell
    Line 41: cell = GridView1.Rows(e.RowIndex).Controls(3)
    Line 42: Dim t As TextBox = cell.Controls(0)
    Line 43: Try
    Line 44: Dim q As Integer



    Here is my shopping cart class

    Imports Microsoft.VisualBasic
    Imports System.Collections.Generic
    Public Class ShoppingCart
        Private _cart As List(Of CartItem)
        Public Sub New()
            _cart = New List(Of CartItem)()
        End Sub
        Public Function GetItems() As List(Of CartItem)
            Return _cart
        End Function
        Public Sub AddItem(ByVal id As String, _
    ByVal name As String, _
    ByVal price As Decimal)
            Dim itemFound As Boolean = False
            For Each item As CartItem In _cart
                If item.ID = id Then
                    item.Quantity += 1
                    itemFound = True
                End If
            Next
            If Not itemFound Then
                Dim item As CartItem
                item = New CartItem(id, name, price, 1)
                _cart.Add(item)
            End If
        End Sub
        Public Sub UpdateQuantity(ByVal index As Integer, ByVal quantity As Integer)
            Dim item As CartItem
            item = _cart(index)
            item.Quantity = quantity
        End Sub
        Public Sub DeleteItem(ByVal index As Integer)
            _cart.RemoveAt(index)
        End Sub
        Public ReadOnly Property Count() As Integer
            Get
                Return _cart.Count
            End Get
        End Property
    End Class


    Thanks a lot alessandro. I am really stuck at it.

    Sunday, July 19, 2009 6:07 AM
  • User232384818 posted

    well, keep the previous changes I asked you to make. In addition, you also have erratically wired the event handlers for gridview ItemUpdating,ItemDeleting, RowCancelingEdit, RowEditing..... all these event handlers you have registered two times.

    So this means, everytime you click the delete button for example, the ItemDeleting will fire 2 times. This is the main cause for your Index out of range error as the delete, update is performed 2 times for each postback.

    Please note how you use the Handles clause eg : 

    Protected Sub GridView1_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting
            cart.DeleteItem(e.RowIndex)
            GridView1.DataBind()
        End Sub

    note that the handles clause registers the event handler once. But you register it a second time declaratively, look here :

    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" AllowSorting="True"
                                CssClass="datatable" CellPadding="0" BorderWidth="0px" GridLines="None" OnRowDeleting="GridView1_RowDeleting"
                                OnRowEditing="GridView1_RowEditing" OnRowUpdating="GridView1_RowUpdating" OnRowCancelingEdit="GridView1_RowCancelingEdit">


    you pretty much do this for all your event handlers. Also in your page_load you use the handles clause, remove that since by default, AutoEventWireup="true" for your page. This means, all you need to do is add a method Page_Load eg :

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) <strike>Handles Me.Load</strike>
    End sub

    and the framework will do the rest.

    Remove the handles clause for the rest of your event handlers as you have already wired the event handlers declaratively. And your code should just work :-)

    Unfortunately, c# is my main language and i was a bit slow to catch this mistake in your code.  Undecided

    have a good weekend.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, July 19, 2009 10:04 AM
  • User-1501204699 posted

    Thank you so much alessandro.. Your solution worked like a charm..

    And ya thank you so much for such a nice, clean and elaborate advice. I dont think i would have learnt anything like what i just did from your post from any book... It was really good..

    You too have a nice weekend

    Sunday, July 19, 2009 5:45 PM
  • User232384818 posted

    and you sir are a very kind man. Your welcome Wink

    Many thanks for reporting back :-)

    Sunday, July 19, 2009 6:44 PM