The Repeater Demo

This demo binds the authors table to a Repeater, allows users to select items with checkboxes, and then creates a list of selected names when the OK button is clicked. You can see the demo as it first appears in Figure 6.2.

Figure 6.2. The Repeater Demo Shows a Checkbox for Each Row.

graphics/06fig02.jpg

The User Interface

There is some incidental text, but to build the meat of the user interface, I first placed a Repeater onto the screen and named it Authors. Below the Repeater, I put a Label that doubles as an error-report mechanism and the destination for the list of selected authors this object is named ErrorMessage. Below the Label is a button that fires an event handler.

The Repeater has three columns when it renders: one for the author's name, one for the author's phone, and one for the author's contact. Three templates are used in the Repeater: a HeaderTemplate, an ItemTemplate, and a FooterTemplate. The following code shows a simplified version of the Repeater. We'll get to the details shortly.

 <asp:repeater  runat="server">   <HeaderTemplate>     <table border="1" width="80%">       <tr>         <th>           Author         </th>         <th>           Phone         </th>         <th>           Contact         </th>       </tr>   </HeaderTemplate>   <ItemTemplate>     <tr>     <td>      <asp:Label  runat="server"        text='Populate name data here' />     </td>     <td>      <asp:Label  runat="server"        text='Populate phone data here' />     </td>     <td>      <asp:CheckBox runat="server"  />      </td>     </tr>   </ItemTemplate>   <FooterTemplate>     </table>   </FooterTemplate> </asp:repeater> 

If you look at the HeaderTemplate in the code above, you'll see the start of a table and three table headings. Repeaters do not generate the table start tag, so you must put it either in the HeaderTemplate or before the Repeater starts.

Take a look at the FooterTemplate next. It contains just the table end tag.

The ItemTemplate has three columns (within <td></td> tags). The first column contains the author name, and the name data will be in a Label object named Name. The second column contains the author phone, and the phone data will be in a Label object named Phone. The third column contains a CheckBox object that users can select.

That's the nickel tour of the Repeater's templates. The next thing you need to know is how to populate the Labels with the name and phone data. There are several ways to do it, but the way I find easiest and most maintainable is with the following syntax:

 DataBinder.Eval(Container.DataItem, "fieldname") 

The code above, though, must be within the <%# and %> symbols to indicate that it's code, as follows:

 <%# DataBinder.Eval(Container.DataItem, "fieldname") %> 

This syntax inserts the contents of the named field into the Repeater template. The following is the complete .aspx code for the Repeater:

 <asp:repeater  runat="server">   <HeaderTemplate>     <table border="1" width="80%">       <tr>         <th>           Author         </th>         <th>           Phone         </th>         <th>           Contact         </th>       </tr>   </HeaderTemplate>   <ItemTemplate>     <tr>     <td>      <asp:Label  runat="server"        text='<%# DataBinder.Eval(Container.DataItem, "au_lname") +          ", " + DataBinder.Eval(Container.DataItem, "au_fname")' />     </td>     <td>      <asp:Label  runat="server"        text='<%# DataBinder.Eval(Container.DataItem, "Phone") %>' />     </td>     <td>      <asp:CheckBox runat="server"  />      </td>     </tr>   </ItemTemplate>   <FooterTemplate>     </table>   </FooterTemplate> </asp:repeater> 

NOTE: When you place Label objects onto an ASP.NET form and set the text in the Property window, the text content that you specified will appear between the <asp:Label> and </asp:Label> tags. Let's say, for example, that you have a Label object named Address. You put the text 1234 Main Street into the text field of the property window. If you go the HTML view and look at the code, you'll see something like the following:

 <asp:Label  runat="server">1234 Main Street</asp:Label> 

Then, to access the text contents in code, you simply use the Label.Text property. I ran into a small dilemma that I couldn't solve when I added the code as follows to populate the Label objects (as you would expect to do):

 <asp:Label  runat="server">   <%# DataBinder.Eval(Container.DataItem, "Phone") %> </asp:Label> 

When I tried to retrieve the contents by accessing the Label.Text property, they were invariably empty. But when I set the Label's Text attribute as follows, it worked perfectly:

 <asp:Label  runat="server"   Text='<%# DataBinder.Eval(Container.DataItem, "Phone") %>'> </asp:Label> 

To make matters even stranger, the Text attribute of a Label object doesn't come up with autocomplete, as do all other available attributes.


NOTE: The Code behind the Repeater Demo

There are two methods in the code that we'll talk about. The first is the Page_Load() method, in which the Repeater is bound to a recordset. The second method is the button handler event that's fired when the user clicks the button labeled OK.

