Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(ebook) Visual Studio .NET Mastering Visual Basic.pdf
Скачиваний:
136
Добавлен:
17.08.2013
Размер:
15.38 Mб
Скачать

942 Chapter 21 BUILDING DATABASE APPLICATIONS WITH ADO.NET

Data Binding

What you’ve done so far was to bind the DataGrid control to the rows of a DataSet. This process is called data binding, and it’s not an exclusive feature of the DataGrid control. In fact, all controls can be bound to a DataSet and display a specific field of the current row from the DataSet. You can create a form with TextBox controls on it and bind each control’s Text property to a different DataSet field. As you move through the rows of the DataSet, the values on the controls will change to reflect the values of the corresponding fields in the current row. If you edit the TextBox controls, the new values will overwrite the ones in the DataSet. No changes, however, will be immediately sent to the data source, because the DataSet resides on the client computer and is disconnected from its source. To update the underlying table(s), you must call the DataAdapter object’s Update method.

Figure 21.11 shows a simple interface built with data-bound TextBox controls. Each control is bound to a different field in the Customers table, and the control values change as you navigate through the rows of the table with the help of the buttons at the bottom of the form. Again, the Customers table resides in a DataSet object on the client. The form shown in the figure is the main form of the ViewEditCustomers project, which you will find on the CD.

Figure 21.11

Viewing and editing the Customers table through data-bound TextBox controls

Before looking at the application of Figure 21.11, let me overview the process of data binding. To begin with, there are two types of data binding: simple and complex. This distinction is necessary because some controls, such as the DataGrid and ListBox, can display multiple fields and/or rows, while other controls, including the TextBox control, can only display a single field from the current row.

The complex data-bound controls have a DataSource and a DataMember property. DataSource determines where the data will come from and is usually set to the name of DataSet object. If the DataSet contains multiple tables, then you must also specify which of the tables you want to display on the control. You do so by setting the control’s DataMember property to the name of the appropriate table. As you saw in the preceding section, the DataGrid control can display multiple related tables. If that’s what you want, then don’t set the DataMember property. A DataSet may contain (and usually does) multiple unrelated tables, in which case you must set the DataMember property to one of the tables in the DataSet.

Simple data-bound controls don’t have a DataSource property. Instead, they have a group of properties under the heading DataBinding. Under the DataBinding section in the control’s Properties window, you will see the names of the properties you can bind to a DataSet object. The TextBox properties that can be bound are Text and Tag. We usually set the Text property to a general field

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

CREATING A DATASET 943

and the Tag property to the table’s primary key, so that we can read it at any time and identify the current row in the table. The most common scenario is to bind the Text property to the customer’s name (or other information useful to the user) and the Tag property to the customer’s ID. With this arrangement, we can instantly locate related rows in other tables (the customer’s orders, for example) because we have the ID of the current customer.

The CheckBox control has more properties you can bind to data. The Checked property can be bound to a True/False field, and the value of the field sets or clears the check mark on the control. You can also bind the control’s CheckAlign property to a data field, but this a bit far-fetched. As you will see in the example of the following section, you can bind one or more controls on the form to the fields of a DataSet with point-and-click operations.

As can see, it’s actually easier to bind a so-called complex control, because you don’t have to specify which property binds to which field. You simply display all the fields. There are two controls, the ListBox and ComboBox controls, that are a little more complicated, and you will see shortly how to bind these two controls and use them as lookup devices. First, we’ll build a simple application for viewing and editing the rows of a single table.

VB.NET at Work: The ViewEditCustomers Project

Start a new project and design its form like the one shown in Figure 21.11. Place the controls on the form, then create a DataSet with the rows of the Customers table as follows. Open the Server Explorer, open the Northwind branch, and drop the Customers table on the form. Rename the SqlDataAdapter1 object that will be automatically created to DACustomers. This is the DataAdapter object that will retrieve the rows of the table and update the underlying tables. Then configure the DataAdapter—just accept the default SQL statement that retrieves all the rows of the table. Create the DataSet object and name it DSCustomers. The DSCustomers1 object will be placed at the controls tray below the form’s design surface.

At this point, you can bind the controls on the form to the DSCustomers1 DataSet. Select the top TextBox control (make sure its ReadOnly property is set to True, because we’ll use it to display the customer’s ID, which the user isn’t allowed to edit). Open the DataBinding section in the control’s Properties window, locate the Text item, and expand its list of possible settings (Figure 21.12). You will see the DSCustomers1 DataSet object. Click the plus symbol in front of its name and you will see the name of the Customers table (here you will see the names of all tables in the DataSet, but this specific DataSet contains a single table). Expand the table and you will see the names of the fields in the table. Select the CustomerID field; this will bind the first TextBox control on the form to the CustomerID field of the Customers table. At any given time, it will display the value of the CustomerID field on the current row.

