Creating Select Command Buttons

All the examples we've looked at in this and the previous chapter have had one underlying theme in common: the user is presented with a command button of some kind on each row in the data Web control that performs some sort of action based upon the row whose command button was clicked. In our running example in this chapter, we've been looking at how to add a Details button to each row that displays more in-depth information about the particular row.

On an aesthetic level, it would be nice to let users know what row they have clicked through the use of visual cues. Perhaps the row whose command button was clicked will have its text displayed in bold or a different color background than the other rows. To facilitate this, the DataGrid and DataList controls contain a SelectedIndex property that can be used to designate which row of the DataGrid or DataList is the "selected" row. In addition to this, both controls contain a display property called SelectedItemStyle, through which style information for the selected row can be specified.

There are two ways to designate what row is the selected row:

  1. Explicitly, by programmatically setting the SelectedIndex property.

  2. Implicitly, by setting the command button's CommandName property to Select.

To explicitly indicate that a row is the selected row, you first need to create a command button that makes the row the selected row. In our Details example, this would simply be the Details button. In the ItemCommand event handler, you would test to see whether the Details button is the button that triggered the ItemCommand event; if it is, you want to then set the DataGrid or DataList's SelectedIndex property equal to the ItemIndex property of the DataGrid's DataGridItem or DataList's DataListItem that was clicked. That is, if we were using a DataList, you would declare your DataList like so:

 <asp:DataList runat="server"      OnItemCommand="dlTitles_ItemCommand" ...>   <ItemTemplate>    <asp:Button runat="server" Text="Details" CommandName="Details" />    ...   </ItemTemplate>  </asp:DataList> 

Then, in the dlTitles_ItemCommand event handler, you would set the SelectedIndex property with

 Sub dlTitles_ItemCommand(sender as Object, e as DataListCommandEventArgs)   ' Make sure it was the "Details" command button that was clicked...   If e.CommandName = "Details" then    ' Now, programmatically set the SelectedIndex property    dlTitles.SelectedIndex = e.Item.ItemIndex   End If  End Sub 

Although explicitly setting the SelectedIndex property is not terribly difficult, the DataGrid and DataList will automatically set the SelectedIndex property accordingly when a command button with its CommandName property set to "Select" is clicked. Listing 5.6, which we'll examine shortly, illustrates using a command button with its CommandName set to "Select".

Altering the Display Properties of the Selected Row

The DataGrid and DataList contain a SelectedItemStyle display property that is applied to the selected item. Recall from Chapter 3 that style properties are actually full-blown classes themselves and incorporate a number of properties, such as Font, HorizontalAlign, BackColor, ForeColor, and so on. Listing 5.6 contains a DataGrid declaration that specifies a SelectedItemStyle the server-side script block has been omitted, for it simply contains the Page_Load event handler and the BindData function that has already been presented in previous code listings in this chapter.

Listing 5.6 The SelectedItemStyle Property Specifies the Aesthetic Settings for the Selected Item
  1: <form runat="server">   2:  <asp:DataGrid AutoGenerateColumns="False"   3:    runat="server"    4:    Font-Name="Verdana" Font-Size="9pt">   5:   6:   <SelectedItemStyle BackColor="#dddddd" Font-Italic="True"   7:      Font-Size="15pt" />   8:   9:   <HeaderStyle BackColor="Navy" ForeColor="White"  10:      Font-Bold="True" HorizontalAlign="Center"  11:      Font-Size="11pt" />  12:  13:   <Columns>  14:    <asp:ButtonColumn Text="Details" CommandName="Select"  15:        HeaderText="View Details" ItemStyle-HorizontalAlign="Center" />  16:    <asp:BoundColumn DataField="Title" HeaderText="Title" />  17:   </Columns>  18:  </asp:DataGrid>  19: </form> 

When the ASP.NET Web page on which the DataGrid from Listing 5.6 resides on is first visited, each row of the DataGrid will look the same, with its Verdana 9 pt. font. Each row will also contain a Details hyperlink created by the ButtonColumn control (line 14). Note that the CommandName is set to "Select", which will cause the SelectedIndex to be updated to the index of the row whose Details button was clicked. (Note that the initial value of the SelectedIndex is -1.)

When a row's Details button is clicked, the ASP.NET page posts back and the DataGrid's SelectedIndex property is automatically updated. In addition, the DataGrid's SelectedIndexChanged event is fired. This event is fired whenever the DataGrid's SelectedIndex property changes between postbacks. We'll examine some potential uses for this event in a bit, but for now realize that the SelectedIndex property is updated for you automatically when you use a command button with its CommandName property set to "Select".

