Geeks With Blogs
Amit's Blog Sharing Thoughts and Learning

In my previous post, I have presented few cool css examples of the new Asp.net ListView control. In this post, I will show how you can setup the data binding of the ListView control with the new LinqDataSource control as well as through code, which outputs the previous post examples.

Like its ancestor, the ListView comes up with few templates and some of them are really new. In order to bind data we first have to define the LayoutTemplate. The LayoutTemplate is a new template that acts as a container for either group or item templates. Since our previous example presents the data in tabular format, we will exclude the GroupTemplate from discussing in this post. One of the required thing you have to keep in mind while defining the LayoutTemplate is, you must have to declare an itemContainer/groupContainer where the item/group will be repeated. For example, I have declared the tbody as the itemContainer like the following:

<LayoutTemplate>
    <table>
        <thead>
            <tr>
                <th>Company</th>
                <th>Contact</th>
                <th>Title</th>
                <th>Address</th>
                <th>City</th>
                <th>Postal Code</th>
                <th>Country</th>
                <th>Phone</th>
            </tr>
        </thead>
        <tbody id="itemContainer" runat="server"></tbody>
        <tfoot>
            <tr>
                <th style="text-align:right" colspan="8">
                    <asp:DataPager runat="server" ID="dpCustomers" PageSize="10">
                        <Fields>
                            <asp:NumericPagerField ButtonCount="5"/>
                        </Fields>
                    </asp:DataPager>
                </th>
            </tr>
        </tfoot>
    </table>
</LayoutTemplate>

As you can see, the LayoutTemplate also contains another new control DataPager that I will discuss later. Another important thing is that unlike the Repeater control where usually the HeaderTemplate contains the starting tag and the FooterTemplate contains the ending tag of the container , the LayoutTemplate contains the both except the repeating part.

Next, we have to define the ItemTemplate and the AlteringItemTemplate like the following:

<ItemTemplate>
    <tr>
        <td>
            <asp:Label ID="lblCompany" runat="server" Text='<% #Eval("CompanyName")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblContact" runat="server" Text='<% #Eval("ContactName")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblTitle" runat="server" Text='<% #Eval("ContactTitle")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblAddress" runat="server" Text='<% #Eval("Address")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblCity" runat="server" Text='<% #Eval("City")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblPostalCode" runat="server" Text='<% #Eval("PostalCode")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblCountry" runat="server" Text='<% #Eval("Country")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblPhone" runat="server" Text='<% #Eval("Phone")%>'></asp:Label>
        </td>
    </tr>
</ItemTemplate>
<AlternatingItemTemplate>
    <tr class="odd">
        <td>
            <asp:Label ID="lblCompany" runat="server" Text='<% #Eval("CompanyName")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblContact" runat="server" Text='<% #Eval("ContactName")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblTitle" runat="server" Text='<% #Eval("ContactTitle")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblAddress" runat="server" Text='<% #Eval("Address")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblCity" runat="server" Text='<% #Eval("City")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblPostalCode" runat="server" Text='<% #Eval("PostalCode")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblCountry" runat="server" Text='<% #Eval("Country")%>'></asp:Label>
        </td>
        <td>
            <asp:Label ID="lblPhone" runat="server" Text='<% #Eval("Phone")%>'></asp:Label>
        </td>
    </tr>
</AlternatingItemTemplate>

At last, we will add a LinqDataSource control which will refer the Customers table of Northwind database. Certainly you have to add a LinqToSQLClasses previously and define the data model. The following shows the LinqDataSource:

<asp:LinqDataSource ID="linqCustomers" runat="server" ContextTypeName="NorthwindDataContext" TableName="Customers"/>

One of the benefits of using LinqDataSource over the other DataSource controls is it produces very optimized SQL without writing a single line of code. For example, the following SQL is generated when I moved to page two by clicking the DataPager.

exec sp_executesql N'SELECT TOP 10 [t1].[CustomerID], [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Address], [t1].[City], [t1].[Region], [t1].[PostalCode], [t1].[Country], [t1].[Phone], [t1].[Fax]
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]) AS [ROW_NUMBER], [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]
    FROM [dbo].[Customers] AS [t0]
    ) AS [t1]
WHERE [t1].[ROW_NUMBER] > @p0',N'@p0 int',@p0=10

Like the other data controls, both the ListView and DataPager are tightly coupled with the DataSource controls.

So far we have seen how to bind data with the DataSource Control, now lets see how to bind data with code. The first issue you will face while binding pageable data that like the GridView built-in paging, there is no way you can utilize the DataPager control unless you use the DataSource controls. So you have to roll your own pager, in this example I have substitute the DataPager control with the server side version of my AjaxDataControls pager. Thus the LayoutTemplate becomes:

