[ Team LiB ]
Recipe 7.3 Binding DatatoaWebForms DataList
Problem
You need to bind the result set from a query toa DataList control.
Solution
Set the DataList's advanced properties as demonstrated by this solution.
The schema of table TBL0703 that is used in the solution is shown in Table 7-2
.
Table 7-2. TBL0703 schema
Column name Data type Length Allow nulls?
Id int 4 No
IntField int 4 Yes
StringField nvarchar 50 Yes
The WebForms page sample code defines the DataList control and the three templates—
SelectedItemTemplate, ItemTemplate, and EditItemTemplate—which control the display
of data for selected items, unselected items, and items being edited. The static Eval( )
method of the DataBinder class is used to fill the field values in each template.
Container.DataItem specifies the container argument for the method which when used in
a list in a template resolves to DataListItem.DataItem. The code for the WebForms page
is shown Example 7-5
.
Example 7-5. File: ADOCookbookCS0703.aspx
<asp:DataList id="dataList" style="Z-INDEX: 102; LEFT: 16px;
POSITION: absolute; TOP: 56px" runat="server">
<SelectedItemTemplate>
<asp:Button id="editButton" runat="server" Text="Edit"
CommandName="Edit">
</asp:Button>
<B>
<%# DataBinder.Eval(Container.DataItem, "Id") %>;
<%# DataBinder.Eval(Container.DataItem, "IntField") %>;
<%# DataBinder.Eval(Container.DataItem, "StringField") %>
</B>
</SelectedItemTemplate>
<ItemTemplate>
<asp:Button id="selectButton" runat="server" Text="Select"
CommandName="Select">
</asp:Button>
<%# DataBinder.Eval(Container.DataItem, "Id") %>;
<%# DataBinder.Eval(Container.DataItem, "IntField") %>;
<%# DataBinder.Eval(Container.DataItem, "StringField") %>
</ItemTemplate>
<EditItemTemplate>
<asp:Button id="updateButton" runat="server" Text="Update"
CommandName="Update">
</asp:Button>
<asp:Button id="deleteButton" runat="server" Text="Delete"
CommandName="Delete">
</asp:Button>
<asp:Button id="cancelButton" runat="server" Text="Cancel"
CommandName="Cancel">
</asp:Button>
<BR>
<asp:Label id="Label1" runat="server">ID: </asp:Label>
<asp:TextBox id="idTextBox" runat="server" Width="96px"
ReadOnly="True"
Text='<%# DataBinder.Eval(Container.DataItem, "Id") %>'>
</asp:TextBox>
<BR>
<asp:Label id="Label2" runat="server">IntField: </asp:Label>
<asp:TextBox id="intFieldTextBox" runat="server"
Text='<%# DataBinder.Eval(Container.DataItem,
"IntField") %>'>
</asp:TextBox>
<BR>
<asp:Label id="Label3" runat="server">StringField: </asp:Label>
<asp:TextBox id="stringFieldTextBox" runat="server"
Text='<%# DataBinder.Eval(Container.DataItem,
"StringField") %>'>
</asp:TextBox>
</EditItemTemplate>
</asp:DataList>
The code-behind contains six event handlers and three methods:
Page.Load
Calls the CreateDataSource( ) method and binds datato the WebForms DataList,
if the page is being loaded for the first time.
CreateDataSource( )
This method fills a DataTable with the TBL0703 table and stores the DataTable to
a Session variable to cache the data source for the DataList.
UpdateDataSource( )
This method creates a DataAdapter and uses it together with updating logic
generated by a CommandBuilder to update the data source with changes made to
the cached DataTable. The updated DataTable is stored to the Session variable,
which is used to cache the data source for the DataList.
BindDataList( )
This method gets the cached data from the Session variable and binds its default
view to the DataList.
DataList.CancelCommand
Sets the index of the item being edited to -1 to cancel any current editing and calls
BindDataList( ) to refresh the list.
DataList.DeleteCommand
Finds and deletes the specified row from the data cached in the Session variable
and calls the UpdateDataSource( ) method to persist the change back to the data
source. BindDataList( ) is called to refresh the list.
DataList.EditCommand
Sets the index of the selected item to -1 to cancel its selection. The index of the
item being edited is then set to the index of the row corresponding to the Edit
button putting that row into edit mode. BindDataList( ) is called to refresh the list.
DataList.ItemCommand
Checks if the Select button was pressed. If it was, the index of the item being
edited is set to -1 to cancel its editing. The index of the selected item is then set to
the index of the row corresponding to the Select button to put that row into select
mode. Finally, BindDataList( ) is called to refresh the list.
DataList.UpdateCommand
Finds and updates the specified row in the data cached in the Session variable and
calls the UpdateDataSource( ) method to persist the change back to the data
source. BindDataList( ) is called to refresh the list.
The C# code for the code-behind is shown in Example 7-6
.
Example 7-6. File: ADOCookbookCS0703.aspx.cs
// Namespaces, variables, and constants
using System;
using System.Configuration;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
private const String TABLENAME = "TBL0703";
// . . .
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
dataList.DataSource = CreateDataSource( );
dataList.DataKeyField = "Id";
dataList.DataBind( );
}
}
private DataTable CreateDataSource( )
{
DataTable dt = new DataTable(TABLENAME);
// Create the DataAdapter and fill the table using it.
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM " + TABLENAME +
" ORDER BY Id",
ConfigurationSettings.AppSettings["DataConnectString"]);
da.Fill(dt);
da.FillSchema(dt, SchemaType.Source);
// Store data in session variable to store data between
// posts to server.
Session["DataSource"] = dt;
return dt;
}
private DataTable UpdateDataSource(DataTable dt)
{
// Create a DataAdapter for the update.
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM " + TABLENAME +
" ORDER BY Id",
ConfigurationSettings.AppSettings["DataConnectString"]);
// Create a CommandBuilder to generate update logic.
SqlCommandBuilder cb = new SqlCommandBuilder(da);
// Update the data source with changes to the table.
da.Update(dt);
// Store updated data in session variable to store data between
// posts to server.
Session["DataSource"] = dt;
return dt;
}
private void BindDataList( )
{
// Get the data from the session variable.
DataView dv = ((DataTable)Session["DataSource"]).DefaultView;
// Bind the data view to the data list.
dataList.DataSource = dv;
dataList.DataBind( );
}
private void dataList_CancelCommand(object source,
System.Web.UI.WebControls.DataListCommandEventArgs e)
{
// Set the index of the item being edited out of range.
dataList.EditItemIndex = -1;
BindDataList( );
}
private void dataList_DeleteCommand(object source,
System.Web.UI.WebControls.DataListCommandEventArgs e)
{
// Get the data from the session variable.
DataTable dt = (DataTable)Session["DataSource"];
// Get the ID of the row to delete.
int id = (int)dataList.DataKeys[e.Item.ItemIndex];
// Delete the row from the table.
dt.Rows.Find(id).Delete( );
// Update the data source with the changes to the table.
UpdateDataSource(dt);
// Set the index of the item being edited out of range.
dataList.EditItemIndex = -1;
BindDataList( );
}
private void dataList_EditCommand(object source,
System.Web.UI.WebControls.DataListCommandEventArgs e)
{
// Set the index of the selected item out of range.
dataList.SelectedIndex = -1;
// Set the index of the item being edited to the current record.
dataList.EditItemIndex = e.Item.ItemIndex;
BindDataList( );
}
private void dataList_ItemCommand(object source,
System.Web.UI.WebControls.DataListCommandEventArgs e)
{
// Check if the "select" button is pressed.
if (e.CommandName == "Select")
{
// Set the index of the item being edited out of range.
dataList.EditItemIndex = -1;
// Set the index of the selected item to the current record.
dataList.SelectedIndex = e.Item.ItemIndex;
BindDataList( );
}
}
private void dataList_UpdateCommand(object source,
System.Web.UI.WebControls.DataListCommandEventArgs e)
{
// Get the data from the session variable.
DataTable dt = (DataTable)Session["DataSource"];
// Get the ID of the row to update.
int id = (int)dataList.DataKeys[e.Item.ItemIndex];
// Get the DataRow to update using the ID.
DataRow dr = dt.Rows.Find(id);
// Get the column values for the current record from the DataList.
dr["IntField"] =
Int32.Parse(((TextBox)e.Item.FindControl("intFieldTextBox")).Text);
dr["StringField"] =
((TextBox)e.Item.FindControl("stringFieldTextBox")).Text;
// Update the data source with the changes to the table.
UpdateDataSource(dt);
// Set the index of the item being edited out of range.
dataList.EditItemIndex = -1;
BindDataList( );
}
Discussion
The DataListWebForms control displays tabular data from adata source and controls
the formatting using templates and styles. The DataList must be bound toadata source
such as a DataReader, DataSet, DataTable, or DataView—any class that implements the
IEnumerable interface can be bound. The easiest way to create aDataList control is to
drag the DataList control onto the web page design surface.
The DataListWeb Form control uses templates to display items, control layout, and
provide functional capabilities. Table 7-3 describes the different templates for the
DataList.
Table 7-3. DataList templates
Template Description
AlternatingItemTemplate
Elements to render for every other row in the control. This is
normally used to specify a different display style for
alternating rows. This template is defined within the
<AlternatingItemTemplate> and
</AlternatingItemTemplate> tags.
EditItemTemplate
Elements to render when an item is put into edit mode. This
template is invoked for the row specified in the
EditItemIndex property; setting the EditItemIndex property
to -1 cancels the edit mode. This template is defined within
the <EditItemTemplate> and </EditItemTemplate> tags.
FooterTemplate
Elements to render at the bottom of the control. The footer
template cannot be data bound. This template is defined
within the <FooterTemplate> and </FooterTemplate> tags.
HeaderTemplate
Elements to render at the top of the control. The header
template cannot be data bound. This template is defined
within the <HeaderTemplate> and </HeaderTemplate> tags.
ItemTemplate
Elements to render for each row in the data source. This
template is defined within the <ItemTemplate> and
</ItemTemplate> tags.
SelectedItemTemplate
Elements to render when an item in the control is selected.
This template is invoked for the row specified by the
SelectedIndex property; setting the SelectedIndex property to
-1 cancels the select mode. This template is defined within
the <SelectedItemTemplate> and </SelectedItemTemplate>
tags.
SeparatorTemplate
Elements to render between each item. The
SeparatorTemplate cannot be data bound. This template is
defined within the <SeparatorTemplate> and
</SeparatorTemplate> tags.
To format the templates, right-click on the DataList control on the design surface and
select one of the three editing submenus of the Edit Template menu. To end editing,
right-click the DataList control and select End Template Editing. Templates can also be
customized by editing the HTML directly. One of the item templates must contain adata
bound control for the DataList control to render at runtime.
A Button, LinkButton, or ImageButton web server control can be added to the control
templates. These buttons can let the user switch between the different item modes, for
example. The buttons bubble their events to the containing DataList control. The events
that the DataList raises in response to button clicks on the list items are described in
Table 7-4
.
Table 7-4. DataList Button click events
Event Description
CancelCommand Raised when the Cancel button is clicked for an item in the control.
DeleteCommand Raised when the Delete button is clicked for an item in the control.
EditCommand Raised when the Edit button is clicked for an item in the control.
ItemCommand
Raised when any button is clicked for an item in the control. The
button clicked can be determined by reading the CommandName
property of the DataListCommandEventArgs object in the
ItemCommand event handler. This property contains the value of
CommandName property of the button that was clicked.
UpdateCommand Raised when the Update button is clicked for an item in the control.
After the properties appropriate to the control are set, call the DataBind( ) method of the
control or of the page to bind the data source to the server control.
[ Team LiB ]
.
private DataTable CreateDataSource( )
{
DataTable dt = new DataTable(TABLENAME);
// Create the DataAdapter and fill the table using it.
SqlDataAdapter. The DataList must be bound to a data source
such as a DataReader, DataSet, DataTable, or DataView—any class that implements the
IEnumerable interface can