When a Details button is clicked and the SelectedIndex property is set accordingly, the SelectedItemStyle property's attributes are applied to the selected row. Figure 5.6 illustrates this note that after a particular row has been clicked, the ASP.NET page is posted back and the row that was clicked is then displayed with a different color background, in italics, and with a larger font.

Figure 5.6. The row whose Details button was clicked is clearly marked.

graphics/05fig06.gif

Figure 5.6 shows that when a row is selected, it takes on a different appearance from the other rows in the DataGrid. However, the details for the selected row are not shown. In Listing 5.5, we saw how to display such details in a separate DataGrid Web control when setting each row's primary key field information to the command button's CommandArgument property.

In Listing 5.6, however, we're using a ButtonColumn control, which doesn't contain a CommandArgument property. At this point, we have two options. The first is to convert the ButtonColumn into a TemplateColumn, which would then include a command button in the ItemTemplate. This command button would have its CommandName property set to "Select" and its CommandArgument property set to the primary key field via data-binding syntax. That is, lines 14 and 15 in Listing 5.6 would become

 <asp:TemplateColumn>   <ItemTemplate>    <asp:LinkButton runat="server" CommandName="Select" Text="Details"         CommandArgument='<%# DataBinder.Eval(Container.DataItem, "title_id") %>' />   </ItemTemplate>  </asp:TemplateColumn> 

This primary key field information could then be extracted in the ItemCommand event handler, which would look like

 Sub dgTitles_ItemCommand(sender As Object, e As DataGridCommandEventArgs)   If e.CommandName = "Select" then    ' The details button has been clicked, find out the PK field value    Dim strTitleID as String = e.CommandArgument    ' Display the book's details    dgBookDetails.DataSource = GetBookDetails(strTitleID)    dgBookDetails.DataBind()    ' Make sure the dgBookDetails DataGrid is Visible    dgBookDetails.Visible = True   End If  End Sub 

Note that the If statement on the second line checks to see whether the CommandName equals "Select", because that is the name of our LinkButton control in the DataGrid's TemplateColumn. This is the technique we discussed earlier in this chapter in the "Storing Primary Key Field Information in the CommandArgument Property" section.

The other option involves leaving the ButtonColumn control untouched and moving the logic to the DataGrid's SelectedItemChanged event handler. Recall that the SelectedItemChanged event handler is fired whenever the DataGrid's SelectedIndex property's value changes between postbacks. Hence, when the code in the SelectedItemChanged event handler is being executed, we know that the user has selected a new row. Therefore, we can move the logic to populate the dgBookDetails DataGrid with the particular book's details into this event handler. This means that the SelectedItemChanged event handler will have to call the GetBookDetails(TitleID ) function, but to do this, we need to know the primary key field value of the selected row. Because we're using the ButtonColumn control and not a command button in a template, we can't use the CommandArgument approach. Instead, we'll fall back on the preferred technique: using the DataKeyField and DataKeys properties.

Listing 5.7 enhances Listing 5.6 so as to actually display the book's details when the user selects a particular row. Note that the semantics of Listing 5.7 are identical to that of Listing 5.5; the only differences are visual ones. For example, using the SelectedItemStyle and a command button with a CommandName of "Select", Listing 5.7 has the selected row visually different from the other rows.

