Adding HyperLinkColumns to the DataGrid Web Control

In the previous section we saw how to use the ButtonColumn control to add a button or hyperlink to each row in a DataGrid. Recall that the semantics of the ButtonColumn were as follows: When a user clicks a button or hyperlink generated by the ButtonColumn, the ASP.NET Web page is posted back and the DataGrid's ItemCommand event is fired. To have server-side code execute in response to the clicking of a ButtonColumn button or hyperlink, we simply needed to provide a suitable event handler and wire up the event handler to the DataGrid's ItemCommand event, which can be done in the DataGrid's declaration.

There are times, though, when this series of events is much more complex than necessary. For example, with many Web site search engines, when the user searches on a particular query, she is shown a listing of links of articles that match the search query. The first few sentences of the article might even be included in the search result. To view the full details of the article, though, the user must click on a link to an article, whereby she'll be taken directly to the complete article.

The DataGrid provides a special built-in column type to handle situations just like this one: the HyperLinkColumn. In its simplest form, the HyperLinkColumn need only supply two properties:

  • Text The text for the hyperlink

  • NavigateUrl The URL for the hyperlink

For example, Listing 4.8 illustrates this simplified usage of the HyperLinkColumn. The HyperLinkColumn (line 27) specifies only the Text and NavigateUrl properties.

Listing 4.8 The HyperLinkColumn Displays a Hyperlink in Each Row of the DataGrid
  1: <%@ import Namespace="System.Data" %>   2: <%@ import Namespace="System.Data.SqlClient" %>   3: <script runat="server" language="VB">   4:   Sub Page_Load(sender as Object, e as EventArgs)   5:    If Not Page.IsPostBack then   6:     BindData()   7:    End If   8:   End Sub   9:  10:  11:   Sub BindData()  12:    '... Code removed for brevity, same as Listing 4.4 ...  13:   End Sub  14: </script>  15:  16: <asp:datagrid  runat="server"   17:    AutoGenerateColumns="False"  18:    Font-Name="Verdana" Width="50%"  19:    HorizontalAlign="Center" ItemStyle-Font-Size="9pt">  20:  21:  <HeaderStyle BackColor="Navy" ForeColor="White"  22:     HorizontalAlign="Center" Font-Bold="True" />  23:  24:  <AlternatingItemStyle BackColor="#dddddd" />  25:  26:  <Columns>  27:   <asp:HyperLinkColumn Text="View Details" NavigateUrl="details.aspx" />  28:   <asp:BoundColumn DataField="title" HeaderText="Title"  29:            ItemStyle-Width="70%" />  30:  </Columns>  31: </asp:datagrid> 

As you can see from the screenshot in Figure 4.6, the value of the Text property is the value of the hyperlink's text when rendered to the browser. What's a bit harder to see from the screenshot is that each of these hyperlinks goes to the URL specified by NavigateUrl. That is, each and every one of the hyperlinks in the HyperLinkColumn in Figure 4.6 will take the user to details.aspx.

Figure 4.6. The HyperLinkColumn isn't very useful when using the Text and NavigateUrl properties.

graphics/04fig02.gif

Clearly, we'd like to be able to have the URL of each hyperlink generated by the HyperLinkColumn to be distinct. For example, rather than having all hyperlinks link to details.aspx, we might want each hyperlink to link to details.aspx?id=title_id , where title_id is the primary key, uniquely identifying each book.

To accomplish this with the HyperLinkColumn, we need to use the DataNavigateUrlField and DataNavigateUrlFormatString properties instead of the NavigateUrl property. The DataNavigateUrlField is a string property that should be set to the DataSource field that you want to have vary for each hyperlink generated by the HyperLinkColumn. If we want to have the hyperlinks navigate the user to details..aspx?id=title_id , we'd set the DataNavigateUrlField to title_id, the primary key field of the title database table.

The DataNavigateUrlFormatString property specifies the URL to which the hyperlink should direct the user. In this URL string, you can specify where you want the value of the DataNavigateurlField property to appear by using {0}. Given our earlier example, we'd set the DataNavigateUrlFormatString property to details.aspx?id={0}.

Similarly, we can specify dynamic text for the hyperlinks by using the DataTextField and DataTextFormatString properties, which work in the same fashion as the DataNavigateUrlField and DataNavigateUrlFormatString properties.

Listing 4.9 is a slight update from Listing 4.8; instead of having a static hyperlink text and URL, though, Listing 4.9 uses the DataTextField, DataTextFormatString, DataNavigateUrlField, and DataNavigateUrlFormatString properties to have the text and URLs customized for each DataGrid row. Listing 4.9 contains only the DataGrid declaration the server-side script block for Listing 4.9 has been omitted, because it is identical to that of Listing 4.8.

Listing 4.9 The Text and URLs of the Hyperlinks Are Now Customized for Each DataGrid Row
  1: <asp:datagrid  runat="server"   2:    AutoGenerateColumns="False"   3:    Font-Name="Verdana" Width="50%"   4:    HorizontalAlign="Center" ItemStyle-Font-Size="9pt">   5:   6:  <HeaderStyle BackColor="Navy" ForeColor="White"   7:     HorizontalAlign="Center" Font-Bold="True" />   8:   9:  <AlternatingItemStyle BackColor="#dddddd" />  10:  11:  <Columns>  12:   <asp:HyperLinkColumn DataTextField="title"  13:        DataTextFormatString="View Details for {0}"   14:        DataNavigateUrlField="title_id"  15:        DataNavigateUrlFormatString="/details.aspx?id={0}" />  16:   <asp:BoundColumn DataField="title" HeaderText="Title"  17:            ItemStyle-Width="70%" />  18:  </Columns>  19: </asp:datagrid> 

Figure 4.7 contains a screenshot of the DataGrid in Listing 4.9 when viewed through a browser. Note that the text of the hyperlinks in the HyperLinkColumn contains the title of the book. Also, the URLs that the hyperlinks navigate to differ for each row. For example, the link for The Busy Executive's Database Guide points to details.aspx?id=BU1032, while the link for Cooking with Computers points to details.aspx?id=PC8888.

Figure 4.7. The text and URLs of the hyperlink are different for each DataGrid row.

graphics/04fig03.gif

NOTE

Recall that when using a ButtonColumn in a DataGrid, we needed to place the DataGrid within a server-side Web form because when the button is clicked, the ASP.NET Web page is posted back. HyperLinkColumns, however, are rendered as hyperlinks and do not cause a postback. Therefore, when using a HyperLinkColumn, you do not need to place the DataGrid within a Web form.


Using Two or More DataSource Fields in the Text and NavigateUrl Properties

Although the DataTextField, DataTextFormatString, DataNavigateUrlField, and DataNavigateUrlFormatString properties are quite useful for generating dynamic text and URLs for the hyperlinks created by the HyperLinkColumn, they are limited in that they can only add one DataSource field to the Text or NavigateUrl properties. That is, you can't use the DataNavigateUrlField and DataNavigateUrlFormatString properties to build a hyperlink with the form

 details.aspx?id=title_id&title=bookTitle 

where title_ id and bookTitle are the ID and title of the book, fields provided in the DataSource. Similarly, if you wanted the hyperlink's text to incorporate more than one DataSource field, you would be out of luck if you tried to use the DataTextField and DataTextFormatString properties.

There are three workaround options to this shortcoming:

  1. Use a ButtonColumn instead of a HyperLinkColumn (you can have the ButtonColumn rendered as a hyperlink if you like, to maintain a visual similarity between the ButtonColumn and HyperLinkColumn). In the DataGrid's ItemCommand event handler, you can build up a URL with the proper DataSource fields and then use Response.Redirect() to send the user to the desired page.

  2. Use actual HTML markup code within a TemplateColumn, using data-binding syntax to populate the hyperlink's text and URL portions with the proper DataSource fields.

  3. Programmatically set the HyperLinkColumn's Text and NavigateUrl properties through the DataGrid's ItemDataBound event.

Option 1 was discussed briefly at the end of the ButtonColumn section in this chapter. The two main downsides with this approach are that the Text of the ButtonColumn is static, unless you use a method similar to option 3, and the user will have to endure two Web page requests as opposed to one to get to the desired page one for the postback, and then a second one for the Response.Redirect() to the appropriate page.

Options 2 and 3 deserve a bit more attention. We'll examine these two approaches in the next two sections.

Using a TemplateColumn to Create the Hyperlink

As we saw in Chapter 3, DataGrids can include a TemplateColumn. This TemplateColumn contains, at minimum, an ItemTemplate, which specifies both HTML markup and data that is to be included dynamically from the DataSource. Using a TemplateColumn to generate the hyperlink offers the most flexibility. Listing 4.10 contains the DataGrid declaration for a DataGrid that utilizes option 2.

Listing 4.10 A Hyperlink Can Be Created in a TemplateColumn

