FilteredBindingList and paging

FilteredBindingList and paging

Old forum URL: forums.lhotka.net/forums/t/2526.aspx


colema18 posted on Wednesday, March 14, 2007

I have custom paging for a datagrid control that is binding to a BulletinList :
    ReadOnlyListBase<BulletinList, BulletinInfo> collection.

The 2.1 handbook refers to implementing paging, but it is more focused on only returning the rows JIT from the database.  I however already have the fully populated BulletinList (under 200 rows) and my datagrid is only showing 10 rows at a time.  This seemed to plug in just fine with the standard paging of the datagrid, but when I am trying to do custom navigation controls it is always displaying the 1st 10 records, no matter what currentpageindex is being set on the grid.

Can someone look at the snippets below and give me some ideas:

SearchResults.ascx
...
<asp:datagrid  id="dgSearchResults" runat="server" BorderColor="#CCCCCC"  BorderWidth="1px" CellPadding="0"
         HorizontalAlign="Center" Width="100%" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False"
         DataKeyField="" BorderStyle="Solid" AllowCustomPaging="True" PagerStyle-Visible="False" PageSize="4" >
        <AlternatingItemStyle HorizontalAlign="Left" CssClass="resultsTableEvenItemNoBorder"></AlternatingItemStyle>
        <ItemStyle HorizontalAlign="Left" CssClass="resultsTableOddItemNoBorder"></ItemStyle>
        <HeaderStyle HorizontalAlign="Left"   CssClass="resultsTableHeaderNoBorder" VerticalAlign="Middle"></HeaderStyle>
        <Columns>
   
    <asp:TemplateColumn HeaderStyle-HorizontalAlign ="Left" HeaderText = "<%$Resources:cde, resSlct %>" ItemStyle-Width="12px">
        <ItemTemplate >
        <asp:HyperLink id="lnkGo" runat="server" ImageUrl="../Images/view.gif" NavigateUrl='http://dev.vwcredit.com/dealers/applications/bulletins/PDFs/<%# DataBinder.Eval(Container.DataItem, "EncryptedPdfLink")%>'  />
        </ItemTemplate>
   </asp:TemplateColumn>
   <asp:TemplateColumn HeaderStyle-HorizontalAlign ="Left" SortExpression="Number" HeaderText = "<%$Resources:FinanceSource, resBulletin %>" >
         <ItemTemplate >
            <asp:Label  runat="server" ID= "lblBulletin"  Text ='<%# DataBinder.Eval(Container.DataItem, "Number") %>'  ></asp:Label>
         </ItemTemplate >
    </asp:TemplateColumn>
    <asp:TemplateColumn HeaderStyle-HorizontalAlign ="Left"  SortExpression="Title" HeaderText="<%$Resources:FinanceSource, resTitle %>">
        <ItemTemplate >
            <asp:Label  runat="server" ID= "lblTitle"  Text ='<%# DataBinder.Eval(Container.DataItem, "Title") %>'  ></asp:Label>
        </ItemTemplate >
    </asp:TemplateColumn>
    <asp:TemplateColumn HeaderStyle-HorizontalAlign ="Left" SortExpression="Comments" HeaderText="<%$Resources:cde, resComments%>">
        <ItemTemplate >
            <asp:Label  runat="server" ID= "lblComments"  Text ='<%# DataBinder.Eval(Container.DataItem, "Comments") %>'  ></asp:Label>
        </ItemTemplate >
    </asp:TemplateColumn>
      </Columns>
    </asp:datagrid>
<!--CUSTOM PAGING NAVIGATION -->
    <table width="100%">
    <tr>
        <td>Page
            <asp:Label ID="lblCurrentPage" runat="server" Text="1"></asp:Label>
            of
            <asp:Label ID="lblTotalPages" runat="server" Text="2"></asp:Label></td>
        <td align="right">Result Pages:
            <asp:LinkButton ID="lbtnPrevious" runat="server" CausesValidation="False" CommandArgument="Previous"
                CommandName="SetPage" OnClick="PageNav_Click">&lt;&lt;Prev</asp:LinkButton>
            <asp:PlaceHolder ID="phPages" runat="server"></asp:PlaceHolder>
            <asp:LinkButton ID="lbtnNext" runat="server" CausesValidation="False" CommandArgument="Next"
                CommandName="SetPage" OnClick="PageNav_Click">Next&gt;&gt;</asp:LinkButton></td>
    </tr>
    </table>

...

SearchResults.ascx
...
protected void Page_Load(object sender, EventArgs e)
    {
        Session["days"] = "30";
        BulletinList bulletins;
        if (Session[key] != null)
        {
            bulletins = (BulletinList)Session[key];
        }
        else
        {
            bulletins = BulletinList.GetBulletinList(_dealerNumber);
            Session[key] = bulletins;
        }

        if (bulletins.Count != 0)
        {
            filteredBulletins = new FilteredBindingList<BulletinInfo>(bulletins);
            filteredBulletins.ApplyFilter("Language", Page.UICulture);
            if (Session["SortBy"] != null)
            {
                SortedBindingList<BulletinInfo> sortedBulletins = new SortedBindingList<BulletinInfo>(filteredBulletins);
                sortedBulletins.ApplySort((string)Session["SortBy"], (ListSortDirection)Session["SortByOrder"]);
                dgSearchResults.DataSource = sortedBulletins;
            }
            else
            {
                dgSearchResults.DataSource = filteredBulletins;
            }
        }
        if (!IsPostBack)
        {
            if (bulletins.Count != 0)
            {
                string ModifiedDaysRows;
                ModifiedDaysRows = Resources.FinanceSource.resBulletinResult.Replace("[rows]", bulletins.Count.ToString());
                lblText.Text = ModifiedDaysRows.Replace("[days]", Session["days"].ToString());
                dgSearchResults.VirtualItemCount = filteredBulletins.Count;
                BindGrid();
            }
            else
            {
                lblText.Text = Resources.FinanceSource.resNoSearchResults;
                dgSearchResults.Visible = false;
            }
        }
    }

---

    protected void BindGrid()
    {
        dgSearchResults.DataSource = filteredBulletins;
        dgSearchResults.DataBind();
    }

...

    protected void PageNav_Click(object sender, EventArgs e)
    {
        LinkButton lb = (LinkButton)sender;
        switch (lb.CommandArgument)
        {
            case "Previous":
                currentPage = dgSearchResults.CurrentPageIndex - 1;
                break;
            case "Next":
                currentPage = dgSearchResults.CurrentPageIndex + 1;
                break;
            default:
                currentPage = int.Parse(lb.CommandArgument) - 1;
                break;
        }
        dgSearchResults.CurrentPageIndex = currentPage;

        dgSearchResults.DataBind();
    }



somayajulu replied on Thursday, March 15, 2007

Hi there,

Here's a post regarding custom paging.

http://forums.lhotka.net/forums/thread/12529.aspx

Hope this might help you in solving the problem.

Regards,

Som.

RockfordLhotka replied on Thursday, March 15, 2007

If you already have the entire list in memory, then you need to take a different approach from what's shown in the book.

Data binding will raise the SelectObject event each time it needs a page. And that's where your options begin. You can either

  1. Do the paging in the SelectObject event handler
  2. Do the paging in your factory method
  3. Do the paging in your DataPortal_Fetch method
  4. Do the paging in your stored procedure

In your case only 1 and 2 are options, because those are the only options that run on the client (or web server) in all cases.

You'll need to create a list object that only contains the requested page of data. In 2.1.3+ the paging data comes to you in the EventArgs parameter passed to the SelectObject event handler. The solution is like this (pseudocode, I don't remember all the property names from the args):

CustomerList source = // get your complete data list
List<Customer> result = new List<Customer>();
int position;
foreach (Customer item in source)
{
  if (position >= e.StartRow)
    result.Add(item);
  if (position > e.StartRow + e.PageSize)
    break; // exit loop, we're done
  position++;
}
return result;

That assumes you put the code in the factory method. You could just as easily put it in the SelectObject event handler.

mongo replied on Saturday, April 14, 2007

I expanded on this earlier post with a new code sample: http://forums.lhotka.net/forums/thread/13802.aspx

I reduced the sorting and paging to a class derived from IList<T>.  This works very nice with in-memory sets taken from any of the CSLA collection objects.

 

Copyright (c) Marimer LLC