Programming Code-Behind Forms

Adding code to the modules behind forms is how you make them smart and interactive. This section introduces the topic, but it keeps the focus on forms rather than the controls in forms. The section starts by drilling down into the Windows Form Designer code automatically generated behind a form and contrasts it with code that you can place in form event procedures. The section then demonstrates how to add code to the form Load and Closing events. You also learn how to abort an attempt to close a form ”for example, if your application s logic prevents a form from closing when a user clicks the Close control. This section also shows how to persist a value to a disk file when a form closes and how to reuse the value the next time that form opens.

Windows Form Designer Generated Code Region

When you start a Windows application project, the Windows Form Designer creates a blank form ( Form1 ) based on the Form class in the System.Windows.Forms namespace. For this reason, the first statement in the code module behind Form 1 is an Inherits statement. Directly below the Inherits statement is a region created by the Windows Forms Designer. This region, which is collapsed by default, includes automatically generated code; you can expand the region to view its code. When you first start a Windows application project, the Form Designer puts some code in this region to instantiate the form, initialize it, and prepare for its removal from memory when your application no longer needs it. As you manually add controls or manipulate the form in other ways, the Form Designer will create new code to reflect the changes you ve made to the form.

You typically should not place code in the Windows Form Designer region, but knowing what s in this region will help you to write better code to manage your forms. The following listing from the CodeBehindFormSamples project is the code for Form1 in the Windows Form Designer region for a new Windows application project. You can create this code by creating a project with the Windows Application template. (See Chapter 2 for specific instructions on doing so.) Open the code module behind Form1 by right-clicking Form1 and choosing View Code. Then, click the + icon next to the label marking the Windows Form Designer generated code region. This expands the region so that you can view the code.

Note  

The code listing for the Windows Form Designer region in Form1 for the CodeBehindFormSamples project contains a couple of additional lines that are not referenced in the next section. These lines are for a subsequent sample.

As you can see, the Form Designer region initially contains three procedures. The New procedure instantiates a form instance based on the Form class. As you ve learned, the MyBase keyword refers to the class named in the Inherits statement. Although the New procedure has a comment inviting you to place initialization code after it, you can perform any necessary customization code with the Form1_Load event procedure. It is good practice not to populate this region with custom code. The next procedure has the name Dispose . The code in this procedure sets up the form instance for removal from memory by the .NET Framework garbage collector. When you need to program an action to occur immediately before or after closing a form, use the Closing or Closed events instead of placing custom code in the Dispose procedure.

The third procedure in the Form Designer generated code region has the name InitializeComponent . A Private declaration for components , System.ComponentModel.IContainer , appears just before the procedure declaration. The Form Designer actively manages both of these code blocks. Placing custom code in either of these areas makes it highly vulnerable to being overridden by the Form Designer. I like to manage the layout of my forms programmatically rather than use the visual layout techniques. In my opinion, programmatically managing the form layout makes it easy to read and maintain because you do not have to go through the Properties window for every change to an object. The program documents the layout, and the program makes it easy to change the layout by changing one or two lines of code. You can place this code in the Load event procedure for a form. However, if you are stumped on how to program some layout feature for a form or a control on a form, you can make the change visually and then view the InitializeComponent procedure to see how to make a property assignment. For example, the listing that follows shows how to set the caption for a form as its Text property. (See Me.Text = "Form1" .)

 #Region " Windows Form Designer generated code " Public Sub New() MyBase.New() This call is required by the Windows Form Designer. InitializeComponent() Add any initialization after the InitializeComponent call. End Sub Form overrides Dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub Required by the Windows Form Designer. Private components As System.ComponentModel.IContainer NOTE: The following procedure is required by the Windows Form Designer. It can be modified using the Windows Form Designer. Do not modify it using the code editor. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() components = New System.ComponentModel.Container() Me.Text = "Form1" End Sub #End Region 

Adding Custom Code to the Module Behind a Form

It is often useful to program actions around the initialization and the termination of a form. Program a Load event procedure for actions that need to take place before a form opens. You can program data access or handle layout issues in a form Load event procedure. Visual Basic .NET raises the Load event for a form after instantiating the form with the New procedure from the Windows Form Designer region. Instances of the Windows Form class offer a couple of events for helping to manage actions around the closing of a form; both of these events occur before the invocation of the Dispose procedure in the Windows Form Designer region. Use the Closing event to program actions that should take place before a form closes. Program a Closed event procedure for actions that should take place after a form closes.