[View full width]

  1: <asp:datagrid  runat="server"   2:    AutoGenerateColumns="False"   3:    Font-Name="Verdana" Width="50%"   4:    HorizontalAlign="Center" ItemStyle-Font-Size="9pt">   5:   6:  <HeaderStyle BackColor="Navy" ForeColor="White"   7:     HorizontalAlign="Center" Font-Bold="True" />   8:   9:  <AlternatingItemStyle BackColor="#dddddd" />  10:  11:  <Columns>  12:   <asp:TemplateColumn>  13:    <ItemTemplate>  14:     <a href="details.aspx?id=<%# Server.UrlEncode(DataBinder.Eval (Container.DataItem, graphics/ccc.gif "title_id")) %>&title=<%# Server.UrlEncode (DataBinder.Eval(Container.DataItem,  graphics/ccc.gif"title")) %>">  15:      Details for <%# DataBinder.Eval(Container.DataItem, "title") %>  16:     </a>  17:    </ItemTemplate>  18:   </asp:TemplateColumn>  19:   <asp:BoundColumn DataField="title" HeaderText="Title"  20:            ItemStyle-Width="70%" />  21:  </Columns>  22: </asp:datagrid> 

Listing 4.10 creates an actual HTML href tag. The URL for the href tag contains two dynamic fields: id and title. Note that the dynamic values are "inserted" by simply placing the proper data-binding syntax precisely where the dynamic text should be inserted. This method of creating data-driven Web pages will be all too familiar with the classic ASP developer.

NOTE

Notice that the presence of the call to Server.UrlEncode inside each of the data-binding calls in the URL portion of the href tag. Server.UrlEncode transforms characters that are illegal URL characters into legal ones. For example, each space is converted into +, each apostrophe into a %22, and so on.


The HTML generated by the preceding TemplateColumn will, of course, differ per DataGrid row. For example, for the book You Can Combat Computer Stress, the following HTML is generated:

 <a href="details.aspx?title=BU2075&price=You+Can+Combat+Computer+Stress!">    Details for You Can Combat Computer Stress!  </a> 

Whereas for the book The Busy Executive's Database Guide, the following HTML is generated:

 <a  href="details.aspx?id=BU1032&title=The+Busy+Executive's+Database+Guide">    Details for The Busy Executive's Database Guide  </a> 

When viewing the DataGrid in Listing 4.10 through a browser, the user will see the same output as shown in Figure 4.7.

Using the ItemDataBound Event to Programmatically Set the HyperLinkColumn's Text and NavigateUrl Properties

Although the TemplateColumn approach affords the most customizability, it clearly mixes the source code (the data-binding syntax) with the HTML content. Ideally, we'd like to keep these two things separate, which is possible with option 3: using the DataGrid's ItemDataBound event to programmatically set the Text and NavigateUrl properties of the HyperLinkColumn.

Recall from Chapter 2 that each of the three data Web controls performs data binding in roughly the same manner. The DataSource is enumerated over one record at a time, and for each record, something is added to the data Web control. For the DataGrid, each DataSource record corresponds to a DataGridItem; for the DataList, a DataListItem; and for the Repeater, a RepeaterItem.

At each iteration through the DataSource, two events are raised: The first one is the ItemCreated event, which is raised when the DataGridItem, DataListItem, or RepeaterItem is created, but before it is data-bound; the second event is the ItemDataBound event, which is raised after the current DataSource item has been data-bound to the DataGridItem, DataListItem, or RepeaterItem, but before the DataGridItem, DataListItem, or RepeaterItem has been rendered.

We can provide an event handler for the DataGrid's ItemDataBound event using the following definition:

 Sub EventHandlerName(sender As Object, e As DataGridItemEventArgs) 

Like the ItemCommand event handler, we need to wire up the DataGrid's ItemDataBound event to the event handler we create. This is accomplished by adding

 OnItemDataBound="EventHandlerName" 

to the DataGrid's declaration.

In the event handler, we need to programmatically reference the HyperLinkColumn column. After we've done this, we can set the HyperLinkColumn's Text and NavigateUrl properties in whatever manner we see fit. Listing 4.11 illustrates how to accomplish this with code.

