ASP.NET 4.5 GridView: PostBack de la dernière page

j'ai découvert un problème avec le pager GridView en ASP.NET 4.5 et 4.5.1. Depuis .NET 2 - 4, je n'ai jamais connu un tel problème.

Pour le point, j'ai un gridview que je suis le remplissage avec des données dans le code derrière comme ceci:

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();
}

le problème est que si je clique sur la dernière page de GridView et que j'essaie de revenir à n'importe quelle autre page, Mon PageIndexChanging ne démarre pas. Le problème se produit uniquement si la dernière page n'ont pas le même nombre d'enregistrements que PageSize. Le comportement est que ma page est rechargée, la page de gridview est remplie de lignes de données vides jusqu'à la PageSize. VirtualItemCount représente correctement total ItemCount.

Balisage, si vous trouvez quelque chose là:

<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>

Merci beaucoup, je m'en occupe depuis des jours. Bien sûr, je pourrais utiliser L'approche de QueryString, mais comme je vais utiliser beaucoup de tables, je voudrais rester avec l'approche de postback, si possible...


EDIT:

la solution la plus simple que j'ai trouvée était de faire un BindGrid sur chaque Page_Load. Pour une raison quelconque, le PageIndexChanging ne démarre pas sur la dernière page à moins que LastPageSize = = PageSize. Alors la base de données N'est pas rappelée afin de lier les Command arguements, donc je ne peux pas postback correctement.

d'autre part, il n'est pas très clair et peut causer des problèmes... Au moins double binding = double calls vers SQL pour les données sur pagechange... Sinon, je n'ai aucune idée comment forcer PageIndexChanging ici et semble comme une nouvelle question.Net pour moi.

8
demandé sur Gitzerai 2013-09-13 23:26:58

2 réponses

pour ceux qui connaissent les mêmes problèmes, je fournis un contrôle personnalisé qui fonctionne bien (bien sûr, ne met pas en œuvre PagerSettings et PagerTemplates, mais apporte la fonctionnalité de base).

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);
    }
}

assurez-vous simplement que votre marge est: - Les cases à cocher allowcustompaging="true" - AllowCustomPaging= " false" - PageSize="quel que soit le" - et vous fournissez toujours VirtualItemCount en code derrière

Code derrière l'utilisation de SelectMethod pourrait être comme ceci:

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();
}

comme c'est plusieurs fois que je suis créé des contrôles serverside pour .NET en utilisant un excellent Bootstrap framework, j'ai créé un git ici https://github.com/Gitzerai/Bootstrap.NET où je mets des commandes qui rendent dans un bootstrap de manière appropriée.

2
répondu Gitzerai 2013-09-14 19:24:02

j'ai trouvé que cela m'arrivait aussi. Sur un postback, la dernière page "remplirait" la dernière page avec les lignes de la première page, sauf la première ligne après les données. Exemple: si la taille de la page était 10 et que j'avais 25 lignes. La dernière page montrerait les lignes 21-25 d'abord, et ensuite sur un postback il ajouterait les lignes 7-10.

j'ai ajouté le "hack" suivant au RowCreated de gridview pour empêcher de dessiner ces lignes fantômes. GV est le contrôle gridview. DataRowCount est une fonction qui renvoie le nombre de lignes de la source de données. PageIndex est une propriété qui utilise une session pour contenir l'Index de la Page courante.

        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

Et puis j'ai ajout de la fonction:

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

depuis que RowCreated se produit avant que ViewState soit chargé, le PageIndex du GV n'était pas disponible. J'ai donc créé une propriété pour conserver le PageIndex. Donc mon code met maintenant à jour la nouvelle propriété et la propriété la sauvegarde en session et met à jour la propriété de la GV. Et c'est la propriété, je ajouté

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
0
répondu Thomas Johnson 2015-06-23 22:10:59