<LayoutTemplate>
    <table>
        <thead>
            <tr>
                <th>Company</th>
                <th>Contact</th>
                <th>Title</th>
                <th>Address</th>
                <th>City</th>
                <th>Postal Code</th>
                <th>Country</th>
                <th>Phone</th>
            </tr>
        </thead>
        <tbody id="itemContainer" runat="server"></tbody>
        <tfoot>
            <tr>
                <th colspan="8" style="text-align:right">
                    <cc1:Pager ID="pager" runat="server" OnPageChange="pager_PageChange" SliderSize="5" ShowFirstAndLast="false" ShowPreviousAndNext="true"/>
                </th>
            </tr>
        </tfoot>
    </table>
</LayoutTemplate>

The next issue you will face once you put the pager in the LayoutTemplate is, you will not be able to get the reference of the control by FindControl() until you bind the data of the ListView. So we have to first bind with a dummy data to get the reference, once done we will bind with the original data like the following:

private void BindList()
{
    using (NorthwindDataContext db = new NorthwindDataContext())
    {
        //Unless we bind the data we will not be able to refer the pager control
        //so bind it with a dummy data
        lvwCustomers.DataSource = new Customer[] { new Customer() };
        lvwCustomers.DataBind();

        Pager pager = (Pager)lvwCustomers.FindControl("pager");
        //Calculate the startIndex based upon the Current and RowPerPage
        int startIndex = (pager.CurrentPageNo - 1) * pager.RowPerPage;

        //Now bind it with the actual data.
        lvwCustomers.DataSource = db.Customers.Skip(startIndex).Take(pager.RowPerPage);
        lvwCustomers.DataBind();

        //We also need to know the total row in order to properly render the pager
        pager.TotalRow = db.Customers.Count();
    }
}

Next we have to handle the PageChange event of the pager to render the new page records. The following shows the code of this event:

protected void pager_PageChange(object sender, PageChangeEventArgs e)
{
    ((Pager)sender).CurrentPageNo = e.PageNo;
    BindList();
}

That's it. You will find the full source code of both these example in the bottom of this post. In my next post, I will show how we can leverage the data editing capabilities of ListView control.

Download: Full Source

kick it on DotNetKicks.com

Posted on Sunday, September 9, 2007 1:18 AM Asp.net , ListView | Back to top


Comments on this post: Asp.net ListView - DataBinding

# re: Asp.net ListView - DataBinding
Requesting Gravatar...
Great, but is there some good patter for managing this , cause using <% #Eval("CompanyName")%>'> in page level, soon make it unusable and hard to debug.
Left by Mehfuz Hossain on Sep 12, 2007 10:11 PM

# re: Asp.net ListView - DataBinding
Requesting Gravatar...
Yes it is quite true and I also prefer to use the code behind to bind the data. Like the previous data controls the ListView also has the DataBound which we can use instead of Eval and Bind.
Left by Kazi Manzur Rashid on Sep 13, 2007 12:07 AM

# re: Asp.net ListView - DataBinding
Requesting Gravatar...
Thanks for these articles. One thing that will really simplify your code is to simply do this:

<tr class="<%# Container.ItemIndex %2 == 0) ? "odd" : "even" %>">

so you just have the ItemTemplate and don't need an AlternatingTemplate just for the <tr> class.
Left by John Dyer on Jan 17, 2008 1:47 AM

# re: Asp.net ListView Paging with LINQ
Requesting Gravatar...
Amazing work!
There is though one major issue with using the AjaxDataControls Pager and LINQ limiting the wide abilities of LINQ.

Since, quote: "Unless we bind the data we will not be able to refer the pager control. so bind it with a dummy data"

if the dbml file is comprised of table A and Table B, and the dummy data is a class based on table a

ListView1.DataSource = new TableA[] { new TableA() };

You can not do in LINQ (what U should be able to):

var Query = from p in db.SomeThing
select new
{
MyID = p.TableB.ID
};

Only refering TableA will work

Bottom line is that AjaxDataControls Pager is really cool. lets you utilize the power of LINQ in server side and NOT in markup and have paging (why didn't Microsoft this that far?) but it limits very much the LINQ capabilities

Thanx
Left by SputnikRobot on May 24, 2008 10:37 PM

Your comment:
 (will show your gravatar)


Copyright © Kazi Manzur Rashid | Powered by: GeeksWithBlogs.net | Join free