Binding Data to Single-Value Web Controls

Web controls are divided into two logical categories: single-value controls and multi-value controls. Controls like the TextBox , LinkButton , and Image controls are single-value controls. Those like the DataList , DataGrid , and Repeater controls are multi-value controls. In the next section we'll talk about multi-value controls; in this section we'll look at how we can get data into single-value controls, specifically the TextBox control.

Single-value controls do not have a DataSource property like multi-value controls do. The easiest way to get data into a single-value control is to assign the data value to the appropriate property. For example, you can assign data values to a TextBox.Text property. This is easy to do.

You can also define a data binding by using the DataBindings dialog or by entering a script block in the HTML editor. When you have defined the data binding, you can update all controls by calling the containing control's DataBind method. For example, Page.DataBind will bind both single-value and multi-value controls for a Web page (also referred to as a Web form ).

Using the DataBindings Dialog

The DataBindings dialog is selected from the Properties window on a per-control basis. Click the control for which you want to define a data binding and press F4 to focus the Properties window (Figure 16.5). The first item in the list of properties ”if the properties are sorted, rather than grouped ”invokes the DataBindings editor (Figure 16.6).

Figure 16.5. The Properties window for a TextBox control, from which you can access the DataBindings editor.


Figure 16.6. The DataBindings editor for a TextBox control.


To define a data binding for a control, select the property whose value you want to bind, and select the custom binding expression group , as shown in Figure 16.6. For single-value controls you are precisely defining where the data for that control comes from. For the example shown in the figure I defined a binding for the TextBoxCompany.Text property. It is natural to want to read the company name from some repository. The binding I defined is Contacts(CurrentIndex)("CompanyName") . This refers to an indexable object named Contacts and a variable I have to manage named CurrentIndex ; the object return is indexable by a string. A DataView control is one example of a control that fits this description. An indexed DataView control returns a DataRowView control, which in turn is indexable by the string name of a column. Combined, row and column, a single field value is returned, which is exactly what we need for a TextBox control's Text property.

The code in Listing 16.6 implements a single-row view of a Contacts data view. Each of the TextBox controls is bound to a suitable field in the DataView control. I had to implement navigation, tracking a current index. (As you will see in the next section, we can use a DataList or similar control to do this for us.)

Listing 16.6 Displaying a Single Row and Managing Navigation without Rehitting the Data Source
 1:  Imports System.Data 2:  Imports System.Data.OleDb 3: 4:  Public Class WebForm1 5:    Inherits System.Web.UI.Page 6:    Protected WithEvents Label1 As System.Web.UI.WebControls.Label 7:    Protected WithEvents Label2 As System.Web.UI.WebControls.Label 8:    Protected WithEvents Label3 As System.Web.UI.WebControls.Label 9:    Protected WithEvents Label4 As System.Web.UI.WebControls.Label 10:   Protected WithEvents TextBoxCompany As _ 11:     System.Web.UI.WebControls.TextBox 12:   Protected WithEvents TextBoxContact As _ 13:     System.Web.UI.WebControls.TextBox 14:   Protected WithEvents TextBoxTitle As _ 15:     System.Web.UI.WebControls.TextBox 16:   Protected WithEvents TextBoxPhone As _ 17:     System.Web.UI.WebControls.TextBox 18:   Protected WithEvents TextBoxFax As _ 19:     System.Web.UI.WebControls.TextBox 20:   Protected WithEvents Label6 As _ 21:     System.Web.UI.WebControls.Label 22:   Protected WithEvents TextBoxCountry As _ 23:     System.Web.UI.WebControls.TextBox 24:   Protected WithEvents HyperLink1 As _ 25:     System.Web.UI.WebControls.HyperLink 26:   Protected WithEvents HyperLink2 As _ 27:     System.Web.UI.WebControls.HyperLink 28:   Protected WithEvents HyperLinkPrevious As _ 29:     System.Web.UI.WebControls.HyperLink 30:   Protected WithEvents HyperLinkNext As _ 31:     System.Web.UI.WebControls.HyperLink 32:   Protected WithEvents LabelPosition As _ 33:     System.Web.UI.WebControls.Label 34:   Protected WithEvents Label5 As _ 35:     System.Web.UI.WebControls.Label 36: 37: [ Web Form Designer generated code ] 38: 39:   Private Sub Page_Load(ByVal sender As System.Object, _ 40:     ByVal e As System.EventArgs) Handles MyBase.Load 41: 42:     CheckCommand() 43:     UpdatePositionLabel() 44:     Page.DataBind() 45: 46:   End Sub 47: 48:   Private Sub UpdatePositionLabel() 49:     LabelPosition.Text = String.Format("{0} of {1}", _ 50:     CurrentIndex + 1, Contacts.Count) 51:   End Sub 52: 53:   Private Sub CheckCommand() 54:     If (Request.QueryString("CurrentIndex") Is Nothing = False) Then 55:       Try 56:         CurrentIndex = CType(Request.QueryString("CurrentIndex"), _ 57:           Integer) - 1 58:       Catch 59:       End Try 60:     End If 61:   End Sub 62: 63:   Private Function GetMax() As Integer 64:     Return Contacts.Count 65:   End Function 66: 67:   Protected ReadOnly Property Contacts() As DataView 68:   Get 69:     If (Session("Contacts") Is Nothing) Then 70:       Session("Contacts") = GetContacts() 71:     End If 72: 73:     Return CType(Session("Contacts"), DataView) 74:   End Get 75:   End Property 76: 77:   Protected Property CurrentIndex() As Integer 78:   Get 79:     If (Session("CurrentIndex") Is Nothing) Then 80:       Session("CurrentIndex") = 0 81:     End If 82: 83:     Return CType(Session("CurrentIndex"), Integer) 84: 85:   End Get 86:   Set(ByVal Value As Integer) 87:     If (Value >= GetMax()) Then 88:       Session("CurrentIndex") = GetMax() - 1 89:     ElseIf (Value < 0) Then 90:       Session("CurrentIndex") = 0 91:     Else 92:       Session("CurrentIndex") = Value 93:     End If 94:   End Set 95:   End Property 96: 97:   Private Function GetContacts() As DataView 98: 99:     Const SQL As String = _ 100:      "SELECT CompanyName, ContactName, " + _ 101:      "ContactTitle, Country, Phone, " + _ 102:      "Fax FROM CUSTOMERS ORDER BY Country" 103: 104:    Dim Adapter As IDataAdapter = _ 105:      Database.GetAdapter(SQL) 106: 107:    Dim DataSet As DataSet = New DataSet("Contacts") 108:    Database.GetAdapter(SQL).Fill(DataSet) 109:    Return DataSet.Tables(0).DefaultView 110: 111:  End Function 112: 113: End Class 

The result of the code is shown in Figure 16.7. Each TextBox control in the application uses a similar Text property “binding statement as the one shown in Figure 16.6. The only information that changes is the indexing column name. The solution itself is broken up into a handful of methods and properties: a Page_Load event handler, an UpdatePositionLabel method, a CheckCommand method, a GetMax Function, a Contacts property, a CurrentIndex property, and a GetContacts function. I will quickly review each of these.

Figure 16.7. Viewing the contact information from a single row of the Northwind database.


Page_Load (lines 39 through 46) invokes CheckCommand , updates the record indicator, and calls Page.DataBind . Examining the code from bottom to top of this event handler, DataBind gets the data onto the Web page. UpdatePositionLabel displays the value index of total records shown in Figure 16.7 as 1 of 91. The CheckCommand subroutine examines the HttpRequest object's QueryString property to determine whether a new CurrentIndex has been passed to the page. I subtracted 1 from the CurrentIndex passed because internally the DataView control is zero-based , but I chose to show a one-based index (see Figure 16.7). If the passed CurrentIndex is invalid, it is silently ignored in the Try . . . Catch block in lines 55 through 59. QueryString values are passed as URL-encoded queries. For example, http://localhost/BindControlsDemo/WebForm1.aspx?CurrentIndex=3 is an example of a URI-encoded query string.

GetMax (lines 63 through 65) simply returns the number of contacts, which we will discuss next. The Contacts property is a lazy-instance, session-cached value. The lazy-instance idiom simply means I create the object on first use, not before. Combined with the session cache, the Contacts property checks to see whether an object referred to by the key "Contacts" is in the session cache (line 69). If the cache has expired or, as is the case on the first call, no object has been stuffed in the cache yet, I call GetContacts (line 70) to initialize the session cache. Finally, the value in the session cache is converted to the DataView object we know it is.

GetContacts uses code from earlier in the chapter to initialize a new DataSet object, from which we retrieve a DataView object. Lines 97 through 111 demonstrate how we can get the right data in the DefaultView object by refining the SQL text. The SQL text in lines 99 through 102 selects on the contact columns . (Recall that Database is the class we defined earlier in the chapter.)

The final piece is the CurrentIndex property in lines 77 through 95. Again I used the session cache and the lazy-instance technique, placing CurrentIndex in the cache upon first request. The basic setter logic is that if the cache exceeds the maximum number of contacts in the DataView object, CurrentIndex is the maximum value. The same kind of logic is used for the low index. If a new CurrentIndex value is within range, we simply place it in the cache. Both Contacts and CurrentIndex in the data binding text are retrieved from the Contacts and CurrentIndex properties.

Defining a Data Binding in the HTML Editor

When I define data binding I usually do it in the HTML editor. Whether to use the HTML editor or the DataBinding dialog is simply a matter of preference. The actual result is identical. The code fragment below shows the result of the data binding statement for the TextBoxCompany.Text property from the HTML perspective.

 <asp:textbox id=TextBoxCompany runat="server" Text='<%# Contacts(CurrentIndex)("CompanyName") %>'> 

The <asp:textbox> tag represents how an ASP.NET TextBox control is rendered in HTML. (You can add a TextBox control by typing the text in the HTML editor directly, too.) The part we are interested in is the Text attribute (also referred to as the Text property in object-oriented programmming terms.) Text='<%# Contacts(CurrentIndex)("CompanyName") %>' represents an inline script block assignment to the Text property. Think of the code between <%# and %> as a fragment of runnable code. This code performs precisely the same job as TextBoxCompany.Text = Contacts(CurrentIndex).Contacts("Company") would in the code-behind file.

An intuitive question might be, "Why would I use script blocks over code-behind files?" The answer is that you can use either, as long as you can use either. I am not trying to be glib here; it just seems that sometimes it's more convenient to use script blocks and other times code-behind files. As a programmer who started programming before the Web, I prefer code to script. In our example we could have used either code-behind files or script blocks to get the data in the TextBox controls.

Visual Basic. NET Power Coding
Visual Basic(R) .NET Power Coding
ISBN: 0672324075
EAN: 2147483647
Year: 2005
Pages: 215
Authors: Paul Kimmel © 2008-2017.
If you may any questions please contact us: