Visual basic

BUILDING A LOAN CALCULATOR 129
Aligning the Controls
Your next step is to align the controls on the form. The IDE provides commands to align the
controls on the form, all of which can be accessed through the Format menu. To align the controls
that are already on the form, follow these steps:
1. Select the four labels on the form. The handles of all selected controls will be black, except
for one control whose handles will be white. To specify the control that will be used as a
reference for aligning the other controls, click it after making the selection. (You can select
multiple controls either by drawing a rectangle that encloses them with the mouse, or by
clicking each control while holding down the Ctrl button.)
2. With the four text boxes selected, choose Format  Align  Left to left-align them. Don’t
include the check box in this selection.
3. Resize the CheckBox control. Its left edge should align with the left edges of the Label
controls, and its right edge should align with the right edges of the Label controls.
4. Select all the Labels and the CheckBox controls and choose Format  Vertical Spacing
 Make Equal. This action will space the controls vertically. Then align the baseline of
each TextBox control with the baseline of the matching Label control. To do so, move each
TextBox control with the mouse until you see a magenta line that connects the baseline
of the TextBox control you’re moving and that of the matching Label control.
Your form should now look like the one shown in Figure 4.1. Take a good look at it and check
to see whether any of your controls are misaligned. In the interface design process, you tend
to overlook small problems such as a slightly misaligned control. The user of the application,
however, instantly spots such mistakes.
Programming the Loan Application
Now that you’ve created the interface, run the application and see how it behaves. Enter a few
values in the text boxes, change the state of the check box, and test the functionality already built
into the application. Clicking the Monthly Payment button won’t have any effect because we
have not yet added any code. If this were a prototype you were building for a customer, you
would add a statement in the Monthly Payment button to display a random value in the Monthly
Payment box. The purpose of the prototype is to get the customer’s approval on the appearance
and functionality of an application before you start coding it.
If you’re happywith the user interface, stop the application, open the form, and double-click the
Monthly Payment Button control. Visual Basic opens the code window and displays the de?nition
of the ShowPayment Click event:
Private Sub bttnShowPayment Click(...)
Handles bttnShowPayment.Click
End Sub
Because all Click event handlers have the same signature (they provide the same two argu-
ments), I’ll be omitting the list of arguments from now on. Actually, all event handlers have two
arguments, and the ?rst of them is always the control that ?red the event. The type of the secondPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 130
130 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
argument differs depending on the type of the event. Place the pointer between the lines Private
Sub and End Sub, and enter the rest of the lines of Listing 4.1. (You don’t have to reenter the ?rst
and last lines that declare the event handler.)
Listing 4.1: The Code behind theMonthly Payment Button
Private Sub bttnShowPayment Click(...)
Handles bttnShowPayment.Click
Dim Payment As Double
Dim LoanIRate As Double
Dim LoanDuration As Integer
Dim LoanAmount As Integer
LoanAmount = Convert.ToInt32(txtAmount.Text)
LoanIRate = 0.01 * Convert.ToDecimal(txtRate.Text) / 12
LoanDuration = Convert.ToInt32(txtDuration.Text)
Dim payEarly As DueDate
If chkPayEarly.Checked Then
payEarly = DueDate.BegOfPeriod
Else
payEarly = DueDate.EndOfPeriod
End If
Payment = Pmt(LoanIRate, LoanDuration, -LoanAmount, 0, payEarly)
txtPayment.Text = Payment.ToString(”#.00”)
End Sub
The code window should now look like the one shown in Figure 4.2. Notice the underscore
character at the end of the ?rst part of the long line. The underscore lets you break long lines so
that they will ?t nicely in the code window. I’m using this convention in this book a lot to ?t long
lines on the printed page. The same statement you see as multiple lines in the book may appear in
a single, long line in the project.
You don’t have to break long lines manually as you enter code in the editor’s window.
Open the Edit menu and choose Advanced  Word Wrap. The editor will wrap long lines auto-
matically at a word boundary. While the word wrap feature is on, a check mark appears in front
of the Edit  Advanced  Word Wrap command. To turn off word wrapping, select the same
command again.
In Listing 4.1, the ?rst line of code within the subroutine declares a variable. It lets the applica-
tion know that Payment is a variable for storing a ?oating-point number (a number with a decimal
part)— the Double data type. The line before the If statement declares a variable of the DueDate
type. This is the type of the argument that determines whether the payment takes place at the
beginning or the end of the month. The last argument of the Pmt() function must be a variable
of this type, so we declare a variable of the DueDate type. As mentioned earlier in this chapter,
DueDate is an enumeration with two members: BegOfPeriod and EndOfPeriod.
The ?rst really interesting statement in the subroutine is the If statement that examines the
value of the chkPayEarly CheckBox control. If the control is selected, the code sets the payEarly
variable to DueDate.BegOfPeriod. If not, the code sets the same variable to DueDate.EndOfPeriod.Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 131
BUILDING A LOAN CALCULATOR 131
Figure 4.2
The Show Payment
button’s Click event
subroutine.
The ComboBox control’s Checked property returns True if the control is selected at the time, and
returns False otherwise. After setting the value of the payEarly variable, the code calls the Pmt()
function, passing the values of the controls as arguments:
? The ?rst argument is the interest rate. The value entered by the user in the txtRate TextBox
is multiplied by 0.01 so that the value 14.5 (which corresponds to 14.5 percent) is passed to
the Pmt() function as 0.145. Although we humans prefer to specify interest rates as inte-
gers (8 percent) or ?oating-point numbers larger than 1 (8.24 percent), the Pmt() function
expects to read a number less than 1. The value 1 corresponds to 100 percent. Therefore, the
value 0.1 corresponds to 10 percent. This value is also divided by 12 to yield the monthly
interest rate.
? The second argument is the duration of the loan in months (the value entered in the
txtDuration TextBox).
? The third argument is the loan’s amount (the value entered in the txtAmount TextBox).
? The fourth argument (the loan’s future value) is 0 by de?nition.
? The last argument is the payEarly variable, which is set according to the status of the chk-
PayEarly control.
The last statement in Listing 4.1 converts the numeric value returned by the Pmt() function to a
string and displays this string in the fourth TextBox control. The result is formatted appropriately
with the following expression:
Payment.ToString(”#.00”)
The Payment variable is numeric, and all numeric variables provide the method ToString,
which formats the numeric value and converts it to a string. The character # stands for the integer
part of the variable. The period separates the integer from the fractional part, which is roundedPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 132
132 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
to two decimal digits. The Pmt() function returns a precise number, such as 372.2235687646345,
and you must round it to two decimal digits and format it nicely before displaying it. For more
information on formatting numeric (and other) values, see the section ‘‘Formatting Numbers’’
in Chapter 2, ‘‘Variables and Data Types.’’ Finally, the formatted string is assigned to the Text
property of the TextBox control on the form.
A Code Snippet for Calculating Monthly Loan Payments
If you didn’t know about the Pmt() built-in function, how would you go about calculating loan pay-
ments? Code snippets to the rescue! Right-click somewhere in the code window and from the con-
text menu choose the Insert Snippet command. Double-click the fundamentals to see another list of
items. This time double-click the Math folder and then select the snippet Calculate a Monthly Payment
on a Loan. The following code will be inserted at the location of the pointer (I’ve broken the last long
statement into two lines to ?t it on the printed page):
Dim futureValue As Double = 0
Dim payment As Double
payment1 = Pmt(0.05 / 12, 36, -1000, futureValue, DueDate.EndOfPeriod)
The snippet demonstrates the use of the Pmt() function. All you have to do is replace the values of
the various parameters with the data from the appropriate controls on the form.
If you don’t know how to use the arguments of the Pmt() function, rest the pointer over each argu-
ment and you will see a description for each argument, as shown here:
The code of the LoanCalculator sample project is a bit different and considerably longer
than what I have presented here. The statements discussed in the preceding text are the bare
minimum for calculating a loan payment. The user can enter all kinds of unreasonable values
on the form and cause the program to crash. In the next section, you’ll see how you can validate
the data entered by the user, catch errors, and handle them gracefully (that is, give the user a
chance to correct the data and proceed), as opposed to terminating the application with a run-
time error.Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 133
BUILDING A LOAN CALCULATOR 133
Validating the Data
If you enter a non-numeric value in one of the ?elds, the program will crash and display an error
message. For example, if you enter twenty in the Duration text box, the program will display the
error message shown in Figure 4.3. A simple typing error can crash the program. This isn’t the
way Windows applications should work. Your applications must be able to handle all kinds of
user errors, provide helpful messages, and in general, guide the user in running the application
ef?ciently. If a user error goes unnoticed, your application will either end abruptly or will produce
incorrect results without an indication.
Figure 4.3
The FormatException
error message means
that you supplied a
string where a numeric
value was expected.
Visual Basic will take you back to the application’s code window, in which the statements that
caused the error will be highlighted in green. Obviously, we must do something about user errors.
One way to take care of typing errors is to examine each control’s contents; if the controls don’t
contain valid numeric values, display your own descriptive message and give the user another
chance. Listing 4.2 is the revised Click event handler that examines the value of each text box
before attempting to use it in any calculations.
Listing 4.2: Revised Show Payment Button
Private Sub bttnShowPayment Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles bttnShowPayment.Click
Dim Payment As Double
Dim LoanIRate As Double
Dim LoanDuration As Integer
Dim LoanAmount As Integer
’ Validate amount
If IsNumeric(txtAmount.Text) Then
LoanAmount = Convert.ToInt32(txtAmount.Text)
Else
MsgBox(”Please enter a valid amount”)
Exit Sub
End If
’ Validate interest rate
If IsNumeric(txtRate.Text) Then
LoanIRate = 0.01 * Convert.ToDouble(txtRate.Text) / 12
ElsePetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 134
134 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
MsgBox(”Invalid interest rate, please re-enter”)
Exit Sub
End If
’ Validate loan’s duration
If IsNumeric(txtDuration.Text) Then
LoanDuration = Convert.ToInt32(txtDuration.Text)
Else
MsgBox(”Please specify the loan’s duration as a number of months”)
Exit Sub
End If
’ If all data were validated, proceed with calculations
Dim payEarly As DueDate
If chkPayEarly.Checked Then
payEarly = DueDate.BegOfPeriod
Else
payEarly = DueDate.EndOfPeriod
End If
Payment = Pmt(LoanIRate, LoanDuration, -LoanAmount, 0, payEarly)
txtPayment.Text = Payment.ToString(”#.00”)
End Sub
First, we declare three variables in which the loan’s parameters will be stored: LoanAmount,
LoanIRate,and LoanDuration. These values will be passed to the Pmt() function as arguments.
Each text box’s value is examined with an If structure. If the corresponding text box holds a valid
number, its value is assigned to the numeric variable. If not, the program displays a warning
and exits the subroutine without attempting to calculate the monthly payment. Before exiting the
subroutine, however, the code moves the focus to the text box with the invalid value because this
is the control that the user will most likely edit. After ?xing the incorrect value, the user can click
the Show Payment button again. IsNumeric() is another built-in function that accepts a variable
and returns True if the variable is a number, and returns False otherwise.
You can run the revised application and check it out by entering invalid values in the ?elds.
Notice that you can’t specify an invalid value for the last argument; the CheckBox control won’t let
you enter a value. You can only select or clear it, and both options are valid. The actual calculation
of the monthly payment takes a single line of Visual Basic code. Displaying it requires another
line of code. Adding the code to validate the data entered by the user, however, is an entire pro-
gram. And that’s the way things are.
WritingWell-Behaved Applications
A well-behaved application must contain data-validation code. If an application such as LoanCalcu-
lator crashes because of a typing mistake, nothing really bad will happen. The user will try again or
else give up on your application and look for a more professional one. However, if the user has been
entering data for hours, the situation is far more serious. It’s your responsibility as a programmer to
make sure that only valid data are used by the application and that the application keeps working, no
matter how the user misuses or abuses it.
The amount of code you write to validate user input is comparable to the amount of code that pro-
duces the results. Our sample application is not typical, because it calculates the result with a singlePetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 135
BUILDING A LOAN CALCULATOR 135
function call, but in developing typical business applications, you must write a substantial amount
of code to validate user input. The reason for validating user input is that you should provide speci?c
error messages to help the user identify the error and correct it.
The applications in this book don’t contain much data-validation code because it would obscure the
‘‘useful’’ code that applies to the topic at hand. Instead, they demonstrate speci?c techniques. You
can use parts of the examples in your applications, but you should provide your own data-validation
code (and error-handling code, as you’ll see in a moment).
Now run the application one last time and enter an enormous loan amount. Try to ?nd out
what it would take to pay off the national debt with a reasonable interest rate in, say, 72 months.
The program will crash again (as if you didn’t know). This time the program will go down with
a different error message, as shown in Figure 4.4. Visual Basic will complain about an over?ow.
The exact message is Value was either too large or too small for an Int32, and the program will stop at
the line that assigns the contents of the txtAmount TextBox to the LoanAmount variable. Press the
Break button, and the offending statement in the code will be highlighted.
Figure 4.4
Very large values can
cause the application to
crash and display this
error message.
An over?ow is a numeric value too large for the program to handle. This error is usually pro-
duced when you divide a number by a very small value. When you attempt to assign a very large
value to an Integer variable, you’ll also get an over?ow exception.
Actually, in the LoanCalculator application, any amount greater than 2,147,483,647 will cause
an over?ow condition. This is the largest value you can assign to an Integer variable; it’s plenty
for our banking needs, but not nearly adequate for handling government de?cits. As you’ll see
in the next chapter, Visual Basic provides other types of variables, which can store enormous
values (making the national debt look really small). In the meantime, if you want to use the loan
calculator, change the declaration of the LoanAmount variable to the following:
Dim LoanAmount As DoublePetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 136
136 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
The Double data type can hold much larger values. Besides, the Double data type can also hold
noninteger values. Not that anyone will ever apply for a loan of $25,000 and some cents, but if you
want to calculate the precise monthly payment for a debt you have accumulated, you should be
able to specify a noninteger amount. In short, we should have declared the LoanAmount variable
with the Double data type in the ?rst place. By the way, there’s another integer data type, the Long
data type, which can hold much larger integer values.
An over?ow error can’t be caught with data-validation code. There’s always a chance that your
calculations will produce over?ows or other types of math errors. Data validation won’t help
here; you just don’t know the result before you carry out the calculations. We need something
called error handling,or exception handling. This is additional code that can handle errors after they
occur. In effect, you’re telling VB that it shouldn’t stop with an error message, which would be
embarrassing for you and wouldn’t help the user one bit. Instead, VB should detect the error
and execute the proper statements that will handle the error. Obviously, you must supply these
statements. (You’ll see examples of handling errors at runtime shortly.)
The sample application works as advertised and it’s fail-safe. Yet there’s one last touch we can
add to our application. The various values on the form are not always in synch. Let’s say you’ve
calculated the monthly payment for a speci?c loan and then you want to change the duration of
the loan to see how it affects themonthly payment. As soon as you change the duration of the loan,
and before you click the Monthly Payment button, the value in the Monthly Payment box doesn’t
correspond to the parameters of the loan. Ideally, the monthly payment should be cleared as
soon as the user starts editing one of the loan’s parameters. To do so, you must insert a statement
that clears the txtPayment control. But what’s the proper event handler for this statement? The
TextBox control ?res the TextChanged event every time its text is changed, and this is the proper
place to execute the statement that clears themonthly payment on the form. Because there are three
TextBox controls on the form, you must program the TextChanged event of all three controls, or
write an event handler that handles all three events:
Private Sub txtAmount TextChanged(...)
Handles txtAmount.TextChanged,
txtDuration.TextChanged, txtRate.TextChanged
txtPayment.Clear()
End Sub
Yes, you can write a common handler for multiple events, as long as the events are of the same
type and they’re all listed after the Handles keyword. You’ll see another example of the same
technique in the following sample project.
One of the sample projects for this chapter is a revised version of the LoanCalculator project, the
LoanCalculator-Dates project, which uses a different interface. Instead of specifying the duration
of the loan in months, this application provides two instances of the DateTimePicker control,
which is used to specify dates. Delete the TextBox control and the corresponding Labels and
insert two new Labels and two DateTimePicker controls on the form. Users can set the loan’s
starting and ending dates on these two controls and the program calculates the duration of the
loan in moths with the following statement:
LoanDuration = DateDiff(DateInterval.Month,
dtFrom.Value, dtTo.Value) + 1
dtFrom and dtTo are the names of the two DateTimePicker controls. The DateDiff() function
returns the difference between two dates in the interval supplier as the ?rst argument to thePetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 137
BUILDING A CALCULATOR 137
function. The rest of the code doesn’t change; as long as the LoanDuration variable has the correct
value, the same statements will produce the correct result. If you open the project you’ll ?nd a few
more interesting statements that set the dtFrom control to the ?rst date of the selected month and
the dtTo control to the last date of the selected month.
Building a Calculator
Our next application is more advanced, but not as advanced as it looks. It’s a calculator with
a typical visual interface that demonstrates how Visual Basic can simplify the programming of
fairly advanced operations. If you haven’t tried it, you may think that writing an application such
as this one is way too complicated for a beginner, but it isn’t. The MathCalculator application is
shown in Figure 4.5.
Figure 4.5
Calculator application
window
The application emulates the operation of a hand-held calculator and implements the basic
arithmetic operations. It has the look of a math calculator, and you can easily expand it by adding
more features. In fact, adding features such as cosines and logarithms is actually simpler than
performing the basic arithmetic operations. This interface will also give us a chance to exercise
most of the tools of the IDE for aligning and spacing the controls on a form.
Designing the User Interface
The application’s interface is straightforward, but it takes a bit of effort. You must align the but-
tons on the form and make the calculator look as much like a hand-held calculator as possible.
Start a new project, the MathCalculator project, and rename its main form from Form1.vb to
frmCalculator.vb.
Designing the interface of the application isn’t trivial because it’s made up of many buttons, all
perfectly aligned on the form. To simplify the design, follow these steps:
1. Select a font that you like for the form. All the command buttons you’ll place on the form
will inherit this font. The MathCalculator sample application uses 10-point Verdana font.
I’ve used a size of 12 points for the Period button, because the 10-point period was too
small and very near the bottom of the control.
2. Add the Label control, which will become the calculator’s display. Set its BorderStyle
property to Fixed3D so that it will have a 3D look, as shown in Figure 4.5. Change itsPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 138
138 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
ForeColor and BackColor properties too, if you want it to look different from the rest
of the form. The sample project uses colors that emulate the— now extinct— green CRT
monitors.
3. Draw a Button control on the form, change its Text property to 1, and name it bttn1.Size
the button carefully so that its caption is centered on the control. The other buttons on the
form will be copies of this one, so make sure you’ve designed the ?rst button as best as
you can before you start making copies of it. You can also change the button’s style with
the FlatStyle property. (You can experiment with the Popup, Standard, and System set-
tings of this property.)
4. Place the button in its ?nal position on the form. At this point, you’re ready to create the
other buttons for the calculator’s digits. Right-click the button and choose Copy from the
context menu. The Button control is copied to the Clipboard, and now you can paste it on
the form (which is much faster than designing an identical button).
5. Right-click somewhere on the form, choose Paste, and the button copied to the Clipboard
will be pasted on the form. The copy will have the same caption as the button it was
copied from, and its name will be Button1.
6. Now set the button’s Name to bttn2 and its Text property to 2. This button is the digit 2.
Place the new button to the right of the previous button. You don’t have to align the two
buttons perfectly now; later we’ll use the Format menu to align the buttons on the form.
As you move the control around on the form, one or more lines may appear at times.
These lines are called snap lines, and they appear as soon as a control is aligned (verti-
cally or horizontally) with one or more of the existing controls on the form. The snap lines
allow you to align controls with the mouse. Blue snap lines appear when the control’s
edge is aligned with the edge of another control. Red snap lines appear when the control’s
baseline is aligned with the baseline of another control. The baseline is the invisible line on
which the characters of the control’s caption are based.
7. Repeat steps 5 and 6 eight more times, once for each numeric digit. Each time a new
Button control is pasted on the form, Visual Basic names it Button1 and sets its caption
to 1; you must change the Name and Text properties. You can name the buttons any-
thing you like, but a name that indicates their role in the application is preferred.
8. When the buttons of the numeric digits are all on the form, place two more buttons, one
for the C (Clear) operation and one for the Period button. Name them bttnClear and
bttnPeriod, and set their captions accordingly. Use a larger font size for the Period but-
ton to make its caption easier to read.
9. When all the digit buttons of the ?rst group are on the form and in their approximate posi-
tions, align them by using the commands of the Format menu. You can use the snap lines
to align horizontally and vertically the various buttons on the form, but you must still
space the controls manually, which isn’t a trivial task. Here’s how you can align the but-
tons perfectly via the Format menu:
a. First, align the buttons of the top row. Start by aligning the 1 button with the left side
of the lblDisplay Label. Then select all the buttons of the top row and make their
horizontal spacing equal (choose Format  Horizontal Spacing  Make Equal). Then
do the same with the buttons in the ?rst column; this time, make sure that their vertical
distances are equal (Format  Vertical Spacing  Make Equal).Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 139
BUILDING A CALCULATOR 139
b. Now you can align the buttons in each row and each column separately. Use one
of the buttons you aligned in the last step as the guide for the rest of them. The but-
tons can be aligned in many ways, so don’t worry if somewhere in the process you
ruin the alignment. You can always use the Undo command in the Edit menu. Select
the three buttons on the second row and align their Tops by using the ?rst button
as a reference. To set the anchor control for the alignment, click it with the mouse
while holding down the Ctrl key. Do the same for the third and fourth rows of but-
tons. Then do the same for the four columns of buttons, using the top button as a
reference.
10. Now, place the buttons for the arithmetic operations on the form— addition (+), subtrac-
tion (-), multiplication (*), and division (/).
11. Finally, place the Equals button on the form and make it wide enough to span the space of
two operation buttons. Use the commands on the Format menu to align these buttons,
as shown in Figure 4.5. The form shown in Figure 4.5 has a few more buttons, which
you can align by using the same techniques you used to align the numeric buttons.
If you don’t feel quite comfortable with the alignment tools of the IDE, you can still position
the controls on the form through the x and y components of each control’s Location property.
(They’re the x- and y-coordinates of the control’s upper-left corner on the form.) The various
alignment tools are among the ?rst tools of the IDE you’ll master, and you’ll be creating forms
with perfectly aligned controls in no time at all.
Programming the MathCalculator
Now you’re ready to add some code to the application. Double-click one of the digit buttons on
the form, and you’ll see the following in the code window:
Private Sub bttn1 Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles bttn1.Click
End Sub
This is the Click event’s handler for a single digit button. Your ?rst attempt is to program
the Click event handler of each digit button, but repeating the same code 10 times isn’t very
productive. (Not to mention that if we decide to edit the code later, the process must be repeated
10 times.) We’re going to use the same event handler for all buttons that represent digits. All
you have to do is append the names of the events to be handled by the same subroutine after
the Handles keyword. You should also change the name of the event handler to something that
indicates its role. Because this subroutine handles the Click event for all the digit buttons, let’s
call it DigitClick(). Here’s the revised declaration of a subroutine that can handle all the digit
buttons:
Private Sub DigitClick(ByVal sender As System.Object,
ByVal e As System.EventArgs)
Handles bttn0.Click, bttn1.Click, bttn2.Click,
bttn3.Click, bttn4.Click, bttn5.Click, bttn6.Click,
bttn7.Click, bttn8.Click, bttn9.Click
End SubPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 140
140 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
You don’t have to type all the event names; as soon as you insert the ?rst comma after
bttn0.Click, a drop-down list with the names of the controls will open, and you can select the
name of the next button with the down arrow. Press the spacebar to select the desired control
(bttn1, bttn2, and so on), and then type the period. This time, you’ll see another list with the
names of the events for the selected control. Locate the Click event and select it by pressing the
spacebar. Type the next comma and repeat the process for all the buttons. This extremely conve-
nient feature of the language is IntelliSense: The IDE presents the available and valid keywords as
you type.
When you press a digit button on a hand-held calculator, the corresponding digit is appended
to the display. To emulate this behavior, insert the following line in the Click event handler:
lblDisplay.Text = lblDisplay.Text + sender.Text
This line appends the digit clicked to the calculator’s display. The sender argument of the
Click event represents the control that was clicked (the control that ?red the event). The Text
property of this control is the caption of the button that was clicked. For example, if you have
already entered the value 345, clicking the digit 0 displays the value 3450 on the Label control that
acts as the calculator’s display.
The expression sender.Text is not the bestmethod of accessing the Text property of the button
that was clicked, but it will work as long as the Strict option is off. As discussed in Chapter 2, we
must cast the sender object to a speci?c type (the Button type) and then call its Text method:
CType(sender, Button).Text
The code behind the digit buttons needs a few more lines. After certain actions, the display
should be cleared. After pressing one of the buttons that correspond to math operations, the dis-
play should be cleared in anticipation of the second operand. Actually, the display must be cleared
as soon as the ?rst digit of the second operand is pressed, and not as soon as the math operator
button is pressed. Likewise, the display should also be cleared after the user clicks the Equals
button. Revise the DigitClick event handler, as shown in Listing 4.3.
Listing 4.3: The DigitClick Event
Private Sub DigitClick(ByVal sender As System.Object,
ByVal e As System.EventArgs)
Handles bttn1.Click, bttn2.Click, bttn3.Click,
bttn4.Click, bttn5.Click, bttn6.Click,
bttn7.Click, bttn8.Click, bttn9.Click
If clearDisplay Then
lblDisplay.Text = ””
clearDisplay = False
End If
lblDisplay.Text = lblDisplay.Text + sender.text
End SubPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 141
BUILDING A CALCULATOR 141
The clearDisplay variable is declared as Boolean, which means it can take a True or False
value. Suppose that the user has performed an operation and the result is on the calculator’s
display. The user now starts typing another number. Without the If clause, the program would
continue to append digits to the number already on the display. This is not how calculators work.
When the user starts entering a new number, the display must be cleared. And our program uses
the clearDisplay variable to know when to clear the display.
The Equals button sets the clearDisplay variable to True to indicate that the display contains
the result of an operation. The DigitClick() subroutine examines the value of this variable each
time a new digit button is pressed. If the value is True, DigitClick() clears the display and then
prints the new digit on it. The subroutine also sets clearDisplay to False so that when the next
digit is pressed, the program won’t clear the display again.
What if the user makes a mistake and wants to undo an entry? The typical hand-held calculator
has no Backspace key. The Clear key erases the current number on the display. Let’s implement
this feature. Double-click the C button and enter the code of Listing 4.4 in its Click event.
Listing 4.4: Programming the Clear Button
Private Sub bttnClear Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles bttnClear.Click
lblDisplay.Text = ””
End Sub
Now we can look at the Period button. A calculator, no matter how simple, should be able to
handle fractional numbers. The Period button works just like the digit buttons, with one excep-
tion. A digit can appear any number of times in a numeric value, but the period can appear only
once. A number such as 99.991 is valid, but you must make sure that the user can’t enter numbers
such as 23.456.55. After a period is entered, this button must not insert another one. The code in
Listing 4.5 accounts for this.
Listing 4.5: Programming the Period Button
Private Sub bttnPeriodClick(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles bttnPeriod.Click
If lblDisplay.Text.IndexOf(”.”) >= 0 Then
Exit Sub
Else
lblDisplay.Text = lblDisplay.Text & ”.”
End If
End Sub
IndexOf is a method that can be applied to any string. The expression lblDisplay.Text
is a string (the text on the Label control), so we can call its IndexOf method. The expression
lblDisplay.Text.IndexOf(‘‘.’’) returns the location of the ?rst instance of the period in thePetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 142
142 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
caption of the Label control. If this number is zero or positive, the number entered contains a
period already, and another can’t be entered. In this case, the program exits the subroutine. If the
method returns -1, the period is appended to the number entered so far, just like a regular digit.
Check out the operation of the application. We have already created a functional user interface
that emulates a hand-held calculator with data-entry capabilities. It doesn’t perform any oper-
ations yet, but we have already created a functional user interface with only a small number of
statements.
Coding the Math Operations
Now we can move to the interesting part of the application: the coding of the math operations.
Let’s start by de?ning three variables:
Operand1 The ?rst number in the operation
Operator The desired operation
Operand2 The second number in the operation
When the user clicks one of the math symbols, the value on the display is stored in the variable
Operand1. If the user then clicks the Plus button, the program must make a note to itself that the
current operation is an addition and set the clearDisplay variable to True so that the user can
enter another value (the second value to be added). The symbol of the operation is stored in the
Operator variable. The user enters another value and then clicks the Equals button to see the
result. At this point, our program must do the following:
1. Read the value on the display into the Operand2 variable.
2. Perform the operation indicated by the Operator variable with the two operands.
3. Display the result and set the clearDisplay variable to True.
The Equals button must perform the following operation:
Operand1 Operator Operand2
Suppose that the number on the display when the user clicks the Plus button is 3342. The user
then enters the value 23 and clicks the Equals button. The program must carry out the addition:
3342 + 23
If the user clicked the Division button, the operation is as follows:
3342 / 23
Variables are local in the subroutines in which they are declared. Other subroutines have no
access to them and can’t read or set their values. Sometimes, however, variables must be accessed
from many places in a program. The variables Operand1, Operand2,and Operator,aswellasthe
clearDisplay variable, must be accessed from within more than one subroutine, so they must bePetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 143
BUILDING A CALCULATOR 143
declared outside any subroutine; their declarations usually appear at the beginning of the code
with the following statements:
Dim clearDisplay As Boolean
Dim Operand1 As Double
Dim Operand2 As Double
Dim Operator As String
These variables are called form-wide variables,orsimply form variables, because they are visible
from within any subroutine on the form. Let’s see how the program uses the Operator variable.
When the user clicks the Plus button, the program must store the value ‘‘+’’ in the Operator
variable. This takes place from within the Plus button’s Click event.
All variables that store numeric values are declared as variables of the Double type, which can
store values with the greatest possible precision. The Boolean type takes two values: True and
False. You have already seen how the clearDisplay variable is used.
With the variable declarations out of the way, we can now implement the operator buttons.
Double-click the Plus button and, in the Click event’s handler, enter the lines shown in Listing 4.6.
Listing 4.6: The Plus Button
Private Sub bttnPlus Click(...) Handles bttnPlus.Click
Operand1 = Convert.ToDouble(lblDisplay.Text)
Operator = ”+”
clearDisplay = True
End Sub
The variable Operand1 is assigned the value currently on the display. The Convert.ToDouble()
method converts its argument to a double value. The Text property of the Label control is a string.
The actual value stored in the Text property is not a number. It’s a string such as 428,whichis
different from the numeric value 428. That’s why we use the Convert.ToDouble method to con-
vert the value of the Label’s caption to a numeric value. The remaining buttons do the same, and I
won’t show their listings here.
After the second operand is entered, the user can click the Equals button to calculate the result.
When this happens, the code of Listing 4.7 is executed.
Listing 4.7: The Equals Button
Private Sub bttnEquals Click(...) Handles bttnEquals.Click
Dim result As Double
Operand2 = Convert.ToDouble(lblDisplay.Text)
Select Case Operator
Case ”+”
result = Operand1 + Operand2
Case ”-”Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 144
144 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
result = Operand1 - Operand2
Case ”*”
result = Operand1 * Operand2
Case ”/”
If Operand2 <> ”0” Then
result = Operand1 / Operand2
End Select
lblDisplay.Text = result.ToString
clearDisplay = True
End Sub
The result variable is declared as Double so that the result of the operation will be stored with
maximum precision. The code extracts the value displayed in the Label control and stores it in the
variable Operand2. It then performs the operation with a Select Case statement. This statement
compares the value of the Operator variable to the values listed after each Case statement. If
the value of the Operator variable matches one of the Case values, the following statement is
executed.
Division takes into consideration the value of the second operand, because if it’s zero, the
division can’t be carried out. The last statement carries out the division only if the divisor is not
zero. If Operand2 happens to be zero, nothing happens.
Now run the application and check it out. It works just like a hand-held calculator, and you
can’t crash it by specifying invalid data. We didn’t have to use any data-validation code in this
example because the user doesn’t get a chance to type invalid data. The data-entry mechanism is
foolproof. The user can enter only numeric values because there are only numeric digits on the
calculator. The only possible error is to divide by zero, and that’s handled in the Equals button.
Of course, users should be able to just type the numeric values; you shouldn’t force them
to click their digits. To intercept keystrokes from within your code, you must ?rst set the form’s
KeyPreview property to True. Each keystroke is reported to the control that has the focus at the
time and ?res the keystroke-related events: the KeyDown, KeyPress,and KeyUp events. Sometimes
we need to handle certain keystrokes from a central place, and we set the form’s KeyPreview
property to True, so that keystrokes are reported ?rst to the form and then to the control that
has the focus. We can intercept the keystrokes in the form’s KeyPress event and handle them
in this event handler. Insert the statements shown in Listing 4.8 in the form’s KeyPress event
handler.
Listing 4.8: Handling Keystrokes at the Form’s Level
Private Sub CalculatorForm KeyPress(...) Handles Me.KeyPress
Select Case e.KeyChar
Case ”1” : bttn1.PerformClick()
Case ”2” : bttn2.PerformClick()
Case ”3” : bttn3.PerformClick()
Case ”4” : bttn4.PerformClick()
Case ”5” : bttn5.PerformClick()
Case ”6” : bttn6.PerformClick()
Case ”7” : bttn7.PerformClick()Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 145
BUILDING A CALCULATOR 145
Case ”8” : bttn8.PerformClick()
Case ”9” : bttn9.PerformClick()
Case ”0” : bttn0.PerformClick()
Case ”.” : bttnPeriod.PerformClick()
Case ”C”, ”c” : bttnClear.PerformClick()
Case ”+” : bttnPlus.PerformClick()
Case ”-” : bttnMinus.PerformClick()
Case ”*” : bttnMultiply.PerformClick()
Case ”/” : bttnDivide.PerformClick()
Case ”=” : bttnEquals.PerformClick()
End Select
End Sub
This event handler examines the key pressed by the user and invokes the Click event handler
of the appropriate button by calling its PerformClick method. This method allows you to ‘‘click’’
a button from within your code. When the user presses the digit 3,theform’s KeyPress event
handler intercepts the keystrokes and emulates the click of the bttn3 button.
Using Simple Debugging Tools
Our sample applications work nicely and are quite easy to test and ?x if you discover something
wrong with them (but only because they’re very simple applications). As you write code, you’ll
soon discover that something doesn’t work as expected, and you should be able to ?nd out why
and then ?x it. The process of eliminating errors is called debugging, and Visual Studio provides
the tools to simplify the process of debugging. (These tools are discussed in detail in Appendix B.)
There are a few simple debugging techniques you should know, even as you work with simple
projects.
Open the MathCalculator project in the code editor and place the pointer in the line that calcu-
lates the difference between the two operands. Let’s pretend there’s a problem with this line, and
we want to follow the execution of the program closely to ?nd out what’s going wrong with the
application. Press F9, and the line will be highlighted in brown. This line has become a breakpoint:
As soon as it is reached, the program will stop.
Press F5 to run the application and perform a subtraction. Enter a number; then click the minus
button, and then another number, and ?nally the Equals button. The application will stop, and the
code editor will open. The breakpoint will be highlighted in yellow. You’re still in runtime mode,
but the execution of the application is suspended. You can even edit the code in break mode and
then press F5 to continue the execution of the application. Hover the pointer over the Operand1
and Operand2 variables in the code editor’s window. The value of the corresponding variable will
appear in a small ToolTip box. Move the pointer over any variable in the current event handler
to see its value. These are the values of the variables just prior to the execution of the highlighted
statement.
The result variable is zero because the statement hasn’t been executed yet. If the variables
involved in this statement have their proper values (if they don’t, you know that the problem is
prior to this statement and perhaps in another event handler), you can execute this statement by
pressing F10, which executes only the highlighted statement. The program will stop at the next
line. The next statement to be executed is the End Select statement.Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 146
146 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
Find an instance of the result variable in the current event handler, rest the pointer over it,
and you will see the value of the variable after it has been assigned a value. Now you can press
F10 to execute another statement or press F5 to return to normal execution mode.
You can also evaluate expressions involving any of the variables in the current event handler by
entering the appropriate statement in the Immediate window. The Immediate window appears at
the bottom of the IDE. If it’s not visible, open the Debug menu and chooseWindows  Immediate.
The current line in the command window is pre?xed with the greater-than symbol (reminiscent of
the DOS days). Place the cursor next to it and enter the following statement:
? Operand1 / Operand2
The quotient of the two values will appear in the following line. The question mark is just a
shorthand notation for the Print command. If you want to know the current value on the calcula-
tor’s display, enter the following statement:
? lblDisplay.Text
This statement requests the value of a control’s property on the form. The current value of
the Label control’s Text property will appear in the following line. You can also evaluate math
expressions with statements such as the following:
? Math.Log(3/4)
Log() is the logarithm function and a method of the Math class. With time, you’ll discover that
the Immediate window is a handy tool for debugging applications. If you have a statement with
a complicated expression, you can request the values of the expression’s individual components
and make sure they can be evaluated.
Now move the pointer over the breakpoint and press F9 again. This will toggle the breakpoint
status, and the execution of the program won’t halt the next time this statement is executed.
If the execution of the program doesn’t stop at a breakpoint, it means that the statement is
never reached. In this case, you must search for the bug in statements that are executed before the
breakpoint is reached. If you didn’t assign the proper value to the Operator variable, the Case
clause for the subtraction operation will never be reached. You should place the breakpoint at the
?rst executable statement of the Equal button’s Click event handler to examine the values of all
variables the moment this subroutine starts its execution. If all variables have the expected values,
you will continue testing the code forward. If not, you’d have to test the statements that lead to
this statement— the statements in the event handlers of the various buttons.
Another simple technique for debugging applications is to print the values of certain vari-
ables in the Immediate window. Although this isn’t a debugging tool, it’s common among VB
programmers (and very practical, I might add). Many programmers print the values of selected
variables before and after the execution of some complicated statements. To do so, use the state-
ment Debug.WriteLine followed by the name of the variable you want to print, or an expression:
Debug.WriteLine(Operand1)
This statement sends its output to the Immediate window. This is a simple technique, but it
works. You can also use it to test a function or method call. If you’re not sure about the syntax of aPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 147
BUILDING A CALCULATOR 147
function, pass an expression that contains the speci?c function to the Debug.WriteLine statement
as an argument. If the expected value appears in the Immediate window, you can go ahead and
use it in your code.
In the project’s folder, you will ?nd the MoreFeatures.txt document, which describes how
to add more features to the math calculator. Such features include the inversion of a number (the
1/x button), the negation of a number (the +/- button), and the usual math functions (logarithms,
square roots, trigonometric functions, and so on).
Exception Handling
Crashing this application won’t be as easy as crashing the LoanCalculator application. If you
start multiplying very large numbers, you won’t get an over?ow exception. Enter a very large
number by repeatedly typing the digit 9; thenmultiply this value with another equally large value.
When the result appears, click the multiplication symbol and enter another very large value. Keep
multiplying the result with very large numbers until you exhaust the value range of the Double
data type (that is, until the result is so large that it can’t be stored to a variable of the Double
type). When this happens, the string in?nity will appear in the display. This is Visual Basic’s way
of telling you that it can’t handle very large numbers. This isn’t a limitation of VB; it’s the way
computers store numeric values: They provide a limited number of bytes for each variable. (We
discussed oddities such as in?nity in Chapter 2.)
You can’t create an over?ow exception by dividing a number by zero, either, because the code
will not even attempt to carry out this calculation. In short, the MathCalculator application is
pretty robust. However, we can’t be sure that users won’t cause the application to generate an
exception, so we must provide some code to handle all types of errors.
Exceptions versus Errors
Errors are now called exceptions. You can think of them as exceptions to the normal (or intended)
?ow of execution. If an exception occurs, the program must execute special statements to handle
the exception — statements that wouldn’t be executed normally. I think they’re called exceptions
because error is a word nobody likes, and most people can’t admit they wrote code that contains
errors. The term exception can be vague. What would you rather tell your customers: that the appli-
cation you wrote has errors or that your code has raised an exception? You may not have noticed
it, but the term bug is not used as frequently anymore; bugs are now called known issues.Theterm
debugging, however, hasn’t changed yet.
How do you prevent an exception raised by a calculation? Data validation won’t help. You
just can’t predict the result of an operation without actually performing the operation. And if the
operation causes an over?ow, you can’t prevent it. The answer is to add a structured exception han-
dler. Most of the application’s code is straightforward, and you can’t easily generate an exception
for demonstration purposes. The only place where an exception may occur is the handler of the
Equals button, where the calculations take place. This is where we must add an exception handler.
The outline of the structured exception handler is the following:
Try
{ statements block}
Catch ExceptionPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 148
148 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
{ handler block}
Finally
{ clean-up statements block}
End Try
The program will attempt to perform the calculations, which are coded in the statements block.
If the program succeeds, it continues with the cleanup statements. These statements are mostly
cleanup code, and the Finally section of the statement is optional. If missing, the program exe-
cution continues with the statement following the End Try statement. If an error occurs in the
?rst block of statements, the Catch Exception section is activated, and the statements in the
handler block are executed.
The Catch block is where you handle the error. There’s not much you can do about errors that
result from calculations. All you can do is display a warning and give the user a chance to change
the values. There are other types of errors, however, that can be handled much more gracefully.
If your program can’t read a ?le from a CD drive, you can give the user a chance to insert the CD
and retry. In other situations, you can prompt the user for a missing value and continue. If the
application attempts to write to a read-only ?le, for example, chances are that the user speci?ed
a ?le on a CD drive, or a ?le with its read-only attribute set. You can display a warning, exit the
subroutine that saves the data, and give the user a chance to either select another ?lename or
change the read-only attribute of the selected ?le.
In general, there’s no unique method to handle all exceptions. You must consider all types
of exceptions that your application may cause and handle them on an individual basis. What’s
important about error handlers is that your application doesn’t crash; it simply doesn’t perform
the operation that caused the exception (this is also known as the offending operation,or offending
statement) and continues.
The error handler for the MathCalculator application must inform the user that an error
occurred and abort the calculations — not even attempt to display a result. If you open the Equals
button’s Click event handler, you will ?nd the statements detailed in Listing 4.9.
Listing 4.9: Revised Equals Button
Private Sub bttnEquals Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles bttnEquals.Click
Dim result As Double
Operand2 = Convert.ToDouble(lblDisplay.Text)
Try
Select Case Operator
Case ”+”
result = Operand1 + Operand2
Case ”-”
result = Operand1 - Operand2
Case ”*”
result = Operand1 * Operand2
Case ”/”
If Operand2 <> ”0” Then result = Operand1 / Operand2
End Select
lblDisplay.Text = resultPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 149
THE BOTTOM LINE 149
Catch exc As Exception
MsgBox(exc.Message)
result = ”ERROR”
Finally
clearDisplay = True
End Try
End Sub
Most of the time, the error handler remains inactive and doesn’t interfere with the operation
of the program. If an error occurs, which most likely will be an over?ow error, the error-handling
section of the Try...Catch...End Try statement will be executed. This code displays a message
box with the description of the error, and it also displays the string ERROR on the calculator’s
display. The Finally section is executed regardless of whether an exception occurred. In this
example, the Finally section sets the clearDisplay variable to True so that when another digit
button is clicked, a new number will appear on the display.
The BottomLine
Design graphical user interfaces. A Windows application consists of a graphical user inter-
face and code. The interface of the application is designed with visual tools and consists of
controls that are common to all Windows applications. You drop controls from the Toolbox
window onto the form, size and align the controls on the form, and ?nally set their properties
through the Properties window. The controls include quite a bit of functionality right out of the
box, and this functionality is readily available to your application without a single line of code.
Master It Describe the process of aligning controls on a form.
Program events. Windows applications follow an event-driven model:We code the events to
which we want our application to respond. The Click events of the various buttons are typical
events to which an application reacts. You select the actions to which you want your applica-
tion to react and program these events accordingly.
When an event is ?red, the appropriate event handler is automatically invoked. Event han-
dlers are subroutines that pass two arguments to the application: the sender object (which is an
object that represents the control that ?red the event) and the e argument (which carries addi-
tional information about the event).
Master It How will you handle certain keystrokes regardless of the control that receives
them?
Write robust applications with error handling. Numerous conditions can cause an applica-
tion to crash, but a professional application should be able to detect abnormal conditions and
handle them gracefully. To begin with, you should always validate your data before you attempt
to use them in your code. A well-known computer term is ‘‘garbage in, garbage out’’, which
means you shouldn’t perform any calculations on invalid data.
Master It How will you execute one or more statements in the context of a structured
exception handler?Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 150Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 151
Chapter 5
The Vista Interface
With the introduction of Windows Vista and the .NET Framework 3.5, Microsoft has overhauled
its entire graphical presentation technology. The new application programming interface (API)
is known as the Windows Presentation Foundation (WPF). WPF is one of the core technologies in
the .NET Framework 3.5 and is integrated into Windows Vista. WPF is also supported on
Windows XP.
WPF offers a whole new approach to developing graphical user interfaces (UIs) for the
Windows platform. WPF is designed to take advantage of the graphics engines and display
capabilities of the modern computer, and is vector based and resolution independent. This means
that your UIs automatically scale depending on the size and resolution of the user’s screen. This
is enhanced by the ability to place objects using relative positioning (so that objects sit relative to
other objects) rather than the more traditional absolute positioning used in WinForms.
You can create UIs for traditional desktop applications as well as for web-based applications
with WPF. Although initially limited to Internet Explorer for web-based applications, the
introduction of Microsoft’s Silverlight enablesWPF to go cross-browser. You can ?nd more
information on Silverlight at www.microsoft.com/silverlight/.
WPF offers the ability to truly separate the UI from the business logic of your application.
Although we will be working with WPF in Visual Studio 2008, there are additional Microsoft
and other third-party tools for creating UIs in WPF. In particular, Microsoft’s Expression Blend
(as part of Expression Studio) offers a powerful graphical tool for creating user interface designs.
More information on Microsoft’s Expression products can be obtained from www.microsoft.com/
expression.
In this chapter, you will learn how to do the following:
? Create a simple WPF application
? Data-bind controls in WPF
? Use a data template to control data presentation
IntroducingXAML
Extensible Application Markup Language (XAML) is the XML language used to describe the user
interface de?nition. When you create a WPF-based UI, it is written into an XAML ?le. You can
create and edit XAML with a simple text editor such as Notepad if you wish, or use a more
sophisticated tool such as XML Notepad 2007, available from www.microsoft.com/downloads/
details.aspx?familyid = 72 d6aa49-787 d-4118-ba5f-4f30fe913628. When working
with Visual Studio 2008, you have the option to write the code behind your UIs, creatingPetroutsos c05.tex V2 - 01/28/2008 12:46pm Page 152
152 CHAPTER 5 THE VISTA INTERFACE
functionality along with your user interface; you also have the ability to create and attach any
of the full range of resources available through Visual Studio.
Documents created with XAML have the ?le extension .xaml. In Visual Studio 2008, the design
surface for XAML documents is a tabbed panel where you can easily swap between the graphical
user interface (GUI) view and source code view of your work.
When projects containing XAML ?les are compiled, the XAML is converted into Binary
Application Markup Language (BAML) before being included in the assembly. The main
purpose of this is to improve application performance because compiled BAML will process much
faster than raw XAML. From a development point of view, it is not necessary to have an intimate
understanding of BAML because you will be working mainly in XAML. It is, however, possible
to manually compile your XAML into BAML by using the Windows Application Compiler that
ships with the .NET Framework, if you are so inclined.
XAML is very ?exible, and can be used to represent everything from layout panels, controls,
and graphics to 3D representations and animations.
The following code snippet gives the basic format of an XAML page. This is the typical code
skeleton that is generated when you create a newWPF window in Visual Studio 2008. Most of the
formatting and layout code will go between the <Grid> tags.
<Window x:Class=”Window3”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Window3” Height=”300” Width=”300”>
<Grid>
</Grid>
The following XAML snippet demonstrates the representation for a TextBox control. Normally,
if we were to drop a TextBox control onto the XAML page shown in the preceding code, the
following code would appear between the <Grid> tags:
<TextBox Height=”21” Margin=”56,106,102,0” Name=”TextBox1”
VerticalAlignment=”Top” BorderThickness=”2”>
<TextBox.BitmapEffect>
<EmbossBitmapEffect />
</TextBox.BitmapEffect>
</TextBox>
This example of the TextBox control not only includes some basic properties for the
control such as Name and Height, but also includes a more sophisticated visual effect property:
EmbossBitmapEffect.
You can also use XAML to generate simple shapes (primitives) such as circles and rectangles.
The following code snippet demonstrates how you can use XAML to generate a simple rectangle:
<Rectangle Height=”74” Margin=”20,0,64,27” Name=”Rectangle1”
Stroke=”Black” VerticalAlignment=”Bottom” Fill=”Red”>
<Rectangle.BitmapEffect>
<DropShadowBitmapEffect />
</Rectangle.BitmapEffect>
</Rectangle>Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 153
INTRODUCING THE WPF CONTROLS 153
In this example, the rectangle has a red ?ll color and black border. We have also included a
drop shadow effect. These effects were all achieved by simply modifying the Properties window
for the TextBox and Rectangle controls. However, many of WPF’s properties are available to be
used across virtually all the controls, even if they do not appear in the Properties window. For
example, you can rewrite the code snippet for the rectangle to modify the Fill property to create
a linear gradient from red to blue, as follows:
<Rectangle Height=”74” Margin=”20,0,64,27” Name=”Rectangle1”
Stroke=”Black” VerticalAlignment=”Bottom” >
<Rectangle.BitmapEffect>
<DropShadowBitmapEffect />
</Rectangle.BitmapEffect>
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Color=”Red” Offset=”0”/>
<GradientStop Color=”Blue” Offset=”1”/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
You cannot achieve this effect through the available settings in the Properties window for the
Rectangle — it needs to be typed directly into the XAML.
A number of these additional properties can be picked up from using Microsoft’s Expression
Blend tool to create XAML pages and examining the code generated. Refer to the ‘‘Expression Blend
Overview’’ section later in this chapter.
Introducing theWPF Controls
When you ?rst open aWPF project in Visual Studio 2008, you will notice that the Toolbox contains
a very similar set of controls to those found in the other development environments. However,
although most of the controls appear similar, they can behave very differently.
This section introduces some of the core controls and lists some of the fundamental differences
between them and their traditional Windows counterparts.
One of the ?rst things you will notice when opening up Visual Studio 2008 to a WPF
page is that the page has a magni?cation control in the top-left corner, and resizing the page
automatically resizes any controls on the page as well. Controls stay placed on the page relative
to each other, rather than ?xed into some position relative to the page itself. Controls also behave
differently from the traditional Windows Forms model as you move them around the page, and
the underlying form (or rather window) itself looks a little different.
To create a newWPF project, choose File  New Project. In the New Project dialog box, choose
WPF Application. Keep the default name and click OK. In keeping with the idea that you are
designing an interface separated from the business logic of your application, the default designer
opens to Window1.xaml.
If you examine the Toolbox on the left side of Visual Studio, you will see many familiar items
from the Standard Toolbox there. However, as you will see, some of them exhibit different
behavior. Note that all the WPF controls differ from their WinForms cousins in the wide rangePetroutsos c05.tex V2 - 01/28/2008 12:46pm Page 154
154 CHAPTER 5 THE VISTA INTERFACE
of style and formatting properties that are available to them. Table 5.1 gives a brief overview of
the roles of some of the new controls and some changes in the existing controls. This is not an
exhaustive list of the controls, but it does look at some key ones.
Table 5.1: The WPF Standard Controls
WPF Control Features
Border Creates a border around an object. A broad range of properties exists to enable you to
change the appearance of the border.
Button Apart from the obvious and extensive range of style properties common to virtually all
the WPF controls, the Button control looks and behaves as you would expect.
Double-clicking the control opens to a code skeleton for the Button Click event
handler in code-behind (typically Window1.xaml.vb).
Grid De?nes a tabular area of columns and rows. Useful for displaying data. One of the main
layout controls.
Label Displays data via the Content property.
StackPanel Arranges child components (other controls) either horizontally or vertically. One of the
main layout controls.
TextBox Unlike the Label control, TextBox continues to use the Text property to display data.
Canvas Provides an area where you can explicitly position controls relative to the position of
the Canvas control.
DockPanel Provides a space where you arrange controls vertically or horizontally relative to each
other. One of the main layout controls.
InkCanvas Sets up a drawing surface within your application.
MediaElement Contains audio or video content.
TextBlock Displays small chunks of text.
UniformGrid Creates a grid with ?xed cell size.
WrapPanel Displays elements sequentially (depending on the orientation property) and wraps to
the next line where necessary.
Next we will create a couple of simple applications to demonstrate the functionality of the
WPF controls.
Simple ‘‘Hello World’’ WPF Application
In this section, you will come to grips with setting up a basic WPF application and using the
controls by creating a simple ‘‘Hello World’’ application.Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 155
INTRODUCING THE WPF CONTROLS 155
Open Visual Studio 2008 and complete the following steps:
1. Choose File  New Project. From the New Project dialog box, chooseWPF Application and
rename the project MyWpfApplication1. Click OK.
2. The Designer should open to Window1.xaml in Split mode (Design And Source Code). If
you need more space, you can collapse the bottom pane (usually the XAML pane, although
this can be swapped around) and tab between the two views.
3. Drag a Button control and a Label control onto your form.Move the controls around on the
form to see how the positioning and resize properties work. The <Grid> tags in XAML
view should now contain the following (without the line breaks and with variations in the
Height and Margin properties):
<Grid>
<Button Height=”23” HorizontalAlignment=”Left” Margin=”43,19,0,0”
Name=”Button1” VerticalAlignment=”Top” Width=”75”>Button</Button>
<Label Height=”23” Margin=”49,83,109,0” Name=”Label1”
VerticalAlignment=”Top”>Label</Label>
</Grid>
4. In Design mode, double-click the Button control to enter code-behind. This should open
up to Window1.xaml.vb with a Button1 Click event code skeleton. Compete the
Button1 Click event with the following code:
Private Sub Button1 Click(ByVal sender As System.Object, ByVal e As
System.Windows.RoutedEventArgs) Handles Button1.Click
Label1.Content = ”Hi There!”
End Sub
Press F5 to run the application. Figure 5.1 illustrates the running application in the Designer
window after Button1 has been clicked.
Figure 5.1
The running
MyWpfApplicationPetroutsos c05.tex V2 - 01/28/2008 12:46pm Page 156
156 CHAPTER 5 THE VISTA INTERFACE
Simple Drawing Program
This next example illustrates how you can easily create a simple drawing program in WPF with a
few controls and very little code. In this example, we will use the InkCanvas control to create the
drawing surface. The control will be added at runtime, enabling us to dynamically alter properties
such as pen color. We will use a ComboBox control to set the pen color and a Button control to
clear the screen.
Begin by opening Visual Studio 2008 and choosing File  New Project. Then complete the
following steps:
1. From the New Project dialog box, chooseWPF Application and rename the project
WpfDraw. Click OK.
2. This should open Window.xaml in Split mode. From the Standard Toolbox, drop a
StackPanel control onto the Window1 form on the Design surface and set the Margin
property of the StackPanel (in the Properties box) to ‘‘0,0,0,25’’. This Margin property will
extend the StackPanel to the top, left, and right borders of the form. The margin will leave
a 25-pixel (px) gutter at the bottom of the form, where we can place a Button control. Keep
the default name for the control of StackPanel1.
3. Set the VerticalAlignment property of StackPanel1 to Top.
4. From the Standard Toolbox, drop a ComboBox control into the StackPanel1 control. In the
Properties window for the ComboBox control, set the HorizontalAlignment property to
Left. Keep the default name of ComboBox1. The ComboBox should be located in the top-left
corner of Window1.
5. In the XAML window, adjust the entry for ComboBox1 to read as shown here. Keep any
of the illustrated line breaks on a single line. This will create the pen color items in the
ComboBox.
<ComboBox Height=”25” Name=”ComboBox1” Width=”120”
HorizontalAlignment=”Left”>
<ComboBoxItem IsSelected=”True”>Red Pen</ComboBoxItem>
<ComboBoxItem>Green Pen</ComboBoxItem>
<ComboBoxItem>Blue Pen</ComboBoxItem>
</ComboBox>
6. From the Standard Toolbox, drop a Button control onto Window1 in the space under
the StackPanel. Keep the default name of Button1. In the Properties window for Button1,
set the Height property to 25, the VerticalAlignment property to Bottom, the
HorizontalAlignment to Left, and the Content property to Clear Screen.
7. The ?nal XAML markup for Button1 should be similar to the following snippet (ignore the
line break):
<Button Height=”25” Name=”Button1” Width=”75” HorizontalAlignment=”Left”
VerticalAlignment=”Bottom”>Clear Screen</Button>Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 157
INTRODUCING THE WPF CONTROLS 157
Listing 5.1 gives the full XAML markup for this stage of the development.
Listing 5.1: Full XAMLMarkup forWpfDraw
<Window x:Class=”Window1”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Window1” Height=”300” Width=”300”>
<Grid>
<StackPanel Name=”StackPanel1” Margin=”0,0,0,25”
VerticalAlignment=”Top”>
<ComboBox Height=”25” Name=”ComboBox1” Width=”120”
HorizontalAlignment=”Left”>
<ComboBoxItem IsSelected=”True”>Red Pen</ComboBoxItem>
<ComboBoxItem>Green Pen</ComboBoxItem>
<ComboBoxItem>Blue Pen</ComboBoxItem>
</ComboBox>
</StackPanel>
<Button Height=”25” Name=”Button1” Width=”75”
HorizontalAlignment=”Left” VerticalAlignment=”Bottom”>
Clear Screen</Button>
</Grid>
</Window>
The next step is to add the code-behind for the application. In the Design window,
double-click the Button1 control to enter code-behind (Window1.xaml.vb). Continue with the
following steps:
1. Directly under the Class Window declaration, add the following line of code to declare an
instance of the InkCanvas control:
Dim myink As New InkCanvas
2. Select the Window1 Loaded code skeleton (choose Class Name  Window Events, and
Method Name  Loaded).
3. Add the following line of code to the Window Loaded skeleton. This will add the InkCanvas
control to the StackPanel control in Window1 when the window loads:
StackPanel1.Children.Add(myink)
4. In the Button1 Click event handler, add the following line of code. This will enable the
user to erase any drawings he has created:
myink.Strokes.Clear()Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 158
158 CHAPTER 5 THE VISTA INTERFACE
5. Selectthecodeskeletonfor ComboBox1 SelectionChanged and add the following snippet.
This code will set the pen color of the InkCanvas control depending on the selected color in
the ComboBox:
If ComboBox1.SelectedIndex = 0 Then
myink.DefaultDrawingAttributes.Color = Colors.Red
ElseIf ComboBox1.SelectedIndex = 1 Then
myink.DefaultDrawingAttributes.Color = Colors.Green
ElseIf ComboBox1.SelectedIndex = 2 Then
myink.DefaultDrawingAttributes.Color = Colors.Blue
End If
Listing 5.2 gives the full code-behind listing forWpfDraw.
Listing 5.2: Full Code-Behind Listing forWpfDraw
Class Window1
Dim myink As New InkCanvas
Private Sub Window1 Loaded(ByVal sender As Object, ByVal e As
System.Windows.RoutedEventArgs) Handles Me.Loaded
StackPanel1.Children.Add(myink)
End Sub
Private Sub Button1 Click(ByVal sender As System.Object,
ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
myink.Strokes.Clear()
End Sub
Private Sub ComboBox1 SelectionChanged(ByVal sender As
System.Object, ByVal e As
System.Windows.Controls.SelectionChangedEventArgs) Handles
ComboBox1.SelectionChanged
If ComboBox1.SelectedIndex = 0 Then
myink.DefaultDrawingAttributes.Color = Colors.Red
ElseIf ComboBox1.SelectedIndex = 1 Then
myink.DefaultDrawingAttributes.Color = Colors.Green
ElseIf ComboBox1.SelectedIndex = 2 Then
myink.DefaultDrawingAttributes.Color = Colors.Blue
End If
End Sub
End ClassPetroutsos c05.tex V2 - 01/28/2008 12:46pm Page 159
DATA-BINDING WPF CONTROLS 159
Press F5 to test the application. Figure 5.2 illustrates the running application.
Figure 5.2
The running WpfDraw
Data-BindingWPF Controls
The ability to bind WPF controls to external (and internal) data sources is an important aspect of
being able to separate UI design from business logic and functionality.
WPF controls can be bound to data sources as well as style sources. This way, you can set
up a set of styles for your application and then bind each control to those styles, thus enabling
centralized management of the look and feel of your user interfaces.
There are many options available to the developer when connecting to data with WPF. WPF
offers a ?exible and powerful framework for data connectivity and management. A full discussion
is beyond the scope of this chapter; refer to the Microsoft documentation for a more detailed view.
The article titled ‘‘Data Binding Overview’’ (search the Help documentation) is a good start.
In this section, you will see how to carry out three basic data-binding tasks withWPF. You will
bind controls to an array, to a data template, and to a database.
Data-Binding Example 1: Binding to an Array and a Data Template
In this example, we will set up a simple class called Contacts to hold Surname and FirstName
elements. We will then use an array of contacts to hold some data that can be accessed from our
XAML page. The presentation of the data in the XAML page will be de?ned by a data template.
To keep things simple, we will do everything within the one project.
Begin by opening Visual Studio 2008 and choosing File  New Project. Then complete the
following steps:
1. From the New Project dialog box, chooseWPF Application and rename the project
WpfBinding1. Click OK.
2. We will begin by creating the Contacts class. You should be open to Window1.xaml in
Split view. From Solution Explorer, click the View Code icon to switch to code-behindPetroutsos c05.tex V2 - 01/28/2008 12:46pm Page 160
160 CHAPTER 5 THE VISTA INTERFACE
(Window1.xaml.vb). Alternatively, you can double-click on the Window1 heading in the
Window1 form in the Designer.
3. In code-behind, add the following code for the Contacts class directly under the Class
Window1 declaration. The Contacts class has two properties: FirstName and Surname.You
will ?nd that as you type the following code, much of the code skeleton is automatically
generated by Visual Studio:
Private Class contacts
Dim name As String
Dim surname As String
Public Sub New(ByVal FirstName As String, ByVal Surname As String)
name = FirstName
surname = Surname
End Sub
Public ReadOnly Property FirstName() As String
Get
Return name
End Get
End Property
Public ReadOnly Property Surname() As String
Get
Return surname
End Get
End Property
End Class
4. Select the Window1 Loaded code skeleton (choose Class Name  Window Events, and
Method Name  Loaded).
5. Add the following code to the Window1 Loaded skeleton. This code declares an array of
contacts named person and adds some names to it. The ?nal line uses the DataContext
property of Window1 to bind the person array to Window1.
Dim person As New ArrayList
person.Add(New contacts(”Fred”, ”Bloggs”))
person.Add(New contacts(”Betty”, ”Smith”))
person.Add(New contacts(”Jane”, ”Doe”))
person.Add(New contacts(”Bill”, ”Jones”))
person.Add(New contacts(”Jenny”, ”Day”))
Me.DataContext = person
This completes the code-behind for this project.
The next set of steps involves setting up the XAML for the project. For this example, we will
write directly to the XAML code. You will ?nd that as you continue to work with WPF, it is often
easier to work directly with the XAML and use the Designer only to provide a visual check that
everything is going together as it should.Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 161
DATA-BINDING WPF CONTROLS 161
1. Switch back to XAML view for Window1.xaml. The default XAML should look similar to
the following snippet:
<Window x:Class=”Window4”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Window4” Height=”300” Width=”300” Name=”Window1”>
<Grid>
</Grid>
</Window>
2. Our key areas of interest here are the <Grid> tags. Add a name attribute to the <Grid>
tag to read <Grid Name = ‘‘MyGrid’’>.
3. The next step is to add the data template. This is contained within <GridResources> tags,
which sit within the <Grid Name = ‘‘MyGrid’’> tags. Create the following snippet:
<Grid.Resources>
<DataTemplate x:Key=”NameStyle”>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”60” />
<ColumnDefinition Width=”*” />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column=”0” Text=”{Binding Path=FirstName}”/>
<TextBlock Grid.Column=”1” Text=”{Binding Path=Surname}”/>
</Grid>
</DataTemplate>
</Grid.Resources>
The purpose of this code is to de?ne a data template that can be referenced by using its key,
NameStyle. The data template de?nes a grid with two columns — the ?rst column is 60px
wide, and the second column occupies the remainder of the available space. Attached to
the ?rst column is a TextBlock control that has its Text property bound to the FirstName
element of the person array that we declared in the code-behind. Remember that we used
the DataContext property to attach person to Window1. Similarly, the second TextBlock
has its Text property bound to Surname, and the control is attached to the second column
of the grid.
4. Add the following snippet directly below the <Grid.Resources >...< /Grid.Resources>
section. Do not include the line breaks:
<TextBlock Text=”Current Selection = ” />
<TextBlock Text=”{Binding Path=FirstName}” Margin=”110,0,0,0” />
<ListBox Margin=”0,40,0,0”
ItemTemplate=”{StaticResource NameStyle}” ItemsSource=”{Binding} ”
IsSynchronizedWithCurrentItem=”true” Name=”ListBox1” />Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 162
162 CHAPTER 5 THE VISTA INTERFACE
The purpose of this code is to provide the content controls (two TextBlocks and a ListBox)
to present the data on the window. We have used the Margin property to control the layout of
the controls. In this instance, the use of Margin is suitable because we wish to simplify the code,
but laying out in this manner is limiting if you wish to alter text content or styles at a later date.
There are a number of alternative methods for achieving the same layout using combinations of
the layout controls, which provide a little more ?exibility. For example, the following snippet
achieves the same result by using Grid rows and a nested StackPanel control to manage the layout
of the content controls:
<Grid.RowDefinitions>
<RowDefinition Height=”40” />
<RowDefinition Height=”*” />
</Grid.RowDefinitions>
<StackPanel Orientation=”Horizontal” Grid.Row=”0”>
<TextBlock Text=”Current Selection = ” />
<TextBlock Text=”{Binding Path=FirstName}”/>
</StackPanel>
<ListBox Grid.Row=”1”
ItemTemplate=”{StaticResource NameStyle}” ItemsSource=”{Binding} ”
IsSynchronizedWithCurrentItem=”true” Name=”ListBox1” />
The second TextBlock uses Binding to data-bind the control to the FirstName ?eld of the
person array. The ListBox uses the StaticResource statement to bind to the NameStyle data
layout. By simply writing Binding, we indicate that the control is bound to the data source (in this
case, the person array) attached to the parent container (Window1). In this way, the ListBox will
display the full set of records in the array. The NameStyle data layout ensures that each record
is displayed as a FirstName, Surname combination by using two TextBlock controls set up in
adjacent Grid columns.
Listing 5.3 gives the full XAML source for this project. Delete the line breaks.
Listing 5.3: Full XAML Source Code for theWpfBinding1 Project
<Window x:Class=”Window1”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Window1” Height=”300” Width=”300”>
<Grid Name=”myGrid”>
<Grid.Resources>
<DataTemplate x:Key=”NameStyle”>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”60” />
<ColumnDefinition Width=”*” />
</Grid.ColumnDefinitions>Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 163
DATA-BINDING WPF CONTROLS 163
<TextBlock Grid.Column=”0” Text=”{Binding
Path=FirstName}”/>
<TextBlock Grid.Column=”1”
Text=”{Binding Path=Surname}”/>
</Grid>
</DataTemplate>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height=”40” />
<RowDefinition Height=”*” />
</Grid.RowDefinitions>
<StackPanel Orientation=”Horizontal” Grid.Row=”0”>
<TextBlock Text=”Current Selection = ” />
<TextBlock Text=”{Binding Path=FirstName}”/>
</StackPanel>
<ListBox Grid.Row=”1”
ItemTemplate=”{StaticResource NameStyle}”
ItemsSource=”{Binding} ” IsSynchronizedWithCurrentItem=”true”
Name=”ListBox1” />
</Grid>
</Window>
Finish up by testing the application. Making a selection in the list should be re?ected in the
Current Selection TextBlock. The running application is shown in Figure 5.3.
Figure 5.3
The running
WpfBinding1 projectPetroutsos c05.tex V2 - 01/28/2008 12:46pm Page 164
164 CHAPTER 5 THE VISTA INTERFACE
Data-Binding Example 2: Binding to a Database
In this next example, we will see how to connect the WPF page created in the previous example
to a database. This project not only demonstrates the technique of connecting to a database, but
also emphasizes the way that WPF enables the developer to separate the user interface aspects of
a project from the data and business logic.
Begin by opening the previous project,WpfBinding1. Continue with the following steps:
1. First, we will use SQL Server Express to create a new database. From the Project menu,
choose Add New Item.
2. From the Add New Item dialog box, select Service-Based Database. Name the database
Contacts.mdf and click the Add button.
3. You will be presented with the Data Source Con?guration Wizard with a message saying
that the database does not contain any objects. Keep the default name: ContactsDataSet.
Click the Finish button to create an empty dataset and close the wizard. We will return to
the dataset later to complete it.
4. Over in the Toolbox area, click the Server Explorer tab. Under the Data Connections tree,
expand the entry for Contacts.mdf. Right-click the Tables entry and choose Add New
Table from the context menu.
5. The new database table should now be open in the Designer window. Set up the database
?eldsasshowninTable5.2.
Table 5.2: Database Fields for Contacts.mdf
Column Name Data Type
ID nchar(10)
FirstName nchar(10)
Surname nchar(10)
6. Right-click the ID entry and choose Set Primary Key from the context menu.
7. Click the Save button on the Standard Toolbar. A Choose Name dialog box should
open for the table. Enter Customers and click OK. The Customers table should now be
visible in the Tables entry of Contacts.mdf in the Data Connections tree in
Server Explorer.
8. Over in Solution Explorer, double-click the entry for ContactsDataSet.xsd to open the
dataset in the Designer window.
9. Return to the Server Explorer. Drag the Customers table from the Data Connections tree in
Server Explorer onto the Design surface for the dataset. This should set up the Customers
DataTable in the dataset and also establish a CustomersTableAdapter.Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 165
DATA-BINDING WPF CONTROLS 165
10. Save your work.
11. In Server Explorer, right-click the Customers table in the Data Connections tree and choose
Show Table Data.
12. Enter the data from Table 5.3 into the Customers table.
Table 5.3: Data Entries for Customers Table
ID FirstName Surname
1 Fred Bloggs
2 Wilma Smith
3 Bill Green
13. You are now ready to attach the database to Window1.xaml. We will do this in
code-behind for Window1.xaml. Double-click the entry for Window1.xaml.vb in
Solution Explorer.
14. Add the following snippet to the code screen just under the entry for Class Window1.
This code declares instances of the ContactsDataSet and the CustomersTableAdapter.
Dim myDataset As New ContactsDataSet
Dim myCustomersAdapter As New
ContactsDataSetTableAdapters.CustomersTableAdapter
15. In the sub for Window1 Loaded, add the following code snippet. The purpose of the
?rst of these lines is to use the myCustomersAdapter to load the data from the Contacts
database into myDataset. The second line attaches the dataset as the data source
for Window1:
myCustomersAdapter.Fill(myDataset.Tables(”Customers”))
Me.DataContext = myDataset.Tables(”Customers”)
16. Finally, comment out (or delete) the line of code attaching the original person array to
Window1: ‘Me.DataContext = person.
The ?eld names in the dataset are the same as the ones used in the original array, so we
can run the application without needing to change Window1.xaml. Note that you can now
delete or comment out any of the code that we originally used to create the person array or
contacts class.
This project is now completed. Test the application by pressing F5 or clicking the green arrow.
The running version should appear as shown in Figure 5.4.Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 166
166 CHAPTER 5 THE VISTA INTERFACE
Figure 5.4
The updated
WpfBinding1 application
Creating aWPF BrowserApplication
WPF applications can also be displayed as web applications. The XAML for such an application is
virtually identical to its desktop equivalent. You may have to make only some minor layout and
presentation changes to optimize the appearance of your application in a web browser window as
opposed to on the desktop.
The main limitation to this technology is that such applications are restricted to Internet
Explorer 6 and above unless you create a Silverlight implementation. Microsoft is currently
releasing Silverlight as a cross-platform, cross-browser plug-in. Refer to www.microsoft.com
/silverlight for more information.
In this example, we will create a WPF browser version of the simple drawing program,
WpfDraw, that we created earlier in this chapter.
1. Start Visual Studio 2008 and begin by choosing File  New Project.
2. In the New Project dialog box, chooseWPF Browser Application. Keep the default name of
WpfBrowserApplication1 and click OK.
3. This will open up Page1.xaml in Split mode. Switch to XAML view and add the code from
Listing 5.4 (without the line breaks). This is essentially the same markup that we used for
WpfDraw earlier in the chapter, with some layout modi?cations to control the distribution
of the controls and make the application a little more presentable in a web browser
window.
Listing 5.4: XAML for WpfBrowserApplication1
<Page x:Class=”Page1”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Page1”>
<Grid>
<StackPanel Margin=”25”>
<StackPanel Name=”StackPanel1” Margin=”0,0,0,0”Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 167
CREATING A WPF BROWSER APPLICATION 167
VerticalAlignment=”Top”>
<ComboBox Height=”25” Name=”ComboBox1” Width=”120”
HorizontalAlignment=”Left”>
<ComboBoxItem IsSelected=”True”>Red Pen
</ComboBoxItem>
<ComboBoxItem>Green Pen</ComboBoxItem>
<ComboBoxItem>Blue Pen</ComboBoxItem>
</ComboBox>
</StackPanel>
<Button Height=”25” Name=”Button1” Width=”75”
HorizontalAlignment=”Left” VerticalAlignment=”Bottom”>Clear Screen
</Button>
</StackPanel>
</Grid>
</Page>
4. The code-behind forWpfBrowserApplication1 remains virtually unchanged from
WpfDraw as well. Use the Solution Explorer to switch to code-behind (Page1.xaml.vb)
and add the code from Listing 5.5. The only difference with this code from the original
WpfDraw is that we add some additional layout and design properties to myink in the
Page1 Loaded sub to again help with presentation in the web browser window.
Listing 5.5: Code-Behind for WpfBrowserApplication1
Class Page1
Dim myink As New InkCanvas
Private Sub Page1 Loaded(ByVal sender As Object,
ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
StackPanel1.Children.Add(myink)
myink.Background = Brushes.Cornsilk
myink.HorizontalAlignment = Windows.HorizontalAlignment.Left
myink.Height = 400
myink.Width = 400
End Sub
Private Sub Button1 Click(ByVal sender As System.Object,
ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
myink.Strokes.Clear()
End Sub
Private Sub ComboBox1 SelectionChanged(ByVal sender As
System.Object, ByVal e As
System.Windows.Controls.SelectionChangedEventArgs) Handles
ComboBox1.SelectionChanged
If ComboBox1.SelectedIndex = 0 Then
myink.DefaultDrawingAttributes.Color = Colors.Red
ElseIf ComboBox1.SelectedIndex = 1 Then
myink.DefaultDrawingAttributes.Color = Colors.GreenPetroutsos c05.tex V2 - 01/28/2008 12:46pm Page 168
168 CHAPTER 5 THE VISTA INTERFACE
ElseIf ComboBox1.SelectedIndex = 2 Then
myink.DefaultDrawingAttributes.Color = Colors.Blue
End If
End Sub
End Class
Press F5 or click the green arrow to run the application. It will open in a web browser window
and should appear and function as shown in Figure 5.5.
Figure 5.5
The running
WpfBrowserApplication1
Expression BlendOverview
Expression Blend is part of Microsoft’s new Expression Studio package. Expression Studio con-
tains four major components:
Expression Web Website designer
Expression Blend User interface designer
Expression Design Vector and bitmap graphics editor
Expression Media Media manager
Each component can be purchased independently or as part of the Expression Studio
package. A ?fth component, Expression Encoder, is currently available as an independent
purchase. Expression Encoder encodes media content into a format suitable for Silverlight.Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 169
EXPRESSION BLEND OVERVIEW 169
More information and trial downloads can be obtained from the Microsoft website at
www.microsoft.com/expression/expression-studio/overview.aspx.
Expression Blend is speci?cally designed as a tool for creating XAML-based (WPF) interfaces. It
has amuch stronger graphical focus on design than theWPF tools in Visual Studio 2008 andwould
suit developers who are more focused on visual design than working with code. Expression Blend
also exposes a greater range of tools and properties at the GUI level than Visual Studio 2008,
and as such is a great way to explore the possibilities of UI design with WPF. For example, if
you are interested in animation with WPF, and want to work with Visual Studio 2008 but are
struggling with the documentation, you can create a simple animation in Expression Blend using
the graphical tools, examine the XAML markup that is generated, and transfer it to Visual Studio.
A demonstration version of Expression Blend can be downloaded from the Microsoft website.
A number of samples ship with the package that you can open and work with.
Figure 5.6 illustrates the interface for Expression Blend with a simple animation project.
Figure 5.7 illustrates the simple animation project shown in Figure 5.6, running in a test window.
Figure 5.6
Interface for Expression
Blend
Figure 5.7
Expression Blend with
running projectPetroutsos c05.tex V2 - 01/28/2008 12:46pm Page 170
170 CHAPTER 5 THE VISTA INTERFACE
We can extract the markup for the animated rectangle from the XAML generated in Expression
Blend and use it in a Visual Studio 2008 WPF project. Two sections of code are used to generate
the animation. The ?rst section is the code de?ning the rectangle and its behavior, as illustrated
in the following code snippet. This code includes the red-to-blue ?ll gradient that was illustrated
earlier in the chapter (remove the line breaks):
<Rectangle HorizontalAlignment=”Left” Margin=”57,106,0,0”
VerticalAlignment=”Top” Width=”165” Height=”111”
Stroke=”#FF000000” RenderTransformOrigin=”0.5,0.5”
x:Name=”rectangle”>
<Rectangle.Fill>
<LinearGradientBrush EndPoint=”1,0.5” StartPoint=”0,0.5”>
<GradientStop Color=”Red” Offset=”0”/>
<GradientStop Color=”Blue” Offset=”1”/>
</LinearGradientBrush>
</Rectangle.Fill>
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX=”1” ScaleY=”1”/>
<SkewTransform AngleX=”0” AngleY=”0”/>
<RotateTransform Angle=”0”/>
<TranslateTransform X=”0” Y=”0”/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
The second code chunk used with the animation is the one generated to handle the actual time
line of the animation and the trigger used to start it. In this example, the code has been doctored
slightly to animate only a single rectangle and to be used in a Page.xaml ?le in a WPF browser
application. The trigger to ?re the animation in this case is the loading of the page. The time line
information is managed in the <Page.Resources> tags while the triggers are handled by the
<Page.Triggers> tags. The code is illustrated in the following snippet (remove the line breaks):
<Page.Resources>
<Storyboard x:Key=”Timeline1”>
<DoubleAnimationUsingKeyFrames BeginTime=”00:00:00”
Storyboard.TargetName=”rectangle”
Storyboard.TargetProperty=”(UIElement.RenderTransform).
(TransformGroup.Children)[2].(RotateTransform.Angle)”>
<SplineDoubleKeyFrame KeyTime=”00:00:05” Value=”500”/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<Page.Triggers>
<EventTrigger RoutedEvent=”FrameworkElement.Loaded”>
<BeginStoryboard Storyboard=”{StaticResource Timeline1}”/>
</EventTrigger>
</Page.Triggers>Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 171
THE BOTTOM LINE 171
To test this code in aWPF browser application, create a newWPF Browser Application project.
Copy the contents of the <Page.Resources> and <Page.Triggers > code from the preceding
snippet into the XAML for Page1.xaml, immediately following the class declaration and before
the <Grid> tags. Copy the ?rst code snippet governing the rectangle and its behavior between the
<Grid>. . .</Grid> tags. Run the project and you should have a rectangle performing a rotation
in a web page. If you play with the attribute values in the <SplineDoubleKeyFrame> tag, you can
alter the length and extent of the rotation.
A comprehensive user guide is available under the Help menu of the Expression Blend
package.
The BottomLine
Create a simple WPF application. WPF is a new and powerful technology for creating user
interfaces. WPF is one of the core technologies in the .NET Framework 3.5 and is integrated
into Windows Vista. WPF is also supported on Windows XP. WPF takes advantage of the
graphics engines and display capabilities of the modern computer and is vector based and res-
olution independent.
Master It Develop a simple ‘‘Hello World’’ type of WPF application that displays a
Button control and Label control. Clicking the button should set the content property of a
Label control to Hi There!
Data-bind controls inWPF. The ability to bind controls to a data source is an essential aspect
of separating the UI from the business logic in an application.
Master It Data-bind a Label control to one ?eld in a record returned from a database on
your computer.
Use a data template to control data presentation. WPF enables a very ?exible approach to
presenting data by using data templates. The developer can create and fully customize data
templates for data formatting.
Master It Create a data template to display a Name, Surname, Gender combination in
a horizontal row in a ComboBox control. Create a simple array and class of data to feed the
application.Petroutsos c05.tex V2 - 01/28/2008 12:46pm Page 172Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 173
Chapter 6
Basic Windows Controls
In previous chapters, we explored the environment of Visual Basic and the principles of
event-driven programming, which is the core of VB’s programming model. In the process,
we brie?y explored a few basic controls through the examples. The .NET Framework provides
many more controls, and all of them have a multitude of trivial properties (such as Font,
BackgroundColor, and so on), which you can set either in the Properties window or from within
your code.
This chapter explores in depth the basic Windows controls: the controls you’ll use most often
in your applications because they are the basic building blocks of typical rich client-user
interfaces. Rather than look at controls’ background and foreground color, font, and other trivial
properties, we’ll look at the properties unique to each control and see how these properties are
used in building functional, rich user interfaces.
In this chapter, you’ll learn how to do the following:
? Use the TextBox control as a data-entry and text-editing tool
? Use the ListBox, CheckedListBox, and ComboBox controls to present lists
of items
? Use the ScrollBar and TrackBar controls to enable users to specify sizes and positions with
the mouse
The TextBox Control
The TextBox control is the primary mechanism for displaying and entering text. It is a small text
editor that provides all the basic text-editing facilities: inserting and selecting text, scrolling if the
text doesn’t ?t in the control’s area, and even exchanging text with other applications through
the Clipboard.
The TextBox control is an extremely versatile data-entry tool that can be used for entering
and editing single lines of text, such as a number or a password, or an entire text ?le. Figure 6.1
shows a few typical examples. All the boxes in Figure 6.1 contain text — some a single line, some
several lines. The scroll bars you see in some text boxes are part of the control. You can specify
which scroll bars (vertical and/or horizontal) will be attached to the control, and they will appear
automatically whenever the control’s contents exceed the visible area of the control.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 174
174 CHAPTER 6 BASIC WINDOWS CONTROLS
Figure 6.1
Typical uses of the
TextBox control
Basic Properties
Let’s start with the properties that specify the appearance and, to some degree, the functionality of
the TextBox control; these properties are usually set at design time through the Propertieswindow.
Then, we’ll look at the properties that allow you to manipulate the control’s contents and interact
with users from within your code.
TextAlign
This property sets (or returns) the alignment of the text on the control, and its value is a member
of the HorizontalAlignment enumeration: Left, Right,or Center. The TextBox control doesn’t
allow you to format text (mix different fonts, attributes, or colors), but you can set the font in
which the text will be displayed with the Font property,aswellasthecontrol’sbackgroundcolor
with the BackColor property.
MultiLine
This property determines whether the TextBox control will hold a single line or multiple lines
of text. Every time you place a TextBox control on your form, it’s sized for a single line of text
and you can change its width only. To change this behavior, set the MultiLine property to True.
When creating multiline TextBoxes, you will most likely have to set one or more of the MaxLength,
ScrollBars,and WordWrap properties in the Properties window.
MaxLength
This property determines the number of characters that the TextBox control will accept. Its default
value is 32,767, which was the maximum number of characters the VB 6 version of the control
could hold. Set this property to zero, so that the text can have any length, up to the control’s
capacity limit — 2,147,483,647 characters, to be exact. To restrict the number of characters that the
user can type, set the value of this property accordingly.
The MaxLength property of the TextBox control is often set to a speci?c value in data-entry
applications, which prevents users from entering more characters than can be stored in a database
?eld. A TextBox control for entering international standard book numbers (ISBNs), for instance,
shouldn’t accept more than 13 characters.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 175
THE TEXTBOX CONTROL 175
ScrollBars
This property lets you specify the scroll bars you want to attach to the TextBox if the text exceeds
the control’s dimensions. Single-line text boxes can’t have a scroll bar attached, even if the text
exceeds the width of the control. Multiline text boxes can have a horizontal or a vertical scroll bar,
or both.
If you attach a horizontal scroll bar to the TextBox control, the text won’t wrap automatically
as the user types. To start a new line, the user must press Enter. This arrangement is useful for
implementing code editors in which lines must break explicitly. If the horizontal scroll bar is
missing, the control inserts soft line breaks when the text reaches the end of a line, and the text is
wrapped automatically. You can change the default behavior by setting the WordWrap property.
WordWrap
This property determines whether the text is wrapped automatically when it reaches the right
edge of the control. The default value of this property is True. If the control has a horizontal scroll
bar, however, you can enter very long lines of text. The contents of the control will scroll to the
left, so the insertion point is always visible as you type. You can turn off the horizontal scroll bar
and still enter long lines of text; just use the left/right arrows to bring any part of the text into
view. You can experiment with the WordWrap and ScrollBars properties in the TextPad sample
application, which is described later in this chapter.
Notice that the WordWrap property has no effect on the actual line breaks. The lines are wrapped
automatically, and there are no hard breaks (returns) at the end of each line. Open the TextPad
project, enter a long paragraph, and resize the window — the text is automatically adjusted to the
new width of the control.
A Functional Text Editor by Design
A TextBox control with its MaxLength property set to 0, its MultiLine and WordWrap properties set
to True, and its ScrollBars property set to Vertical is, on its own, a functional text editor. Place a
TextBox control with these settings on a form, run the application, and check out the following:
? Enter text and manipulate it with the usual editing keys: Delete, Insert, Home, and End.
? Select multiple characters with the mouse or the arrow keys while holding down the
Shift key.
? Move segments of text around with Copy (Ctrl+C), Cut (Ctrl+X), and Paste (Ctrl+V, or Shift+
Insert) operations.
? Right-click the control to see its context menu; it contains all the usual text-editing commands.
? Exchange data with other applications through the Clipboard.
You can do all this without a single line of code! If you use the My object, you can save and load ?les
by using two lines of code. Shortly, you’ll see what you can do with the TextBox control if you add
some code to your application, but ?rst let’s continue our exploration of the properties that allow us
to manipulate the control’s functionality.
AcceptsReturn, AcceptsTab
These two properties specify how the TextBox control reacts to the Return (Enter) and Tab keys.
The Enter key activates the default button on the form, if there is one. The default button is usuallyPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 176
176 CHAPTER 6 BASIC WINDOWS CONTROLS
an OK button that can be activated with the Enter key, even if it doesn’t have the focus. In a
multiline TextBox control, however, we want to be able to use the Enter key to change lines. The
default value of the AcceptsReturn property is True, so pressing Enter creates a new line on the
control. If you set it to False, users can still create new lines in the TextBox control, but they’ll
have to press Ctrl+Enter. If the form contains no default button, the Enter key creates a new line
regardless of the AcceptsReturn setting.
Likewise, the AcceptsTab property determines howthe control reacts to the Tab key.Normally,
the Tab key takes you to the next control in the Tab order, and we generally avoid changing the
default setting of the AcceptsTab property. In a multiline TextBox control, however, you may
want the Tab key to insert a Tab character in the text of the control instead; to do this, set the
control’s AcceptsTab property to True (the default value is False). If you change the default value,
users can still move to the next control in the Tab order by pressing Ctrl+Tab. Notice that the
AcceptsTab property has no effect on other controls. Users may have to press Ctrl+Tab to move
to the next control while a TextBox control has the focus, but they can use the Tab key to move
from any other control to the next one.
CharacterCasing
This property tells the control to change the casing of the characters as they’re entered by the user.
Its default value is Normal, and characters are displayed as typed. You can set it to Upper or Lower
to convert the characters to upper- or lowercase automatically.
PasswordChar
This property turns the characters typed into any character you specify. If you don’t want to
display the actual characters typed by the user (when entering a password, for instance), use this
property to de?ne the character to appear in place of each character the user types.
The default value of this property is an empty string, which tells the control to display the
characters as entered. If you set this value to an asterisk (*), for example, the user sees an asterisk
in the place of every character typed. This property doesn’t affect the control’s Text property,
which contains the actual characters. If the PasswordChar property is set to any character, the user
can’t copy or cut the text on the control.
ReadOnly, Locked
If you want to display text on a TextBox control but prevent users from editing it (such as for an
agreement or a contract they must read, software installation instructions, and so on), you can set
the ReadOnly property to True.When ReadOnly is set to True, you can put text on the control from
within your code, and users can view it, yet they can’t edit it.
To prevent editing of the TextBox control with VB 6, you had to set the Locked property to
True. Oddly, the Locked property is also supported, but now it has a very different function. The
Locked property of VB 2008 locks the control at design time (so that you won’t move it or change
its properties by mistake as you design the form).
Text-Manipulation Properties
Most of the properties for manipulating text in a TextBox control are available at runtime only.
This section presents a breakdown of each property.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 177
THE TEXTBOX CONTROL 177
Text
Themost important property of the TextBox control is the Text property,which holds the control’s
text. You can set this property at design time to display some text on the control initially.
Notice that there are two methods of setting the Text property at design time. For single-line
TextBox controls, set the Text property to a short string, as usual. For multiline TextBox controls,
open the Lines property and enter the text in the String Collection Editor window, which will
appear. In this window, each paragraph is entered as a single line of text. When you’re ?nished,
click OK to close the window; the text you entered in the String Collection Editor window will
be placed on the control. Depending on the width of the control and the setting of the WordWrap
property, paragraphs may be broken into multiple lines.
At runtime, use the Text property to extract the text entered by the user or to replace
the existing text. The Text property is a string and can be used as an argument with the usual
string-manipulation functions of Visual Basic. You can also manipulate it with the members of the
String class. The following expression returns the number of characters in the TextBox1 control:
Dim strLen As Integer = TextBox1.Text.Length
The IndexOf method of the String class will locate a speci?c string in the control’s text.
The following statement returns the location of the ?rst occurrence of the string Visual
in the text:
Dim location As Integer
location = TextBox1.Text.IndexOf(”Visual”)
Formore information on locating strings in a TextBox control, see the section ‘‘VB 2008 atWork:
The TextPad Project’’ later in this chapter, where we’ll build a text editor with search-and-replace
capabilities. For a detailed discussion of the String class, see Chapter 13, ‘‘Handling Strings,
Characters, and Dates.’’
To store the control’s contents in a ?le, use a statement such as the following:
StrWriter.Write(TextBox1.Text)
Similarly, you can read the contents of a text ?le into a TextBox control by using a statement
such as the following:
TextBox1.Text = StrReader.ReadToEnd
where StrReader and StrWriter are two properly declared StreamReader and StreamWriter
variables. File operations are discussed in detail in Chapter 15, ‘‘Accessing Folders and Files.’’ You
will also ?nd out how to print text ?les in Chapter 20, ‘‘Printing with Visual Basic 2008.’’
To locate all instances of a string in the text, use a loop like the one in Listing 6.1. This loop
locates successive instances of the string Basic and then continues searching from the character
following the previous instance of the word in the text. To locate the last instance of a string in the
text, use the LastIndexOf method. You can write a loop similar to the one in Listing 6.1 that scans
the text backward.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 178
178 CHAPTER 6 BASIC WINDOWS CONTROLS
Listing 6.1: Locating All Instances of a String in a TextBox
Dim startIndex = -1
startIndex = TextBox1.Text.IndexOf(”Basic”, startIndex + 1)
While startIndex > 0
Console.WriteLine ”String found at ” & startIndex
startIndex = TextBox1.Text.IndexOf(”Basic”, startIndex + 1)
End While
To test this code segment, place a multiline TextBox and a Button control on a form; then enter
the statements of the listing in the button’s Click event handler. Run the application and enter
some text on the TextBox control. Make sure that the text contains the word Basic or change the
code to locate another word, and click the button. Notice that the IndexOf method performs a
case-sensitive search.
Use the Replace method to replace a string with another within the line, the Split method
to split the line into smaller components (such as words), and any other method exposed by the
String class to manipulate the control’s text. The following statement appends a string to the
existing text on the control:
TextBox1.Text = TextBox1.Text & newString
This statement has appeared in just about any VB 6 application that manipulated text with the
TextBox control. It is an inef?cient method to append text to the control, especially if the control
contains a lot of text already.
Now, you can use the AppendText method to append strings to the control, which is far more
ef?cient than manipulating the Text property directly. To append a string to a TextBox control,
use the following statement:
TextBox1.AppendText(newString)
The AppendText method appends the speci?ed text to the control as is, without any line breaks
between successive calls. If you want to append individual paragraphs to the control’s text, you
must insert the line breaks explicitly, with a statement such as the following (vbCrLf is a constant
for the carriage return/new line characters):
TextBox1.AppendText(newString & vbCrLf)
Lines
In addition to the Text property, you can access the text on the control by using the Lines
property. The Lines property is a string array, and each element holds a paragraph of text. The
?rst paragraph is stored in the element Lines(0), the second paragraph in the element Lines(1),
and so on. You can iterate through the text lines with a loop such as the following:
Dim iLine As Integer
For iLine = 0 To TextBox1.Lines.GetUpperBound(0) - 1
{ process string TextBox1.Lines(iLine) }
NextPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 179
THE TEXTBOX CONTROL 179
You must replace the line in brackets with the appropriate code, of course. Because the Lines
property is an array, it supports the GetUpperBound method, which returns the index of the last
element in the array. Each element of the Lines array is a string, and you can call any of the String
class’s methods to manipulate it. Just keep in mind that you can’t alter the text on the control by
editing the Lines array. However, you can set the control’s text by assigning an array of strings to
the Lines property.
Text-Selection Properties
The TextBox control provides three properties for manipulating the text selected by the user:
SelectedText, SelectionStart,and SelectionLength. Users can select a range of text with a
click-and-drag operation, and the selected text will appear in reverse color. You can access the
selected text from within your code through the SelectedText property, and its location in
the control’s text through the SelectionStart and SelectionLength properties.
SelectedText
This property returns the selected text, enabling you to manipulate the current selection from
within your code. For example, you can replace the selection by assigning a new value to the
SelectedText property. To convert the selected text to uppercase, use the ToUpper method of
the String class:
TextBox1.SelectedText = TextBox1.SelectedText.ToUpper
SelectionStart, SelectionLength
Use these two properties to read the text selected by the user on the control, or to select text from
within your code. The SelectionStart property returns or sets the position of the ?rst character
of the selected text, somewhat like placing the cursor at a speci?c location in the text and selecting
text by dragging the mouse. The SelectionLength property returns or sets the length of the
selected text.
Suppose that the user is seeking the word Visual in the control’s text. The IndexOf method
locates the string but doesn’t select it. The following statements select the word in the text,
highlight it, and bring it into view, so that users can spot it instantly:
Dim seekString As String = ”Visual”
Dim strLocation As Long
strLocation = TextBox1.Text.IndexOf(seekString)
If strLocation > 0 Then
TextBox1.SelectionStart = strLocation
TextBox1.SelectionLength = seekString.Length
End If
TextBox1.ScrollToCaret()
These lines locate the string Visual (or any user-supplied string stored in the seekString
variable) in the text and select it by setting the SelectionStart and SelectionLength properties
of the TextBox control. If the located string lies outside the visible area of the control, the user must
scroll the text to bring the selection into view. The TextBox control provides the ScrollToCaret
method, which brings the section of the text with the cursor (the caret position)intoview.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 180
180 CHAPTER 6 BASIC WINDOWS CONTROLS
The few lines of code shown previously form the core of a text editor’s Find command.
Replacing the current selection with another string is as simple as assigning a new value to the
SelectedText property, and this technique provides you with an easy implementation of a Find
and Replace operation.
Locating the Cursor Position in the Control
The SelectionStart and SelectionLength properties always have a value even if no text is selected
on the control. In this case, SelectionLength is 0, and SelectionStart is the current position of
the pointer in the text. If you want to insert some text at the pointer’s location, simply assign it to the
SelectedText property, even if no text is selected on the control.
HideSelection
The selected text in the TextBox does not remain highlighted when the user moves to another
control or form; to change this default behavior, set the HideSelection property to False. Use this
property to keep the selected text highlighted, even if another form or a dialog box, such as a Find
& Replace dialog box, has the focus. Its default value is True, which means that the text doesn’t
remain highlighted when the TextBox loses the focus.
Text-Selection Methods
In addition to properties, the TextBox control exposes two methods for selecting text. You can
select some text by using the Select method, whose syntax is shown next:
TextBox1.Select(start, length)
The Select method is equivalent to setting the SelectionStart and SelectionLength prop-
erties. To select the characters 100 through 105 on the control, call the Select method, passing the
values 99 and 6 as arguments:
TextBox1.Select(99, 6)
As a reminder, the order of the characters starts at 0 (the ?rst character’s index is 0, the second
character’s index is 1, and the last character’s index is the length of the string minus 1).
If the range of characters you select contains hard line breaks, you must take them into
consideration as well. Each hard line break counts for two characters (carriage return and line
feed). If the TextBox control contains the string ABCDEFGHI, the following statement will select the
range DEFG:
TextBox1.Select(3, 4)
If you insert a line break every third character and the text becomes the following, the same
statement will select the characters DE only:
ABC
DEF
GHIPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 181
THE TEXTBOX CONTROL 181
In reality, it has also selected the two characters that separate the ?rst two lines, but special
characters aren’t displayed and can’t be highlighted. The length of the selection, however, is 4.
A variation of the Select method is the SelectAll method, which selects all the text on
the control.
Undoing Edits
An interesting feature of the TextBox control is that it can automatically undo the most recent
edit operation. To undo an operation from within your code, you must ?rst examine the value of
the CanUndo property. If it’s True, the control can undo the operation; then you can call the Undo
method to undo the most recent edit.
An edit operation is the insertion or deletion of characters. Entering text without deleting any
is considered a single operation and will be undone in a single step. Even if the user has spent
an hour entering text (without making any corrections), you can make all the text disappear with
asinglecalltothe Undo method. Fortunately, the deletion of the text becomes the most recent
operation, which can be undone with another call to the Undo method. In effect, the Undo method
is a toggle. When you call it for the ?rst time, it undoes the last edit operation. If you call it again,
it redoes the operation it previously undid. The deletion of text can be undone only if no other
editing operation has taken place in the meantime. You can disable the redo operation by calling
the ClearUndo method, which clears the undo buffer of the control. You should call it from within
an Undo command’s event handler to prevent an operation from being redone. In most cases, you
should give users the option to redo an operation, especially because the Undo method can delete
an enormous amount of text from the control.
VB 2008 at Work: The TextPad Project
The TextPad application, shown in Figure 6.2, demonstrates most of the TextBox control’s proper-
ties and methods described so far. TextPad is a basic text editor that you can incorporate into your
programs and customize for special applications. The TextPad project’s main form is covered by a
TextBox control, whose size is adjusted every time the user resizes the form. This feature doesn’t
require any programming — just set the Dock property of the TextBox control to Fill.
Figure 6.2
TextPad demonstrates
the most useful
properties and methods
of the TextBox control.
The name of the application’s main form is frmTextPad, and the name of the Find & Replace
dialog box is frmFind. You can design the two forms as shown in the ?gures of this chapter, orPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 182
182 CHAPTER 6 BASIC WINDOWS CONTROLS
open the TextPad project. To design the application’s interface from scratch, place a MenuStrip
control on the form and dock it to the top of the form. Then place a TextBox control on the main
form, name it txtEditor, and set the following properties: Multiline to True, MaxLength to 0
(to edit text documents of any length), HideSelection to False (so that the selected text remains
highlighted even when the main form doesn’t have the focus), and Dock to Fill, so that it will ?ll
the form.
The menu bar of the form contains all the commands you’d expect to ?nd in text-editing
applications; they’re listed in Table 6.1.
Table 6.1: The TextPad Form’s Menu
Menu Command Description
File New Clears the text
Open Loads a new text ?le from disk
Save Saves the text to its ?le on disk
Save As Saves the text with a new ?lename on disk
Print Prints the text
Exit Terminates the application
Edit Undo/Redo Undoes/redoes the last edit operation
Copy Copies selected text to the Clipboard
Cut Cuts the selected text
Paste Pastes the Clipboard’s contents to the editor
Select All Selects all text in the control
Find & Replace Displays a dialog box with Find and Replace options
Process Convert To Upper Converts selected text to uppercase
Convert To Lower Converts selected text to lowercase
Number Lines Numbers the text lines
Format Font Sets the text’s font, size, and attributes
Page Color Sets the control’s background color
Text Color Sets the color of the text
WordWrap Toggle menu item that turns text wrapping on and off
The File menu commands are implemented with the Open and Save As dialog boxes, the
Font command with the Font dialog box, and the Color command with the Color dialog box.
These dialog boxes are discussed in the following chapters, and as you’ll see, you don’t have toPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 183
THE TEXTBOX CONTROL 183
design them yourself. All you have to do is place a control on the form and set a few properties;
the Framework takes it from there. The application will display the standard Open File/Save
File/Font/Color dialog boxes, in which the user can select or specify a ?lename or select a font
or color. Of course, we’ll provide a few lines of code to actually move the text into a ?le (or read
it from a ?le and display it on the control), change the control’s background color, and so on. I’ll
discuss the commands of the File menu in Chapter 8, ‘‘MoreWindows Controls.’’
The Editing Commands
The options on the Edit menu move the selected text to and from the Clipboard. For the TextPad
application, all you need to know about the Clipboard are the SetText method, which places the
currently selected text on the Clipboard, and the GetText method, which retrieves information
from the Clipboard (see Figure 6.3).
Figure 6.3
The Copy, Cut, and
Paste operations can
be used to exchange text
with any other
application.
The Copy command, for example, is implemented with a single line of code (txtEditor is the
name of the TextBox control). The Cut command does the same, and it also clears the selected text.
The code for these and for the Paste command, which assigns the contents of the Clipboard to the
current selection, is presented in Listing 6.2.
Listing 6.2: The Cut, Copy, and Paste Commands
Private Sub EditCopyItem Click(...)
Handles EditCopyItem.Click
If txtEditor.SelectionLength > 0 Then
Clipboard.SetText(txtEditor.SelectedText)
End If
End SubPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 184
184 CHAPTER 6 BASIC WINDOWS CONTROLS
Private Sub EditCutItem Click(...)
Handles EditCutItem.Click
Clipboard.SetText(txtEditor.SelectedText)
txtEditor.SelectedText = ””
End Sub
Private Sub EditPasteItem Click(...)
Handles EditPasteItem.Click
If Clipboard.ContainsText Then
txtEditor.SelectedText = Clipboard.GetText
End If
End Sub
If no text is currently selected, the Clipboard’s text is pasted at the pointer’s current location.
If the Clipboard contains a bitmap (placed there by another application) or any other type of
data that the TextBox control can’t handle, the paste operation will fail; that’s why we handle the
Paste operation with an If statement. You could provide some hint to the user by including an
Else clause that informs them that the data on the Clipboard can’t be used with a text-editing
application.
The Process and Format Menus
The commands of the Process and Format menus are straightforward. The Format menu
commands open the Font or Color dialog box and change the control’s Font, ForeColor,and
BackColor properties. You will learn how to use these controls in the following chapter. The
Upper Case and Lower Case commands of the Process menu are also trivial: they select all the text,
convert it to uppercase or lowercase, respectively, and assign the converted text to the control’s
SelectedText property with the following statements:
txtEditor.SelectedText = txtEditor.SelectedText.ToLower
txtEditor.SelectedText = txtEditor.SelectedText.ToUpper
Notice that the code uses the SelectedText property to convert only the selected text, not
the entire document. The Number Lines command inserts a number in front of each text line
and demonstrates how to process the individual lines of text on the control. However, it doesn’t
remove the line numbers, and there’s no mechanism to prevent the user from editing the line
numbers or inserting/deleting lines after they have been numbered. Use this feature to create a
numbered listing or to number the lines of a ?le just before saving it or sharing it with another user.
Listing 6.3 shows the Number Lines command’s code and demonstrates how to iterate through
the TextBox control’s Lines array.
Listing 6.3: The Number Lines Command
Private Sub ProcessNumberLinesItem Click(...)
Handles ProcessNumberLines.Click
Dim iLine As Integer
Dim newText As New System.Text.StringBuilder()
For iLine = 0 To txtEditor.Lines.Length - 1Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 185
THE TEXTBOX CONTROL 185
newText.Append((iLine + 1).ToString & vbTab &
txtEditor.Lines(iLine) & vbCrLf)
Next
txtEditor.SelectAll()
Clipboard.SetText(newText.ToString)
txtEditor.Paste()
End Sub
This event handler uses a StringBuilder variable. The StringBuilder class, which is discussed
in detail in Chapter 12, ‘‘Designing Custom Windows Controls,’’ is equivalent to the String class;
it exposes similar methods and properties, but it’s much faster at manipulating dynamic strings
than the String class.
Search and Replace Operations
The last option in the Edit menu — and the most interesting — displays a Find & Replace dialog
box (shown in Figure 6.2). This dialog box works like the similarly named dialog box of Microsoft
Word and many other Windows applications. The buttons in the Find & Replace dialog box are
relatively self-explanatory:
Find The Find command locates the ?rst instance of the speci?ed string in the text after
the cursor location. If a match is found, the Find Next, Replace, and Replace All buttons
are enabled.
Find Next This command locates the next instance of the string in the text. Initially,
this button is disabled; it’s enabled only after a successful Find operation.
Replace This replaces the current selection with the replacement string and then locates the
next instance of the same string in the text. Like the Find Next button, it’s disabled until a
successful Find operation occurs.
Replace All This replaces all instances of the string speci?ed in the Search For box with the
string in the Replace With box.
Design a form like the one shown in Figure 6.2 and set its TopMost property to True. We want
this form to remain on top of the main form, even when it doesn’t have the focus.
Whether the search is case-sensitive or not depends on the status of the Case Sensitive
CheckBox control. If the string is found in the control’s text, the program highlights it by
selecting it. In addition, the program calls the TextBox control’s ScrollToCaret method to bring
the selection into view. The Find Next button takes into consideration the location of the pointer
and searches for a match after the current location. If the user moves the pointer somewhere
else and then clicks the Find Next button, the program will locate the ?rst instance of the string
after the current location of the pointer — and not after the last match. Of course, you can always
keep track of the location of each match and continue the search from this location. The Find
button executes the code shown in Listing 6.4.
Listing 6.4: The Find Button
Private Sub bttnFind Click(...) Handles bttnFind.Click
Dim selStart As Integer
If chkCase.Checked = True Then
selStart =Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 186
186 CHAPTER 6 BASIC WINDOWS CONTROLS
frmTextPad.txtEditor.Text.IndexOf(
searchWord.Text, StringComparison.Ordinal)
Else
selStart =
frmTextPad.txtEditor.Text.IndexOf(
searchWord.Text,
StringComparison.OrdinalIgnoreCase)
End If
If selStart = -1 Then
MsgBox(”Can’t find word”)
Exit Sub
End If
frmTextPad.txtEditor.Select(
selStart, searchWord.Text.Length)
bttnFindNext.Enabled = True
bttnReplace.Enabled = True
bttnReplaceAll.Enabled = True
frmTextPad.txtEditor.ScrollToCaret()
End Sub
The Find button examines the value of the chkCase CheckBox control, which speci?es whether
the search will be case-sensitive and calls the appropriate form of the IndexOf method. The ?rst
argument of this method is the string we’re searching for; the second argument is the search mode,
and its value is a member of the StringComparison enumeration: Ordinal for case-sensitive
searches and OrdinalIgnoreCase for case-insensitive searches. If the IndexOf method locates
the string, the program selects it by calling the control’s Select method with the appropriate
arguments. If not, it displays a message. Notice that after a successful Find operation, the Find
Next, Replace, and Replace All buttons on the form are enabled.
The code of the Find Next button is the same, but it starts searching at the character following
the current selection. This way, the IndexOf method locates the next instance of the same string.
Here’s the statement that locates the next instance of the search argument:
selStart = frmTextPad.txtEditor.Text.IndexOf(
searchWord.Text,
frmTextPad.txtEditor.SelectionStart + 1,
StringComparison.Ordinal)
The Replace button replaces the current selection with the replacement string and then locates
the next instance of the ?nd string. The Replace All button replaces all instances of the search word
in the document. Listing 6.5 presents the code behind the Replace and Replace All buttons.
Listing 6.5: The Replace and Replace All Operations
Private Sub bttnReplace Click(...)
Handles bttnReplace.Click
If frmTextPad.txtEditor.SelectedText <> ”” Then
frmTextPad.txtEditor.SelectedText = replaceWord.Text
End If
bttnFindNext Click(sender, e)
End SubPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 187
THE TEXTBOX CONTROL 187
Private Sub bttnReplaceAll Click(...)
Handles bttnReplaceAll.Click
Dim curPos, curSel As Integer
curPos = frmTextPad.txtEditor.SelectionStart
curSel = frmTextPad.txtEditor.SelectionLength
frmTextPad.txtEditor.Text =
frmTextPad.txtEditor.Text.Replace(
searchWord.Text.Trim, replaceWord.Text.Trim)
frmTextPad.txtEditor.SelectionStart = curPos
frmTextPad.txtEditor.SelectionLength = curSel
End Sub
The Replace method is case-sensitive, which means that it replaces instances of the search
argument in the text that have the exact same spelling as its ?rst argument. For a case-insensitive
replace operation, you must write the code to perform consecutive case-insensitive search-
and-replace operations. Alternatively, you can use the Replace built-in function to perform
case-insensitive searches. Here’s how you’d call the Replace function to performa case-insensitive
replace operation:
Replace(frmTextPad.txtEditor.Text, searchWord.Text.Trim,
replaceWord.Text.Trim, , , CompareMethod.Text)
The last, optional, argument determines whether the search will be case-sensitive
(CompareMethod.Binary) or case-insensitive (CompareMethod.Text).
The Undo/Redo Commands
The Undo command (shown in Listing 6.6) is implemented with a call to the Undo method.
However, because the Undo method works like a toggle, we must also toggle its caption from
Undo to Redo (and vice versa) each time the command is activated.
Listing 6.6: The Undo/Redo Command of the EditMenu
Private Sub EditUndoItem Click(...)
Handles EditUndoItem.Click
If EditUndoItem.Text = ”Undo” Then
If txtEditor.CanUndo Then
txtEditor.Undo()
EditUndoItem.Text = ”Redo”
End If
Else
If txtEditor.CanUndo Then
txtEditor.Undo()
EditUndoItem.Text = ”Undo”
End If
End If
End SubPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 188
188 CHAPTER 6 BASIC WINDOWS CONTROLS
If you edit the text after an undo operation, you can no longer redo the last undo operation.
This means that as soon as the contents of the TextBox control change, the caption of the ?rst
command in the Edit menu must become Undo, even if it’s Redo at the time. The Redo command
is available only after undoing an operation and before editing the text. So, how do we know that
the text has been edited? The TextBox control ?res the TextChanged event every time its contents
change. We’ll use this event to restore the caption of the Undo/Redo command to Undo. Insert
the following statement in the TextChanged event of the TextBox control:
EditUndoItem.Text = ”Undo”
The TextBox control can’t provide more-granular undo operations— unlike Word, which
keeps track of user actions (insertions, deletions, replacements, and so on) and then undoes them
in steps. If you need a more-granular undo feature, you should use the RichTextBox control, which
is discussed in detail in Chapter 8. The RichTextBox control can display formatted text, but it can
also be used as an enhanced TextBox control. By the way, setting the menu item’s caption from
within the TextChanged event handler is an overkill, because this event takes place every time the
user presses a key. However, the operation takes no time at all and doesn’t make the application
less responsive. A better choice would be the DropDownOpening event of the editFormat item,
which is ?red every time the user opens the Edit menu.
Capturing Keystrokes
The TextBox control has a single unique event, the TextChanged event, which is ?red every time
the text on the control is changed, either because the user has typed a character or because of
a paste operation. Another event that is quite common in programming the TextBox control
is the KeyPress event, which occurs every time a key is pressed and reports the character that
was pressed. You can use this event to capture certain keys and modify the program’s behavior
depending on the character typed.
Suppose that you want to use the TextPad application to prepare messages for transmission
over a telex line. As you may know, a telex can’t transmit lowercase characters or special symbols.
Theeditormustconvertthetexttouppercaseandreplace the special symbols with their equivalent
strings: DLR for $, AT for @, O/O for %, BPT for #, and AND for &. You can modify the default
behavior of the TextBox control fromwithin the KeyPress event so that it converts these characters
as the user types.
By capturing keystrokes, you can process the data as they are entered, in real time. For example,
you can make sure that a TextBox accepts only numeric or hexadecimal characters and rejects all
others. To implement an editor for preparing text for telex transmission, use the KeyPress event
handler shown in Listing 6.7.
Listing 6.7: Handling Keystrokes for a TELEXmessage
Private Sub txtEditor KeyPress(
ByVal sender As Object,
ByVal e As System.Windows.
Forms.KeyPressEventArgs)
Handles txtEditor.KeyPress
If System.Char.IsControl(e.KeyChar) Then Exit Sub
Dim ch As Char = Char.ToUpper(e.KeyChar)Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 189
THE TEXTBOX CONTROL 189
Select Case ch.ToString
Case ”@”
txtEditor.SelectedText = ”AT”
Case ”#”
txtEditor.SelectedText = ”BPT”
Case ”$”
txtEditor.SelectedText = ”DLR”
Case ”%”
txtEditor.SelectedText = ”O/O”
Case ”&”
txtEditor.SelectedText = ”AND”
Case Else
txtEditor.SelectedText = ch
End Select
e.Handled = True
End Sub
The very ?rst executable statement in the event handler examines the key that was pressed and
exits if it is a special editing key (Delete, Backspace, Ctrl+V, and so on). If so, the handler exits
without taking any action. The KeyChar property of the e argument of the KeyPress event reports
the key that was pressed. The code converts it to a string and then uses a Case statement to handle
individual keystrokes. If the user pressed the $ key, for example, the code displays the characters
DLR. If no special character was pressed, the code displays the character pressed as is from within
the Case Else clause of the Select statement.
Cancelling Keystrokes
Before you exit the event handler, you must ‘‘kill’’ the original key pressed, so that it won’t appear
on the control. You do this by setting the Handled property to True, which tells VB that it shouldn’t
process the keystroke any further. If you omit this statement, the special characters will be printed
twice: once in their transformed format (DLR$, AT@, and so on) and once as regular characters. You
can also set the SuppressKeyPress property to True to cancel a keystroke; the Common Language
Runtime (CLR) will not pass the keystroke to the appropriate control.
Capturing Function Keys
Another common feature in text-editing applications is the assignment of special operations to
the function keys. The Notepad application, for example, uses the F5 function key to insert the
current date at the cursor’s location. You can do the same with the TextPad application, but you
can’t use the KeyPress event —the KeyChar argument doesn’t report function keys. The events
that can capture the function keys are the KeyDown and KeyUp events. Also, unlike the KeyPress
event, these two events don’t report the character pressed, but instead report the key’s code (a
special number that distinguishes each key on the keyboard, also known as the scancode), through
the e.KeyCode property.
The keycode is unique for each key, not each character. Lower- and uppercase characters have
different ASCII values but the same keycode because they are on the same key. For example,
the number 4 and the $ symbol have the same keycode because the same key on the keyboardPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 190
190 CHAPTER 6 BASIC WINDOWS CONTROLS
generates both characters. When the key’s code is reported, the KeyDown and KeyUp events
also report the state of the Shift, Ctrl, and Alt keys through the e.Shift, e.Alt,and
e.Control properties.
The KeyUp event handler shown in Listing 6.8 uses the F5 and F6 function keys to insert the
current date and time in the document. It also uses the F7 and F8 keys to insert two prede?ned
strings in the document.
Listing 6.8: KeyUp Event Examples
Private Sub txtEditor KeyUp(ByVal sender As Object,
ByVal e As System.Windows.Forms.KeyEventArgs)
Handles txtEditor.KeyUp
Select Case e.KeyCode
Case Keys.F5 :
txtEditor.SelectedText =
Now().ToLongDateString
Case Keys.F6 :
txtEditor.SelectedText =
Now().ToLongTimeString
Case Keys.F7 :
txtEditor.SelectedText =
”MicroWeb Designs, Inc.”
Case Keys.F8 :
txtEditor.SelectedText =
”Another user-supplied string”
End Select
End Sub
Windows already uses many of the function keys (for example, the F1 key for help), and you
shouldn’tmodify their original functions.With a little additional effort, you can provide userswith
a dialog box that lets them assign their own strings to function keys. You’ll probably have to take
into consideration the status of the Shift, Control,and Alt properties of the event’s e argument,
which report the status of the Shift, Ctrl, and Alt keys, respectively. To ?nd out whether two of the
modi?er keys are pressed along with a key, use the AND operator with the appropriate properties
of the e argument. The following If clause detects the Ctrl and Alt keys:
If e.Control AND e.Alt Then
{ Both Alt and Control keys were down}
End If
Auto-complete Properties
One set of interesting properties of the TextBox control are the autocomplete properties. Have
you noticed how Internet Explorer prompts you with possible matches as soon as you startPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 191
THE TEXTBOX CONTROL 191
typing an address or your username in a text box (or in the address bar of the browser)? You can
easily implement such boxes with a single-line TextBox control and the autocomplete properties.
Basically, you have to tell the TextBox control how it should prompt the user with strings that
match the characters already entered on the control and where the matches will come from. Then,
the control can display in a drop-down list the strings that begin with the characters already typed
by the user. The user can either continue typing (in which case the list of options becomes shorter)
or select an item from the list. The autocomplete properties apply to single-line TextBox controls
only; they do not take effect on multiline TextBox controls.
In many cases, an autocomplete TextBox control is more functional than a ComboBox con-
trol, and you should prefer it. You will see that the ComboBox also supports the autocomplete
properties, because they make the control so much easier to use only with the keyboard.
The AutoCompleteMode property determines whether, and how, the TextBox control will
prompt users, and its setting is a member of the AutoCompleteMode enumeration (AutoSuggest,
AutoAppend, AutoSuggestAppend,and None). In AutoAppend mode, the TextBox control selects
the ?rst matching item in the list of suggestions and completes the text. In AutoSuggestAppend
mode, the control suggests the ?rst matching item in the list, as before, but it also expands the list.
In AutoSuggest mode, the control simply opens a list with the matching items but doesn’t select
any of them. Regular TextBox controls have their AutoCompleteMode property set to False.
The AutoCompleteSource property determines where the list of suggestions comes from; its
value is a member of the AutoCompleteSource enumeration, which is shown in Table 6.2.
Table 6.2: The Members of the AutoCompleteSource
Member Description
AllSystemSources The suggested items are the names of system resources.
AllUrl The suggested items are the URLs visited by the target computer. Does not
work if you’re deleting the recently viewed pages.
CustomSource The suggested items come from a custom collection.
FileSystem The suggested items are ?lenames.
HistoryList The suggested items come from the computer’s history list.
RecentlyUsedList The suggested items come from the Recently Used folder.
None The control doesn’t suggest any items.
To demonstrate the basics of the autocomplete properties, I’ve included the AutoComplete-
TextBoxes project, whose main form is shown in Figure 6.4. This project allows you to set the
autocomplete mode and source for a single-line TextBox control. The top TextBox control uses
a custom list of words, while the lower one uses one of the built-in autocomplete sources (?le
system, URLs, and so on).Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 192
192 CHAPTER 6 BASIC WINDOWS CONTROLS
Figure 6.4
Suggesting words with
the AutoComplete-
Source property
If you set the AutoCompleteSource to CustomSource, you must also populate an
AutoCompleteStringCollection object with the desired suggestions and assign it to
the AutoCompleteCustomSource property. The AutoCompleteStringCollection is just a
collection of strings. Listing 6.9 shows statements in a form’s Load event that prepare such a list
and use it with the TextBox1 control.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 193
THE TEXTBOX CONTROL 193
Listing 6.9: Populating a CustomAutoCompleteSource Property
Private Sub Form1 Load(...)
Handles MyBase.Load
Dim knownWords As New AutoCompleteStringCollection
knownWords.Add(”Visual Basic 2008”)
knownWords.Add(”Visual Basic .NET”)
knownWords.Add(”Visual Basic 6”)
knownWords.Add(”Visual Basic”)
knownWords.Add(”Framework”)
TextBox1.AutoCompleteCustomSource = knownWords
TextBox1.AutoCompleteSource = AutoCompleteSource.CustomSource
TextBox1.AutoCompleteMode =
AutoCompleteMode.Suggest
TextBox2.AutoCompleteSource =
AutoCompleteSource.RecentlyUsedList
TextBox2.AutoCompleteMode =
AutoCompleteMode.Suggest
End Sub
The TextBox1 control on the form will open a drop-down list with all possible matches in the
knownWords collection as soon as the user starts typing in the control, as shown in the top part of
Figure 6.4. To see the autocomplete properties in action, open the AutoCompleteTextBoxes project
and examine its code. The main form of the application, shown in Figure 6.4, allows you to change
the AutoCompleteMode property of both TextBox controls on the form, and the AutoComplete-
Source property of the bottom TextBox control. The ?rst TextBox uses a list of custom words,
which is set up when the form is loaded, with the statements in Listing 6.9.
Real-World Data-Entry Applications
Typical business applications contain numerous forms for data entry, and the most common element
on data-entry forms is the TextBox control. Data-entry operators are very ef?cient with the keyboard
and they should be able to use your application without reaching for the mouse.
Seasoned data-entry operators can’t live without the Enter key; they reach for this key at the end of
each operation. In my experience, a functional interface should add intelligence to this keystroke: the
Enter key should perform the ‘‘obvious’’ or ‘‘most likely’’ operation at any time.When entering data,
for example, it should take the user to the next control in the Tab order. Consider a data-entry screen
like the one shown in the following image, which contains several TextBox controls, a DataTimePicker
control for entering dates, and two CheckBox controls. This is the main form of the Simple Data Entry
Form sample project, which you will ?nd along with the other chapter’s projects.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 194
194 CHAPTER 6 BASIC WINDOWS CONTROLS
The application uses the Enter key intelligently: every time the Enter key is pressed, the focus ismoved
to the next control in the Tab order. Even if the current control is a CheckBox, this keystroke doesn’t
change the status of the CheckBox controls; it simply moves the focus forward.
You could program the KeyUp event of each control to react to the Enter key, but this approach can
lead tomaintenance problems if you’re going to add new controls to an existing form. The best approach
is to intercept the Enter keystroke at the form’s level, before it reaches a control. To do so, you must
set the KeyPreview property of the form to True. This setting causes the key events to be ?red at the
form’s level ?rst and then to the control that has the focus. In essence, it allows you to handle certain
keystrokes for multiple controls at once. The KeyUp event handler of the sample project’s main form
intercepts the Enter keystroke and reacts to it by moving the focus to the next control in the Tab order
via the ProcessTabKey method. This method simulates the pressing of the Tab key, and it’s called
with a single argument, which is a Boolean value: True moves the focus forward, and False moves it
backward. Here’s the code in the KeyUp event handler of the application’s form that makes the inter-
face much more functional and intuitive:
Private Sub frmDataEntry KeyUp(
ByVal sender As Object,
ByVal e As System.Windows.Forms.KeyEventArgs)
Handles Me.KeyUp
If e.KeyCode = Keys.Enter And Not (e.Alt Or e.Control) Then
If Me.ActiveControl.GetType Is GetType(TextBox) Or
Me.ActiveControl.GetType Is GetType(CheckBox) Or
Me.ActiveControl.GetType Is
GetType(DateTimePicker) Then
If e.Shift Then
Me.ProcessTabKey(False)
Else
Me.ProcessTabKey(True)
End If
End If
End If
End SubPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 195
THE LISTBOX, CHECKEDLISTBOX, AND COMBOBOX CONTROLS 195
There are a couple of things you should notice about this handler. First, it doesn’t react to the Enter
key if it was pressed along with the Alt or Ctrl keys. The Shift key, on the other hand, is used to control
the direction in the Tab order. The focus moves forward with the Enter keystroke and moves back-
ward with the Shift + Enter keystroke. Also, the focus is handled automatically only for the TextBox,
CheckBox, and DataTimePicker controls. When the user presses the Enter key when a button has the
focus, the program reacts as expected by invoking the button’s Click event handler.
The ListBox, CheckedListBox, and ComboBox Controls
The ListBox, CheckedListBox, and ComboBox controls present lists of choices, from which the
user can select one or more. The ?rst two are illustrated in Figure 6.5.
Figure 6.5
The ListBox and
CheckedListBox controls
The ListBox control occupies a user-speci?ed amount of space on the form and is populated
with a list of items. If the list of items is longer than can ?t on the control, a vertical scroll bar
appears automatically.
The CheckedListBox control is a variation of the ListBox control. It’s identical to the ListBox
control, but a check box appears in front of each item. The user can select any number of items by
selecting the check boxes in front of them. As you know, you can also select multiple items from a
ListBox control by pressing the Shift and Ctrl keys.
The ComboBox control also contains multiple items but typically occupies less space on the
screen. The ComboBox control is an expandable ListBox control: The user can expand it to make a
selection, and collapse it after the selection is made. The real advantage of the ComboBox control,
however, is that the user can enter new information in the ComboBox, rather than being forced to
select from the items listed.
To add items at design time, locate the Items property in the control’s Properties window and
click the ellipsis button. A new window will pop up — the String Collection Editor window — in
which you can add the items you want to display in the list. Each item must appear on a separate
text line, and blank text lines will result in blank lines in the list. These items will appear in the list
when the form is loaded, but you can add more items (or remove existing ones) from within your
code at any time. They appear in the same order as entered on the String Collection Editor window
unless the control has its Sorted property set to True, in which case the items are automatically
sorted, regardless of the order in which you’ve speci?ed them.
This section ?rst examines the ListBox control’s properties and methods. Later, you’ll see how
the same properties and methods can be used with the ComboBox control.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 196
196 CHAPTER 6 BASIC WINDOWS CONTROLS
Basic Properties
In this section, you’ll ?nd the properties that determine the functionality of the three controls.
These properties are usually set at design time, but you can change their setting from within your
application’s code.
IntegralHeight
This property is a Boolean value (True/False) that indicates whether the control’s height will be
adjusted to avoid the partial display of the last item. When set to True, the control’s actual height
changes in multiples of the height of a single line, so only an integer number of rows are displayed
at all times.
Items
The Items property is a collection that holds the control’s items. At design time, you can populate
this list through the String Collection Editor window. At runtime, you can access and manipulate
the items through the methods and properties of the Items collection, which are described shortly.
MultiColumn
A ListBox control can display its items in multiple columns if you set its MultiColumn property to
True. The problem with multicolumn ListBoxes is that you can’t specify the column in which each
item will appear. ListBoxes with many items and their MultiColumn property set to True expand
horizontally, not vertically. A horizontal scroll bar will be attached to a multicolumn ListBox, so
that users can bring any column into view. This property does not apply to the ComboBox control.
SelectionMode
This property, which applies to the ListBox and CheckedListBox controls only, determines how
the user can select the list’s items. The possiblevaluesofthisproperty—membersofthe
SelectionMode enumeration— are shown in Table 6.3.
Table 6.3: The SelectionMode Enumeration
Value Description
None No selection at all is allowed.
One (Default) Only a single item can be selected.
MultiSimple Simple multiple selection: A mouse click (or pressing the spacebar) selects or deselects
an item in the list. You must click all the items you want to select.
MultiExtended Extended multiple selection: Press Shift and click the mouse (or press one of the arrow
keys) to expand the selection. This process highlights all the items between the
previously selected item and the current selection. Press Ctrl and click the mouse to
select or deselect single items in the list.
Sorted
When this property is True, the items remain sorted at all times. The default is False, because it
takes longer to insert new items in their proper location. This property’s value can be set at design
time as well as runtime.
The items in a sorted ListBox control are sorted in ascending and case-sensitive order.
Uppercase characters appear before the equivalent lowercase characters, but both upper- andPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 197
THE LISTBOX, CHECKEDLISTBOX, AND COMBOBOX CONTROLS 197
lowercase characters appear together. All words beginning with B appear after the words begin-
ning with A and before the words beginning with C. Within the group of words beginning with
B, those beginning with a capital B appear before those beginning with a lowercase b. This sorting
order is known as phone book order.
Moreover, the ListBox control won’t sort numeric data. The number 10 will appear in front of
the number 5 because the string 10 is smaller than the string 5. If the numbers are formatted as 010
and 005, they will be sorted correctly.
Text
The Text property returns the selected text on the control. Although you can set the Text property
for the ComboBox control at design time, this property is available only at runtime for the other
two controls. Notice that the items need not be strings. By default, each item is an object. For each
object, however, the control displays a string, which is the same string returned by the object’s
ToString method.
Manipulating the Items Collection
To manipulate a ListBox control from within your application, you should be able to do
the following:
? Add items to the list
? Remove items from the list
? Access individual items in the list
The items in the list are represented by the Items collection. You use the members of the Items
collection to access the control’s items and to add or remove items. The Items property exposes
the standard members of a collection, which are described later in this section.
Each member of the Items collection is an object. In most cases, we use ListBox controls to
store strings, but it’s possible to store objects.When you add an object to a ListBox control, a string
is displayed on the corresponding line of the control. This is the string returned by the object’s
ToString method. This is the property of the object that will be displayed by default. You can
display any other property of the object by setting the control’s ValueMember property to the
name of the property.
If you add a Color object and a Rectangle object to the Items collection with the following
statements:
ListBox1.Items.Add(New Font(”Verdana”, 12,
FontStyle.Bold)
ListBox1.Items.Add(New Rectangle(0, 0, 100, 100))
then the following strings appear on the ?rst two lines of the control:
[Font: Name=Verdana, Size=12, Units=3, GdiCharSet=1, gdiVerticalFont=False]
{X=0, Y=0, Width=100, Height=100}
However, you can access the members of the two objects because the ListBox stores objects, not
their descriptions. The following statement prints the width of the Rectangle object (the output
produced by the statement is highlighted):
Debug.WriteLine(ListBox1.Items.Item(1).Width)
100Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 198
198 CHAPTER 6 BASIC WINDOWS CONTROLS
The expression in the preceding statement is late-bound, which means that the compiler doesn’t
know whether the ?rst object in the Items collection is a Rectangle object and it can’t verify the
member Width. If you attempt to call the Width property of the ?rst item in the collection, you’ll
get an exception at runtime indicating that the code has attempted to access a missing member.
The missing member is the Width property of the Font object.
The proper way to read the objects stored in a ListBox control is to examine the type of the
object ?rst and then attempt to retrieve a property (or call a method) of the object, only if it’s of
the appropriate type. Here’s how you would read the Width property of a Rectangle object:
If ListBox1.Items.Item(0).GetType Is
GetType(Rectangle) Then
Debug.WriteLine(
CType(ListBox1.Items.Item(0), Rectangle).Width)
End If
The Add Method
To add items to the list, use the Items.Add or Items.Insert method. The syntax of the Add
method is as follows:
ListBox1.Items.Add(item)
The item parameter is the object to be added to the list. You can add any object to the ListBox
control, but items are usually strings. The Add method appends new items to the end of the list,
unless the Sorted property has been set to True.
The following loop adds the elements of the array words to a ListBox control, one at a time:
Dim words(100) As String
{ statements to populate array }
Dim i As Integer
Fori=0To99
ListBox1.Items.Add(words(i))
Next
Similarly, you can iterate through all the items on the control by using a loop such as the
following:
Dim i As Integer
Fori=0To ListBox1.Items.Count - 1
{ statements to process item ListBox1.Items(i) }
Next
You can also use the For Each ... Next statement to iterate through the Items collection, as
shown here:
Dim itm As Object
For Each itm In ListBox1.Items
{ process the current item, represented by the itm variable }
NextPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 199
THE LISTBOX, CHECKEDLISTBOX, AND COMBOBOX CONTROLS 199
When you populate a ListBox control with a large number of items, call the BeginUpdate
method before starting the loop and call the EndUpdate method when you’re done. These
two methods turn off the visual update of the control while you’re populating it and they speed
up the process considerably. When the EndUpdate method is called, the control is redrawn with
all the items.
The Insert Method
To insert an item at a speci?c location, use the Insert method, whose syntax is as follows:
ListBox1.Items.Insert(index, item)
The item parameter is the object to be added, and index is the location of the new item. The ?rst
item’s index in the list is zero. Note that you need not insert items at speci?c locations when the list
is sorted. If you do, the items will be inserted at the speci?ed locations, but the list will no longer
be sorted.
The Clear Method
The Clear method removes all the items from the control. Its syntax is quite simple:
List1.Items.Clear
The Count Property
This is the number of items in the list. If you want to access all the items with a For ... Next loop,
the loop’s counter must go from 0 to ListBox.Items.Count - 1,asshownintheexampleofthe
Add method.
The CopyTo Method
The CopyTo method of the Items collection retrieves all the items from a ListBox control and stores
them in the array passed to the method as an argument. The syntax of the CopyTo method is
ListBox.CopyTo(destination, index)
where destination is the name of the array that will accept the items, and index is the index of
an element in the array where the ?rst item will be stored. The array that will hold the items of the
control must be declared explicitly and must be large enough to hold all the items.
The Remove and RemoveAt Methods
To remove an itemfromthe list, you can simply call the Items collection’s Remove method, passing
the object to be removed as an argument. If the control contains strings, pass the string to be
removed. If the same string appears multiple times on the control, only the ?rst instance will
be removed.
You can also remove an item by specifying its position in the list via the RemoveAt method,
which accepts as argument the position of the item to be removed:
ListBox1.Items.RemoveAt(index)
The index parameter is the order of the item to be removed, and the ?rst item’s order is 0.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 200
200 CHAPTER 6 BASIC WINDOWS CONTROLS
The Contains Method
The Contains method of the Items collection — not to be confused with the control’s Contains
method — accepts an object as an argument and returns a True/False value that indicates whether
the collection contains this object. Use the Contains method to avoid the insertion of identical
objects into the ListBox control. The following statements add a string to the Items collection, only
if the string isn’t already part of the collection:
Dim itm As String = ”Remote Computing”
If Not ListBox1.Items.Contains(itm) Then
ListBox1.Items.Add(itm)
End If
Selecting Items
The ListBox control allows the user to select either one or multiple items, depending on the setting
of the SelectionMode property. In a single-selection ListBox control, you can retrieve the selected
item by using the SelectedItem property, and its index by using the SelectedIndex property.
SelectedItem returns the selected item, which is an object. The text of the selected itemis reported
by the Text property.
If the control allows the selection of multiple items, they’re reported with the SelectedItems
property. This property is a collection of objects and exposes the same members as the Items
collection. Because the ComboBox does not allow the selection of multiple items, it provides only
the SelectedIndex and SelectedItem properties.
To iterate through all the selected items in a multiselection ListBox control, use a loop such as
the following:
Dim itm As Object
For Each itm In ListBox1.SelectedItems
Debug.WriteLine(itm)
Next
The itm variable should be declared as Object because the items in the ListBox control are
objects. If they’re all of the same type, you can convert them to the speci?c type and then call their
methods. If all the items are of the Rectangle type, you can use a loop like the following to print
the area of each rectangle:
Dim itm As Rectangle
For Each itm In ListBox1.SelectedItems
Debug.WriteLine(itm.Width * itm.Height)
Next
VB 2008 at Work: The ListBox Demo Project
The ListBox Demo application (shown in Figure 6.6) demonstrates the basic operations of the
ListBox control. The two ListBox controls on the form operate slightly differently. The ?rst has
the default con?guration: Only one item can be selected at a time, and new items are appended
after the existing item. The second ListBox control has its Sorted property set to True and its
MultiSelect property set according to the values of the two RadioButton controls at the bottom
of the form.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 201
THE LISTBOX, CHECKEDLISTBOX, AND COMBOBOX CONTROLS 201
The code for the ListBox Demo application contains much of the logic you’ll need in your
ListBox manipulation routines. It shows you how to do the following:
? Add and remove items at runtime
? Transfer items between lists at runtime
? Handle multiple selected items
? Maintain sorted lists
Figure 6.6
ListBox Demo
demonstrates most of
the operations
you’ll perform with
ListBoxes.
The Add Item Buttons
The Add Item buttons use the InputBox() function to prompt the user for input, and then they
add the user-supplied string to the ListBox control. The code is identical for both buttons
(see Listing 6.10).
Listing 6.10: The Add New Element Buttons
Private Sub bttnSourceAdd Click(...)
Handles bttnSourceAdd.Click
Dim ListItem As String
ListItem = InputBox(”Enter new item’s name”)Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 202
202 CHAPTER 6 BASIC WINDOWS CONTROLS
If ListItem.Trim <> ”” Then
sourceList.Items.Add(ListItem)
End If
End Sub
Notice that the subroutine examines the data entered by the user to avoid adding blank strings
to the list. The code for the Clear buttons is also straightforward; it simply calls the Clear method
of the Items collection to remove all entries from the corresponding list.
Removing Items from the Two Lists
The code for the Remove Selected Item button is different from that for the Remove Selected Items
button (both are presented in Listing 6.11). The code for the Remove Selected Item button removes
the selected item, while the Remove Selected Items buttons must scan all the items of the left list
and remove the selected one(s).
Listing 6.11: The Remove Buttons
Private Sub bttnDestinationRemove Click(...)
Handles bttnDestinationRemove.Click
destinationList.Items.Remove( destinationList.SelectedItem)
End Sub
Private Sub bttnSourceRemove Click(...)
Handles bttnSourceRemove.Click
Dim i As Integer
For i = 0 To sourceList.SelectedIndices.Count - 1
sourceList.Items.RemoveAt( sourceList.SelectedIndices(0))
Next
End Sub
Even if it’s possible to remove an item by its value, this is not a safe approach. If two items have
the same name, the Remove method will remove the ?rst one. Unless you’ve provided the code to
make sure that no identical items can be added to the list, remove them by their index, which
is unique.
Notice that the code always removes the ?rst item in the SelectedIndices collection. If you
attempt to remove the item SelectedIndices(i), you will remove the ?rst selected item, but
after that you will not remove all the selected items. After removing an item from the selection,
the remaining items are no longer at the same locations. (In effect, you have to refresh the
SelectedIndices collection.) The second selected itemwill take the place of the ?rst selected item,
which was just deleted, and so on. By removing the ?rst item in the SelectedIndices collection,
we make sure that all selected items, and only those items, will be eventually removed.
Moving Items between Lists
The two single-arrow buttons that are between the ListBox controls shown in Figure 6.6 transfer
selected items from one list to another. The button with the single arrow pointing to the rightPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 203
THE LISTBOX, CHECKEDLISTBOX, AND COMBOBOX CONTROLS 203
transfers the items selected in the left list, after it ensures that the list contains at least one selected
item. Its code is presented in Listing 6.12. First, it adds the item to the second list, and then it
removes the item from the original list. Notice that the code removes an item by passing it as an
argument to the Remove method because it doesn’t make any difference which one of two identical
objects will be removed.
Listing 6.12: Moving the Selected Items
Private Sub bttnSourceMove Click(...)
Handles bttnSourceMove.Click
While sourceList.SelectedIndices.Count > 0
destinationList.Items.Add(sourceList.Items(
sourceList.SelectedIndices(0)))
sourceList.Items.Remove(sourceList.Items(
sourceList.SelectedIndices(0)))
End While
End Sub
The second single-arrow button transfers items in the opposite direction. The destination
control (the one on the right) doesn’t allow the selection of multiple items, so you could use the
SelectedIndex and SelectedItem properties. Because the single selected element is also part of
the SelectedItems collection, you need not use a different approach. The statements that move a
single item from the right to the left ListBox are shown next:
sourceList.Items.Add(destinationList.SelectedItem)
destinationList.Items.RemoveAt(
destinationList.SelectedIndex)
Searching the ListBox
Two of the most useful methods of the ListBox control are the FindString and FindStringExact
methods, which allow you to quickly locate any item in the list. The FindString method locates
a string that partially matches the one you’re searching for; FindStringExact ?nds an exact
match. If you’re searching for Man, and the control contains a name such asMans?eld, FindString
matches the item, but FindStringExact does not.
Both the FindString and FindStringExact methods perform case-insensitive searches.
If you’re searching for visual, and the list contains the item Visual, both methods will locate it.
Their syntax is the same:
itemIndex = ListBox1.FindString(searchStr As String)
where searchStr is the string you’re searching for. An alternative formof bothmethods allows
you to specify the order of the item at which the search will begin:
itemIndex = ListBox1.FindString(searchStr As String,
startIndex As Integer)Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 204
204 CHAPTER 6 BASIC WINDOWS CONTROLS
The startIndex argument allows you to specify the beginning of the search, but you can’t
specify where the search will end.
The FindString and FindStringExact methods work even if the ListBox control is not sorted.
You need not set the Sorted property to True before you call one of the searching methods on
the control. Sorting the list will help the search operation, but it takes the control less than 100
milliseconds to ?nd an item in a list of 100,000 items, so time spent to sort the list isn’t worth it.
Before you load thousands of items in a ListBox control, however, you should probably consider
a more-functional interface.
VB 2008 at Work: The ListBoxFind Application
The application you’ll build in this section (seen in Figure 6.7) populates a list with a large
number of items and then locates any string you specify. Click the button Populate List to populate
the ListBox control with 10,000 random strings. This process will take a few seconds and will
populate the control with different random strings every time. Then, you can enter a string in
the TextBox control at the bottom of the form. As you type characters (or even delete characters
in the TextBox), the program will locate the closest match in the list and select (highlight) this item.
Figure 6.7
The ListBoxFind
application
The sample application reacts to each keystroke in the TextBox control and locates the string
you’re searching for instantly. The Find Item button does the same, but I thought I should
demonstrate the ef?ciency of the ListBox control and the type of functionality you’d expect in a
rich client application.
The code (shown in Listing 6.13) attempts to locate an exact match via the FindStringExact
method. If it succeeds, it reports the index of the matching element. If not, it attempts to locate
a near match with the FindString method. If it succeeds, it reports the index of the near match
(which is the ?rst item on the control that partially matches the search argument) and terminates.
If it fails to ?nd an exact match, it reports that the string wasn’t found in the list.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 205
THE LISTBOX, CHECKEDLISTBOX, AND COMBOBOX CONTROLS 205
Listing 6.13: Searching the List
Private Sub TextBox1 TextChanged(...) Handles TextBox1.TextChanged
Dim srchWord As String = TextBox1.Text.Trim
If srchWord.Length = 0 Then Exit Sub
Dim wordIndex As Integer
wordIndex = ListBox1.FindStringExact(srchWord)
If wordIndex >= 0 Then
ListBox1.TopIndex = wordIndex
ListBox1.SelectedIndex = wordIndex
Else
wordIndex = ListBox1.FindString(srchWord)
If wordIndex >= 0 Then
ListBox1.TopIndex = wordIndex
ListBox1.SelectedIndex = wordIndex
Else
Debug.WriteLine(”Item ” & srchWord &
” is not in the list”)
End If
End If
End Sub
If you search for SAC, for example, and the control contains a string such as ”SAC” or ”sac” or
”sAc”, the program will return the index of the item in the list and will report an exact match. If
no exact match can be found, the program will return something like ”SACDEF”,ifsuchastring
exists on the control, as a near match. If none of the strings on the control starts with the characters
SAC, the search will fail.
Populating the List
The Populate List button creates 10,000 random items with the help of the Random class. First, it
generates a randomvalue in the range 1 through 20,which is the length of the string (not all strings
have the same length). Then the program generates as many random characters as the length of
the string and builds the string by appending each character to it. These random numbers are
in the range of 65 to 91 and they’re the ANSI values of the uppercase characters.
The ComboBox Control
The ComboBox control is similar to the ListBox control in the sense that it contains multiple items
and the user may select one, but it typically occupies less space onscreen. The ComboBox is
practically an expandable ListBox control, which can grow when the user wants to make a selec-
tion and retract after the selection is made. Normally, the ComboBox control displays one line
with the selected item, as this control doesn’t allow multiple item selection. The essential differ-
ence, however, between ComboBox and ListBox controls is that the ComboBox allows the user to
specify items that don’t exist in the list.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 206
206 CHAPTER 6 BASIC WINDOWS CONTROLS
There are three types of ComboBox controls. The value of the control’s Style property
determines which box is used; these values are shown in Table 6.4.
Table 6.4: Styles of the ComboBox Control
Value Effect
DropDown (Default) The control is made up of a drop-down list, which is visible at all times, and a
text box. The user can select an item from the list or type a new one in the text box.
DropDownList This style is a drop-down list from which the user can select one of its items but can’t
enter a new one. The control displays a single item, and the list is expanded as needed.
Simple The control includes a text box and a list that doesn’t drop down. The user can select
from the list or type in the text box.
The ComboBox Styles project, shown in Figure 6.8, demonstrates the three styles of the
ComboBox control. This is another common element of the Windows interface, and its properties
and methods are identical to those of the ListBox control. Load the ComboBox Styles project in the
Visual Basic IDE and experiment with the three styles of the ComboBox control.
The DropDown and Simple ComboBox controls allow the user to select an item from the
list or enter a new one in the edit box of the control. Moreover, they’re collapsed by default
and they display a single item, unless the user expands the list of items to make a selection.
The DropDownList ComboBox is similar to a ListBox control in the sense that it restricts the user
to selecting an item (the user cannot enter a new one). However, it takes much less space on the
form than a ListBox does, because normally it displays a single item.When the user wants to make
a selection, the DropDownList expands to display more items. After the user has made a selection,
the list contracts to a single line again.
Figure 6.8a
The Simple ComboBox
displays a ?xed number
of items at all times.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 207
THE LISTBOX, CHECKEDLISTBOX, AND COMBOBOX CONTROLS 207
Figure 6.8b
The DropDown
ComboBox displays a
single item, and users
can either expand the
items or type something
in the edit box.
Figure 6.8c
The DropDownList
ComboBox expands to
display its items, but
doesn’t allow users to
type anything in the
edit box.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 208
208 CHAPTER 6 BASIC WINDOWS CONTROLS
Most of the properties and methods of the ListBox control also apply to the ComboBox
control. The Items collection gives you access to the control’s items, and the SelectedIndices
and SelectedItems collections give you access to the items in the current selection. If the
control allows only a single item to be selected, use the properties SelectedIndex and
SelectedItem. You can also use the FindString and FindStringExact methods to locate
any item in the control.
There’s one aspect worth mentioning regarding the operation of the control. Although the edit
box at the top allows you to enter a new string, the new string doesn’t become a new item in the
list. It remains there until you select another item or you clear the edit box. You can provide some
code to make any string entered by the user in the control’s edit box be added to the list of
existing items.
The most common use of the ComboBox control is as a lookup table. The ComboBox control
takes up very little space on the form, but it can be expanded at will. You can save evenmore space
when the ComboBox is contracted by setting it to a width that’s too small for the longest item. Use
the DropDownWidth property, which is the width of the segment of the drop-down list. By default,
this property is equal to the control’s Width property. The second ComboBox control in Figure 6.8
contains an unusually long item. The control is wide enough to display the default selection.When
the user clicks the arrow to expand the control, the drop-down section of the control is wider
than the default width, so that the long items can be read.
Adding Items to a ComboBox at Runtime
Although the ComboBox control allows users to enter text in the control’s edit box, it doesn’t
provide a simple mechanism for adding new items at runtime. Let’s say you provide a ComboBox
with city names. Users can type the ?rst few characters and quickly locate the desired item. But
what if you want to allow users to add new city names? You can provide this feature with two
simple techniques. The simpler one is to place a button with an ellipsis (three periods) right next
to the control. When users want to add a new item to the control, they can click the button and be
prompted for the new item.
A more-elegant approach is to examine the control’s Text property as soon as the control loses
focus, or the user presses the Enter key. If the string entered by the user doesn’t match an item on
the control, youmust add a new itemto the control’s Items collection and select the new itemfrom
within your code. The FlexComboBox project demonstrates how to use both techniques in your
code. The main form of the project, which is shown in Figure 6.9, is a simple data-entry screen. It’s
not the best data-entry form, but it’s meant for demonstration purposes.
Figure 6.9
The FlexComboBox
project demonstrates
two techniques for
adding new items to
aComboBoxatruntime.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 209
THE LISTBOX, CHECKEDLISTBOX, AND COMBOBOX CONTROLS 209
You can either enter a city name (or country name) and press the Tab key to move to another
control or click the button next to the control to be prompted for a new city/country name. The
application will let you enter any city/country combination. You should provide code to limit
the cities within the selected country, but this is a nontrivial task. You also need to store the new
city names entered on the ?rst ComboBox control to a ?le (or a database table), so users will ?nd
them there the next time they execute the application. I haven’t made the application elaborate;
I’ve added the code only to demonstrate how to add new items to a ComboBox control at runtime.
VB 2008 At Work: The FlexCombo Project
The ellipsis button next to the City ComboBox control prompts the user for the new item via
the InputBox() function. Then it searches the Items collection of the control via the FindString
method, and if the new item isn’t found, it’s added to the control. Then the code selects the new
item in the list. To do so, it sets the control’s SelectedIndex property to the value returned by the
Items.Add method, or the value returned by the FindString method, depending on whether
the item was located or added to the list. Listing 6.14 shows the code behind the ellipsis button.
Listing 6.14: Adding a New Itemto the ComboBox Control at Runtime
Private Sub Button1 Click(...) Button1.Click
Dim itm As String
itm = InputBox(”Enter new item”, ”New Item”)
If itm.Trim <> ”” Then AddElement(itm)
End Sub
The AddElement() subroutine, which accepts a string as an argument and adds it to the control,
is shown in Listing 6.15. If the item doesn’t exist in the control, it’s added to the Items collection.
If the item is a member of the Items collection, it’s selected. As you will see, the same subroutine
will be used by the second method for adding items to the control at runtime.
Listing 6.15: The AddElement() Subroutine
Sub AddElement(ByVal newItem As String)
Dim idx As Integer
If ComboBox1.FindString(newItem) > 0 Then
idx = ComboBox1.FindString(newItem)
Else
idx = ComboBox1.Items.Add(newItem)
End If
ComboBox1.SelectedIndex = idx
End Sub
You can also add new items at runtime by adding the same code in the control’s LostFocus
event handler:
Private Sub ComboBox1 LostFocus(...) Handles ComboBox1.LostFocus
Dim newItem As String = ComboBox1.Text
AddElement(newItem)
End SubPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 210
210 CHAPTER 6 BASIC WINDOWS CONTROLS
The ScrollBar and TrackBar Controls
The ScrollBar and TrackBar controls let the user specify a magnitude by scrolling a selector
between its minimum and maximum values. In some situations, the user doesn’t know in advance
the exact value of the quantity to specify (in which case, a text box would suf?ce), so your
application must provide a more-?exible mechanism for specifying a value, along with some
type of visual feedback.
The vertical scroll bar that lets a user move up and down a long document is a typical example
of the use of the ScrollBar control. The scroll bar and visual feedback are the prime mechanisms for
repositioning the view in a long document or in a large picture thatwon’t ?t entirely in its window.
The TrackBar control is similar to the ScrollBar control, but it doesn’t cover a continuous range
of values. The TrackBar control has a ?xed number of tick marks, which the developer can label
(for example, Still, Slow, and Warp Speed, as shown in Figure 6.10). Users can place the slider’s
indicator to the desired value.Whereas the ScrollBar control relies on some visual feedback outside
the control to help the user position the indicator to the desired value, the TrackBar control
forces the user to select from a range of valid values.
In short, the ScrollBar control should be used when the exact value isn’t as important as the
value’s effect on another object or data element. The TrackBar control should be used when
the user can type a numeric value and the value your application expects is a number in a speci?c
range; for example, integers between 0 and 100, or a value between 0 and 5 inches in steps of 0.1
inches (0.0, 0.1, 0.2 ... 5.0). The TrackBar control is preferred to the TextBox control in similar
situations because there’s no need for data validation on your part. The user can specify only valid
numeric values with the mouse.
Figure 6.10
The TrackBar control
lets the user select one
of several discrete
values.
The ScrollBar Control
There’s no ScrollBar control per se in the Toolbox; instead, there are two versions of it: the HScroll-
Bar and VScrollBar controls. They differ only in their orientation, but because they share the same
members, I will refer to both controls collectively as ScrollBar controls. Actually, both controls
inherit from the ScrollBar control, which is an abstract control: It can be used to implement ver-
tical and horizontal scroll bars, but it can’t be used directly on a form. Moreover, the HScrollBar
and VScrollBar controls are not displayed in the Common Controls tab of the Toolbox. You have
to open the All Windows Forms tab to locate these two controls.
The ScrollBar control is a long stripe with an indicator that lets the user select a value between
the two ends of the control. The left (or bottom) end of the control corresponds to its minimum
value; the other end is the control’smaximumvalue. The current value of the control is determined
by the position of the indicator, which can be scrolled between the minimum and maximum
values. The basic properties of the ScrollBar control, therefore, are properly named Minimum,
Maximum,and Value.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 211
THE SCROLLBAR AND TRACKBAR CONTROLS 211
Minimum The control’s minimum value. The default value is 0, but because this is an
Integer value, you can set it to negative values as well.
Maximum The control’s maximum value. The default value is 100, but you can set it to any
value that you can represent with the Integer data type.
Value The control’s current value, speci?ed by the indicator’s position.
The Minimum and Maximum properties are Integer values. To cover a range of nonintegers, you
must supply the code to map the actual values to Integer values. For example, to cover a range
from 2.5 to 8.5, set the Minimum property to 25, set the Maximum property to 85, and divide the
control’s value by 10. If the range you need is from –2.5 to 8.5, do the same but set the Minimum
property to –25 and the Maximum value to 85, and divide the Value property by 10.
There are two more properties that allow you to control the movement of the indicator: the
SmallChange and LargeChange properties. The ?rst property is the amount by which the indicator
changes when the user clicks one of the arrows at the two ends of the control. The LargeChange
property is the displacement of the indicator when the user clicks somewhere in the scroll bar
itself. You can manipulate a scroll bar by using the keyboard as well. Press the arrow keys to
move the indicator in the corresponding direction by SmallChange, and the PageUp/PageDown
keys to move the indicator by LargeChange.
VB 2008 at Work: The Colors Project
Figure 6.11 shows the main form of the Colors sample project, which lets the user specify a color
by manipulating the value of its basic colors (red, green, and blue) through scroll bars. Each basic
color is controlled by a scroll bar and has a minimum value of 0 and a maximum value of 255. If
you aren’t familiar with color de?nition in the Windows environment, see the section ‘‘Specifying
Colors’’ in Chapter 19, ‘‘Manipulating Images and Bitmaps.’’
Figure 6.11
The Colors application
demonstrates the use of
the ScrollBar control.
As the scroll bar is moved, the corresponding color is displayed, and the user can easily specify
a color without knowing the exact values of its primary components. All the user needs to know
is whether the desired color contains, for example, too much red or too little green. With the help
of the scroll bars and the immediate feedback from the application, the user can easily pinpoint
the desired color. Notice that the exact values of the color’s basic components are of no practical
interest; only the ?nal color counts.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 212
212 CHAPTER 6 BASIC WINDOWS CONTROLS
The ScrollBar Control’s Events
The user can change the ScrollBar control’s value in three ways: by clicking the two arrows at its
ends, by clicking the area between the indicator and the arrows, and by dragging the indicator
with the mouse. You can monitor the changes of the ScrollBar’s value from within your code by
using two events: ValueChanged and Scroll. Both events are ?red every time the indicator’s
position is changed. If you change the control’s value from within your code, only the
ValueChanged event will be ?red.
The Scroll event can be ?red in response to many different actions, such as the scrolling of the
indicator with the mouse, a click on one of the two buttons at the ends of the scroll bars, and so
on. If you want to know the action that caused this event, you can examine the Type property of
the second argument of the event handler. The settings of the e.Type property are members of the
ScrollEventType enumeration (LargeDecrement, SmallIncrement, Track,andsoon).
Handling the Events in the Colors Application
The Colors application demonstrates how to program the two events of the ScrollBar control. The
two PictureBox controls display the color designed with the three scroll bars. The left PictureBox
is colored from within the Scroll event, whereas the other one is colored from within the
ValueChanged event. Both events are ?red as the user scrolls the scrollbar’s indicator, but in
the Scroll event handler of the three scroll bars, the code examines the value of the e.Type
property and reacts to it only if the event was ?red because the scrolling of the indicator has ended.
For all other actions, the event handler doesn’t update the color of the left PictureBox.
If the user attempts to change the Color value by clicking the two arrows of the scroll bars or by
clicking in the area to the left or to the right of the indicator, both PictureBox controls are updated.
While the user slides the indicator or keeps pressing one of the end arrows, only the PictureBox to
the right is updated.
The conclusion from this experiment is that you can program either event to provide
continuous feedback to the user. If this feedback requires too many calculations, which would
slow down the reaction of the corresponding event handler, you can postpone the reaction until
the user has stopped scrolling the indicator. You can detect this condition by examining the value
of the e.Type property.When it’s ScrollEventType.EndScroll, you can execute the appropriate
statements. Listing 6.16 shows the code behind the Scroll and ValueChanged events of the scroll
bar that controls the red component of the color. The code of the corresponding events of the other
two controls is identical.
Listing 6.16: Programming the ScrollBar Control’s Scroll Event
Private Sub redBar Scroll(...) Handles redBar.Scroll
If e.Type = ScrollEventType.EndScroll Then
ColorBox1()
lblRed.Text = ”RED ” & redBar.Value.ToString(”###”)
End If
End Sub
Private Sub redBar ValueChanged(...) Handles redBar.ValueChanged
ColorBox2()
End SubPetroutsos c06.tex V3 - 01/28/2008 12:50pm Page 213
THE SCROLLBAR AND TRACKBAR CONTROLS 213
The ColorBox1() and ColorBox2() subroutines update the color of the two PictureBox
controls by setting their background colors. You can open the Colors project in Visual Studio and
examine the code of these two routines.
The TrackBar Control
The TrackBar control is similar to the ScrollBar control, but it lacks the granularity of ScrollBar.
Suppose that you want the user of an application to supply a value in a speci?c range, such as the
speed of a moving object. Moreover, you don’t want to allow extreme precision; you need only
a few settings, as shown in the examples of Figures 6.10 and 6.12. The user can set the control’s
value by sliding the indicator or by clicking on either side of the indicator.
Figure 6.12
The Inches application
demonstrates the use
of the TrackBar control
in specifying an exact
value in a speci?c range.
Granularity is how speci?c youwant to be inmeasuring. Inmeasuring distances between towns,
a granularity of amile is quite adequate. In measuring (or specifying) the dimensions of a building,
the granularity could be on the order of a foot or an inch. The TrackBar control lets you set the type
of granularity that’s necessary for your application.
Similar to the ScrollBar control, SmallChange and LargeChange properties are available.
SmallChange is the smallest increment by which the Slider value can change. The user can change
the slider by the SmallChange value only by sliding the indicator. (Unlike the ScrollBar
control, there are no arrows at the two ends of the Slider control.) To change the Slider’s value by
LargeChange, the user can click on either side of the indicator.
VB 2008 at Work: The Inches Project
Figure 6.12 demonstrates a typical use of the TrackBar control. The form in the ?gure is an
element of a program’s user interface that lets the user specify a distance between 0 and 10 inches
in increments of 0.2 inches. As the user slides the indicator, the current value is displayed on a
Label control below the TrackBar. If you open the Inches application, you’ll notice that there are
more stops than there are tick marks on the control. This is made possible with the TickFrequency
property, which determines the frequency of the visible tick marks.
You might specify that the control has 50 stops (divisions), but that only 10 of them will be
visible. The user can, however, position the indicator on any of the 40 invisible tick marks. You can
think of the visible marks as the major tick marks, and the invisible ones as the minor tick marks.
If the TickFrequency property is 5, only every ?fth mark will be visible. The slider’s indicator,
however, will stop at all tick marks.
When using the TrackBar control on your interfaces, you should set the TickFrequency
property to a value that helps the user select the desired setting. Too many tick marks are
confusing and dif?cult to read. Without tick marks, the control isn’t of much help. You might also
consider placing a few labels to indicate the value of selected tick marks, as I have done in
this example.Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 214
214 CHAPTER 6 BASIC WINDOWS CONTROLS
The properties of the TrackBar control in the Inches application are as follows:
Minimum =0
Maximum =50
SmallChange =1
LargeChange =5
TickFrequency =5
The TrackBar needs to cover a range of 10 inches in increments of 0.2 inches. If you set the
SmallChange property to 1, you have to set LargeChange to 5. Moreover, the TickFrequency is
set to 5, so there will be a total of ?ve divisions in every inch. The numbers below the tick marks
were placed there with properly aligned Label controls.
The label at the bottomneeds to be updated as the TrackBar’s value changes. This is signaled to
the application with the Change event, which occurs every time the value of the control changes,
either through scrolling or from within your code. The ValueChanged event handler of the
TrackBar control is shown next:
Private Sub TrackBar1 ValueChanged(...)
Handles TrackBar1.ValueChanged
lblInches.Text = ”Length in inches = ” &
Format(TrackBar1.Value / 5, ”#.00”)
End Sub
The Label controls below the tick marks can also be used to set the value of the control. Every
time you click one of the labels, the following statement sets the TrackBar control’s value. Notice
that all the Label controls’ Click events are handled by a common handler:
Private Sub Label Click(...)
Handles Label1.Click, Label9.Click
TrackBar1.Value = sender.text * 5
End Sub
The BottomLine
Use the TextBox control as a data-entry and text-editing tool. The TextBox control is the
most common element of the Windows interface, short of the Button control, and it’s used
to display and edit text. You can use a TextBox control to prompt users for a single line of
text (such as a product name) or a small document (a product’s detailed description).
Master It What are the most important properties of the TextBox control? Which ones
would you set in the Properties windows at design-time?
Master It How will you implement a control that suggests lists of words matching the
characters entered by the user?
Use the ListBox, CheckedListBox, and ComboBox controls to present lists of items. The
ListBox control contains a list of items from which the user can select one or more, depending
on the setting of the SelectionMode property.
Master It How will you locate an item in a ListBox control?Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 215
THE BOTTOM LINE 215
Use the ScrollBar and TrackBar controls to enable users to specify sizes and positions with
the mouse. The ScrollBar and TrackBar controls let the user specify a magnitude by scrolling
a selector between its minimum and maximum values. The ScrollBar control uses some visual
feedback to display the effects of scrolling on another entity, such as the current view in a long
document.
Master It Which event of the ScrollBar control would you code to provide visual feedback to
the user?Petroutsos c06.tex V3 - 01/28/2008 12:50pm Page 216Petroutsos c07.tex V3 - 01/28/2008 1:11pm Page 217
Chapter 7
Working with Forms
In Visual Basic, the form is the container for all the controls that make up the user interface. When
a Visual Basic application is executing, each window it displays on the desktop is a form. The
terms form and window describe the same entity. A window is what the user sees on the desktop
when the application is running. A form is the same entity at design time. The proper term is a
Windows form, as opposed to a web form,butIwillrefertothemas forms. This term includes both
the regular forms and dialog boxes, which are simple forms you use for very speci?c actions, such
as to prompt the user for a particular piece of data or to display critical information. A dialog box
is a form with a small number of controls, no menus, and usually an OK and a Cancel button to
close it.
Forms have a built-in functionality that is always available without any programming effort on
your part. You can move a form around, resize it, and even cover it with other forms. You do so
with the mouse or with the keyboard through the Control menu.
In previous chapters, you concentrated on placing the elements of the user interface on forms,
setting their properties, and adding code behind selected events. Now, you’ll look at forms
themselves and at a few related topics. In this chapter, you’ll learn how to do the following:
? Use forms’ properties
? Design applications with multiple forms
? Design dynamic forms
? Design menus
Forms have many trivial properties that won’t be discussed here. Instead, let’s jump directly to
the properties that are unique to forms and then look at how to manipulate forms from within an
application’s code.
TheAppearance of Forms
Applications are made up of one or more forms — usually more than one. You should craft your
forms carefully, make them functional, and keep them simple and intuitive. You already know
how to place controls on the form, but there’s more to designing forms than populating them with
controls. The main characteristic of a form is the title bar on which the form’s caption is displayed
(see Figure 7.1).
Clicking the icon on the left end of the title bar opens the Control menu, which contains the
commands shown in Table 7.1. On the right end of the title bar are three buttons: Minimize,
Maximize, and Close. Clicking these buttons performs the associated function. When a form isPetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 218
218 CHAPTER 7 WORKING WITH FORMS
maximized, the Maximize button is replaced by the Restore button. When clicked, the Restore
button resets the form to the size and position before it was maximized, and it’s replaced by the
Maximize button. To access the Control menu without a mouse, press Alt and then the down
arrow key.
Figure 7.1
The elements of the
form
Table 7.1: Commands of the Control Menu
Command Effect
Restore Restores a maximized form to the size it was before it was maximized; available only if the
form has been maximized.
Move Lets the user move the form around with the arrow keys.
Size Lets the user resize the form with the arrow keys.
Minimize Minimizes the form.
Maximize Maximizes the form.
Close Closes the current form. (Closing the application’s main form terminates the application.)
Properties of the Form Object
You’re familiar with the appearance of forms, even if you haven’t programmed in the Windows
environment in the past; you have seen nearly all types of windows in the applications you’rePetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 219
THE APPEARANCE OF FORMS 219
using every day. The ?oating toolbars used by many graphics applications, for example, are actu-
ally forms with a narrow title bar. The dialog boxes that display critical information or prompt
you to select the ?le to be opened are also forms. You can duplicate the look of any window or
dialog box through the following properties of the Form object.
AcceptButton, CancelButton
These two properties let you specify the default Accept and Cancel buttons. The Accept button
is the one that’s automatically activated when you press Enter, no matter which control has the
focus at the time, and is usually the button with the OK caption. Likewise, the Cancel button is
the one that’s automatically activated when you hit the Esc key and is usually the button with the
Cancel caption. To specify the Accept and Cancel buttons on a form, locate the AcceptButton and
CancelButton properties of the form and select the corresponding controls from a drop-down
list, which contains the names of all the buttons on the form. For more information on these two
properties, see the section ‘‘Forms versus Dialog Boxes,’’ later in this chapter.
AutoScaleMode
This property determines how the control is scaled, and its value is a member of the AutoScale-
Mode enumeration: None (automatic scaling is disabled), Font (the controls on the form are scaled
relative to the size of their font), Dpi, which stands for dots per inch (the controls on the form are
scaled relative to the display resolution), and Inherit (the controls are scaled according to the
AutoScaleMode property of their parent class). The default value is Font; if you change the form’s
font size, the controls on it are scaled to the new font size.
AutoScroll
The AutoScroll property is a True/False value that indicates whether scroll bars will be auto-
matically attached to the form (as seen in Figure 7.2) if the form is resized to a point that not all
itscontrolsarevisible.Usethispropertytodesign large forms without having to worry about
the resolution of the monitor on which they’ll be displayed. The AutoScroll property is used in
conjunction with two other properties (described a little later in this section): AutoScrollMargin
and AutoScrollMinSize. Note that the AutoScroll property applies to a few controls as well,
including the Panel and SplitContainer controls. For example, you can create a form with a ?xed
and a scrolling pane by placing two Panel controls on it and setting the AutoScroll property of
one of them (the Panel you want to scroll) to True.
AutoScrollPosition
This property is available from within your code only (you can’t set this property at design time),
and it indicates the number of pixels that the form was scrolled up or down. Its initial value is
zero, and it assumes a value when the user scrolls the form (provided that the form’s AutoScroll
property is True). Use this property to ?nd out the visible controls from within your code, or scroll
the form programmatically to bring a speci?c control into view.
AutoScrollMargin
This is a margin, expressed in pixels, that’s added around all the controls on the form. If the form
is smaller than the rectangle that encloses all the controls adjusted by the margin, the appropriate
scroll bar(s) will be displayed automatically.Petroutsos c07.tex V3 - 01/28/2008 1:11pm Page 220
220 CHAPTER 7 WORKING WITH FORMS
Figure 7.2
If the controls don’t ?t
in the form’s visible
area, scroll bars can be
attached automatically.
AutoScrollMinSize
This property lets you specify the minimum size of the form before the scroll bars are attached.
If your form contains graphics that you want to be visible at all times, set the Width and Height
members of the AutoScrollMinSize property to the dimensions of the graphics. (Of course, the
graphics won’t be visible at all times, but the scroll bars indicate that there’s more to the form than
can ?t in the current window.) Notice that this isn’t the form’s minimum size; users can make
the form even smaller. To specify a minimum size for the form, use the MinimumSize property,
described later in this section.
Let’s say the AutoScrollMargin property of the form is 180 × 150. If the form is resized to
fewer than 180 pixels horizontally or 150 pixels vertically, the appropriate scroll bars will appear
automatically, as long as the AutoScroll property is True. If you want to enable the Auto-
Scroll feature when the form’s width is reduced to anything fewer than 250 pixels, set the
AutoScrollMinSize property to (250, 0). In this example, setting AutoScrollMinSize.Width
to anything less than 180, or AutoScrollMinSize.Height to anything less than 150, will have no
effect on the appearance of the form and its scroll bars.
Bringing Selected Controls into View
In addition to the Autoscroll properties, the Form object provides the Scroll method, which
allows you to scroll a form programmatically, and ScrollControlIntoView, which scrolls the form
until the speci?ed control comes into view. The Scroll method accepts as arguments the horizontal
and vertical displacements of the scrolling operation, whereas ScrollControlIntoView accepts as
an argument the control you want to bring into view. Notice that activating a control with the Tab key
automatically brings the control into view if it’s not already visible on the form. Finally, the Scroll
event is ?red every time a form is scrolled.
FormBorderStyle
The FormBorderStyle property determines the style of the form’s border; its value is one
of the FormBorderStyle enumeration’s members, which are shown in Table 7.2. You can make
the form’s title bar disappear altogether by setting the form’s FormBorderStyle property toPetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 221
THE APPEARANCE OF FORMS 221
FixedToolWindow,the ControlBox property to False, and the Text property (the form’s caption)
to an empty string. However, a form like this can’t be moved around with the mouse and will
probably frustrate users.
Table 7.2: The FormBorderStyle Enumeration
Value Effect
None A borderless window that can’t be resized. This setting is rarely used.
Sizable (default) A resizable window that’s used for displaying regular forms.
Fixed3D A window with a ?xed visible border, ‘‘raised’’ relative to the main area. Unlike the
None setting, this setting allows users to minimize and close the window.
FixedDialog A ?xed window used to implement dialog boxes.
FixedSingle A ?xed window with a single-line border.
FixedToolWindow A ?xed window with a Close button only. It looks like a toolbar displayed by
drawing and imaging applications.
SizableToolWindow Same as the FixedToolWindow, but is resizable. In addition, its caption font is
smaller than the usual.
ControlBox
This property is also True by default. Set it to False to hide the control box icon and disable the
Control menu. Although the Control menu is rarely used, Windows applications don’t disable it.
When the ControlBox property is False, the three buttons on the title bar are also disabled. If you
set the Text property to an empty string, the title bar disappears altogether.
MinimizeBox, MaximizeBox
These two properties, which specify whether the Minimize and Maximize buttons will appear on
the form’s title bar, are True by default. Set them to False to hide the corresponding buttons on the
form’s title bar.
MinimumSize, MaximumSize
These two properties read or set the minimum and maximum size of a form. When users resize
the form at runtime, the form won’t become any smaller than the dimensions speci?ed by the
MinimumSize property and no larger than the dimensions speci?ed by the MaximumSize property.
The MinimumSize property is a Size object, and you can set it with a statement like the following:
Me.MinimumSize = New Size(400, 300)
Or you can set the width and height separately:
Me.MinimumSize.Width = 400
Me.MinimumSize.Height = 300Petroutsos c07.tex V3 - 01/28/2008 1:11pm Page 222
222 CHAPTER 7 WORKING WITH FORMS
The MinimumSize.Height property includes the height of the form’s title bar; you should take
that into consideration. If the minimum usable size of the form is 400 × 300, use the following
statement to set the MinimumSize property:
Me.MinimumSize = New Size(400, 300 + SystemInformation.CaptionHeight)
The default value of both properties is (0, 0), which means that no minimum or maximum size
is imposed on the form, and the user can resize it as desired.
Use the SystemInformation Class to Read System Information
The height of the caption is not a property of the Form object, even though it’s used to determine
the useful area of the form (the total height minus the caption bar). Keep in mind that the height
of the caption bar is given by the CaptionHeight property of the SystemInformation object. You
should look up the SystemInformation object, which exposes a lot of useful properties — such as
BorderSize (the size of the form’s borders), Border3DSize (the size of three-dimensional borders),
CursorSize (the cursor’s size), and many more.
KeyPreview
This property enables the form to capture all keystrokes before they’re passed to the control that
has the focus. Normally, when you press a key, the KeyPress event of the control with the focus
is triggered (as well as the KeyUp and KeyDown events), and you can handle the keystroke from
within the control’s appropriate handler. In most cases, you let the control handle the keystroke
and don’t write any form code for that.
If you want to use ‘‘universal’’ keystrokes in your application, you must set the KeyPreview
property to True. Doing so enables the form to intercept all keystrokes, so you can process them
fromwithin the form’s keystroke event handlers. To handle a speci?c keystroke at the form’s level,
set the form’s KeyPreview property to True and insert the appropriate code in the form’s KeyDown
or KeyUp event handler (the KeyPress event isn’t ?red for the function keys).
The same keystrokes are then passed to the control with the focus, unless you ‘‘kill’’ the
keystroke by setting its SuppressKeystroke property to True when you process it on the form’s
level. Formore information on processing keystrokes at the formlevel and using special keystrokes
throughout your application, see the Contacts project later in this chapter.
SizeGripStyle
This property gets or sets the style of the sizing handle to display in the bottom-right corner of
the form. You can set it to a member of the SizeGripStyle enumeration: Auto (the size grip is
displayed as needed), Show (the size grip is displayed at all times), or Hide (the size grip is not
displayed, but users can still resize the form with the mouse).
StartPosition, Location
The StartPosition property, which determines the initial position of the form when it’s ?rst
displayed, can be set to one of the members of the FormStartPosition enumeration: Center-
Parent (the form is centered in the area of its parent form), CenterScreen (the form is centered
on the monitor), Manual (the position of the form is determined by the Location property),
WindowsDefaultLocation (the form is positioned at the Windows default location), andPetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 223
THE APPEARANCE OF FORMS 223
WindowsDefaultBound (the form’s location and bounds are determined by Windows defaults).
The Location property allows you to set the form’s initial position at design time or to change the
form’s location at runtime.
TopMost
This property is a True/False value that lets you specify whether the form will remain on top of all
other forms in your application. Its default property is False, and you should change it only on rare
occasions. Some dialog boxes, such as the Find & Replace dialog box of any text-processing appli-
cation, are always visible, even when they don’t have the focus. For more information on using
the TopMost property, see the discussion of the TextPad project in Chapter 6, ‘‘Basic Windows
Controls.’’ You can also add a professional touch to your application by providing a CheckBox
control that determines whether a form should remain on top of all other forms of the application.
Size
Use the Size property to set the form’s size at design time or at runtime. Normally, the form’s
width and height are controlled by the user at runtime. This property is usually set from within
the form’s Resize event handler to maintain a reasonable aspect ratio when the user resizes the
form. The Form object also exposes the Width and Height properties for controlling its size.
Placing Controls on Forms
The ?rst step in designing your application’s interface is, of course, the analysis and careful
planning of the basic operations you want to provide through your interface. The second step is
to design the forms. Designing a form means placing Windows controls on it, setting the controls’
properties, and then writing code to handle the events of interest. Visual Studio 2008 is a rapid
application development (RAD) environment. This doesn’t mean that you’re expected to develop
applications rapidly. It has come to mean that you can rapidly prototype an application and show
something to the customer. And this is made possible through the visual tools that come with VS
2008, especially the new Form Designer.
To place controls on your form, you select them in the Toolbox and then draw, on the form,
the rectangle in which the control will be enclosed. Or you can double-click the control’s icon to
place an instance of the control on the form. All controls have a default size, and you can resize
the control on the form by using the mouse.
Each control’s dimensions can also be set in the Properties window through the Size property.
The Size property exposes the Width and Height components, which are expressed in pixels.
Likewise, the Location property returns (or sets) the coordinates of the top-left corner of the
control. In the section ‘‘Building Dynamic Forms at Runtime,’’ later in this chapter, you’ll see how
to create new controls at runtime and place them in a speci?c location on a form from within
your code.
As you place controls on the form, you can align them in groups by using the commands of the
Format menu. Select multiple controls on the form by using the mouse and the Shift (or Ctrl) key,
and then align their edges or their middles with the appropriate command of the Format menu.
To align the left edges of a column of TextBoxes, choose the Format  Align  Left command. You
can also use the commands of the Format  Make Same Size command to adjust the dimensions
of the selected controls. (To make them equal in size, make their widths or heights equal.)
As you move controls around with the mouse, a blue snap line appears when the controls
become nearly aligned with another control. Release the mouse while the snap line is visible to
leave the control aligned with the one indicated by the snap lines. The blue snap lines indicate edge
alignment. Most of the time, we need to align not the edges of two controls, but their baselinesPetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 224
224 CHAPTER 7 WORKING WITH FORMS
(the baseline of the text on the control). The snap lines that indicate baseline alignment are red.
Figure 7.3 shows both types of snap lines. When we’re aligning a Label control with its matching
TextBox control on a form, we want to align their baselines, not their frames (especially if you con-
sider that the Label controls are always displayed without borders). If the control is aligned with
other controls in both directions, two snap lines will appear— a horizontal one and a vertical one.
Figure 7.3
Edge alignment (top)
and baseline alignment
(bottom)
Setting the TabOrder Property
Another important issue in form design is the tab order of the controls on the form. As you know,
pressing the Tab key at runtime takes you to the next control on the form. The order of the controls
is the order in which they were placed on the form, but this is never what we want. When you
design the application, you can specify in which order the controls receive the focus (the tab order,
as it is known) with the help of the TabOrder property. Each control has its own TabOrder setting,
which is an integer value. When the Tab key is pressed, the focus is moved to the control whosePetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 225
THE APPEARANCE OF FORMS 225
tab order immediately follows the tab order of the current control. The values of the TabOrder
properties of the various controls on the form need not be consecutive.
To specify the tab order of the various controls, you can set their TabOrder property in the
Properties window or you can choose the Tab Order command from the View menu. The tab
order of each control will be displayed on the corresponding control, as shown in Figure 7.4. (The
form shown in the ?gure is the Contacts application, which is discussed shortly.)
Figure 7.4
Setting the tab order of
the controls on the main
form of the Contacts
project
To set the tab order of the controls, click each control in the order in which you want them to
receive the focus. You must click all of them in the desired order, starting with the ?rst control in
the tab order. Each control’s index in the tab order appears in the upper-left corner of the control.
When you’re ?nished, choose the Tab Order command from the View menu again to hide these
numbers.
As you place controls on the form, don’t forget to lock them, so that you won’t move them
around by mistake as you work with other controls. You can lock the controls in their places either
by setting each control’s Locked property to True or by locking all the controls on the form at once
via the Format  Lock Controls command.
Design with the User In Mind
Designing functional forms is a crucial step in the process of developing Windows applications. Most
data-entry operators don’t work with the mouse, and you mustmake sure that all the actions (such as
switching to another control, opening a menu, clicking a button, and so on) can be performed with
the keyboard. This requirement doesn’t apply to graphics applications, of course, but most applica-
tions developed with VB are business applications, and users should be able to perform most of the
tasks with the keyboard, not with the mouse.Petroutsos c07.tex V3 - 01/28/2008 1:11pm Page 226
226 CHAPTER 7 WORKING WITH FORMS
In my experience, the most important aspect of the user interface of a business application is the
handling of the Enter keystroke. When a TextBox control has the focus, the Enter keystroke should
advance the focus to the next control in the tab order; when a list control (such as the ListBox or
ListView control) has the focus, the Enter keystroke should invoke the same action as double-clicking
the current item. The sample project in the following section demonstrates many of the features
you’d expect from a data-entry application.
If you’re developing a data-entry form, you must take into consideration the needs of the users. Make
a prototype and ask the people who will use the application to test-drive it. Listen to their objections
carefully, collect all the information, and then use it to re?ne your application’s user interface. Don’t
defend your design — just learn from the users. They will uncover all the ?aws of the application and
they’ll help you design the most functional interface. In addition, they will accept the ?nished appli-
cation with fewer objections and complaints if they know what to expect.
VB 2008 at Work: The Contacts Project
I want to conclude this section with a simple data-entry application that demonstrates many of
the topics discussed here, as well as a few techniques for designing easy-to-use forms. Figure 7.5
shows a data-entry form for maintaining contact information, and I’m sure you will add your own
?elds to make this application more useful.
Figure 7.5
A simple data-entry
screen
You can navigate through the contacts by clicking the buttons with the arrows, as well as add
new contacts or delete existing ones by clicking the appropriate buttons. When you’re entering a
new contact, the buttons shown in Figure 7.5 are replaced by the usual OK and Cancel buttons.
The action of adding a new contact, or editing an existing one, must end by clicking one of these
two buttons. After committing a new contact or canceling the action, the usual navigation buttons
appear again.Petroutsos c07.tex V3 - 01/28/2008 1:11pm Page 227
THE APPEARANCE OF FORMS 227
Place the controls you see in Figure 7.5 on the form and align them appropriately. After the
controls are on the form, the next step is to set their tab order. You must specify a TabOrder
even for controls that never receive focus, such as the Label controls. In addition to the tab order
of the controls, we’ll also use shortcut keys to give the user quick access to the most common
?elds. The shortcut keys are displayed as underlined characters on the corresponding labels.
Notice that the Label controls have shortcut keys, even though they don’t receive the focus. When
you press the shortcut key of a Label, the focus is moved to the following control in the tab order,
which is the TextBox control next to it.
If you run the application now, you’ll see that the focus moves from one TextBox to the next
and that the labels are skipped. After the last TextBox control, the focus is moved to the buttons
and then back to the ?rst TextBox control. To add a shortcut key for the most common ?elds,
determine which ?elds will have shortcut keys and then which keys will be used for that purpose.
Being the Internet buffs that we all are, let’s assign shortcut keys to the Company, EMail, and URL
?elds. Locate each label’s Text property in the Properties window and insert the & symbol in
front of the character you want to act as a shortcut for each Label. The Text properties of the three
controls should be &Company, &EMail,and &URL.
Shortcut keys are activated at runtime by pressing the shortcut character while holding down
the Alt key. The shortcut key will move the focus to the corresponding Label control, but because
labels can’t receive the focus, the focus is moved immediately to the next control in the tab order,
which is the adjacent TextBox control.
The contacts are stored in an ArrayList object, which is similar to an array but a little more
convenient. We’ll discuss ArrayLists in Chapter 14, ‘‘Storing Data in Collections’’; for now, you
can ignore the parts of the application that manipulate the contacts and focus on the design issues.
Start by loading the sample data included with the application. Open the File menu and choose
Load. You won’t be prompted for a ?lename; the application always opens the same ?le in its root
folder. After reading about the OpenFileDialog and SaveFileDialog controls, you can modify the
code so that it prompts the user about the ?le to read from or write to. Then enter a new contact by
clicking the Add button or edit an existing contact by clicking the Edit button. Both actions must
end with the OK or Cancel button. In other words, we require users to explicitly end the operation,
and we won’t allow them to switch to another contact while adding or editing one.
The code behind the various buttons is straightforward. The Add button hides all the nav-
igational buttons at the bottom of the form and clears the TextBoxes. The OK button saves the
new contact to an ArrayList structure and redisplays the navigational buttons. The Cancel button
ignores the data entered by the user and likewise displays the navigational buttons. In all cases,
when the user switches back to the view mode, the TextBoxes are also locked, by setting their
ReadOnly properties to True.
Handling Keystrokes
Although the Tab key is the Windows method of moving to the next control on the form, most
users will ?nd it more convenient to use the Enter key. The Enter key is the most important one
on the keyboard, and applications should handle it intelligently. When the user presses Enter in a
single-line TextBox, for example, the obvious action is to move the focus to the following control.
I included a few statements in the KeyDown event handlers of the TextBox controls to move the
focus to the following one:
Private Sub txtAddress1 KeyDown(...) Handles txtAddress1.KeyDown
If e.KeyData = Keys.Enter ThenPetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 228
228 CHAPTER 7 WORKING WITH FORMS
e.SuppressKeyPress = True
txtAddress2.Focus()
End If
End Sub
If you use the KeyUp event handler instead, the result won’t be any different, but an annoying
beeping sound will be emitted with each keystroke. The beep occurs when the button is depressed,
so we must intercept the Enter key as soon as it happens, and not after the control receives the
noti?cation for the KeyDown event. The control will still catch the KeyUp event and it will beep
because it’s a single-line TextBox control (an audible warning that the speci?c key shouldn’t be
used in a single-line TextBox control). To avoid the beep sound, the code ‘‘kills’’ the keystroke by
setting the SuppressKeystroke property to True.
Processing Keys from within Your Code
The code shown in the preceding KeyDown event handler will work, but you must repeat it for every
TextBox control on the form. A more convenient approach is to capture the Enter keystroke in the
form’s KeyDown event handler and process it for all TextBox controls. First, we must ?gure out
whether the control with the focus is a TextBox control. The property Me.ActiveControl returns a
reference to the control with the focus. To ?nd out the type of the active control and compare it to
the TextBox control’s type, use the following If statement:
If Me.ActiveControl.GetType Is GetType(TextBox) Then
’ process the Enter key
End If
An interesting method of the Form object is the ProcessTabKey method, which imitates the Tab
keystroke. Calling the ProcessTabKey method is equivalent to pressing the Tab key fromwithin your
code. The method accepts a True/False value as an argument, which indicates whether it will move
the focus to the next control in the tab order (if True), or to the previous control in the tab order. Once
you can ?gure out the active control’s type and you have a method of simulating the Tab keystroke
from within your code, you don’t have to code every TextBox control’s KeyDown event.
Start by setting the form’s KeyPreview property to True and then insert the following statements in
the form’s KeyDown event handler:
If e.KeyCode = Keys.Enter Then
If Me.ActiveControl.GetType Is GetType(TextBox) Then
e.SuppressKeyPress = True
If e.Shift Then
Me.ProcessTabKey(False)
Else
Me.ProcessTabKey(True)
End If
End If
End IfPetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 229
THE APPEARANCE OF FORMS 229
The last topic demonstrated in this example is how to capture certain keystrokes, regardless of
the control that has the focus. We’ll use the F10 keystroke to display the total number of contacts
entered so far. Assuming that you have already set the form’s KeyPreview property to True, enter
the following code in the form’s KeyDown event:
If e.Keycode = keys.F10 Then
MsgBox(”There are ” & Contacts.Count.ToString &
” contacts in the database”)
e.Handled = True
End If
Listing 7.1 shows the complete handler for the form’s KeyDown event, which also allows you to
move to the next or previous contact by using the Alt+Plus or Alt+Minus keys, respectively.
Listing 7.1: Handling Keystrokes in the Form’s KeyDown Event Handler
Public Sub Form1 KeyDown(ByVal sender As Object,
ByVal e As System.WinForms.KeyEventArgs)
Handles Form1.KeyUp
If e.Keycode = Keys.F10 Then
MsgBox(”There are ” & Contacts.Count.ToString &
” contacts in the database”)
e.Handled = True
End If
If e.KeyCode = Keys.Subtract And e.Modifiers = Keys.Alt Then
bttnPrevious.PerformClick
End If
If e.KeyCode = Keys.Add And e.Modifiers = Keys.Alt Then
bttnNext.PerformClick
End If
End Sub
The KeyCode property of the e argument returns the code of the key that was pressed. All key
codes are members of the Keys enumeration, so you need not memorize them. The name of the
key with the plus symbol is Keys.Add.The Modifiers property of the same argument returns the
modi?er key(s) that were held down while the key was pressed. Also, all possible values of the
Modifiers property are members of the Keys enumeration and will appear as soon as you type
the equal sign.
Anchoring and Docking
A common issue in form design is the design of forms that are properly resized. For instance,
you might design a nice form for a given size, but when it’s resized at runtime, the controls are
all clustered in the top-left corner. Or a TextBox control that covers the entire width of the form
at design time suddenly ‘‘cringes’’ on the left when the user drags out the window. If the user
makes the form smaller than the default size, part of the TextBox could be invisible because it’s
outside the form. You can attach scroll bars to the form, but that doesn’t really help — who wantsPetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 230
230 CHAPTER 7 WORKING WITH FORMS
to type text and have to scroll the form horizontally? It makes sense to scroll vertically because
you get to see many lines at once, but if the TextBox control is wider than the form, you can’t read
entire lines.
Anchoring Controls
The Anchor property lets you attach one or more edges of the control to corresponding edges of
the form. The anchored edges of the control maintain the same distance from the corresponding
edges of the form.
Place a TextBox control on a new form, set its MultiLine property to True, and then open
the control’s Anchor property in the Properties window. You will see a rectangle within a larger
rectangle and four pegs that connect the small control to the sides of the larger box (see Figure 7.6).
The large box is the form, and the small one is the control. The four pegs are the anchors, which
can be either white or gray. The gray anchors denote a ?xed distance between the control and
the form. By default, the control is placed at a ?xed distance from the top-left corner of the form.
When the form is resized, the control retains its size and its distance from the top-left corner of
the form.
Figure 7.6
The settings of the
Anchor property
We want our TextBox control to ?ll the width of the form, be aligned to the top of the form, and
leave some space for a few buttons at the bottom.We also want our form to maintain this arrange-
ment, regardless of its size. Make the TextBox control as wide as the form (allowing, perhaps, a
margin of a few pixels on either side). Then place a couple of buttons at the bottom of the form
and make the TextBox control tall enough that it stops above the buttons. This is the form of the
Anchor sample project.Petroutsos c07.tex V3 - 01/28/2008 1:11pm Page 231
THE APPEARANCE OF FORMS 231
Now open the TextBox control’s Anchor property and make all four anchors gray by clicking
them. This action tells the Form Designer to resize the control accordingly at runtime, so that the
distances between the sides of the control and the corresponding sides of the form are the same as
those you set at design time. Select each button on the form and set their Anchor properties in the
Properties window: Anchor the left button to the left and bottom of the form, and the right button
to the right and bottom of the form.
Resize the form at design time without running the project, and you’ll see that all the controls
are resized and rearranged on the form at all times. Figure 7.7 shows the Anchor project’s main
form in two different sizes.
Figure 7.7
Use the Anchor property
of the various controls
to design forms that can
be resized gracefully at
runtime.
Yet, there’s a small problem: If you make the form very narrow, there will be no room for both
buttons across the form’s width. The simplest way to ?x this problem is to impose a minimum size
for the form. To do so, you must ?rst decide the form’s minimum width and height and then set
the MinimumSize property to these values. You can also use the AutoScroll properties, but it’s
not recommended that you add scroll bars to a small form like ours.
Docking Controls
In addition to the Anchor property, most controls provide the Dock property, which determines
how a control will dock on the form. The default value of this property is None.
Create a new form, place a multiline TextBox control on it, and then open the control’s Dock
property. The various rectangular shapes are the settings of the property. If you click the middle
rectangle, the control will be docked over the entire form: It will expand and shrink both hori-
zontally and vertically to cover the entire form. This setting is appropriate for simple forms that
contain a single control, usually a TextBox, and sometimes a menu. Try it out.
Let’s create a more complicated form with two controls (see the Docking sample project). The
form shown in Figure 7.8 contains a TreeView control on the left and a ListView control on the
right. The two controls display folder and ?le data on an interface that’s very similar to that
of Windows Explorer. The TreeView control displays the directory structure, and the ListView
control displays the selected folder’s ?les.
Place a TreeView control on the left side of the form and a ListView control on the right side
of the form. Then dock the TreeView to the left and the ListView to the right. If you run thePetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 232
232 CHAPTER 7 WORKING WITH FORMS
application now, as you resize the form, the two controls remain docked to the two sides of the
form — but their sizes don’t change. If you make the form wider, there will be a gap between the
two controls. If you make the form narrower, one of the controls will overlap the other.
Figure 7.8
Filling a form with two
controls
End the application, return to the Form Designer, select the ListView control, and set its Dock
property to Fill. This time, the ListView will change size to take up all the space to the right of
the TreeView. The ListView control will attempt to ?ll the form, but it won’t take up the space of
another control that has been docked already. The TreeView and ListView controls are discussed
in Chapter 9, ‘‘The TreeView and ListView Controls’’; that’s why I’ve populated them with some
fake data at design time. In Chapter 9, you’ll learn how to populate these two controls at runtime
with folder names and ?lenames, respectively, and build a custom Windows Explorer.
Splitting Forms into Multiple Panes
The form behaves better, but it’s not what you really expect from a Windows application. The
problem with the form in Figure 7.8 is that users can’t change the relative widths of the controls.
In other words, they can’t make one of the controls narrower to make room for the other, which is
a fairly common concept in theWindows interface.
The narrow bar that allows users to control the relative sizes of two controls is a splitter.When
the cursor hovers over a splitter, it changes to a double arrow to indicate that the bar can be
moved. By moving the splitter, you can enlarge one of the two controls while shrinking the other.
The Form Designer provides a special control for placing a splitter between two controls: the
SplitContainer control. We’ll design a new form with two TextBoxes and a splitter between them
so that users can change the relative size of the two controls.
First, place a SplitContainer control on the form. The SplitContainer consists of two Panels, the
Panel1 and Panel2 controls, and a vertical splitter between them. This is the default con?guration;
you can change the orientation of the splitter by using the control’s Orientation property. Also
by default, the two panels of the Splitter control are resized proportionally as you resize the form.
If you want to keep one of the panels ?xed and have the other take up the rest of the form, set the
control’s FixedPanel property to the name of the panel you want to retain its size.
Next, place a TextBox control in the left panel of the SplitControl and set its Multiline property
to True. You don’t need to do anything about its size because we’ll dock it in the panel to which itPetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 233
THE APPEARANCE OF FORMS 233
belongs.With the TextBox control selected, locate its Dock property and set it to Fill.TheTextBox
control will ?ll the left panel of the SplitContainer control. Do the same with another TextBox
control, which will ?ll the right panel of the SplitContainer control. Set this control’s Multiline
property to True and its Dock property to Fill.
Now run the project and check out the functionality of the SplitContainer. Paste some text on
the two controls and then change their relative sizes by sliding the splitter between them, as shown
in Figure 7.9. You will ?nd this project, called Splitter1, among the sample projects of this chapter.
Figure 7.9
The SplitContainer con-
trol lets you change the
relative size of the con-
trols on either side.
Let’s design a more elaborate form with two SplitContainer controls, such as the one shown in
Figure 7.10. (It’s the form in the Splitter2 sample project.) This form, which resembles the interface
of Microsoft Of?ce Outlook, consists of a TreeView control on the left (where the folders are dis-
played), a ListView control (where the selected folder’s items are displayed), and a TextBox control
(where the selected item’s details are displayed). Because we haven’t discussed the ListView and
TreeView controls yet, I’m using three TextBox controls with different background colors; the
process of designing the form is identical, regardless of the controls you put on it.
Figure 7.10
An elaborate form with
two splitter controls
Start by placing a SplitContainer control on the form. Then place a multiline TextBox control on
the left panel of the SplitContainer control and set the TextBox control’s Dock property to Fill.The
TextBox control will ?ll the left panel of the SplitContainer control. Place another SplitContainerPetroutsos c07.tex V3 - 01/28/2008 1:11pm Page 234
234 CHAPTER 7 WORKING WITH FORMS
in the right panel of the ?rst SplitContainer control. This control will be automatically docked in
its panel and will ?ll it. Its orientation, however, is vertical, and the splitter will separate the panel
into two smaller vertical panes. Select the second SplitContainer control, locate its Orientation
property in the Properties window, and set it to Horizontal.
Now you can ?ll each of the panels with a TextBox control. Set each TextBox control’s
BackgroundColor to a different color, its MultiLine property to True, and its Dock property
to Fill. The TextBox controls will ?ll their containers, which are the panels of the two SplitCon-
tainer controls, not the form. If you look up the properties of a SplitContainer control, you’ll see
that it’s made up of two Panel controls, which are exposed as properties of the SplitContainer
control, the Panel1 and Panel2 controls. You can set many of the properties of these two con-
stituent controls, such as their font and color, their minimum size, and so on. They even expose an
AutoScroll property, so that users can scroll the contents of each one independently of the other.
You can also set other properties of the SplitContainer control, such as the SplitterWidth prop-
erty, which is the width of the splitter bar between the two panels in pixels, and the Splitter-
Increment property, which is the smallest number of pixels that the splitter bar can be moved in
either direction.
So far, you’ve seen what the Form Designer and the Form object can do for your application.
Let’s switch our focus to programming forms and explore the events triggered by the Form object.
The Form’s Events
The Form object triggers several events. The most important are Activated, Deactivate, Form-
Closing, Resize,and Paint.
The Activated and Deactivate Events
When more than one form is displayed, the user can switch from one to the other by using the
mouse or by pressing Alt+Tab. Each time a form is activated, the Activated event takes place.
Likewise, when a form is activated, the previously active form receives the Deactivate event.
Insert in these two event handlers the code you want to execute when a form is activated (set
certain control properties, for example) and when a form loses the focus or is deactivated. These
two events are the form’s equivalents of the Enter and Leave events of the various controls.
Notice an inconsistency in the names of the two events: the Activated event takes place after
the form has been activated, whereas the Deactivate event takes place right before the form is
deactivated.
The FormClosing and FormClosed Events
The FormClosing event is ?red when the user closes the form by clicking its Close button. If the
application must terminate because Windows is shutting down, the same event will be ?red as
well. Users don’t always quit applications in an orderly manner, and a professional application
should behave gracefully under all circumstances. The same code you execute in the application’s
Exit command must also be executed from within the closing event. For example, you might
display a warning if the user has unsaved data, you might have to update a database, and so on.
Place the code that performs these tasks in a subroutine and call it from within your menu’s Exit
command, as well as from within the FormClosing event’s handler.
You can cancel the closing of a form by setting the e.Cancel property to True. The event han-
dler in Listing 7.2 displays a message box informing the user that the data hasn’t been saved and
gives him a chance to cancel the action and return to the application.Petroutsos c07.tex V3 - 01/28/2008 1:11pm Page 235
THE APPEARANCE OF FORMS 235
Listing 7.2: Cancelling the Closing of a Form
Public Sub Form1 FormClosing(...) Handles Me.FormClosing
Dim reply As MsgBoxResult
reply = MsgBox(”Document has been edited. ” &
”OK to terminate application, Cancel to ” &
”return to your document.”, MsgBoxStyle.OKCancel)
If reply = MsgBoxResult.Cancel Then
e.Cancel = True
End If
End Sub
The e argument of the FormClosing event provides the CloseReason property, which reports
how the form is closing. Its value is one of the following members of the CloseReason enumera-
tion: FormOwnerClosing, MdiFormClosing, None, TaskManagerClosing, WindowsShutDown.The
names of the members are self-descriptive, and you can query the CloseReason property to deter-
mine how the window is closing.
The FormClosed event ?res after the form has been closed. You can ?nd out the action that
caused the form to be closed through the e.CloseReason property, but it’s too late to cancel the
closing of the form.
The Resize, ResizeBegin,and ResizeEnd Events
The Resize event is ?red every time the user resizes the form by using the mouse. With previous
versions of VB, programmers had to insert quite a bit of code in the Resize event’s handler to
resize the controls and possibly rearrange them on the form.With the Anchor and Dock properties,
much of this overhead can be passed to the form itself. If you want the two sides of the form
to maintain a ?xed ratio, however, you have to resize one of the dimensions from within the
Resize event handler. Let’s say the form’s width-to-height ratio must be 3:4. Assuming that you’re
using the form’s height as a guide, insert the following statement in the Resize event handler to
make the width equal to three-fourths of the height:
Private Form1 Resize(...) Handles Me.Resize
Me.Width = (0.75 * Me.Height)
End Sub
The Resize event is ?red continuously while the formis being resized. If youwant to keep track
of the initial form’s size and perform all the calculations after the user has ?nished resizing the
form, you can use the ResizeBegin and ResizeEnd events, which are ?red at the beginning and
after the end of a resize operation, respectively. Store the form’s width and height to two global
variables in the ResizeBegin event and use these two variables in the ResizeEnd event handler.
The Scroll Event
The Scroll event is ?red by forms that have their AutoScroll property set to True when the
user scrolls the form. The second argument of the Scroll event handler exposes the OldValue
and NewValue properties, which are the displacements of the form before and after the scroll
operation. This event can be used to keep a speci?c control in view when the form’s contents are
scrolled.Petroutsos c07.tex V3 - 01/28/2008 1:11pm Page 236
236 CHAPTER 7 WORKING WITH FORMS
The AutoScroll property is handy for large forms, but it has a serious drawback: It scrolls
the entire form. In most cases, we want to keep certain controls in view at all times. Instead of
a scrollable form, you can create forms with scrollable sections by exploiting the AutoScroll
properties of the Panel and/or the SplitContainer controls. You can also reposition certain controls
from within the form’s Scroll event handler. Let’s say you have placed a few controls on a Panel
container and you want to keep this Panel at the top of a scrolling form. The following statements
in the form’s Scroll event handler reposition the Panel at the top of the form every time the user
scrolls the form:
Private Sub Form1 Scroll(...) Handles Me.Scroll
Panel1.Top = Panel1.Top + (e.NewValue - e.OldValue)
End Sub 

Make a Free Website with Yola.