Often, we'll want to display a list of choices from which our visitors can select more than one item, if they so wish - a list of subjects on which they might like to be sent information, perhaps. In many cases, these choices will be loaded dynamically from a data source, rather than being hard-coded. We have three mechanisms to offer the visitor multiple selections: a CheckBoxList control, or a ListBox or DropDownList control with the SelectionMode property set to Multiple. However, the way we handle the user's multiple selection is the same in all three cases. In this section, we'll cover the topic of multiple selection in two parts: first, how to create the display; and second, how to use the data that's returned.
Displaying Multiple Selection ControlsTo start the process, you must create the asp: CheckBoxList (or asp: ListBox, or asp:DropDownList) control within a form in the body of the HTML block. It's important that both the form and the asp control must have the runat="server" setting.
<form runat="server"> <asp:CheckBoxList runat="server" /> </form> Or:
<form runat="server"> <asp:ListBox runat="server" SelectionMode="Multiple" /> </form> Once the controls are on the page, populating them with data follows the familiar pattern: we open a connection, call the ExecuteReader() method of a command object, assign field names to the web server control's DataTextField and DataTextValue properties, perform the data bind, and close the connection. So far, so good.
Using Data from Multiple SelectionsHandling multiple selections, however, requires more code and planning than the data-aware controls we've worked with so far. If you don't handle multiple selections properly, your code will tend to react only to the first item selected.
The correct technique is the same for CheckBoxList, ListBox, and DropDownList controls, and consists of two steps:
To assist in this task, ADO.NET allows enumeration over its list objects, which means that we can use a ForEach...In loop to test every item in the list. The syntax for the "Is this item selected?" loop could therefore be the following:
Dim strSelectionResult As String Dim liThisOne As ListItem For Each liThisOne In ckbEmployees.Items If liThisOne.Selected Then strSelectionResult &= liThisOne.Value End If Next ' Remove next line prior to deployment Response.Write("strSelectionResult = <br/>" & strSelectionResult & "<hr/>") In the above code, we create a string (strSelectionResult) to hold the output of our loop - the values of the selected items, concatenated together. Often, though, we'll want to have some characters before and after each value in the string. Furthermore, we may have some text that goes outside of the whole list of selected values, such as the SQL WHERE keyword to start things off. You can imagine that such requirements will result in code that looks something like this:
For Each liThisOne In ckbEmployees.Items If liThisOne.Selected Then strSelectionResult &= "MyLeadingCharacters" strSelectionResult &= liThisOne.Value StrSelectionResult &= "MyFollowingCharacters" End If Next strSelectionResult = "WHERE " & strSelectionResult Once we've looped through the choices, we must check whether any of the items were selected. This is easy to do, since the presence of a selection will result in the length of our string immediately after the loop being greater than zero. The following sample assumes that you have a DataGrid object named dgMyDataGrid, and that you only want the grid to appear if a selection has been made.
If strSelectionResult.Length > 0 Then dgMyDataGrid.Visible = True ' Work with the strSelectionResult, perhaps ' in an SQL statement to fill another grid Else dgMyDataGrid.Visible = False End If
Try It Out - Multiple Selections
We're going to create a page that lists all the Northwind employees, with a check box next to each name. When one or more boxes are checked, we'll show a DataGrid containing information about the selected employee(s).
How It WorksIn order of execution, what happens first is that in the Page_Load() handler, a set of check boxes is populated from a data store. Then, in subListChange(), we have code that determines what (if anything) was selected in the check boxes. Last, we have code that populates the DataGrid control. Keep clear in your mind that we connect, use a command, and bind twice - once for the check boxes that show the names, and then again for the DataGrid that displays the information. Starting with the HTML, and ignoring any formatting detail, the first thing to note is that setting the AutoPostBack attribute makes a 'submit' button unnecessary - whenever a box is checked or unchecked, the DataGrid will be repopulated. Also note that we've wired up a method called subListChange() to run whenever there is a change in the selection.
<html> ... <form runat="server"> <asp:CheckBoxList runat="server" ... OnSelectedIndexChanged="subListChange" AutoPostBack="True" /> <br/><br/> <asp:DataGrid runat="server" /> </form> </body> </html> The code that places the check boxes contains nothing new - as usual, it's wrapped in the "If Not IsPostBack" syntax to make sure that the check box list isn't repopulated after every selection. When the user clicks on a check box, the list object will trigger the SelectedIndexChanged event, which calls the subListChange() method below. In it, we build up a string of values from the selected items that will form a SQL WHERE clause for the DataGrid.
Sub subListChange(S As Object, E As EventArgs) ' Remove next line prior to deployment Response.Write("subListChange triggered<hr/>") Dim strWhereClause As String = "" Dim liThisOne As ListItem For Each liThisOne in ckbEmployees.Items If liThisOne.Selected Then strWhereClause &= "Employee OR " End If Next Clearly, it's possible that there will be no selection at all, if the user's action was to uncheck the only checked box. To deal with this, we take a look at the length of the string holding the WHERE clause. If selections were made, then we execute all of the connection, command and binding code for the DataGrid object.
' Remove next line prior to deployment Response.Write("strWhereClause = <br/>" & strWhereClause & "<hr/>") If strWhereClause.Length > 0 Then dgEmployee.Visible = True ' This line removes the final ' OR ' from the WHERE clause strWhereClause = Left(strWhereClause, strWhereClause.Length - 4) strWhereClause = "WHERE " & strWhereClause Dim strConnection As String = ConfigurationSettings.AppSettings("NWind") Dim strSQLforGrid As String = "SELECT TitleOfCourtesy, FirstName, " & _ "LastName, Country, Region, City, Notes " & _ "FROM Employees " & strWhereClause Dim objConnection As New SqlConnection(strConnection) Dim objCommand As New SqlCommand(strSQLforGrid, objConnection) ' Remove next line prior to deployment Response.Write("strSQLforGrid = <br/>" & strSQLforGrid & "<hr/>") objConnection.Open() dgEmployee.DataSource = objCommand.ExecuteReader() dgEmployee.DataBind() objConnection.Close() If the check box list contained no selections, then we can just hide the DataGrid, keeping the page neat and tidy.
Else dgEmployee.Visible = False End If This works quite nicely, but to do more to improve the appearance of the data on our pages, we need to look much more closely at the behavior of the ASP.NET web server controls. We'll start doing that in the next section, in the context of a control we're already quite familiar with: the data grid. |