The .NET Framework Beta 2 has many changes that will break applications written in Beta 1. Among these changes is the templates used in Data Server Controls, such as the DataGrid and DataList. These are simply syntax changes in how templates are used, not programmatic breaks. In this tutorial you will learn how to use Data Server Control templates. Heck, since its a Friday I'll also show you how to do DataGrid editing at the same time. The downloadable sample code for this article contains files in both Visual Basic.NET and C#.
What Good is a Template?
Templates can be used with the Data Server Controls to provide a custom layout of the data bound to the control. The DataGrid provides a basic grid, with one row for each record, and one table column for each field in the row. Templates can be used with a TemplateColumn to custom format the layout of the column. The DataList provides one row for each record in the data source, and templates are used to format the layout of each row. The Repeater control is entirely custom. Templates are used to provide the layout for the entire Repeater control.
Changing a Name is a Big Deal
In Beta 1 you would use a DataGrid, and set up templates using a TemplateColumn. This is the same in Beta 2, however there are some slight changes to the syntax. In Beta 1 a DataGrid using a TemplateColumn would look like the code in Listing 1.
Listing 1
<asp:DataGrid runat="server" id="myGrid"
AutoGenerateColumns="False" >
<property name="columns">
<asp:TemplateColumn HeaderText="Info">
<template name="ItemTemplate">
<b><%# DataBinder.Eval(Container.DataItem,"CompanyName") %></b>
<%# DataBinder.Eval(Container.DataItem, "ContactName")%>
-
<%# DataBinder.Eval(Container.DataItem, "ContactTitle")%>
<%# DataBinder.Eval(Container.DataItem, "Address")%>
<%# DataBinder.Eval(Container.DataItem, "City") %>,
<%# DataBinder.Eval(Container.DataItem, "Region") %>
<%# DataBinder.Eval(Container.DataItem, "PostalCode") %>
</template>
</asp:TemplateColumn>
</property>
</asp:DataGrid>
The majority of the syntax in Listing 1 remains the same. The changes are as follows:
The <property> element changes to <Columns>
The <template> element changes to one of the following:
<AlternatingItemTemplate>
<EditItemTemplate>
<FooterTempalte>
<HeaderTemplate>
<ItemTemplate>
<SeparatorTemplate> (Repeater and DataList)
The same DataGrid shown in Listing 1 can be updated to Beta 2 as shown in Listing 2.
Listing 2
Listing 1
<asp:DataGrid runat="server" id="myGrid"
AutoGenerateColumns="False" >
<Columns>
<asp:TemplateColumn HeaderText="Info">
<ItemTemplate>
<b><%# DataBinder.Eval(Container.DataItem, "CompanyName") %></b>
<%# DataBinder.Eval(Container.DataItem, "ContactName") %>
-
<%# DataBinder.Eval(Container.DataItem, "ContactTitle") %>
<%# DataBinder.Eval(Container.DataItem, "Address") %>
<%# DataBinder.Eval(Container.DataItem, "City") %>,
<%# DataBinder.Eval(Container.DataItem, "Region") %>
<%# DataBinder.Eval(Container.DataItem, "PostalCode") %>
<ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
While Listing 2 shows a DataGrid using templates, the same rules apply to the other Data Server Controls. For example, Listing 3 shows a DataList in Beta 2.
Listing 3
<asp:DataList runat="server" id="myList">
<ItemTemplate>
<b><%# DataBinder.Eval(Container.DataItem, "CompanyName") %></b>
<%# DataBinder.Eval(Container.DataItem, "ContactName") %>
-
<%# DataBinder.Eval(Container.DataItem, "ContactTitle") %>
<%# DataBinder.Eval(Container.DataItem, "Address") %>
<%# DataBinder.Eval(Container.DataItem, "City") %>,
<%# DataBinder.Eval(Container.DataItem, "Region") %>
<%# DataBinder.Eval(Container.DataItem, "PostalCode") %>
<ItemTemplate>
</asp:DataList>
I Get the Template Thing, Get to the Good Stuff
The DataGrid and DataList control have built in functionality to enable editing. When the control is put into edit mode, usually by a user clicking an Edit link, the selected record is rendered differently than the others. If the column containing the data is a BoundColumn, then the data is rendered in a TextBox control. Using templates you can control how the record is rendered. The EditItemTemplate is used to specify how a table cell is rendered when the record is being edited.
In Listing 4 is the code for a Web Form containing one DataGrid that has both an <ItemTemplate> and an <EditItemTemplate>. The ItemTemplate is used to control the format of data when it is rendered in its normal state. The EditItemTemplate is used to control the formatting of the data when the record is being edited. In this case, the data is rendered in TextBoxes, although it could be done with DropDownLists, RadioButtons, or any other server control.
Listing 4 - 20010622T0101.aspx
<% Page language="C#" SRC="20010622T0101.cs" Inherits="TestApp.C20010622T0101" %>
<html>
<body>
<form method="post" runat="server">
<asp:DataGrid runat="server" id="myGrid"
AutoGenerateColumns="False"
BorderColor="Black"
BorderWidth="1" GridLines="Horizontal"
HeaderStyle-BackColor="Maroon"
HeaderStyle-Font-Bold="True"
HeaderStyle-Font-Name="Verdana"
HeaderStyle-Font-Size="9pt"
HeaderStyle-ForeColor="White"
ItemStyle-Font-Name="Verdana"
ItemStyle-Font-Size="8pt"
AlternatingItemStyle-BackColor="Tan" >
<Columns>
<asp:EditCommandColumn ButtonType="LinkButton"
ItemStyle-VerticalAlign="Top"
EditText="Edit"
CancelText="Cancel"
UpdateText="Update" />
<asp:BoundColumn ReadOnly="True" DataField="CustomerID"
HeaderText="ID" ItemStyle-VerticalAlign="Top" />
<asp:TemplateColumn HeaderText="Info">
<ItemTemplate>
<b><%# DataBinder.Eval(Container.DataItem, "CompanyName") %></b>
<%# DataBinder.Eval(Container.DataItem, "ContactName") %>
-
<%# DataBinder.Eval(Container.DataItem, "ContactTitle") %>
<%# DataBinder.Eval(Container.DataItem, "Address") %>
<%# DataBinder.Eval(Container.DataItem, "City") %>,
<%# DataBinder.Eval(Container.DataItem, "Region") %>
<%# DataBinder.Eval(Container.DataItem, "PostalCode") %>
</ItemTemplate>
<EditItemTemplate>
<b><%# DataBinder.Eval(Container.DataItem, "CompanyName") %></b>
<b>Contact Name:</b>
<asp:TextBox Runat="server" id="ContactName"
Text='<%# DataBinder.Eval(Container.DataItem, "ContactName") %>' />
<b>Contact Title:</b>
<asp:TextBox Runat="server" ID="ContactTitle"
Text='<%# DataBinder.Eval(Container.DataItem, "ContactTitle") %>' />
<asp:TextBox Runat="server" ID="Address"
Text='<%# DataBinder.Eval(Container.DataItem, "Address") %>' />
<asp:TextBox Runat="server" ID="City"
Text='<%# DataBinder.Eval(Container.DataItem, "City") %>' />,
<asp:TextBox Runat="server" ID="Region"
Text='<%# DataBinder.Eval(Container.DataItem, "Region") %>' />
<asp:TextBox Runat="server" ID="PostalCode"
Text='<%# DataBinder.Eval(Container.DataItem, "PostalCode") %>' />
</EditItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
</form>
</body>
</html>
The Web Form shown in Listing 4 uses the code behind class TestApp.C20010622T0101. The beginning of the code for the Web Form is shown in Listing 5. This is only the code to get the data for the first request of the page.
Listing 5 - 20010622T0101.cs
using System;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace TestApp
{
public class C20010622T0101 : System.Web.UI.Page
{
protected DataGrid myGrid;
protected void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
BindData();
}
}
protected void BindData()
{
SqlConnection con = new SqlConnection("server=localhost;database=Northwind;uid=sa;pwd=;");
SqlCommand cmd = new SqlCommand("SELECT TOP 10 * FROM Customers", con);
con.Open();
myGrid.DataSource = cmd.ExecuteReader(CommandBehavior.CloseConnection);
myGrid.DataBind();
((SqlDataReader)myGrid.DataSource).Close();
}
}
}
In Listing 5 you use a BindData() method to encapsulate your data access and DataGrid binding. This is important for how the editing will work. You want to be able to call the BindData() method at the right time, rather than relying on the Page_Load() event to handle it for you. In the Page_Load() event handler you make a call to BindData() only when the Web request is not the result of a form post.
You can view the page in the browser now, but the edit functionality will not work. To enable editing there are four steps we have to take:
Write an OnEditCommand() event handler
Write and OnCancelCommand() event handler
Write an OnUpdateCommand() event handler
Add pointers to the event handlers in the DataGrid
Lets start by writing an OnEditCommand() event handler. Listing 6 shows the code you need to add to the code behind class for the event handler.
Listing 6
protected void myGrid_OnEditCommand(object sender, DataGridCommandEventArgs e)
{
myGrid.EditItemIndex = e.Item.ItemIndex;
BindData();
}
The OnEditCommand() event handler does two things, it sets the EditItemIndex of the DataGrid to the value passed in the DataGridCommandEventArgs, and calls BindData(). The DataGridCommandEventArgs.Item.ItemIndex is the index of the row where the Edit links was clicked. This tells the .NET Framework that this row should be rendered using the <EditItemTemplate>. With the EditItemIndex set, calling BindData() will rebind the data to the DataGrid.
Before you test this page, add the following line to the <asp:DataGrid> tag:
OnEditCommand="myGrid_OnEditCommand"
The OnCancelCommand() event handler works in the same way as the OnEditCommand() event handler. You set the EditItemIndex to -1 (indicating that no rows are being edited), and call BindData(). This is shown in Listing 7.
Listing 7
protected void myGrid_OnCancelCommand(object sender, DataGridCommandEventArgs e)
{
myGrid.EditItemIndex = -1;
BindData();
}
To tie the DataGrid to the OnCancelCommand() event handler, add the following code to the <asp:DataGrid> tag:
OnCancelCommand="myGrid_OnCancelCommand"
At this point you can view the Web Form in the browser, and test the Edit link and the Cancel link, but the Update link is still not functional.
Make Seven-Up(date) yours!
The OnUpdateCommand() event handler needs to do a few things. It needs to grab the new data from the controls in the <EditItemTemplate>, connect to the database, execute an UPDATE statement, set the EditItemIndex to -1, and call BindData().
To make life easier, I have created a new stored procedure in the Northwind database, for updating Customer information. This is shown in Listing 8.
Listing 8
CREATE PROCEDURE [sp_UpdateCustomer]
customerID nchar (5),
contactName nvarchar (30),
contactTitle nvarchar (30),
address nvarchar (60),
city nvarchar (15),
region nvarchar (15),
postalCode nvarchar(10)
AS
UPDATE Customers
SET
ContactName = contactName,
ContactTitle = contactTitle,
Address = address,
City = city,
Region = region,
PostalCode = postalCode
WHERE
CustomerID = customerID
GO
Once you have created the stored procedure you can use a parameterized SqlCommand to update the customer data. Lets look at the code, then Ill explain how it works. Listing 9 shows the OnUpdateCommand() event handler.
Listing 9
protected void myGrid_OnUpdateCommand(object sender, DataGridCommandEventArgs e)
{
SqlConnection con = new SqlConnection("server=localhost;database=Northwind;uid=sa;pwd=;");
SqlCommand cmd = new SqlCommand("sp_UpdateCustomer", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("customerID", SqlDbType.NChar, 5));
cmd.Parameters.Add(new SqlParameter("contactName", SqlDbType.NVarChar, 30));
cmd.Parameters.Add(new SqlParameter("contactTitle", SqlDbType.NVarChar, 30));
cmd.Parameters.Add(new SqlParameter("address", SqlDbType.NVarChar, 60));
cmd.Parameters.Add(new SqlParameter("city", SqlDbType.NVarChar, 15));
cmd.Parameters.Add(new SqlParameter("region", SqlDbType.NVarChar, 15));
cmd.Parameters.Add(new SqlParameter("postalCode", SqlDbType.NVarChar, 10));
cmd.Parameters["customerID"].Value = e.Item.Cells[1].Text;
cmd.Parameters["contactName"].Value = ((TextBox)e.Item.FindControl("ContactName")).Text;
cmd.Parameters["contactTitle"].Value = ((TextBox)e.Item.FindControl("ContactTitle")).Text;
cmd.Parameters["address"].Value = ((TextBox)e.Item.FindControl("Address")).Text;
cmd.Parameters["city"].Value = ((TextBox)e.Item.FindControl("City")).Text;
cmd.Parameters["region"].Value = ((TextBox)e.Item.FindControl("Region")).Text;
cmd.Parameters["postalCode"].Value = ((TextBox)e.Item.FindControl("PostalCode")).Text;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
myGrid.EditItemIndex = -1;
BindData();
}
In Listing 9 you create the OnUpdateCommand() event handler. In the event handler you create a SqlCommand and add six SqlParameters to the ParameterCollection. These parameters are mapped directly to the input parameters expected by the stored procedure in Listing 8.
To set the value of the parameters you use the DataGridEditItemEventArgs.Item.FindControl() method to find the control you want the value for. Since FindControl() returns an instance of the Control class, you have to cast the control as a TextBox before you can retrieve the Text property. Once you have set all the parameters you can open the connection and execute the command. Since the stored procedure does not return anything to you, you can use the ExecuteNonQuery() method. This will execute a command and return the number of rows affected. In this example we are not concerned with that information, so we do not capture it.
After the update is executed, you set the EditItemIndex of the DataGrid to -1, and call BindData().
All you need to do is tie the DataGrid to the OnUpdateCommand() by adding the following code to the <asp:DataGrid> tag:
OnUpdateCommand="myGrid_OnUpdateCommand"
Figure 1 shows the page when you click the Edit link on a row.
[ Run Sample ]
Summary
In Beta 2 the templates used in the Data Server Controls have changed a bit. Nothing too drastic, mostly a syntax change. You no longer use the <property> and <template> tags. Instead you use the <Columns> and <ItemTemplate> (or similar template) tags.
Coping with a New Beta - Data Server Control Templ
80酷酷网 80kuku.com