Question

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 can't post images yet, so have to give you a link. Image link http://i.stack.imgur.com/hfFIx.jpg

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

Gridview code

<%@ 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 
        }
    }
}

Thanks in advance!

Edit: Small update, I've been trying to work something out with CustomPaging, but no luck so I am still using the posted code as it is. I find it strange that the paging works as it should now, it is just when I change amount on the last page that it crashes.

Was it helpful?

Solution

The guys at Telerik helped me, the problem was that I was going through all items and not just the one where the amount changed.

Updated tbQuantity_TextChanged

protected void tbQuantity_TextChanged(object sender, EventArgs e)
    {
        if (!_readMode)
        {
            RadNumericTextBox tbQuantity = (RadNumericTextBox)sender;
            GridDataItem dataItem = (GridDataItem)tbQuantity.NamingContainer;

            var shopItemID = (int)dataItem.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();
        }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top