- •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
A “REAL” CLASS 361
openFileDialog1.ShowDialog()
Console.writeline(objStrTools.ExtractPathName(OpenFileDialog1.FileName))
Console.WriteLine(objStrTools.ExtractFileName(OpenFileDialog1.FileName)) End Sub
Reusing the StringTools Class
Let’s see now how the StringTools class can be used in another project, without making the VB file with the class part of every project that requires this functionality. First, you must create the class’s executable file. Unlike Windows applications, classes are compiled into DLL files. Your project most likely contains a test form in addition to the class, so you must exclude the test form from the project. Right-click the name of the test form and select Exclude From Project. This action will exclude the file from the project. You project now contains the StringTools class only.
Classes can’t be executed on their own, so you must also change the type of the project. Right-click the name of the project and select Properties. In the Project Property Pages dialog box, change the project’s output type from Windows Application to Class Library. Then close the project’s property pages, open the Project menu, and select Build. This action will create the StringTools.dll file in the project’s Bin folder. This is the file you must reference in any project that requires the functionality of the StringTools class.
Start a new project, and choose Project Add Reference. On the dialog box that will appear, switch to the Projects tab and click the Browse button. Locate the Bin folder under the project’s folder, where you will find the StringTools.dll file. Select it and close all the dialog boxes. When you’re back to the project, you will see that the StringTools class has been added to the project. You can’t edit the class’s code, which means you can’t break it. You can even extend the functionality of the StringTools class by adding more members to it, without touching its code. The topic of building new classes based on existing ones is discussed in the later section “Inheritance.”
VB.NET at Work: The ClassContacts Project
In Chapter 4, I discussed briefly the Contacts application. This application uses a structure to store the contacts and provides four navigational buttons to allow users to move to the first, last, previous, and next contact. Now that you have learned how to use the ListBox control and how to use custom classes in your code, we’re going to revise the Contacts application. First, we’ll implement the contacts as a class. The fields of each contact (company name, contact name, and so on) will be implemented as properties. The advantage of implementing the contacts as classes, as opposed to structures, is that you can validate the values of the fields from within your class, and not rely on the application developer to validate the data before storing them to an instance of a structure.
Another advantage is that other developers can extend your class and add new properties, or methods, without having access to your code. You will see how to extend classes later in this chapter, in the section on inheritance.
We’ll also improve the user interface of the application. Instead of the rather simplistic navigational buttons, we’ll place all the company names in a sorted ListBox control. The user can easily locate the desired company and select it in the list to view the fields of the selected contact. The editing buttons at the bottom of the form work as usual. Figure 8.10 shows the revised Contacts application, which is the ClassContacts application you will find in this chapter’s CD folder.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
362 Chapter 8 BUILDING CUSTOM CLASSES
Figure 8.10
The interface of the ClassContacts application is based on the ListBox control.
Make a copy of the Contacts folder from Chapter 4 and rename it to ClassContacts. Then open the application in the new folder and likewise rename the project from Contacts to ClassContacts. The next step is to delete the declaration of the Contact structure and add a class to the project.
Name the new class Contact and enter in it the code from Listing 8.28.
Listing 8.28: The Contact Class
<Serializable()> Public Class Contact
Private _companyName As String
Private _contactName As String
Private _address1 As String
Private _address2 As String
Private _city As String
Private _state As String
Private _zip As String
Private _tel As String
Private _email As String
Private _URL As String
Property CompanyName() As String
Get
CompanyName = _companyName
End Get
Set(ByVal Value As String)
If Value Is Nothing Or Value = “” Then
Throw New Exception(“Company Name field can’t be empty”)
Exit Property
End If
_companyName = Value
End Set
End Property
Property ContactName() As String
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
A “REAL” CLASS 363
Get
ContactName = _contactName End Get
Set(ByVal Value As String)
_contactName = Value End Set
End Property
Property Address1() As String Get
Address1 = _address1 End Get
Set(ByVal Value As String) _address1 = Value
End Set
End Property
Property Address2() As String Get
Address2 = _address1 End Get
Set(ByVal Value As String) _address2 = Value
End Set
End Property
Property City() As String Get
City = _city End Get
Set(ByVal Value As String) _city = Value
End Set
End Property
Property State() As String Get
State = _state End Get
Set(ByVal Value As String) _state = Value
End Set
End Property
Property ZIP() As String Get
ZIP = _zip End Get
Set(ByVal Value As String) _zip = Value
End Set
End Property
Property tel() As String
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
364 Chapter 8 BUILDING CUSTOM CLASSES
Get
tel = _tel
End Get
Set(ByVal Value As String)
_tel = Value
End Set
End Property
Property EMail() As String
Get
EMail = _email
End Get
Set(ByVal Value As String)
_email = Value
End Set
End Property
Property URL() As String
Get
URL = _URL
End Get
Set(ByVal Value As String)
_URL = Value
End Set
End Property
Overrides Function ToString() As String
If _contactName = “” Then
Return _companyName
Else
Return _companyName & vbTab & “(“ & _contactName & “)”
End If
End Function
End Class
The first thing you’ll notice is that the class’s definition is prefixed by the <Serializable()> keyword. The topic of serialization is discussed in Chapter 11, but for now all you need to know is that the .NET Framework can convert objects to a text or binary format and store them in files. Surprisingly, this process is quite simple. <Serializable()> is an attribute of the class. As you will see later in this book, there are more attributes you can use with your classes, or even with your methods. The most prominent method attribute is the <WebMethod> attribute, which turns a regular function into a Web method.
The various fields of the contact structure are now properties of the Contact class. The implementation of the properties is trivial, except for the CompanyName property, which contains some validation code. The Contact class requires that the CompanyName property has a value; if it doesn’t, the class throws an exception. Finally, the class provides its own ToString method, which returns the name of the company followed by the contact name in parentheses. We’re going to store all the contacts in the ListBox control. The ListBox control will display the value returned by the object’s ToString
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
A “REAL” CLASS 365
method, so we must provide our own ToString method that describes each contact. The company name should be adequate, but if there are two companies by the same name, you can use another field to differentiate them. I’ve used the contact name, but you can use any of the other properties (the URL would be a good choice).
Each contact is stored in a variable of the Contact type and added to the ListBox control. Now, we must change the code of the main form a little. First, remove the navigational buttons; we no longer need them. Their function will be replaced by a few lines of code in the ListBox control’s SelectedIndexChanged event. Every time the user selects another item on the list, the statements shown in Listing 8.29 display the contact’s properties on the various TextBox controls on the form.
Listing 8.29: Displaying the Fields of the Selected Contact Object
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
currentContact = ListBox1.SelectedIndex ShowContact()
End Sub
The ShowContact() subroutine reads the object stored at the location specified by the currentContact variable and displays its properties on the various TextBox controls on the form.
When a new contact is added, the code creates a new Contact object and adds it to the ListBox control. When a contact is edited, a new Contact object replaces the currently selected object on the control. The code is very similar to the code of the Contacts application. I should mention that the ListBox control is locked while a contact is being added or edited, because it doesn’t make sense to select another contact at that time. Besides, we want to be able to replace the contact being edited when the user is done.
To delete a contact (Listing 8.30), we simply remove the currently selected object on the control. In addition, we must select the next object, or the first object if the deleted object was the last one in the list.
Listing 8.30: Deleting an Object on the ListBox
Private Sub bttnDelete_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles bttnDelete.Click If currentContact > -1 Then
ListBox1.Items.RemoveAt(currentContact)
If currentContact = ListBox1.Items.Count Then _ currentContact = ListBox1.Items.Count - 1
If currentContact = -1 Then ClearFields()
MsgBox(“There are no more contacts”) Else
ShowContact() End If
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
366 Chapter 8 BUILDING CUSTOM CLASSES
Else
MsgBox(“No current contacts to delete”)
End If
End Sub
When you add a new contact, the following code is executed in the Add button’s Click event handler:
Private Sub bttnAdd_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles bttnAdd.Click adding = True
ClearFields()
HideButtons() ListBox1.Enabled = False
End Sub
These statements simply prepare the application to accept a new record. The controls are cleared in anticipation of the new record’s fields, and the adding variable is set to True. The OK button is clicked to end either the addition of a new record or an edit operation. The code behind the OK button is shown in Listing 8.31.
Listing 8.31: Committing a New or Edited Record
Private Sub bttnOK_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles bttnOK.Click
Dim contact As New Contact()
SaveContact()
ListBox1.Enabled = True
ShowButtons()
End Sub
As you can see, the same subroutine handles both the insertion of a new record and the editing of an existing one. All the work is done by the SaveContact() subroutine, which is shown in Listing 8.32.
Listing 8.32: The SaveContact() Subroutine
Sub SaveContact()
Dim contact As New Contact() contact.CompanyName = txtCompany.Text contact.ContactName = txtContact.Text contact.Address1 = txtAddress1.Text contact.Address2 = txtAddress2.Text contact.City = txtCity.Text contact.State = txtState.Text contact.ZIP = txtZIP.Text contact.tel = txtTel.Text
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |