When you're creating a web site that accepts input from its users, it's important to do all that you can to minimize the number of mistakes they can make. One technique we can use is to reduce the amount of typing they have to do. For example, if you asked a visitor to enter the abbreviation for their state or country, you could expect to get numerous variations. You can imagine the kind of validation headache this creates, and the majority of visitors will leave your site rather than fool around trying to fix an error in their data. As an alternative, we'll focus in the next few sections on how to offer choices to your visitors, rather than having them type entries themselves. In this particular section, we'll discuss the ListBox and DropDownList controls together, because they have essentially the same properties and syntax. The difference is in how many list items are shown.
Given our specific interest in this book, there's a further consideration here: we want the items in the ListBox to come from a data source. In other words, we'll choose a single field in the data store, and have our list control display the value of that field for every record we read from the data store. For the purposes of this illustration, we'll assume that we have a connection object, a command object, and a data reader object as described earlier in this chapter. Given those things, our SQL statement for filling the list control will generally be designed to select all or some of the records:
SELECT MyFieldToDisplay FROM MyTable Or:
SELECT MyFieldToDisplay FROM MyTable WHERE SomeOtherField = Expression Of course, we must add an ASP.NET ListBox control to the page - and since we're seeking input from the user, it must be placed inside a form, so that ASP.NET's postback feature will work. The addition of the AutoPostBack attribute to the element means that postback will take place immediately that a change in the selected item occurs, without the need to wait for a "submit" button to be pressed.
<html><body> <form runat="server"> <asp:ListBox runat="server" AutoPostBack="True" /> </form> </body></html> With this in place, we can focus on the code that populates the list box with our values. We (implicitly) create a data reader with the command object's ExecuteReader() method, and declare it to be the source of data for the ListBox. We're going to allow our visitors to search through Northwind employees by their last names, so we also explicitly tell the ListBox that it needs to display the "Lastname" field by setting its DataTextField property.
If Not IsPostBack Then objConnection.Open() lbEmployees.DataSource = objCommand.ExecuteReader() lbEmployees.DataTextField = "Lastname" lbEMployees.DataBind() objConnection.Close() End If In addition to the two we've used above, there's a third important property that you may need: DataValueField. Unlike DataTextField, this won't appear in the list box, but it will be available in your code. To see why this could be useful, imagine that you have a list of food categories to display, but that once the visitor has clicked on one, you need to work with the category ID, not the name that was displayed. Using both properties, we get the best of both worlds: the DataTextField for the human interface, and the DataValueField for a more efficient programming interface. It is absolutely crucial to place the code that populates the list box in an If Not IsPostBack Then block, so that it only runs once, when the page is first loaded. To see why, you need to understand that when a list box is first populated, its SelectedIndex and SelectedItem properties are set to -1 and Nothing respectively, indicating that no selection has been made. When the user makes a selection, the former changes to the position in the list of the selected item, while the latter represents the selected item itself. But when postback of the page occurs, repopulation of the list takes place, both properties revert to their original settings. In other words, you lose the user's selection. The next question to be answered is how you use the visitor's selection from a list box. It turns out that it's possible to derive three different pieces of information from the selection. First, if you want to use the text that the visitor clicked on in the box, you can use the following expression, which will return the value from the field you set in the DataTextField property:
lbxMyListBox.SelectedItem.Text In many cases, however, you won't want to work with the text the user clicked on, but with an associated value called the DataValueField, as discussed above. The second possibility, then, is to retrieve this value with the following:
lbxMyListBox.SelectedItem.Value The third available piece of information is the index of each item in the list, via the SelectedIndex property. (Note that this is zero-based, so your largest index value will be one less then the number of items in the list.) The index number can be used in expressions such as the one below, where the index number is used to identify a particular item in the list:
lbxMyListBox.Items(x) With this theory behind us, we can now move forward to using a list box in the context of an example. Try It Out - Using List Boxes
The visitors to an internal Northwind web site might want to know a little more about particular employees. One way for us to deal with that would be to offer them a list box of employees' names, and to fill a DataGrid with more information when they select one. In this example, we'll do this in two steps. First, we'll display the last names of all the employees. Second, we'll write a WHERE clause that will use the visitor's selection to retrieve further information about that employee.
How It WorksThis time, we added two ASP.NET web server controls to our page: one to display the list of employees, and another to show the employee information. We also chose to specify an OnSelectedIndexChanged event handler.
<body> <h3>Using a ListBox</h3> <form runat="server"> <asp:ListBox runat="server" AutoPostBack="True" Rows="5" OnSelectedIndexChanged="subListChange" /> <br/><br/> <asp:DataGrid runat="server" /> </form> </body> With the controls in place, we use the code we studied earlier to create connection and command objects to populate the list box, and to bind the data to the list box. However, we only do this on the first occasion the page is displayed. Also, although we show the LastName (the DataTextField) to the user, for our programming purposes we will want to use the EmployeeID number (the DataValueField).
Sub Page_Load(Source As Object, E As EventArgs) If Not IsPostBack Then Dim strConnection As String = ConfigurationSettings.AppSettings("NWind") Dim strSQLforListBox As String = "SELECT LastName, EmployeeID " & _ "FROM Employees ORDER BY LastName" Dim objConnection As New SqlConnection(strConnection) Dim objCommand As New SqlCommand(strSQLforListBox, objConnection) objConnection.Open() lbxEmployees.DataSource = objCommand.ExecuteReader() lbxEmployees.DataTextField = "LastName" lbxEmployees.DataValueField = "EmployeeID" lbxEmployees.DataBind() objConnection.Close() End If End Sub Last, we write code into the method that executes when the user selects a name from the list. This code repeats the data acquisition process, but does so for the DataGrid instead of the list box. Notice how we set the value of the SQL WHERE clause to be equal to the DataValueField of whichever name was selected.
Sub subListChange(S As Object, E As EventArgs) ' Response.Write("subListChange triggered") Dim strConnection As String = ConfigurationSettings.AppSettings("NWind") Dim strSQLforGrid As String = "SELECT TitleOfCourtesy, FirstName, " & _ "LastName, Country, Region, City, Notes " & _ "FROM Employees WHERE EmployeeID = " & _ lbxEmployees.SelectedItem.Value Dim objConnection As New SqlConnection(strConnection) Dim objCommand As New SqlCommand(strSQLforGrid, objConnection) objConnection.Open() dgEmployee.DataSource = objCommand.ExecuteReader() dgEmployee.DataBind() objConnection.Close() End Sub
|