Figure 21.12

Binding the Text property of a TextBox control to a field of a table in a DataSet

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

944 Chapter 21 BUILDING DATABASE APPLICATIONS WITH ADO.NET

Bind the remaining TextBoxes to the appropriate fields of the Customers table by repeating the process just described.

Next, you must insert the appropriate code behind the Load Table button, which will move the rows of the Customers table from the database to the local DataSet by calling the DataAdapter’s Fill method:

Private Sub Button1_Click(ByVal sender As System.Object,_

ByVal e As System.EventArgs) Handles Button1.Click

DSCustomers1.Clear()

DACustomers.Fill(DsCustomers1, “Customers”)

End Sub

The BindingContext Object

The interesting code is behind the navigational buttons, which allow you to move from row to row. To change the current location in a DataTable, use the BindingContext object. This object is a property of the form and keeps track of the current position in each DataTable of each DataSet. (Technically, there’s a CurrencyManager object for each DataTable, and the BindingContext object keeps track of all the CurrencyManager objects. Since you’ll never have to program directly against the CurrencyManager object, the BindingContext is the object you must become familiar with).

To specify the appropriate BindingContext object, pass to it as arguments the name of the DataSet and the name of a table in the DataSet. The most important property of the BindingContext object is the Position property, which is the current position in the table. The current position in the Customers DataTable of the DSCustomers1 DataSet object is:

Me.BindingContext(DsCustomers1, “Customers”).Position

To move to any row, set this property to any value between 0 (the first row) and the following expression, which is the index of the last row:

Me.BindingContext(DsCustomers1, “Customers”).Count - 1

To move to the next or previous row, increase or decrease the Position property by one. Of course, you must take into consideration the current position, so that you won’t attempt to move beyond the first or last row in the table. Listing 21.2 shows the minimum code for the previous button.

Listing 21.2: Moving to the Previous Row

Private Sub bttnPrevious_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles bttnPrevious.Click If Me.BindingContext(DsCustomers1, “Customers”).Position > 0 Then

Me.BindingContext(DsCustomers1, “Customers”).Position = _ (Me.BindingContext(DsCustomers1, “Customers”).Position - 1)

PositionChanged() End If

End Sub

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

CREATING A DATASET 945

The PositionChanged() subroutine displays the current row’s number at the bottom of the screen, and its code is shown in Listing 21.3.

Listing 21.3: The PositionChanged() Subroutine

Sub PositionChanged()

lblPosition.Text = (((Me.BindingContext(DsCustomers1, _

“Customers”).Position + 1).ToString + “ / “) + _

Me.BindingContext(DsCustomers1, “Customers”).Count.ToString)

End Sub

If you run the project now, you can iterate through the Customers table’s rows with the navigational buttons and edit any field on any row. The Update Table button submits the changes to the database by calling the DataAdapter’s Update method:

Private Sub Button2_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Button2.Click

DACustomers.Update(DsCustomers1)

End Sub

However, it’s easy to crash the program. If you set the CompanyName field to an empty string, a runtime error will occur when you attempt to move to another row. The DataTable can’t accept a row with a blank CompanyName field, because it would violate one of the restrictions.

To handle this error, we must add some error-trapping code to the handlers of the navigational buttons. We’ll discuss the topic of updating the DataSet and the underlying tables in detail in the following chapter. Here we’ll use a very simple error handler: If a runtime exception occurs, we’ll cancel the edit process by calling the BindingContext object’s CancelCurrentEdit method. We’ll display a message box with a description of the error and then call CancelCurrentEdit, which will restore the original values of the fields on the data-bound controls. The revised event handler of the Previous button is shown in the Listing 21.4.

Listing 21.4: Handling Update Errors

Private Sub bttnPrevious_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles bttnPrevious.Click

Try

If Me.BindingContext(DsCustomers1, “Customers”).Position > 0 Then Me.BindingContext(DsCustomers1, “Customers”).Position = _

(Me.BindingContext(DsCustomers1, “Customers”).Position - 1) PositionChanged()

End If

Catch dataException As Exception MsgBox(dataException.Message)

Me.BindingContext(DsCustomers1, “Customers”).CancelCurrentEdit() End Try

End Sub

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com