ASP.NET 4.5 GridView:最后一页的回发

问题描述 投票:0回答:2

我发现 ASP.NET 4.5 和 4.5.1 版本中的 GridView 分页器存在问题。从 .NET 2 - 4 开始我从未遇到过这样的问题。

到目前为止,我有一个 gridview,我正在用后面的代码填充数据,如下所示:

protected int CurrentPage { get { return SearchResults.PageIndex + 1; } }

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

private void BindGrid()
{
    int totalRowCount = 0;
    SearchResults.DataSource = GetPageData(SearchResults.PageIndex, SearchResults.PageSize, out totalRowCount);
    SearchResults.VirtualItemCount = totalRowCount;                   
    SearchResults.DataBind();
}

private IEnumerable GetPageData(int start, int count, out int totalRowCount)
{
    return Membership.GetAllUsers(start, count, out totalRowCount);
}

protected void SearchResults_PageIndexChanging(object sender, GridViewPageEventArgs e)
{            
    SearchResults.PageIndex = e.NewPageIndex;            
    BindGrid();
}

问题是,如果我点击 GridView 的最后一页并尝试返回任何其他页面,我的 PageIndexChanging 不会触发。仅当最后一页的记录数与 PageSize 不同时,才会出现此问题。行为是我的页面被重新加载,gridview 的页面充满了直到 PageSize 的空数据行。 VirtualItemCount 正确表示总 ItemCount。

标记,如果您在那里找到东西:

<asp:GridView runat="server" CellPadding="0" CellSpacing="0" GridLines="None" CssClass="table table-condensed table-striped table-footer"
        ID="SearchResults" AllowCustomPaging="true" AllowPaging="true" PageSize="6" OnPageIndexChanging="SearchResults_PageIndexChanging" AutoGenerateColumns="false" UseAccessibleHeader="true">
...
<PagerTemplate>
            <span class="pull-left">
                <strong><%= SearchResults.PageIndex * SearchResults.PageSize + 1 %></strong> - <strong><%= CurrentPage * SearchResults.PageSize %></strong>
            </span>
            <span class="pull-left">
                Total records: <strong><%= SearchResults.VirtualItemCount %></strong>
            </span>
            <ul class="pagination pull-right">
                <li><asp:LinkButton runat="server" CommandName="Page" CommandArgument="First"><span class="glyphicon glyphicon-backward"></span></asp:LinkButton></li>

                <li><asp:LinkButton runat="server" CommandName="Page" CommandArgument="<%# CurrentPage - 2 %>" Visible="<%# CurrentPage > 2 %>"><%= CurrentPage - 2 %> </asp:LinkButton></li>
                <li><asp:LinkButton runat="server" CommandName="Page" CommandArgument="<%# CurrentPage - 1 %>" Visible="<%# CurrentPage > 1 %>"><%= CurrentPage - 1 %> </asp:LinkButton></li>
                <li class="active"><a href="#"><%= CurrentPage %></a></li>
                <li><asp:LinkButton runat="server" CommandName="Page" CommandArgument="<%# CurrentPage + 1 %>" Visible="<%# CurrentPage < SearchResults.PageCount %>"><%= CurrentPage + 1 %></asp:LinkButton></li>
                <li><asp:LinkButton runat="server" CommandName="Page" CommandArgument="<%# CurrentPage + 2 %>" Visible="<%# CurrentPage < SearchResults.PageCount - 1 %>"><%= CurrentPage + 2 %></asp:LinkButton></li>

                <li><asp:LinkButton runat="server" CommandName="Page" CommandArgument="Last"><span class="glyphicon glyphicon-forward"></span></asp:LinkButton></li>
            </ul>
        </PagerTemplate>
</asp:GridView>

非常感谢,我已经处理这个问题好几天了。当然,我可以使用 QueryString 方法,但由于我将使用很多表,所以如果可能的话,我想坚持使用回发方法...


编辑:

我发现的最简单的解决方法是在每个 Page_Load 上执行 BindGrid。由于某种原因,除非 LastPageSize == PageSize,否则 PageIndexChanging 不会在最后一页上触发。然后,不会调用 DataBind 来绑定 CommandArguments,因此我无法正确回发。

另一方面,它不是很清楚,可能会导致问题...至少双重绑定 = 双重调用 SQL 来获取 pagechange 上的数据...否则,我不知道如何在这里强制 PageIndexChanging,看起来像是我遇到了新的 .NET 问题。

c# asp.net .net gridview pagination
2个回答
2
投票

由于我对我提出的解决方案不满意(给未来的开发带来了太多问题),我决定采用“控制开发”的方式来确保一切都正确创建。无论我使用哪种类型的 PagerTemplate,都会发生这种情况 - 我正在使用一个,回发不会从最后一页触发。希望我不是唯一一个:-)

对于遇到同样问题的人,我提供了可以正常工作的自定义控件(当然,没有实现 PagerSettings 和 PagerTemplates,但带来了基本功能)。

public class ExtendedGridView : System.Web.UI.WebControls.GridView
{
    protected override void InitializePager(System.Web.UI.WebControls.GridViewRow row, int columnSpan, System.Web.UI.WebControls.PagedDataSource pagedDataSource)
    {
        HtmlGenericControl ul = new HtmlGenericControl("ul");

        ul.Attributes.Add("class", "pagination pull-right");

        AddPager(ul, commandArgument: "First", text: "<span class='glyphicon glyphicon-fast-backward'></span>");

        for (int i = 0; i < PageCount; i++)
        {
            AddPager(ul, i);
        }

        AddPager(ul, commandArgument: "Last", text: "<span class='glyphicon glyphicon-fast-forward'></span>");

        row.CssClass = "table-footer";
        row.Cells.Add(new System.Web.UI.WebControls.TableCell());
        row.Cells[0].ColumnSpan = columnSpan;
        row.Cells[0].Controls.AddAt(0, ul);            
    }

    protected virtual void navigate_Click(object sender, EventArgs e)
    {
        string commandArgument = ((System.Web.UI.WebControls.LinkButton)sender).CommandArgument.ToString();
        int pageIndex = 0;

        if (!int.TryParse(commandArgument, out pageIndex)) {
            switch (commandArgument)
            {
                case "First": pageIndex = 0; break;
                case "Last": pageIndex = PageCount - 1; break;
                case "Prev": pageIndex = PageIndex - 1; break;
                case "Next": pageIndex = PageIndex + 1; break;
            }
        }

        OnPageIndexChanging(new System.Web.UI.WebControls.GridViewPageEventArgs(pageIndex));
    }

    private void AddPager(System.Web.UI.Control parentControl, int pageIndex = -1, string commandArgument = null, string text = null)
    {
        HtmlGenericControl li = new HtmlGenericControl("li");

        if (pageIndex == PageIndex)
            li.Attributes.Add("class", "active");

        System.Web.UI.WebControls.LinkButton button = new System.Web.UI.WebControls.LinkButton();
        button.CommandName = "Page";

        if (text == null)
            button.Text = (pageIndex + 1).ToString();
        else
            button.Text = text;

        if (string.IsNullOrWhiteSpace(commandArgument))
            button.CommandArgument = string.Format("{0}", pageIndex);
        else
            button.CommandArgument = commandArgument;

        button.Click += navigate_Click;

        li.Controls.Add(button);
        parentControl.Controls.Add(li);
    }
}

只需确保您的标记是: - 允许分页=“真” - 允许自定义分页=“假” - 页面大小=“随便” - 并且您仍然在后面的代码中提供 VirtualItemCount

使用 SelectMethod 的代码可能是这样的:

protected void Page_Load(object sender, EventArgs e)
{

}

public IEnumerable SearchResults_GetData(int startRowIndex, int maximumRows, out int totalRowCount, string sortByExpression)
{
    int pageIndex = (int)(startRowIndex / maximumRows);
    return Membership.GetAllUsers(pageIndex, maximumRows, out totalRowCount);
}

protected void SearchResults_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    SearchResults.PageIndex = e.NewPageIndex;
    SearchResults.DataBind();
}

因为这是我使用优秀的 Bootstrap 框架为 .NET 创建服务器端控件的好几次,所以我在这里创建了一个 git https://github.com/Gitzerai/Bootstrap.NET,我在其中放置了以引导程序正确方式呈现的控件.


0
投票

我发现这也发生在我身上。 在回发时,最后一页将用第一页中的行“填充”最后一页,数据后的第一行除外。 示例:如果页面大小为 10 并且我有 25 行。 最后一页最初会显示第 21-25 行,然后在回发时会添加第 7-10 行。

我在 gridview 的 RowCreated 中添加了以下“hack”,以防止绘制这些幻像行。 GV是网格视图。 DataRowCount 是一个返回数据源行数的函数。 PageIndex 是一个使用会话来保存当前页面索引的属性。

        If e.Row.RowType = DataControlRowType.DataRow Then
        Dim RowsLeft As Integer = DataRowCount() - (GV.PageSize * PageIndex)
        Dim RowsExpected As Integer

        If RowsLeft > GV.PageSize Then
            RowsExpected = GV.PageSize
        Else
            RowsExpected = RowsLeft
        End If

        If e.Row.RowIndex >= RowsExpected Then
            'Last page isn't full, need to force writing nothing out for extra rows
            e.Row.SetRenderMethodDelegate(New RenderMethod(AddressOf RenderNothing))
        End If
    End If

然后我添加了以下功能:

Public Sub RenderNothing(writer As HtmlTextWriter, container As Control)
End Sub

由于 RowCreated 发生在 ViewState 加载之前,因此 GV 的 PageIndex 不可用。 所以我创建了一个属性来保存 PageIndex。 所以我的代码现在更新新属性,该属性将其保存到会话中并更新 GV 的属性。 这是我添加的属性

Private Const SS_PagerControl_PageIndex As String = "SSPagerControl_PageIndex"
<Bindable(True), CategoryAttribute("Paging"), DefaultValue("0")>
Public Property PageIndex As Integer
    Get
        If Session(SS_PagerControl_PageIndex) Is Nothing Then
            Return 0
        End If

        Return CInt(Session(SS_PagerControl_PageIndex))
    End Get
    Set(ByVal value As Integer)
        Session(SS_PagerControl_PageIndex) = value
        GV.PageIndex = value
        RebindGrid()
    End Set
End Property
© www.soinside.com 2019 - 2024. All rights reserved.