2
votes

I'm trying to implement custom paging on a GridView but getting odd behaviour when the last page is being displayed. I thought it might be becuase I had implemented it manually by extending the 4.0 GridView control, but I've now tried using the 4.5 features as per http://www.c-sharpcorner.com/UploadFile/99bb20/custom-paging-with-gridview-control-in-Asp-Net-4-5/ but it is displaying exactly the same behaviour.

Basically if the item count of the last page is less than the PageSize then whenever the grid posts back it fills up with empty rows, as seen below:

Page markup:

<asp:GridView ID="gvTest" runat="server" PageSize="10" AllowPaging="true" AllowCustomPaging="true" AutoGenerateColumns="false" OnRowCommand="gvTest_RowCommand" OnPageIndexChanging="gvTest_PageIndexChanging">
    <Columns>
        <asp:BoundField DataField="ItemText" />
        <asp:TemplateField>
            <ItemTemplate>
                <asp:LinkButton ID="btnTest" runat="server" Text="Test postback" CommandName="TEST" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Code-behind:

protected void Page_Load(object sender, EventArgs e) {
    if (!IsPostBack) {
        BindData();
    }
}

private void BindData() {
    List<TestItem> items = new List<TestItem>() {
        new TestItem() { ItemText = "Item1" },
        new TestItem() { ItemText = "Item2" },
        new TestItem() { ItemText = "Item3" },
        new TestItem() { ItemText = "Item4" },
        new TestItem() { ItemText = "Item5" },
        new TestItem() { ItemText = "Item6" },
        new TestItem() { ItemText = "Item7" },
        new TestItem() { ItemText = "Item8" },
        new TestItem() { ItemText = "Item9" },
        new TestItem() { ItemText = "Item10" },
        new TestItem() { ItemText = "Item11" },
        new TestItem() { ItemText = "Item12" }
    };

    gvTest.DataSource = items.Skip(gvTest.PageIndex * gvTest.PageSize).Take(gvTest.PageSize).ToList();
    gvTest.VirtualItemCount = items.Count;
    gvTest.DataBind();
}

protected void gvTest_PageIndexChanging(object sender, GridViewPageEventArgs e) {
    gvTest.PageIndex = e.NewPageIndex;
    BindData();
}

All works as expected, but clicking on a linkbutton on the 2nd (last) page results in the following:

Before postback:

Before postback

After postback:

After postback

Is this a known GridView issue? Not sure what I'm doing wrong....

2
Try to place a break point and see if you get extra data after postback. - Rex
What does BindPagedData? - Tim Schmelter
@TimSchmelter oops meant to remove that, it binds a second GridView (my original customised one) that I was using for comparison. - RossJ
@Rex The VirtualItemCount, PageCount and PageIndex are all correct, but the Rows.Count property is 10 on postback. The datasource is null but this is expected. - RossJ
@RossJ what happens in the 'if (e.CommandName == "TEST")'?? - Rex

2 Answers

0
votes

Hahaha, just noticed this is a relatively old question. Hopefully it helps someone though!

Is it something related to your OnRowCommand? I took out the OnRowCommand since I don't know what you are doing in that block. Otherwise the code works fine

I ran the following code:

aspx page:

<asp:GridView ID="gvTest" runat="server" PageSize="10" AllowPaging="true" AllowCustomPaging="true" AutoGenerateColumns="false" OnPageIndexChanging="gvTest_PageIndexChanging">
        <Columns>
            <asp:BoundField DataField="ItemText" />
            <asp:TemplateField>
                <ItemTemplate>
                    <asp:LinkButton ID="btnTest" runat="server" Text="Test postback" CommandName="TEST" />
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

Code behind with mock class:

protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                BindData();
            }
        }

        private void BindData()
        {
            List<TestItem> items = new List<TestItem>()
            {
                new TestItem() {ItemText = "Item1"},
                new TestItem() {ItemText = "Item2"},
                new TestItem() {ItemText = "Item3"},
                new TestItem() {ItemText = "Item4"},
                new TestItem() {ItemText = "Item5"},
                new TestItem() {ItemText = "Item6"},
                new TestItem() {ItemText = "Item7"},
                new TestItem() {ItemText = "Item8"},
                new TestItem() {ItemText = "Item9"},
                new TestItem() {ItemText = "Item10"},
                new TestItem() {ItemText = "Item11"},
                new TestItem() {ItemText = "Item12"}
            };

            gvTest.DataSource = items.Skip(gvTest.PageIndex * gvTest.PageSize).Take(gvTest.PageSize).ToList();
            gvTest.VirtualItemCount = items.Count;
            gvTest.DataBind();
        }

        protected void gvTest_PageIndexChanging(object sender, GridViewPageEventArgs e)
        {
            gvTest.PageIndex = e.NewPageIndex;
            BindData();
        }
    }

    public class TestItem
    {
        public string ItemText { get; set; }
    }

Which resulted in:

Page 1: enter image description here Page 2: http://i.imgur.com/UPc7Rq6.jpg

0
votes

I used this way to avoid this problem

but this is not a good way...

private int gvDataCount
    {
        get
        {
            object count = ViewState["gvDataCount"];
            if (count == null)
                count = gvTest.PageSize;
            return Convert.ToInt32(count);
        }
        set
        {
            ViewState["gvDataCount"] = value;
        }
    }
private void BindData()
    {

        //....

        var list = items.Skip(gvTest.PageIndex * gvTest.PageSize).Take(gvTest.PageSize).ToList();
        this.gvDataCount = list.Count;
        gvTest.DataSource = list;
        gvTest.VirtualItemCount = items.Count;
        gvTest.DataBind();
    }

protected void gvTest_RowCreated(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType != DataControlRowType.DataRow)
            return;

        if (e.Row.RowIndex > this.gvDataCount)
            e.Row.Visible = false;
    }