To demonstrate when events occur relative to the built-in procedures within the Windows Form Designer region, you can modify the preceding listing to insert two Debug.WriteLine statements. As you can tell from the syntax, the statement specifies the WriteLine method for the Debug object. With the Debug.WriteLine statement, you can write a line of text to the console. The console for output in a Windows application is the Output window in Visual Studio .NET. Therefore, you can view your output lines along with standard output from the .NET Framework about the loading of assemblies and completion of programs. Place the first Debug.WriteLine statement, which follows, immediately after the comment in the New procedure inviting the addition of custom code:

 Debug.WriteLine ("from Sub New") 

Place the second Debug.WriteLine statement just before the End Sub statement in the Dispose procedure. This line reads as follows:

 Debug.WriteLine ("from Sub Dispose") 

Below the Windows Form Designer region in the Form1 code module, you can enter three event procedures for the Load , Closing , and Closed events. Chapter 2 mentioned that you can create a shell for the default event for an object by double-clicking the object in Design view. However, you sometimes need to work with an event besides the default one for an object. In these cases, you can select the object, such as Button1 , from the Class Name drop-down box in the Code window (on the top left) and choose an event for the class from the Method Name drop-down box in the Code window (on the top right).

When working with events for a form, as opposed to the controls on a form, the process is slightly different. From the Class Name drop-down box, select Base Class Events instead of the object name. Figure 5-1 shows the process for generating the Form1_Load event procedure shell with the Class Name and Method Name boxes; the name Form1_Load is the default name for the Load event procedure for Form1 . Insert the following line of code within the event procedure:

 Debug.WriteLine ("from Form1 Load event") 
click to expand
Figure 5-1: The process for creating a Load event procedure shell for a form

You can add Closing and Closed event procedure shells with the same process. Insert a WriteLine statement within each of these other two procedures specifying the name of the event. The application allows you to trace in the Output window the order of the three event procedures relative to the invocation of the New and Dispose procedures in the Windows Form Designer region. The Debug.WriteLine statements leave footprints in the Output window about when a procedure runs relative to other procedures.