Listing 5.7 The Book Whose Details Are Being Displayed Is Visually Different from the Other Books in the DataGrid
  1: <%@ import Namespace="System.Data" %>   2: <%@ import Namespace="System.Data.SqlClient" %>   3: <script runat="server" language="C#">   4:   ' ... the Page_Load event handler, and the BindData and   5:   '   GetBookDetails functions have been omitted for brevity ...   6:   7:   void ShowDetails(object sender, EventArgs e)   8:   {   9:    // Get the TitleID  10:    string strTitleID = dgTitles.DataKeys[dgTitles.SelectedIndex].ToString();  11:  12:    // Display the book's details  13:    dgBookDetails.DataSource = GetBookDetails(strTitleID);  14:    dgBookDetails.DataBind();  15:  16:    // Make sure the dgBookDetails DataGrid is Visible  17:    dgBookDetails.Visible = true;  18:   }  19: </script>  20:  21: <form runat="server">  22:  <%-- The dgBookDetails DataGrid displays the details  23:        for the selected book... --%>  24:  <asp:DataGrid runat="server"   25:     Font-Name="Verdana" HorizontalAlign="Center"  26:     Visible="False" Width="85%">  27:   <HeaderStyle BackColor="Navy" ForeColor="White"  28:      Font-Size="11pt" HorizontalAlign="Center" />  29:  30:   <ItemStyle BackColor="#eeeeee" Font-Size="9pt" />  31:  </asp:DataGrid>  32:  <p>&nbsp;</p>  33:  34:  <%-- The dgTitles DataGrid displays all of the books --%>  35:  <asp:DataGrid AutoGenerateColumns="False"  36:    runat="server"   37:    OnSelectedIndexChanged="ShowDetails"  38:    DataKeyField="title_id"  39:    Font-Name="Verdana" Font-Size="9pt">  40:   41:   <SelectedItemStyle BackColor="#dddddd" Font-Italic="True"  42:      Font-Size="15pt" />  43:  44:   <HeaderStyle BackColor="Navy" ForeColor="White"  45:      Font-Bold="True" HorizontalAlign="Center"  46:      Font-Size="11pt" />  47:  48:   <Columns>  49:    <asp:ButtonColumn Text="Details" CommandName="Select"  50:      HeaderText="View Details" ItemStyle-HorizontalAlign="Center" />  51:    <asp:BoundColumn DataField="Title" HeaderText="Title" />  52:   </Columns>  53:  </asp:DataGrid>  54: </form> 

The major difference between Listing 5.7 and Listing 5.5 is that Listing 5.7 has removed the ItemCommand event handler entirely. Instead, it has been replaced by the SelectedIndexChanged event handler, ShowDetails (lines 7 18). ShowDetails is executed whenever the user clicks on a "Select" command button that is not in the currently selected row.

The first thing we do in ShowDetails is determine the primary key field of the selected row; this is accomplished by consulting the DataKeys collection (line 10) and grabbing the item whose index matches that of the DataGrid's SelectedIndex property. Note that the signature for the SelectedIndexChanged event handler has as its second parameter a variable of type EventArgs, as opposed to the DataGridCommandEventArgs type that was used for the DataGrid's ItemCommand event. This limits us in that we cannot reference the CommandName or CommandArgument that corresponds to the command button that caused the SelectedIndex to change; nor can we access the DataGridItem that corresponds to the DataGrid row that contains the command button that caused the SelectedIndex to change. Fortunately, we can use the DataGrid's SelectedIndex property to correctly index the DataKeys field to get the appropriate primary key field value.

Figure 5.7 contains a screenshot of Listing 5.7 when viewed through a browser. Note that the output generated by Listing 5.5 (Figure 5.5) and Listing 5.7 differs only in visual aspects.

Figure 5.7. The book's details are displayed in a separate DataGrid.

graphics/05fig07.gif

Altering the Content of the Selected Row

In the previous section, we looked at how to alter the display properties of the selected item via the SelectedItemStyle. We also examined how to use a command button that automatically updates the DataGrid's SelectedIndex property. Although our examples in the prior section used a DataGrid Web control, realize that the DataList also supports this same functionality.

In fact, the DataList includes some additional functionality that's missing in the DataGrid. Specifically, when using the DataList, you can specify a SelectedItemTemplate. This template is used instead of the ItemTemplate when rendering the row whose index is equal to the SelectedIndex property.

In our previous examples, we displayed the details of the book by populating a separate DataGrid (dgBookDetails) with the results of a SQL query that returned the details for the particular book. Using the DataList's SelectedItemTemplate, we can have the details shown in row itself. That is, when the user clicks the Details button, the SelectedIndex property will be set to the row clicked and the DataList will be rebound to the DataSource; when the DataList is rendered, the row whose index is equal to the SelectedIndex will be rendered using the SelectedItemTemplate. Hence, the row whose Details button was clicked will have the details for that row displayed in place.

To understand what we're after, take a moment to examine Figure 5.8, which shows a screenshot of the code in Listing 5.8. In Figure 5.8, the user has already clicked on a book's Details button, thus causing a postback and the rebinding of the DataList.

Figure 5.8. The book's details are shown in place.

graphics/05fig08.gif

Now to write the code to produce the output shown in Figure 5.8! Listing 5.8 contains the source code needed to produce a DataList that uses a SelectedItemTemplate to display a book's details in place.

Listing 5.8 The SelectedItemTemplate Allows for Different Content for the Selected Row
  1: <%@ import Namespace="System.Data" %>   2: <%@ import Namespace="System.Data.SqlClient" %>   3: <script runat="server" language="C#">   4:   void Page_Load(object sender, EventArgs e)   5:   {   6:    if (!Page.IsPostBack)   7:     BindData();   8:   }   9:  10:  11:   void BindData()  12:   {  13:    // 1. Create a connection  14:    const string strConnString = "server=localhost;uid=sa;pwd=;database=pubs";  15:    SqlConnection objConn = new SqlConnection(strConnString);  16:  17:    // 2. Create a command object for the query  18:    const string strSQL = "SELECT * FROM titles";  19:    SqlCommand objCmd = new SqlCommand(strSQL, objConn);  20:   21:    objConn.Open();  // Open the connection  22:  23:    //Finally, specify the DataSource and call DataBind()  24:    dlTitles.DataSource = objCmd.ExecuteReader (CommandBehavior.CloseConnection);  25:    dlTitles.DataBind();  26:  27:    objConn.Close();  // Close the connection  28:   }  29:  30:  31:   void DisplayBookDetails(object sender, EventArgs e)  32:   {  33:    // simply rebind the DataList  34:    BindData();  35:   }  36: </script>  37: <form runat="server">  38:  <asp:DataList runat="server"   39:    OnSelectedIndexChanged="DisplayBookDetails"  40:    Font-Name="Verdana" Font-Size="11pt"  41:    ItemStyle-BackColor="#eeeeee"  42:    AlternatingItemStyle-BackColor="White"  43:    HorizontalAlign="Center" CellPadding="8">  44:  45:   <ItemTemplate>  46:    <i><%# DataBinder.Eval(Container.DataItem, "title") %></i>  47:    <br />  48:    [<asp:LinkButton runat="server" CommandName="Select"  49:      Font-Size="8pt" Text="View Book Details" />]  50:   </ItemTemplate>  51:  52:   <SelectedItemTemplate>  53:    <table border="0" style="font-size:9pt;">  54:     <tr><th colspan="2">Book Details</th></tr>  55:     <tr>  56:      <td><b>Title:</b></td>  57:      <td><%# DataBinder.Eval(Container.DataItem, "title") %></td>  58:     </tr>  59:     <tr>  60:      <td><b>Type:</b></td>   61:      <td><%# DataBinder.Eval(Container.DataItem, "type") %></td>  62:     </tr>  63:     <tr>  64:      <td><b>Notes:</b></td>  65:      <td><%# DataBinder.Eval(Container.DataItem, "notes") %></td>  66:     </tr>  67:    </table>  68:   </SelectedItemTemplate>  69:  </asp:DataList>  70: </form> 

The DataList in Listing 5.8 contains two templates the ItemTemplate (lines 45 50) and the SelectedItemTemplate (lines 52 68). The ItemTemplate is used to render each non-selected row, whereas the SelectedItemTemplate is used to render the row whose index equals the DataList's SelectedIndex property.

In the ItemTemplate, a command button is added (lines 48 and 49). Because this command button's CommandName property has been set to "Select", when it is clicked, the row that contained the clicked button will become the selected row. When this happens, the SelectedIndexChanged event will fire. On line 39, we specify that when the SelectedIndexChanged event fires, the DisplayBookDetails event handler should be executed. This event handler, defined on lines 31 35, simply calls the BindData() function, which rebuilds the DataSource and rebinds the DataList (line 34).

If you omit the call to the BindData() method in the DisplayBookDetails event handler, the selected row of the DataList will appear to be delayed. That is, if you click the Details link for The Busy Executive's Database Guide, the ASP.NET page will be posted back, and it will appear as though nothing has happened. If you then click the Details button for But Is It User Friendly?, the details will appear for The Busy Executive's Database Guide. This is because the view state for the DataList is loaded before the SelectedIndex is changed by the DataList. Therefore, the DataList will be rendered using the prior view state representation of the DataList. To get around this dilemma, we simply force the DataList to rebind itself in the SelectedIndexChanged event handler.

NOTE

Although the code in Listing 5.8 does not set any SelectedItemStyle properties, rest assured that the DataList does indeed contain a SelectedItemStyle that can be used to customize the appearance of the selected row, exactly as we saw in the previous section with the DataGrid control. The SelectedItemTemplate, however, is unique to the DataList.




ASP. NET Data Web Controls Kick Start
ASP.NET Data Web Controls Kick Start
ISBN: 0672325012
EAN: 2147483647
Year: 2002
Pages: 111

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