Creating a GridView with a CheckBox in Each Row
Before we examine how to provide functionality to check or uncheck each
checkbox in a GridView, let's first concentrate on building a GridView
control that includes a
CheckBox for each row. A column of CheckBoxes can be added to the
GridView using one of two approaches:
- Using the CheckBoxField - the CheckBoxField is a built-in GridView field type that renders a column of CheckBoxes with each CheckBox's
Checked
property
assigned to some data field in the grid's underlying data source.
- Using a TemplateField - we can add a TemplateField and then, in the
ItemTemplate
, add a CheckBox Web control. If the CheckBox Web control's
Checked
property should be based on some underlying data field value, the Checked
property can be set either declaratively (such as,
<asp:CheckBox runat="server" ... Checked='<%# Eval("ColumnName") %>' ... />
) or programmatically (such as in the RowDataBound
event handler).
The second option - using a TemplateField - has a number of advantages.
First, it's more customizable. With minimal effort we can include
additional markup in each row and can
provide a custom header, which is useful if we want to include a
checkbox in the header row that allows the user to check or uncheck all
checkboxes in the column.
Moreover, if the CheckBox's
Checked
property is not dependent on some underlying data field, then you'll need to use the TemplateField option. This
article, and the demo available for download at the end of the article, uses the TemplateField option.
Imagine that we are building a web-based file management tool that lists
the files in the current directory, allowing the user to select one or
more files to delete.
To select a file, we want to include a checkbox in each row; beneath the
GridView there's a "Delete All Checked Files" Button that, when
clicked, will delete the
selected files. (The demo available for download at the end of this
article doesn't actually delete the files; rather, it just prints a
message indicating what files it would
have deleted, had that functionality been implemented.)
The following GridView accomplishes the needed functionality. Note that
it uses a TemplateField to house a CheckBox control for each GridView
row. Also note that the
GridView's
DataKeyNames
property is assigned
FullName
. Setting the
DataKeyNames
property prompts the GridView to record the
value of each file's
FullName
property in its
DataKeys
collection; this information is used when deleting the selected files. (Some of the
GridView's formatting-related settings have been removed for brevity.)
<asp:GridView ID="gvFileList" runat="server"
AutoGenerateColumns="False" DataKeyNames="FullName">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox runat="server" ID="chkSelected" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:BoundField DataField="CreationTime" HeaderText="Created On" />
<asp:BoundField DataField="Length" HeaderText="File Size" />
</Columns>
</asp:GridView>
|
In the
Page_Load
event handler the files in the current directory are retrieved and bound to the GridView.
(For more information on accessing and displaying the files in a directory, see
Displaying
Files and Folders in a GridView.)
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var dirInfo = new DirectoryInfo(Request.PhysicalApplicationPath);
gvFileList.DataSource = dirInfo.GetFiles();
gvFileList.DataBind();
}
}
|
Additionally, we need a "Delete All Checked Files" Button Web control
that, when clicked, determines what CheckBox controls in the grid have
been selected and
then deletes those files. The demo includes a Button Web control named
DeleteButton
that carries out this purpose. In its
Click
event
handler, the rows of the GridView are enumerated using a
foreach
loop over the GridView's
Rows
collection. For each
GridViewRow
instance,
the
chkSelected
CheckBox is referenced and its
Checked
property is examined. If checked, the file corresponding to that row is deleted.
Note that the file path for each GridView row is accessible via the GridView's
DataKeys
properties.
protected void DeleteButton_Click(object sender, EventArgs e)
{
// Enumerate the GridViewRows
foreach(GridViewRow row in gvFileList.Rows)
{
// Programmatically access the CheckBox from the TemplateField
var cb = row.FindControl("chkSelected") as CheckBox;
// If it's checked, delete it...
if (cb.Checked)
{
var currentRowsFilePath = gvFileList.DataKeys[row.RowIndex].Value.ToString();
// To actually delete the file, uncomment the below line of code...
// File.Delete(currentRowsFilePath);
}
}
}
|
ow that we have the groundwork laid out, we're ready to examine how to
implement functionality to check and uncheck all CheckBoxes in the
GridView using client-side
script. Let's start with a look at adding said functionality using
"Check All" and "Uncheck All" buttons. Following that, we'll see how to
implement the same
functionality using a checkbox in the grid's header row.
Using "Check All" and "Uncheck All" Buttons
With the existing GridView in place, a user can check one or more
checkboxes, click the "Delete All Checked Files" button, and have those
selected files deleted.
But what if there are a lot of files in the directory and they want to
delete them all? As it stands now, they must check each checkbox, one at
a time, until all are
selected. We can improve the user experience by adding a mechanism for
checking or unchecking all checkboxes with one click of the mouse.
One way to let users check (or uncheck) all checkboxes is to add two
buttons to the page titled "Check All" and "Uncheck All." The following
markup adds two such
buttons to the page. (In the screen shot below and in the demo available
for download at the end of this article, these two buttons are
positioned above the GridView,
but you could place them anywhere on the page.)
<p>
<input type="button" id="btnCheckAll" value="Check All" />
<input type="button" id="btnUncheckAll" value="Uncheck All" />
</p>
|
To have the "Check All" button cause all checkboxes to be clicked and to
have the "Uncheck All" button cause all checkboxes to be unchecked, add
the following
JavaScript to your page. (This presumes that you also have a reference
to the jQuery library.)
<script type="text/javascript">
var checkBoxSelector = '#<%=gvFileList.ClientID%> input[id*="chkSelected"]:checkbox';
$(document).ready(function () {
$('#btnCheckAll').live('click', function () {
$(checkBoxSelector).attr('checked', true);
});
$('#btnUncheckAll').live('click', function () {
$(checkBoxSelector).attr('checked', false);
});
});
</script>
|
The above script starts by creating a variable named
checkBoxSelector
that defines the selector syntax for selecting all checkboxes in the GridView.
Let's look at each part of the selector:
#<%=gvFileList.ClientID%>
- gvFileList.ClientID
is server-side code that returns the client-side
id
attribute for the HTML <table>
rendered by the gvFileList
GridView. While the GridView's server-side ID
is gvFileList
, the rendered id
attribute sent down to the client may be modified if the GridView is within any naming containers.
For my demo, the GridView's rendered client-side id
is actually ContentPlaceHolder1_gvFileList
, which is the value returned by
gvFileList.ClientID
. Consequently, the #<%=gvFileList.ClientID%>
in the web page gets rendered to the client as
#ContentPlaceHolder1_gvFileList
, which tells jQuery to start its search by looking for an HTML element with the id
ContentPlaceHolder1_gvFileList
. (For more information on the ClientID
property and related tips, refer to
Take Control Of Web Control ClientID Values in ASP.NET 4.)
input[id*="chkSelected"]
- returns all <input>
elements whose id
attribute contains the text chkSelected
. (Note that each checkbox in the grid has an id
of the form
ContentPlaceHolder1_gvFileList_chkSelected_rowNumber
.) Because this appears after the #<%=gvFileList.ClientID%>
selector, it is limited in its search scope to within the gvFileList GridView. That is, if there is another <input>
element on the page with
a matching id
it will not be returned.
:checkbox
- this limits the set of elements returned by the previous selector to those that are also checkboxes.
Next, in the
$(document).ready
event handler we define
click
event handlers for the two buttons. Both buttons have similar event handlers.
For the
btnCheckAll
button we set the
checked
attribute to
true
for all
chkSelected
checkboxes in the grid; the
btnUncheckAll
event handler sets the
checked
attribute to
false
. The event handlers here are defined using jQuery's
live
function (instead of
click
) to support the case where the GridView may be in an UpdatePanel. (See
Rebinding
Client-Side Events After a Partial Page Postback for more details on this concept.)
With the above script in place, clicking the "Check All" button checks
all checkboxes, and clicking "Uncheck All" unchecks all checkboxes. But
notice that even after
all checkboxes are checked, the "Check All" button remains clickable;
ditto the "Uncheck All" checkbox when no checkboxes are checked.
Ideally, these buttons would be
disabled in these scenarios. To accomplish this we need to do three
things:
- Create a function that determines if all the checkboxes are checked
or if no checkboxes are checked. If all checkboxes are checked then the
"Check All" button
should be disabled. If no checkboxes are checked then "Uncheck All"
should be disabled.
- Whenever a checkbox is checked or unchecked or whenever the "Check
All" or "Uncheck All" buttons are clicked we need to call the function
created in Step 1.
- When the page loads for the first time we need to call the function created in Step 1.
The following function, named
ToggleCheckUncheckAllOptionAsNeeded
, performs the task outlined in Step 1. It starts by getting a reference to the
set of the
chkSelected
checkboxes in the grid as well as those that are checked. It then sets the
disabled
attribute based of the
btnCheckAll
button to
true
if the number of total checkboxes equals the number of checked checkboxes,
false
otherwise. Similarly, the
btnUncheckAll
button's
disabled
attribute is set to
true
if the number of checked checkboxes equals 0, otherwise it's set to
false
.
function ToggleCheckUncheckAllOptionAsNeeded() {
var totalCheckboxes = $(checkBoxSelector),
checkedCheckboxes = totalCheckboxes.filter(":checked"),
noCheckboxesAreChecked = (checkedCheckboxes.length === 0),
allCheckboxesAreChecked = (totalCheckboxes.length === checkedCheckboxes.length);
$('#btnCheckAll').attr('disabled', allCheckboxesAreChecked);
$('#btnUncheckAll').attr('disabled', noCheckboxesAreChecked);
}
|
In the
$(document).ready
event handler the
chkSelected
checkboxes have their
click
event wired up to the
ToggleCheckUncheckAllOptionAsNeeded
function. Likewise, the
click
event handlers for the "Check All" and "Uncheck All" buttons have been updated to call
ToggleCheckUncheckAllOptionAsNeeded
.
And
ToggleCheckUncheckAllOptionAsNeeded
is called when the page first loads, as well.
$(document).ready(function () {
$('#btnCheckAll').live('click', function () {
$(checkBoxSelector).attr('checked', true);
ToggleCheckUncheckAllOptionAsNeeded();
});
$('#btnUncheckAll').live('click', function () {
$(checkBoxSelector).attr('checked', false);
ToggleCheckUncheckAllOptionAsNeeded();
});
$(checkBoxSelector).live('click', ToggleCheckUncheckAllOptionAsNeeded);
ToggleCheckUncheckAllOptionAsNeeded();
});
|
With this new script in place, the buttons are disabled when they would
otherwise be redundant. The screen shot below shows an example. Here, no
checkboxes are checked,
so the "Uncheck All" button is disabled. Checking a single checkbox (or
clicking the "Check All" button) causes the "Uncheck All" button to
become enabled again.
Using a Checkbox in the GridView Header Row
In place of "Check All" and "Uncheck All" buttons we could opt to add a
checkbox to the GridView's header row that serves the same purpose. To
add such a checkbox we
need to add a
HeaderTemplate
with its own CheckBox control to the TemplateField that contains the
chkSelected
CheckBox control:
<asp:GridView ID="gvFileList" runat="server"
AutoGenerateColumns="False" DataKeyNames="FullName">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox runat="server" ID="chkAll" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox runat="server" ID="chkSelected" />
</ItemTemplate>
</asp:TemplateField>
...
</Columns>
</asp:GridView>
|
With this addition the GridView now renders a checkbox in the header row, as the following screen shot shows.
Much like with the "Check All" and "Uncheck All" button demo, we need to have the header row checkbox check (or uncheck) all
chkSelected
checkboxes when
clicked. And if all checkboxes are checked by the user, one at a time,
we need to also check the header row checkbox. If there is at least one
unchecked checkbox then
the header row checkbox should be unchecked.
This can be accomplished in the same way as the button demo. In the
$(document).ready
event handler we need to create an event handler for the header row
checkbox's
click
event that checks (or unchecks) all
chkSelected
checkboxes. We also need a
ToggleCheckUncheckAllOptionAsNeeded
function that checks (or unchecks) the header row checkbox based on whether all
chkSelected
checkboxes are checked, and
ToggleCheckUncheckAllOptionAsNeeded
needs to be called whenever a
chkSelected
checkbox is clicked, whenever the header row checkbox is clicked, and when the page first loads.
<script type="text/javascript">
var allCheckBoxSelector = '#<%=gvFileList.ClientID%> input[id*="chkAll"]:checkbox';
var checkBoxSelector = '#<%=gvFileList.ClientID%> input[id*="chkSelected"]:checkbox';
function ToggleCheckUncheckAllOptionAsNeeded() {
var totalCheckboxes = $(checkBoxSelector),
checkedCheckboxes = totalCheckboxes.filter(":checked"),
noCheckboxesAreChecked = (checkedCheckboxes.length === 0),
allCheckboxesAreChecked = (totalCheckboxes.length === checkedCheckboxes.length);
$(allCheckBoxSelector).attr('checked', allCheckboxesAreChecked);
}
$(document).ready(function () {
$(allCheckBoxSelector).live('click', function () {
$(checkBoxSelector).attr('checked', $(this).is(':checked'));
ToggleCheckUncheckAllOptionAsNeeded();
});
$(checkBoxSelector).live('click', ToggleCheckUncheckAllOptionAsNeeded);
ToggleCheckUncheckAllOptionAsNeeded();
});
</script>
|
In the above script there are two selector variables,
allCheckBoxSelector
and
checkBoxSelector
, which are the jQuery selectors to retrieve the
header row checkbox and the set of
chkSelected
checkboxes in the
gvFileList
grid. In the
ToggleCheckUncheckAllOptionAsNeeded
the header row checkbox is checked if all checkboxes in the grid are checked, otherwise it's unchecked.
No comments:
Post a Comment