Amit's Blog

Sharing Thoughts and Learning

  Home  |   Contact  |   Syndication    |   Login
  43 Posts | 1 Stories | 234 Comments | 14 Trackbacks

News

About Me?
Read it in
Blog Statistics
Proud Member of

Archives

Post Categories

Articles

Book Review

I Visit.

OpenSource Project(s)

Sunday, September 09, 2007 #

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