|
|
|
|
Building Web Solutions with ASP.NET and ADO.NET
Last Updated 2/3/2009 3:43:00 PM
Abstract
This chapter examines techniques and tools for building sophisticated, professional reports using the DataGrid control in ASP.NET.
INTRODUCTION
The DataGrid control not only is the most versatile reporting tool you have in
ASP.NET, but also is likely the only tool you will want to use when building pro-fessional
reports. In the previous chapters, I reviewed the basic set of features
and functionalities supplied by the control. Although the DataGrid control is
useful in many circumstances, you still need to write a lot of code (mostly smart
and tricky code) to build complex solutions.
The DataGrid control deliberately mimics the interface and behavior of a
Microsoft Excel worksheet, so programmers like you expect it to provide the
same level of functionality. Microsoft was just whetting your appetite when it
developed the control's object model, however, because you can actually do so
much more with it than is immediately apparent from scanning its supported
methods and events. In this chapter, you will learn a bunch of practical solu-tions
and tips that take advantage of the object model. So far, we've only just
touched on the concepts that we will explore in the following pages: item
selection and information drill-down.
ITEM SELECTION
If you need a grid of data, you probably also need a way to let your users select
a particular row of that grid and see related information. I already touched on
this topic in Chapter 1 when I discussed the selection mechanism for the DataList
control. Let's see how it works for the DataGrid control.
The internal mechanism for selection when using the DataGrid control is
nearly identical to the one you saw in action for the DataList control. Typically,
users trigger the selection by clicking a column button with the CommandName
attribute set to the keyword select. The same event can also occur pro-grammatically
when the SelectedItemIndex property of the DataGrid control is
set to a value greater than -1.
A selected row can have a custom style that you specify by using the
SelectedItemStyle property; however, columns (including templated columns)
do not support a particular template for a selected item, such as the DataList
control's SelectedItemTemplate template. Only one row in the DataGrid control
can be selected at any time. Multiple selection is not supported. Later in this
chapter I'll show you how to work around this limitation.
|
NOTE: A row is selected only if the user clicks the column button
associated with the Select command. Full row selection is not supported.
There is an architectural issue behind this limitation. To pro-cess
the selection event on the server, you need an interactive element
on the page that, when clicked, posts back to the server. Only link but-tons
allow for this, unless you write some ad-hoc JavaScript client-side
script code.
|
Enabling Item Selection
To enable declarative (as opposed to programmatic) selection, you need to
have in the DataGrid control a button column with the CommandName property
set to select.
<asp:ButtonColumn Co andName="select" HeaderText="Employee"
DataTextField="EmployeeNa e" />
The content of the column can be bound to one data source field as well
as show static text or even a small picture. When you don't want data bound
text, use the Text property instead of DataTextField. (These properties are part
of the programming interface of the ButtonColumn class and have nothing to
do with the actual selection.) You can place the select column anywhere in the
grid and bind it to any column in the data source, just as you can for the EditCommandColumn
discussed in Chapter 4.
NOTE: A grid can have as many select columns as needed. Each
select column must be created using the ButtonColumn class with the
CommandName property set to select. The user can select the row by
clicking any of these columns. By making each column in the grid a
select column, you can simulate full-row selection.
|
The DataGrid control treats select command columns in a special way.
When the column is clicked, the SelectedIndexChanged event fires to enable
you to handle the event. The DataGrid control also applies to the selected row
the graphical settings you set by using the SelectedItemStyle property, as the fol-lowing
example shows:
<SelectedIteStyle BackColor="blue" />
The SelectedIndex property gets and sets the index of the currently
selected item. The index is 0'based and refers to the current page, not to the
whole data source. The SelectedItem property returns the object that represents
the currently selected item. This object is an instance of the class DataGridItem.
|
TIP: You can obtain the absolute index in the data set of the specified
DataGrid control item by using the DataSetIndex property of the
DataGridItem class. Each row in the DataGrid control is rendered using an
instance of the DataGridItem class, and you access the instance by
using the Items collection.
|
Styling the Selected Row
The selection style has a lower priority than any style settings you explicitly set
for the column by using ItemStyle. For example, the following code draws the
Position column with a reddish color, and the style is not overridden when the
user selects the column:
<asp:BoundColumn runat="server" DataField="title" HeaderText="Position" >
<item style backcolor="#ffddff" />
</asp:BoundColumn>
Note that any style attribute set by using ItemStyle or
AlternatingItemStyle at the grid level (as opposed to the column level, shown in
the preceding code) is overridden during selection. Figure 1 shows what
a selected column looks like.
|
CAUTION: In addition to changing the color of a selected
item, you can change the font style to reflect selection. However, when
you change the font, the grid can become slightly larger and the text
in some cells can wrap to the next line. Also pay attention to the colors
you choose. The background color should contrast with both items and
alternating items, but avoid too sharp a contrast. When you plan to use
selection, don't differentiate items from alternating items too much.
|
Using Formatted Text
You can use only button columns to enable selection. Button
columns can contain only plain data bound text or static text. You cannot apply
special tem-plates that mix database fields with special graphical settings,
and as I mentioned earlier in this chapter, templated columns do not
support an ad-hoc template for selection. You can work around this limitation,
however, as Figure 1 shows. The trick is using in-memory columns based on
expressions. An expression-based column doesn't take up too much memory
because it stores only the metadata of the column plus the expression.
After you retrieve the bindable data, run the following
code, which adds a new, customized column. This column embeds in the text any
simple HTML formatting you want.
//ds is the DataSet that has just been filled up
DataTable dt =ds.Tables ["MyTable"];
DataColumn dc =new
DataColumn("EmployeeName",typeof(String),
"titleofcourtesy +'<b>'+lastname +'</b>,'+firstname ");
dt.Columns.Add(dc);
This dynamic column is then bound to the select command
column.
<asp:ButtonColumn CommandName="select "HeaderText="Employee"
DataTextField="EmployeeName "/>
Using Images
You can use small images to identify which column the user
can click to select a row. Just set the Text property of the ButtonColumn class with
the HTML text that points to the URL of the image.
<asp:ButtonColumn CommandName="select"
Text="<img alt='Select 'src=unselected.gif>"/>
For a better graphical result, you might want to explicitly
set the border attribute of the <img> tag to 0 and the align
attribute to absmiddle. To make the grid even more user friendly, you can make a final
refinement and change the bitmap when the row is drawn in selected mode. See Figure 2.
Using the SelectedIndexChanged Event EVENT
When a row is selected, the grid fires the SelectedIndexChanged event. You hook into this event in the usual ASP.NET fashion:
<asp:DataGrid id="grid "runat="server"
.
.
.
OnSelectedIndexChanged="SelectionIndexChanged">
You write a handler for SelectedIndexChanged only when you
need to accomplish tasks in response to the row selection'for
example, changing the bitmap to reflect selection. You don't need the handler to
draw the row in selected mode.
public void SelectionIndexChanged(Object sender,EventArgs e)
{
SelectRecord();
}
The SelectedIndex and SelectedItem properties let you know
about the selected item. To retrieve the DataRow object that produced
the current DataGrid item, you can leverage the combined effect of the
DataKeyField and DataKeys properties. As discussed in previous chapters, you
set DataKeyField with the name of a field that accepts unique values, and
DataKeys gathers those key values. You select an entry within the collection by
using the index returned by SelectedIndex. The following code shows how to
retrieve the key value for the selected row:
public void SelectRecord()
{
int nEmpID =(int)grid.DataKeys [grid.SelectedIndex ];
DataRow dr =RetrieveRowByID(nEmpID);
}
When the SelectedIndexChanged event fires, the SelectedIndex
property is guaranteed to be up-to-date.
The select command column is a button column, so you would
expect it to fire the ItemCommand event when clicked. This is exactly
what happens. With tracing enabled, notice that, as shown in Figure 3,
the ItemCommand event arrives first, before the SelectedIndex property is
updated.
When ItemCommand fires, SelectedIndex contains the index of
the previously selected row.
Selecting Rows Programmatically
In principle, to select a row, you don't need a select
command column. Although clicking a cell is the most intuitive way for a
user to make a selection, you could select rows programmatically, regardless of
whether a specific command column is present. To select a row programmatically, you set
the SelectedIndex property to the 0'based index that corresponds to the
position of the row in the current page. You cannot select a row that belongs to
another page, but if you assign to SelectedIndex a value higher than the
number of items in the page, no exception is thrown.
|
NOTE: When you programmatically select or deselect a row,
neither ItemCommand nor SelectedIndexChanged is fired. Since no
event occurs, your code is responsible for maintaining the
consistency of the application's state. For example, you can simulate the
events by calling directly the subroutines the event handler would execute.
|
Deselecting the Selected Row
The DataGrid control does not provide an interactive way to
deselect the currently selected row. You can do that only programmatically by
setting the SelectedIndex property to -1. This operation will not fire
any event to the page.
Can you remove the selection automatically and interactively?
The intuitive approach would be to enable the user to deselect the row by
clicking the row a second time'one click selects, and two consecutive clicks
restore the original state. But this functionality is impossible for a simple
reason: when the DataGrid control is rendered with a selected row, the cell of the
select column is not clickable and cannot post back for a selection change event.
The workable approach is to provide the page with a link button.
<asp:linkbutton runat="server "id="btnUnselect "enabled="false "
text="Unselect "onclick="OnUnselectRecord "/>
The link button is disabled or invisible until a row is
selected. The state of the link button can be easily managed by using the
SelectedIndexChanged event or any other code that runs after a selection is made.
The link's onclick event will then deselect the row programmatically.
|
NOTE: With a pageable DataGrid control, the selected index is
maintained across pages. For example, if row 3 is selected on page 1
and the user moves to page 2, by default row 3 will also be
selected on the new page. If the new page has fewer rows than the row number
initially selected (in our example, fewer than 3 rows), no row is
selected. This is default behavior. To work around it, cancel the
selection in the PageIndexChanged event.
|
|
Page:
1,
2,
3,
4 |
next page  |
|
|