Listing 4.11 The DataGrid's ItemDataBound Method Can Be Used to Set the HyperLinkColumn's Text and NavigateUrl Properties
  1: <%@ import Namespace="System.Data" %>   2: <%@ import Namespace="System.Data.SqlClient" %>   3: <script runat="server" language="VB">   4:   ... Page_Load and BindData omitted for brevity ...   5:        ... Consult Listing 4.4 ...   6:   7:   Sub SetHyperLinkColumnProps(sender as Object, e as DataGridItemEventArgs)   8:    If e.Item.ItemType <> ListItemType.Header and _   9:       e.Item.ItemType <> ListItemType.Footer then  10:     Dim hl as HyperLink = e.Item.Cells(0).Controls(0)  11:     hl.Text = "Details for " & _  12:          DataBinder.Eval(e.Item.DataItem, "title")  13:  14:     Dim navUrl as String  15:     navUrl = "details.aspx?title_id")) & _  17:         "&title=" & _  18:         Server.UrlEncode(DataBinder.Eval(e.Item.DataItem, "title"))  19:     hl.NavigateUrl = navUrl  20:    End If  21:   End Sub  22: </script>  23: <asp:datagrid  runat="server"  24:    AutoGenerateColumns="False"  25:    Font-Name="Verdana" Width="50%"  26:    HorizontalAlign="Center" ItemStyle-Font-Size="9pt"  27:    OnItemDataBound="SetHyperLinkColumnProps">  28:  29:  <HeaderStyle BackColor="Navy" ForeColor="White"  30:     HorizontalAlign="Center" Font-Bold="True" />  31:  32:  <AlternatingItemStyle BackColor="#dddddd" />  33:  34:  <Columns>  35:   <asp:HyperLinkColumn />   36:   <asp:BoundColumn DataField="title" HeaderText="Title"  37:            ItemStyle-Width="70%" />  38:  </Columns>  39: </asp:datagrid> 

Notice that the HyperLinkColumn in Listing 4.11 (line 35) does not contain any properties. The reason we don't set any is because we are setting them programmatically in the ItemDataBound event handler (lines 7 through 21). Had we set the properties in the HyperLinkColumn declaration on line 35, the values would just be written over in the event handler.

Spanning lines 7 21 you'll find the ItemDataBound event handler, SetHyperLinkColumnProps. Realize that the HyperLinkColumn we added to our DataGrid on line 35 is turned into a HyperLink Web control prior to ItemDataBound being fired. Hence, our event handler needs to find the HyperLink control and set its Text and NavigateUrl properties accordingly.

The ItemDataBound event is fired for every row in the DataGrid, even the header and footer rows; however, these header and footer rows do not contain a HyperLink control. Instead, they contain only a textual label. Therefore, in our SetHyperLinkColumnProps event handler, we want to look for a HyperLink control only if we are dealing with a row other than a header or footer. On line 8 and 9, we check the DataGridItem's ItemType property. Recall from Chapter 2 that the ItemType property indicates the type of the row, and can have values like Header, Footer, Item, AlternatingItem, and so on.

We reach line 10 only if we are not working with a header or footer row. At this point, we want to grab the HyperLink control from the DataGridItem. Because the HyperLinkColumn is the first (0th) column in the DataGrid, we reference Cells(0), which gets us back the proper TableCell object. Next, we grab the first (0th) control from the TableCell's Controls collection.

NOTE

Each ASP.NET control contains a Controls collection, which stores the child controls (if any) for a control. For example, when using a Web form (server-side form), all the controls that appear within the Web form are children of the Web form and appear in the Web form's Controls collection. On line 10, we are simply grabbing the first control out of the first TableCell, which happens to be the HyperLink control we're after.


After we have the HyperLink control, we store it in the variable hl. Next, on lines 11 and 12, the Text property of the HyperLink control is set. Notice that we are using the DataBinder.Eval() function like we would in data-binding syntax in a template. The only difference is that instead of referring to Container.DataItem, we refer to e.Item.DataItem, which is referencing the current item being enumerated through in the DataSource. The reason this code needs to appear in the DataGrid's ItemDataBound event handler as opposed to its ItemCreated event handler is because we need to access the data that is being bound to the DataGridItem from the DataSource. (That data being the title field of the DataSource.) This information is not present when the ItemCreated event fires.

On lines 15 through 18 we build up a string for the NavigateUrl property that will have the title_id and title values for the record in the QueryString portion of the URL. As with our TemplateColumn example, on lines 16 and 18 we use Server.UrlEncode to ensure that we encode any illegal URL characters that might appear in the title_id or title fields.

Finally, note that we wire up the SetHyperLinkColumnProps event handler to the DataGrid's ItemDataBound event on line 27. The output and semantics for Listing 4.11 are identical to those in Listing 4.10. A screenshot can be seen back in Figure 4.7.

NOTE

We will be discussing the ItemDataBound and ItemCreated events for the data Web controls in much greater detail in Chapter 11, "Altering the Data Before It's Rendered."




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