
- •Using Your Sybex Electronic Book
- •Acknowledgments
- •Contents at a Glance
- •Introduction
- •Who Should Read This Book?
- •How About the Advanced Topics?
- •The Structure of the Book
- •How to Reach the Author
- •The Integrated Development Environment
- •The Start Page
- •Project Types
- •Your First VB Application
- •Making the Application More Robust
- •Making the Application More User-Friendly
- •The IDE Components
- •The IDE Menu
- •The Toolbox Window
- •The Solution Explorer
- •The Properties Window
- •The Output Window
- •The Command Window
- •The Task List Window
- •Environment Options
- •A Few Common Properties
- •A Few Common Events
- •A Few Common Methods
- •Building a Console Application
- •Summary
- •Building a Loan Calculator
- •How the Loan Application Works
- •Designing the User Interface
- •Programming the Loan Application
- •Validating the Data
- •Building a Math Calculator
- •Designing the User Interface
- •Programming the MathCalculator App
- •Adding More Features
- •Exception Handling
- •Taking the LoanCalculator to the Web
- •Working with Multiple Forms
- •Working with Multiple Projects
- •Executable Files
- •Distributing an Application
- •VB.NET at Work: Creating a Windows Installer
- •Finishing the Windows Installer
- •Running the Windows Installer
- •Verifying the Installation
- •Summary
- •Variables
- •Declaring Variables
- •Types of Variables
- •Converting Variable Types
- •User-Defined Data Types
- •Examining Variable Types
- •Why Declare Variables?
- •A Variable’s Scope
- •The Lifetime of a Variable
- •Constants
- •Arrays
- •Declaring Arrays
- •Initializing Arrays
- •Array Limits
- •Multidimensional Arrays
- •Dynamic Arrays
- •Arrays of Arrays
- •Variables as Objects
- •So, What’s an Object?
- •Formatting Numbers
- •Formatting Dates
- •Flow-Control Statements
- •Test Structures
- •Loop Structures
- •Nested Control Structures
- •The Exit Statement
- •Summary
- •Modular Coding
- •Subroutines
- •Functions
- •Arguments
- •Argument-Passing Mechanisms
- •Event-Handler Arguments
- •Passing an Unknown Number of Arguments
- •Named Arguments
- •More Types of Function Return Values
- •Overloading Functions
- •Summary
- •The Appearance of Forms
- •Properties of the Form Control
- •Placing Controls on Forms
- •Setting the TabOrder
- •VB.NET at Work: The Contacts Project
- •Anchoring and Docking
- •Loading and Showing Forms
- •The Startup Form
- •Controlling One Form from within Another
- •Forms vs. Dialog Boxes
- •VB.NET at Work: The MultipleForms Project
- •Designing Menus
- •The Menu Editor
- •Manipulating Menus at Runtime
- •Building Dynamic Forms at Runtime
- •The Form.Controls Collection
- •VB.NET at Work: The DynamicForm Project
- •Creating Event Handlers at Runtime
- •Summary
- •The TextBox Control
- •Basic Properties
- •Text-Manipulation Properties
- •Text-Selection Properties
- •Text-Selection Methods
- •Undoing Edits
- •VB.NET at Work: The TextPad Project
- •Capturing Keystrokes
- •The ListBox, CheckedListBox, and ComboBox Controls
- •Basic Properties
- •The Items Collection
- •VB.NET at Work: The ListDemo Project
- •Searching
- •The ComboBox Control
- •The ScrollBar and TrackBar Controls
- •The ScrollBar Control
- •The TrackBar Control
- •Summary
- •The Common Dialog Controls
- •Using the Common Dialog Controls
- •The Color Dialog Box
- •The Font Dialog Box
- •The Open and Save As Dialog Boxes
- •The Print Dialog Box
- •The RichTextBox Control
- •The RTF Language
- •Methods
- •Advanced Editing Features
- •Cutting and Pasting
- •Searching in a RichTextBox Control
- •Formatting URLs
- •VB.NET at Work: The RTFPad Project
- •Summary
- •What Is a Class?
- •Building the Minimal Class
- •Adding Code to the Minimal Class
- •Property Procedures
- •Customizing Default Members
- •Custom Enumerations
- •Using the SimpleClass in Other Projects
- •Firing Events
- •Shared Properties
- •Parsing a Filename String
- •Reusing the StringTools Class
- •Encapsulation and Abstraction
- •Inheritance
- •Inheriting Existing Classes
- •Polymorphism
- •The Shape Class
- •Object Constructors and Destructors
- •Instance and Shared Methods
- •Who Can Inherit What?
- •Parent Class Keywords
- •Derived Class Keyword
- •Parent Class Member Keywords
- •Derived Class Member Keyword
- •MyBase and MyClass
- •Summary
- •On Designing Windows Controls
- •Enhancing Existing Controls
- •Building the FocusedTextBox Control
- •Building Compound Controls
- •VB.NET at Work: The ColorEdit Control
- •VB.NET at Work: The Label3D Control
- •Raising Events
- •Using the Custom Control in Other Projects
- •VB.NET at Work: The Alarm Control
- •Designing Irregularly Shaped Controls
- •Designing Owner-Drawn Menus
- •Designing Owner-Drawn ListBox Controls
- •Using ActiveX Controls
- •Summary
- •Programming Word
- •Objects That Represent Text
- •The Documents Collection and the Document Object
- •Spell-Checking Documents
- •Programming Excel
- •The Worksheets Collection and the Worksheet Object
- •The Range Object
- •Using Excel as a Math Parser
- •Programming Outlook
- •Retrieving Information
- •Recursive Scanning of the Contacts Folder
- •Summary
- •Advanced Array Topics
- •Sorting Arrays
- •Searching Arrays
- •Other Array Operations
- •Array Limitations
- •The ArrayList Collection
- •Creating an ArrayList
- •Adding and Removing Items
- •The HashTable Collection
- •VB.NET at Work: The WordFrequencies Project
- •The SortedList Class
- •The IEnumerator and IComparer Interfaces
- •Enumerating Collections
- •Custom Sorting
- •Custom Sorting of a SortedList
- •The Serialization Class
- •Serializing Individual Objects
- •Serializing a Collection
- •Deserializing Objects
- •Summary
- •Handling Strings and Characters
- •The Char Class
- •The String Class
- •The StringBuilder Class
- •VB.NET at Work: The StringReversal Project
- •VB.NET at Work: The CountWords Project
- •Handling Dates
- •The DateTime Class
- •The TimeSpan Class
- •VB.NET at Work: Timing Operations
- •Summary
- •Accessing Folders and Files
- •The Directory Class
- •The File Class
- •The DirectoryInfo Class
- •The FileInfo Class
- •The Path Class
- •VB.NET at Work: The CustomExplorer Project
- •Accessing Files
- •The FileStream Object
- •The StreamWriter Object
- •The StreamReader Object
- •Sending Data to a File
- •The BinaryWriter Object
- •The BinaryReader Object
- •VB.NET at Work: The RecordSave Project
- •The FileSystemWatcher Component
- •Properties
- •Events
- •VB.NET at Work: The FileSystemWatcher Project
- •Summary
- •Displaying Images
- •The Image Object
- •Exchanging Images through the Clipboard
- •Drawing with GDI+
- •The Basic Drawing Objects
- •Drawing Shapes
- •Drawing Methods
- •Gradients
- •Coordinate Transformations
- •Specifying Transformations
- •VB.NET at Work: Plotting Functions
- •Bitmaps
- •Specifying Colors
- •Defining Colors
- •Processing Bitmaps
- •Summary
- •The Printing Objects
- •PrintDocument
- •PrintDialog
- •PageSetupDialog
- •PrintPreviewDialog
- •PrintPreviewControl
- •Printer and Page Properties
- •Page Geometry
- •Printing Examples
- •Printing Tabular Data
- •Printing Plain Text
- •Printing Bitmaps
- •Using the PrintPreviewControl
- •Summary
- •Examining the Advanced Controls
- •How Tree Structures Work
- •The ImageList Control
- •The TreeView Control
- •Adding New Items at Design Time
- •Adding New Items at Runtime
- •Assigning Images to Nodes
- •Scanning the TreeView Control
- •The ListView Control
- •The Columns Collection
- •The ListItem Object
- •The Items Collection
- •The SubItems Collection
- •Summary
- •Types of Errors
- •Design-Time Errors
- •Runtime Errors
- •Logic Errors
- •Exceptions and Structured Exception Handling
- •Studying an Exception
- •Getting a Handle on this Exception
- •Finally (!)
- •Customizing Exception Handling
- •Throwing Your Own Exceptions
- •Debugging
- •Breakpoints
- •Stepping Through
- •The Local and Watch Windows
- •Summary
- •Basic Concepts
- •Recursion in Real Life
- •A Simple Example
- •Recursion by Mistake
- •Scanning Folders Recursively
- •Describing a Recursive Procedure
- •Translating the Description to Code
- •The Stack Mechanism
- •Stack Defined
- •Recursive Programming and the Stack
- •Passing Arguments through the Stack
- •Special Issues in Recursive Programming
- •Knowing When to Use Recursive Programming
- •Summary
- •MDI Applications: The Basics
- •Building an MDI Application
- •Built-In Capabilities of MDI Applications
- •Accessing Child Forms
- •Ending an MDI Application
- •A Scrollable PictureBox
- •Summary
- •What Is a Database?
- •Relational Databases
- •Exploring the Northwind Database
- •Exploring the Pubs Database
- •Understanding Relations
- •The Server Explorer
- •Working with Tables
- •Relationships, Indices, and Constraints
- •Structured Query Language
- •Executing SQL Statements
- •Selection Queries
- •Calculated Fields
- •SQL Joins
- •Action Queries
- •The Query Builder
- •The Query Builder Interface
- •SQL at Work: Calculating Sums
- •SQL at Work: Counting Rows
- •Limiting the Selection
- •Parameterized Queries
- •Calculated Columns
- •Specifying Left, Right, and Inner Joins
- •Stored Procedures
- •Summary
- •How About XML?
- •Creating a DataSet
- •The DataGrid Control
- •Data Binding
- •VB.NET at Work: The ViewEditCustomers Project
- •Binding Complex Controls
- •Programming the DataAdapter Object
- •The Command Objects
- •The Command and DataReader Objects
- •VB.NET at Work: The DataReader Project
- •VB.NET at Work: The StoredProcedure Project
- •Summary
- •The Structure of a DataSet
- •Navigating the Tables of a DataSet
- •Updating DataSets
- •The DataForm Wizard
- •Handling Identity Fields
- •Transactions
- •Performing Update Operations
- •Updating Tables Manually
- •Building and Using Custom DataSets
- •Summary
- •An HTML Primer
- •HTML Code Elements
- •Server-Client Interaction
- •The Structure of HTML Documents
- •URLs and Hyperlinks
- •The Basic HTML Tags
- •Inserting Graphics
- •Tables
- •Forms and Controls
- •Processing Requests on the Server
- •Building a Web Application
- •Interacting with a Web Application
- •Maintaining State
- •The Web Controls
- •The ASP.NET Objects
- •The Page Object
- •The Response Object
- •The Request Object
- •The Server Object
- •Using Cookies
- •Handling Multiple Forms in Web Applications
- •Summary
- •The Data-Bound Web Controls
- •Simple Data Binding
- •Binding to DataSets
- •Is It a Grid, or a Table?
- •Getting Orders on the Web
- •The Forms of the ProductSearch Application
- •Paging Large DataSets
- •Customizing the Appearance of the DataGrid Control
- •Programming the Select Button
- •Summary
- •How to Serve the Web
- •Building a Web Service
- •Consuming the Web Service
- •Maintaining State in Web Services
- •A Data-Driven Web Service
- •Consuming the Products Web Service in VB
- •Summary

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 |