All of the demos require the System.Data.SqlClient namespace because all the samples use SQL Server. Toward the top of each source code module, you'll see the following:

C#
 using System.Data.SqlClient; 
VB
 Imports System.Data.SqlClient 


The Page_Load() Method of the Repeater Demo

The code for the Page_Load() method follows. A discussion of the code is immediately below it.

C#
 private void Page_Load(object sender, System.EventArgs e) {   // Only populate the Repeater if this is not a post back.   if( !IsPostBack )   {     // Create a connection object.     SqlConnection objConnection =      new SqlConnection("server=localhost;database=pubs;uid=sa;pwd=");     // Use a try/catch/finally construct to     //   gracefully handle errors.     try     {       // Open the connection.       objConnection.Open();       // Create the command object. We'll select all       //   author first and last name along with phone.       SqlCommand objCommand =         new SqlCommand( "SELECT au_lname,au_fname,phone FROM authors " +         "ORDER BY au_lname,au_fname",         objConnection );       // Populate a reader.       SqlDataReader objReader = objCommand.ExecuteReader();       // Set the Repeater's data source and then       //   call the DataBind() method.       Authors.DataSource = objReader;       Authors.DataBind();       // Close the reader.       objReader.Close();     }     catch( Exception ex )     {       // Display the error message to the reader.       ErrorMessage.Text = ex.Message.ToString();     }     finally     {       // See if the connection is open.       if( objConnection.State == ConnectionState.Open )       {         // Close it if it is open.         objConnection.Close();       }     }   } } 
VB
 Private Sub Page_Load(ByVal sender As System.Object, _   ByVal e As System.EventArgs) Handles MyBase.Load     ' Only populate the Repeater if this is not a post back.     If Not IsPostBack Then     ' Create a connection object.      Dim objConnection As _       New SqlConnection("server=localhost;database=pubs;uid=sa;pwd=")         ' Use a try/catch/finally construct to         '   gracefully handle errors.          Try             ' Open the connection.             objConnection.Open()           ' Create the command object. We'll select all           '   author first and last name along with phone.           Dim objCommand As _            New SqlCommand( _              "SELECT au_lname,au_fname,phone FROM authors " + _               "ORDER BY au_lname,au_fname", _               objConnection)             ' Populate a reader.             Dim objReader As SqlDataReader = objCommand.ExecuteReader()             ' Set the Repeater's data source and then             '   call the DataBind() method.             Authors.DataSource = objReader             Authors.DataBind()             ' Close the reader.             objReader.Close()         Catch ex As Exception             ' Display the error message to the reader.             ErrorMessage.Text = ex.Message.ToString()         Finally             ' See if the connection is open.             If objConnection.State = ConnectionState.Open Then                 ' Close it if it is open.                 objConnection.Close()             End If         End Try     End If End Sub 

This code performs a pretty straightforward retrieval of data with which the Repeater is bound. First, a connection to the database is created by creating a SqlConnection object and then calling its Open() method. Any code that can throw an exception is within a try block. The try/catch/finally construct allows the code to be robust and handle any errors that might arise. If everything goes well, all of the code in the try block is executed, followed by the code in the finally block. If an exception is thrown at any point in the try block, execution proceeds to the catch block, after which the finally block will be executed.

All of the connection strings in this section have a blank password for the sa SQL Server account. I've removed these so that the password is blank so that my server remains secure. It is a bad idea, however, to have a blank password for the sa account. For one thing, this leaves a security hole open. For another thing, there is a worm (named DispId) that could strike your server.

Once the connection has been established to the database, a SqlCommand object must be created. This object gives us the capability to execute a query on the database and get a recordset back. The recordset will be contained in a SqlDataReader object. The following SQL will be executed:

 SELECT au_lname,au_fname,phone FROM authors ORDER BY au_lname,au_fname 

A call to the SqlCommand.ExecuteReader() method returns a populated SqlDataReader object. The Repeater is now bound to the data by setting the Repeater.DataSource property to the SqlDataReader, and then calling the Repeater.DataBind() method.

The ExamineRepeater_Click() Method of the Repeater Demo

The code for the ExamineRepeater_Click() method follows. It is fired when users click the OK button. A discussion of the code is immediately below it.

C#
 private void ExamineRepeater_Click(object sender, System.EventArgs e) {   // Clear the Label so that we start with an empty string.   //   (The label that's used to show database exception   //   messages is also used to display the results.)   ErrorMessage.Text = "";   // Loop through the items in the Authors object (which is   //   a Repeater).   foreach( Control control in Authors.Controls )   {     // Make sure we have a line that's not a header or footer.     if( ((RepeaterItem)control).ItemType == ListItemType.Item ||       ((RepeaterItem)control).ItemType == ListItemType.AlternatingItem )     {       // Find the CheckBox object so that we know if this item       //   was selected.       CheckBox cb = (CheckBox)control.FindControl( "Schedule" );       if( cb.Checked )       {         // Find the Label objects from which we'll get the         //   text.         Label Name = (Label)control.FindControl( "Name" );         Label Phone = (Label)control.FindControl( "Phone" );         // Concatenate the text from the Name and Phone         //   Labels onto the Label that will hold the results.         ErrorMessage.Text +=           ( Name.Text + " -- " + Phone.Text + "<br>\r\n" );       }     }   } } 
VB
 Private Sub ExamineRepeater_Click(ByVal sender As System.Object, _   ByVal e As System.EventArgs) Handles ExamineRepeater.Click     ' Clear the Label so that we start with an empty string.     '   (The label that's used to show database exception     '   messages is also used to display the results.)     ErrorMessage.Text = ""     ' Loop through the items in the Authors object (which is     '   a Repeater).     Dim i As Integer     For i = 0 To Authors.Controls.Count - 1         Dim item As RepeaterItem = Authors.Controls(i)         ' Make sure we have a line that's not a header or footer.         If item.ItemType = ListItemType.Item Or _             item.ItemType = ListItemType.AlternatingItem Then             ' Find the CheckBox object so that we know if this item             '   was selected.             Dim cb As CheckBox = item.FindControl("Schedule")             If cb.Checked Then                 ' Find the Label objects from which we'll get the                 '   text.                 Dim Name As Label = item.FindControl("Name")                 Dim Phone As Label = item.FindControl("Phone")                 ' Concatenate the text from the Name and Phone                 '   Labels onto the Label that will hold the results.                 ErrorMessage.Text += _                  (Name.Text + " -- " + Phone.Text + "<br>" + vbCrLf)             End If         End If     Next End Sub 

Let's start with one thing: you can't directly access the server controls. For instance, the following code will not compile:

C#
 string strText = ServerLabelControl.Text; 
VB
 Dim strText as String = ServerLabelControl.Text 

These controls are not accessible at the page level because of the implementation of ASP.NET templates. Each template runs in a separate naming container that makes it impossible for the common language runtime processing the ASP.NET page to retrieve the controls that are in the templates. This setup is so that we can duplicate named controls on the same page working in their respective naming containers.

The code in the ExamineRepeater_Click() method starts off by emptying the ErrorMessage Label object so that it can be used to hold a cumulative listing of the selected names. The code then iterates through the Controls collection in the Authors Repeater object. Note that in C# a foreach loop is used, while in VB a For/Next loop is used. That's because VB does not have a foreach loop.

We make sure that each control in the collection is either an ItemTemplate or an AlternatingItemTemplate. If we don't perform this check, we might be inadvertently looking at the HeaderTemplate and FooterTemplate, in which case the FindControl() method will return a null (or Nothing in VB) because the control won't be found.

Next, we get an object reference to the CheckBox that's in the current row. This is done with the FindControl() method. I've extracted the lines (for C# and VB) that find the CheckBox objects, and they are here:

C#
 CheckBox cb = (CheckBox)control.FindControl( "Schedule" ); 
VB
 Dim cb As CheckBox = item.FindControl("Schedule") 

A simple check to the CheckBox.Checked property lets us know whether it is checked. If it's not, we won't do anything else during this iteration of the loop. If it is checked, though, we'll go on to get object references to the Labels that are in the Repeater, as follows:

C#
 Label Name = (Label)control.FindControl( "Name" ); Label Phone = (Label)control.FindControl( "Phone" ); 
VB
 Dim Name As Label = item.FindControl("Name") Dim Phone As Label = item.FindControl("Phone") 

Once object references to the Labels have been retrieved, it's a simple matter to concatenate their Text properties to the ErrorMessage.Text property. You can see the application below in Figure 6.3, after several rows have been selected and the OK button has been pressed:

Figure 6.3. You Can See the Rows That Were Selected.

graphics/06fig03.jpg



ASP. NET Solutions - 24 Case Studies. Best Practices for Developers
ASP. NET Solutions - 24 Case Studies. Best Practices for Developers
ISBN: 321159659
EAN: N/A
Year: 2003
Pages: 175

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net