ASP.NET 4.5 网格视图:最后一页的回发

本文关键字:一页 最后 视图 NET 网格 ASP | 更新日期: 2023-09-27 18:31:24

我在 4.5 和 4.5.1 版本中发现了 GridView 寻呼器 ASP.NET 问题。自.NET 2 - 4以来,我从未遇到过这样的问题。

说到这里,我有一个网格视图,我正在用代码后面的数据填充,如下所示:

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 不同时,才会出现问题。行为是我的页面被重新加载,网格视图的页面充满了空数据行,直到 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。由于某种原因,PageIndexChange不会在最后一页触发,除非LastPageSize == PageSize。然后,为了绑定命令参数,不会调用数据绑定,因此我无法正确回发。

另一方面,它不是很清楚,可能会导致问题......至少双重绑定 = 对 SQL 的双重调用以获取页面更改中的数据...否则,我不知道如何在这里强制PageIndexChange,对我来说似乎是一个新的.NET问题。

ASP.NET 4.5 网格视图:最后一页的回发

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

对于那些遇到相同问题的人,我提供了工作正常的自定义控件(当然,不实现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 在其中放置以引导方式正确呈现的控件。

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

我将以下"hack"添加到网格视图的 RowCreate 中,以防止绘制这些幻像行。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