The following listing shows the three event procedures. Notice that the Closing event procedure has one argument ( e ) with a different type than the other two event procedures. You can use this argument to manage how and when an application permits the closing of a form. A subsequent sample will illustrate the syntax for managing this process.

 Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Debug.WriteLine("from Form1 Load event") End Sub Private Sub Form1_Closing(ByVal sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles MyBase.Closing Debug.WriteLine("from Form1 Closing event") End Sub Private Sub Form1_Closed(ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Closed Debug.WriteLine("from Form1 Closed event") End Sub 

Figure 5-2 shows an excerpt from the Output window for the CodeBehindFormSamples project from opening and closing Form1 . Open the form by simply pressing the F5 function key. Close Form1 by clicking the X control in the control box that appears in its top right corner. The application s output lines appear interspersed with messages from the .NET Framework. The first output line is from the New procedure, and the last one is from the Dispose procedure. Between these two markers are three additional output lines from the three event procedures. From this output, you can confirm that the Load , Closing , and Closed events occur in order between the invocation of the New and Dispose procedures.

click to expand
Figure 5-2: Output window tracking the Load , Closing , and Closed events relative to one another and the New and Dispose procedures

Manipulating a Form with Event Procedures

Manipulating a form in a program can serve multiple purposes in typical application development environments. For example, specifying a form s parameters in a Load event procedure can make it easy to see all the specifications for a form in one easy-to-read script. Second, when you have to copy all or part of the specifications from one form to another, having the specifications as code reduces setting the second form s parameters to a copy-and-paste operation (for the code). Third, you might want to specify the start location of a form so that the form does not obscure another form that you want a user to view at the same time. You can manipulate the position of several forms to make them appear in an order that emphasizes a point that you want to make. Fourth, you might find it convenient to revamp the look of a form drastically so that one form can serve two purposes in your application. The next code sample illustrates only the basics of manipulating a form with event procedures, but several other samples in this chapter demonstrate typical applications of the techniques presented here.

You can add a second form to any Windows application by choosing Project, Add Windows Form. This opens the Add New Item dialog box with a suggested name for the form, such as Form2.vb. This name applies to a form s Design tab as well as the tab for the code module behind a form. You can accept the default name or specify another that suits the needs of your application by changing the entry in the Name box on the dialog box. Clicking Open creates a new blank form in your application named after whatever entry appears in the Name box.

To start the project with the new form, Form2 , instead of with the original form, you need to specify Form2 as the startup object. Form1 is the default startup object for a Windows application project. You can change the startup object for a project by selecting the project in Solution Explorer. The project item is the second item from the top that has the name of the project. Then, right-click the project name and choose General under Common Properties in the project s Property Pages dialog box. Next, use the drop-down box labeled Startup Object to select Form2 (or any other form you want to start up when your project opens). Finally, commit your change by clicking OK. The next time you press F5, the project starts with the new form that you designated as the startup object.

Add six buttons to the new form that you added to the project. The sample uses these buttons to enable a user to manipulate the size and position of a form on her desktop screen. Figure 5-3 shows the arrangement of buttons on the form in Design view. Notice that the buttons appear with the default Text property assignments as captions ”namely, Button1 , Button2 , and so on. The Form2_Load procedure assigns new names to each button that reflect their roles.


Figure 5-3: The Design view layout of a form before the run-time assignment of Text property settings for the form s buttons

The next listing is for all the event procedures behind Form2 . The form s Load event procedure performs two types of tasks . First, it assigns captions to the buttons by setting their Text property. The buttons perform three kinds of tasks, with one button performing a task one way and its matching button on a row performing the same kind of task in the opposite direction. The buttons on a row essentially undo the actions of one another. For example, Button1 adds 50 pixels to the height of Form 2 , but Button2 decreases the height of Form2 by 50 pixels. Button3 and Button4 complement each other in the same way for the width of Form2 , and Button5 and Button6 move Form2 left or right by 50 pixels. The Form2_Load event procedure assigns Text property settings, such as "+Height" and "-Height" , which reflect the outcome of the event procedures behind the buttons. After assigning the Text property values, the Load event procedure centers the form on the user s screen. This is desirable in the current application because the default start location can end up in the top left corner of the desktop, which can cause a form to move partially off the screen at the first click to Button5 .

Notice that the base Form class members (such as CenterToScreen ) and added controls (such as Button1 ) are both class members of Form2 ( Me ). The designation of a Text property depends on both the form ( Form2 denoted as Me ) and the button. When developing code for multiple forms, you can have two members in different forms with the same name. As long as you designate the form before the member, you can specify the member unambiguously. Subsequent samples will show techniques for assigning values to members in other forms by using this and other design principles.

Windows forms specify their height and width with a scalar value representing the Height and Width properties. The value denotes a number of pixels. The default width and height for a Windows form is 300 pixels. You can change either of these property settings at design time or run time. When you use the Properties window, you are changing the setting at design time ”that is, before the application runs. When you use an event procedure to alter the Height and Width property settings for a procedure, you are updating the property at run time. In general, run-time assignments offer more flexibility because you can accommodate user input and change the value from time to time depending on how an application uses a form.

The Click event procedures for Button1 and Button2 demonstrate the syntax for growing and shrinking the height of Form2 by 50 pixels. The expression for adding 50 pixels uses the += operator. Similarly, the expression for shrinking the height by 50 pixels relies on the -= operator. The Click event procedures for Button3 and Button4 work identically to those for Button1 and Button2 , except that Button3 and Button4 manipulate the form s Width property instead of its Height property.

The Text property settings for Button5 and Button6 are +Left and +Right , which respectively signify a movement of the form to the left or away from the left (that is, to the right). There are at least two tricks to understanding the positioning of a form on a screen. First, the Left and Top property settings are offsets from the left and top edges of a screen. Therefore, decreasing the Left property for a form actually moves the form toward the left, but adding 50 to the Left property moves the form to the right by 50 pixels. The second trick relates to how you actually change the position of a form. Although you can increase and decrease the Left property of a form, doing so does not move a form or persist the property change. You must use a Point structure of a left offset and a top offset and assign this structure to a form property capable of accepting both offsets at once. A form s DesktopLocation property is one of the properties that can accept a point structure value. You can assign a value to the DesktopLocation property with the Point class in the System.Drawing namespace. The Point merely represents a position in a two-dimensional plane based on an ordered pair of integer values.

Because a Windows application has an automatic reference to the System.Drawing namespace, you can optionally represent the namespace when using a Point class instance. The event procedure for Button5 shows the syntax without the namespace designation, and Button6 shows the syntax with the namespace designation. Using the namespace designation is a lengthier approach, but it reminds you about the source for the Point class.

 Private Sub Form2_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Assign captions to buttons. Me.Button1.Text = "+ Height" Me.Button2.Text = "- Height" Me.Button3.Text = "+ Width" Me.Button4.Text = "- Width" Me.Button5.Text = "+ Left" Me.Button6.Text = "+ Right" Designate start location for form. Me.CenterToScreen() End Sub Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click Me.Height += 50 End Sub Private Sub Button2_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button2.Click Me.Height -= 50 End Sub Private Sub Button3_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button3.Click Me.Width += 50 End Sub Private Sub Button4_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button4.Click Me.Width -= 50 End Sub Private Sub Button5_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button5.Click Decrease the form s Left property by 50. Me.Left -= 50 Assign a new position to the form based on the updated Left property setting. Me.DesktopLocation = New Point(Me.Left, Me.Top) End Sub Private Sub Button6_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button6.Click Increase the form s Left property by 50. Me.Left += 50 Assign a new position to the form based on the updated Left property setting. Me.DesktopLocation = _ New System.Drawing.Point(Me.Left, Me.Top) End Sub 

Disabling the Close Control in the Control Box

You can disable the Close control in a form s control box by using the e argument for a form s Closing event. In the discussion of the code behind Form1 in the CodeBehindSamples project, you saw that the type for the e argument of the Closing event is System.ComponentModel.CancelEventArgs . The Cancel property for this type lets an application get or set whether the event should be cancelled. The Cancel property is a Boolean variable that is False by default. When the Cancel property is False , the attempt to close the form succeeds. Assigning a value of True to the Cancel property for the e object causes the attempt to close the form to fail. No run-time error or exception occurs ”the form just doesn t close when the Cancel property is True .

The following code sample for Form3 demonstrates how to use the e object argument for the Closing event to disable the Close control in a form s control box. As mentioned, the control box is the set of three controls in the top right corner of a default Windows form; the control with an X on it is the Close control. The form, Form3 , contains a button, Button1 , with a run-time assigned Text property of Close . The application lets a user close the form only by clicking Button1 , not by clicking the Close control in the control box. This is trickier than it sounds because the Close button in the control box and Button1 both raise the Closing event. (The .NET Framework always raises the Closing event in response to an attempt to close a form.) Therefore, the application s code for the form s Closing event procedure must distinguish between a user clicking the Close control in the control box or in Button1 .

The code in the following sample demonstrates another interesting capability: it toggles the visibility of the control box. When Form3 initially opens, its control box shows. However, because the control box doesn t function or because its Close control fails, you might reasonably decide to suppress the visibility of the control box. The second time that a user opens the form, the control box is not visible. In fact, the application toggles the visibility of the control box on alternate form openings. The application manages the toggling by reading and writing a Boolean value from a disk file. In between the reading and writing of the value, the code toggles the value so that the application saves True if it reads False , and vice versa. This capability to persist one or a few values to a disk file and then reread the values the next time that an application opens is handy in many circumstances. Access database developers might be inclined to use a table with a single row and one or more columns for as many variables that need to be saved and reread. However, using a local disk file can yield superior performance and consume fewer resources. You are especially likely to obtain superior performance when the Access database file is available only via a network connection or the Internet.

If you are creating this sample along with this discussion, create a new form and let the form have the name Form3.vb in the Add New Item dialog box. Open the Toolbox with the View, Toolbox command and drag a button to Form3 . Accept the default Text property of Button1 . Then close the Toolbox.

Right-click a blank area in the form, and choose View Code from the shortcut menu to open the code module behind Form3 . The code sample relies on four procedures that use two module-level Boolean variables. The sample also requires a file, SavedbolShowControlBox.scb, with a single Boolean value whose initial value is True . The file must reside in the project s root folder. The easiest way to populate the code module is to copy the completed sample from the CodeBehindFormSamples project. The file is also available for copying from the root folder for the completed project to your project folder. The bolDisableClose variable tracks whether to abort the attempt to close the form. The bolShowControlBox variable detects whether to show the control box for a form instance. Before attempting to test your code, remember to make Form3 the project s startup object. (You do this from the Property Pages dialog box.)

The Form3_Load event procedure performs three tasks. First, it assigns a caption to Button1 by setting its Text property. Next, the procedure reads the SavedbolShowControlBox.scb file in the root folder for the project to set the value of bolShowControlBox . The value of bolShowControlBox determines whether the application will display the control box on a form. After closing the Filestream and BinaryReader objects for reading the persisted value of bolShowControlBox in the SavedbolShowControlBox.scb file, the procedure sets the value of the form s ControlBox property to either True or False . A value of True shows the control box in the form instance.

The second procedure, Button1_Click , has just two lines. Clicking this button is the only way to close the form. The procedure begins by setting the bolDisableClose variable to False . Notice that the module-level declaration for this variable assigns it a default value of True . The only way for this variable to be False in the Closing event procedure is for the user to click Button1 . Clicking the Close button in the control box does not affect the variable s value. After assigning a new value to the variable, the procedure invokes the form s Close method ( Me.Close ). This statement raises the Closing event. Clicking the Close button in the control box has the same effect.

The Form3_Closing event procedure works in tandem with the fourth procedure, ToggleControlBox . The Closing event procedure might or might not close the form, depending on the value of bolDisableClose . This value will be True until a user clicks Button1 . A value of True for bolDisableClose causes the Closing event procedure to disable the attempt to close the form by setting the Cancel property for the e object to True . The procedure also displays an explanatory message, in this case, explaining how to close the form. If the bolDisableClose variable equals False , the procedure leaves e.Cancel at its default value of False so that the attempt to close the form succeeds when the event procedure relinquishes control. Before closing the form normally, the procedure displays a confirmation message.

In addition to closing the form when the bolDisableClose variable equals False , the Form3_Closing event procedure invokes the ToggleControlBox procedure, which toggles the setting for the Boolean variable persisted in the SavedbolShowControlBox.scb file. As mentioned, the variable in this file determines whether to show the form s control box. The process for toggling the variable value starts by wiping out the old file that persisted the value. The procedure demonstrates the syntax for checking for the existence of a file before attempting to delete it. However, the sample s code requires the file to exist. (For example, you cannot read from the file unless it already exists.) Next, the code instantiates a FileStream object that points at the new version of the file and instantiates a BinaryWriter object for writing a value to the file. After preparing the file, the procedure toggles the current value of the bolShowControlBox variable before writing the variable s value to the file with the BinaryWriter s Write method. The procedure ends by closing the BinaryWriter and FileStream objects.

 Boolean variables for disabling the Close control and showing the form s control box Dim bolDisableClose As Boolean = True Dim bolShowControlBox Private Sub Form3_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Assign label to button. Button1.Text = "My Close" Use FileStream and BinaryReader objects to get value written last time form closed. Dim str1 As String = "..\SavedbolShowControlBox.scb" Dim fst1 As New System.IO.FileStream(str1, _ System.IO.FileMode.Open, _ System.IO.FileAccess.Read) Dim bnr1 As New System.IO.BinaryReader(fst1) bolShowControlBox = bnr1.ReadBoolean bnr1.Close() fst1.Close() Set ControlBox property. If bolShowControlBox = True Then Me.ControlBox = True Else Me.ControlBox = False End If End Sub Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click If user clicks button, set bolDisableClose so that form s Close method succeeds. bolDisableClose = False Me.Close() End Sub Private Sub Form3_Closing(ByVal sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles MyBase.Closing Toggle form s ControlBox property and save the property s value to a file. ToggleControlBox() Disable attempt to close if the user attempts to use the Close button in the control box. If bolDisableClose = True Then e.Cancel = True MsgBox("Use My Close button to close form.") Else MsgBox("See you next time.") End If End Sub Sub ToggleControlBox() Specify file for persisting ControlBox property. Dim str1 As String = _ "..\SavedbolShowControlBox.scb" Delete file if it already exists. If System.IO.File.Exists(str1) Then System.IO.File.Delete(str1) End If Use FileStream and BinaryWriter to Save toggled value of ControlBox property. Dim fst1 As New System.IO.FileStream(str1, _ System.IO.FileMode.CreateNew) Dim bnw1 As New System.IO.BinaryWriter(fst1) If bolShowControlBox = True Then bolShowControlBox = False Else bolShowControlBox = True End If bnw1.Write(bolShowControlBox) Close BinaryWriter and FileStream objects. bnw1.Close() fst1.Close() End Sub 

Figure 5-4 shows the application in operation. The version of Form3 in the top left corner shows the form when the application initially opens. Notice the control box in its top right corner. If a user clicks the Close control (X) from the control box, the application responds with a reminder that the way to close the form is by clicking the button labeled My Close. If the user clicks the My Close button, the application displays a message confirming the successful close. The next time that a user starts the application, Form3 opens without a control box. (See the second version of Form 3 in Figure 5-4.) In a sense, the application remembers its state from the previous time the form was open and toggles to an alternate state. When a user starts the application again, it starts over with the top version of Form3 , even if the computer powers down and boots up again. The capability to remember state derives from a small disk file (SavedbolShowControlBox.scb) that holds a single Boolean variable.

click to expand
Figure 5-4: Form3 opens alternately with and without its control box.
 


Programming Microsoft Visual Basic. NET for Microsoft Access Databases
Programming Microsoft Visual Basic .NET for Microsoft Access Databases (Pro Developer)
ISBN: 0735618194
EAN: 2147483647
Year: 2006
Pages: 111
Authors: Rick Dobson

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net