I'm having some problems with one of our webshops. A Telerik radgrid works as the cart and lists all products currently in the cart. The paging on the Radgrid correctly splits the cart view into different pages. The problem occurs when one manually tries to change the amount of a product, but only if the product is on the LAST page of the radgrid and only if the number of products are less than the page size limit.
I have figured it out as much as the radgrid believes there are always an even amount of products, based on the radgrid's page size.
The crash occurs in the tbQuantity_TextChanged event handler, more specific when var shopItemID = Convert.ToInt32(item.GetDataKeyValue("ID")); is called for an item that doesn't exist on this page, but on another page.
The exception is
System.ArgumentOutOfRangeException was unhandled by user code Message=Index was out of range. Must be non-negative and less than the size of the collection.Parameter name: index <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ShopItems.ascx.cs" Inherits="Litho.Framework.Web.Modules.Shop.ShopItems" %><%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %><telerik:RadGrid ID="gvCartItems" runat="server" AutoGenerateColumns="False" AllowPaging="True" PageSize="5" Skin="Default" GridLines="None" AllowFilteringByColumn="False" AllowSorting="True" ShowFooter="True" OnNeedDataSource="gvCartItems_NeedDataSource" OnItemCreated="gvCartItems_ItemCreated" OnItemDataBound="gvCartItems_ItemDataBound" OnDeleteCommand="gvCartItems_DeleteCommand"> <MasterTableView Width="100%" NoMasterRecordsText="Inga artiklar" ShowHeadersWhenNoRecords="false" DataKeyNames="ID"> <Columns> <telerik:GridButtonColumn ButtonType="ImageButton" CommandName="Delete" Text="Radera" UniqueName="DeleteColumn" HeaderStyle-Width="20" /> <telerik:GridTemplateColumn HeaderText="Antal" HeaderStyle-Width="110px" DataField="Quantity" UniqueName="Quantity" Aggregate="Sum" FooterText="Totalt antal: "> <ItemTemplate> <telerik:RadNumericTextBox ID="tbQuantity" runat="server" AutoPostBack="true" Width="70px" MinValue="1" Visible="false" ShowSpinButtons="true" IncrementSettings-InterceptArrowKeys="false" NumberFormat-GroupSizes="9" NumberFormat-DecimalDigits="0" IncrementSettings-InterceptMouseWheel="true" NumberFormat-AllowRounding="False" OnTextChanged="tbQuantity_TextChanged"> <EnabledStyle HorizontalAlign="Right" /> </telerik:RadNumericTextBox> <telerik:RadComboBox ID="ddlQuantity" DataTextField="Quantity" DataValueField="Quantity" Visible="false" runat="server" Width="50px" AutoPostBack="true" OnSelectedIndexChanged="ddlQuantity_SelectedIndexChanged" /> </ItemTemplate> </telerik:GridTemplateColumn> <telerik:GridBoundColumn HeaderText="Artnr" ReadOnly="True" DataField="ArticleNumber" UniqueName="ArticleNumber" HeaderStyle-Width="80" /> <telerik:GridTemplateColumn HeaderText="Artikel" UniqueName="Title" ShowFilterIcon="false"> <ItemTemplate> <asp:HyperLink ID="hlTitle" runat="server" /> </ItemTemplate> </telerik:GridTemplateColumn> <telerik:GridTemplateColumn HeaderText="a`pris" UniqueName="Price" ShowFilterIcon="false"> <ItemTemplate> <asp:Label ID="lblUnitprice" runat="server" /> </ItemTemplate> </telerik:GridTemplateColumn> <telerik:GridTemplateColumn HeaderText="Totalpris" UniqueName="Totalprice" ShowFilterIcon="false"> <ItemTemplate> <asp:Label ID="lblTotalPrice" runat="server" /> </ItemTemplate> </telerik:GridTemplateColumn> </Columns> </MasterTableView> <FooterStyle Font-Bold="true" BackColor="#e6e6e6" /> <PagerStyle Mode="NextPrevAndNumeric" /> <FilterMenu EnableTheming="True"> <CollapseAnimation Duration="200" Type="OutQuint" /> </FilterMenu></telerik:RadGrid><asp:PlaceHolder ID="phItemSummary" runat="server" />Code behind
using System;using System.Collections.Generic;using System.Web.UI;using System.Web.UI.WebControls;using Litho.Framework.BusinessLayer;using Litho.Framework.BusinessLayer.Base;using Litho.Framework.BusinessLayer.Base.Settings;using Litho.Framework.BusinessLayer.Modules.Shop;using Litho.Framework.PresentationLayer;using Litho.Framework.ServiceLayer;using Telerik.Web.UI;namespace Litho.Framework.Web.Modules.Shop{ public partial class ShopItems : UserControl { IShopItemHolder _shopItemHolder = null; bool _readMode = true; SessionHelper _sessionHelper = new SessionHelper(); #region Public methods public void LoadItems(IShopItemHolder shopItemHolder, bool readMode) { _shopItemHolder = shopItemHolder; _readMode = readMode; gvCartItems.Rebind(); loadItemsSummary(); } private void loadItemsSummary() { phItemSummary.Controls.Clear(); var ucItemSummary = (ShopItemsSummary)Page.LoadControl("~/Modules/Shop/ShopItemsSummary.ascx"); ucItemSummary.LoadItemSummary(_shopItemHolder); phItemSummary.Controls.Add(ucItemSummary); } #endregion #region Events protected void gvCartItems_NeedDataSource(object source, GridNeedDataSourceEventArgs e) { gvCartItems.DataSource = _shopItemHolder.Items; } protected void gvCartItems_ItemCreated(object sender, GridItemEventArgs e) { if (e.Item is GridDataItem) { var item = (GridDataItem)e.Item; var btnDelete = (ImageButton)item["DeleteColumn"].Controls[0]; btnDelete.ImageUrl = string.Format("~/Base/Themes/{0}/Images/Icons16x16/iconDelete.png", SettingsManager.GetGlobalSettings().AdminTheme); btnDelete.Visible = !_readMode; } } protected void gvCartItems_ItemDataBound(object sender, GridItemEventArgs e) { if (e.Item is GridDataItem) { var shopItem = (IShopItem)e.Item.DataItem; var hlTitle = (HyperLink)e.Item.FindControl("hlTitle"); var lblUnitPrice = (Label)e.Item.FindControl("lblUnitprice"); var lblTotalPrice = (Label)e.Item.FindControl("lblTotalPrice"); if (!shopItem.IsExternal) { var tbQuantity = (RadNumericTextBox)e.Item.FindControl("tbQuantity"); tbQuantity.ShowSpinButtons = !_readMode; tbQuantity.Text = shopItem.Quantity.ToString(); tbQuantity.Visible = true; tbQuantity.Enabled = !_readMode; } else { if (!_readMode) { var ddlQuantity = (RadComboBox)e.Item.FindControl("ddlQuantity"); ddlQuantity.DataSource = shopItem.PriceCollection; ddlQuantity.DataBind(); ddlQuantity.SelectedValue = shopItem.Quantity.ToString(); ddlQuantity.Visible = true; } } if (!shopItem.IsExternal) { var parameters = new Dictionary<string, string>(); parameters.Add(KeyMaster.RequestParamsNames.Modules.Shop.PRODUCT_ID, shopItem.ID.ToString()); hlTitle.NavigateUrl = new FWContent().GetContentUrl(ModuleIDConstant.SHOP, ContentIDConstant.Shop.PRODUCT_VIEW, parameters); } hlTitle.Text = shopItem.Title; lblUnitPrice.Text = shopItem.Price.ToString("0.00") + " SEK"; lblTotalPrice.Text = shopItem.GetCost(false).ToString("0.00") + " SEK"; } } protected void tbQuantity_TextChanged(object sender, EventArgs e) { if (!_readMode) { RadNumericTextBox tbQuantity; foreach (GridDataItem item in gvCartItems.Items) { if (item is GridDataItem) { tbQuantity = item.FindControl("tbQuantity") as RadNumericTextBox; var shopItemID = Convert.ToInt32(item.GetDataKeyValue("ID")); var shopItem = _sessionHelper.CurrentCart.CartItems.Find(x => x.ID == shopItemID); if (!shopItem.IsExternal) { _sessionHelper.CurrentCart.CartItems.Find(x => x.ID == shopItemID).Quantity = Convert.ToInt32(tbQuantity.Text); _sessionHelper.CurrentCart.CartItems.Find(x => x.ID == shopItemID).TotalPrice = _sessionHelper.CurrentCart.GetItemCost(shopItemID, false); _shopItemHolder = _sessionHelper.CurrentCart; } } } loadItemsSummary(); gvCartItems.Rebind(); } } protected void gvCartItems_DeleteCommand(object source, GridCommandEventArgs e) { if (!_readMode) { var cartItemID = (int)e.Item.OwnerTableView.DataKeyValues[e.Item.ItemIndex]["ID"]; _sessionHelper.CurrentCart.DeleteItem(cartItemID); _shopItemHolder = _sessionHelper.CurrentCart; if (_sessionHelper.CurrentCart.Items.Count == 0) { Response.Redirect(new FWContent().GetContentUrl(ModuleIDConstant.SHOP, ContentIDConstant.Shop.CART)); } else { gvCartItems.Rebind(); loadItemsSummary(); } } } protected void ddlQuantity_SelectedIndexChanged(object sender, EventArgs e) { RadComboBox ddlQuantity; foreach (GridDataItem item in gvCartItems.Items) { if (item is GridDataItem) { ddlQuantity = item.FindControl("ddlQuantity") as RadComboBox; var cartItemID = Convert.ToInt32(item.GetDataKeyValue("ID")); var cartItem = _sessionHelper.CurrentCart.CartItems.Find(x => x.ID == cartItemID); if (cartItem.IsExternal) { cartItem.Quantity = Convert.ToInt32(ddlQuantity.Text); cartItem.TotalPrice = getProductPrice(cartItem); } } } loadItemsSummary(); gvCartItems.Rebind(); } #endregion private double getProductPrice(CartItem cartitem) { foreach (var price in cartitem.PriceCollection) { if (price.Quantity == cartitem.Quantity) { return price.Price; } } throw new Exception(); // todo lägg till customexception } }}I've been trying to work something out with custom paging, but no luck so far, so I'm still using this code, only changed PageSize to 100 so the shop won't crash that easily. ;)
Thanks in advance!
