A Closer Look at the Code

A Closer Look at the Code

Forms are really classes that describe the user interface for your application. When a form is displayed, an instance of the form's class is created that can be used like any other object. You can add custom methods and properties to a form to have it do whatever it needs to. While object-oriented programming provides an array of benefits, from easy maintenance to protecting data, the real benefit is honest-to-goodness code reuse. As programs become more and more complex in order to deal with the wide variety of hardware platforms and mediums—the Internet and wireless devices, for example—the only way programmers can move ahead is to become familiar with objects. There simply is no other way.

Let's review the code for our simple application in more detail. This review will introduce object-oriented techniques and a few new keywords. I realize that these concepts might be new and possibly a bit daunting to some classic Visual Basic programmers. Just read and digest as much as you can for the remainder of the chapter. I'll amplify these concepts as we progress through the book.

You Mean I Get an Inheritance?

When discussing his discoveries, Isaac Newton once said, "If I have seen further, it is because I've stood on the shoulders of giants." The same concept applies to object-oriented programming—we reap the benefits of what was written before us. To add prebuilt functionality to your programs, you have to import the functionality into your code. Not surprisingly, doing that is a snap with Visual Basic .NET. The new Imports keyword makes it easy.

A module can contain any number of Imports statements. Think of this keyword as a free ticket to import the functionality of other .NET Framework classes into your programs. Imports statements must occur in a module before any references to the other classes' built-in functionality is made within the module. By importing the namespaces that define these framework classes, you can then refer to an included type—such as Form—without having to fully qualify the type name, as in System.Windows.Forms.Form.

Imports System.ComponentModel Imports System.Drawing Imports System.Windows.Forms.Form

With one statement, Imports System.Windows.Forms.Form, you specify that the client class, Form1, inherits the functionality of the Form class in the Windows Forms library. The System.Windows.Forms namespace contains classes for creating Windows-based applications. In this namespace, you'll find not only the Form class but many other controls that can be added to forms to create user interfaces.

Public Class Form1     Inherits System.Windows.Forms.Form

As I mentioned, language independence is an important aspect of the CLR's inheritance model. Not only can you inherit functionality from the run time, but you can inherit it from classes written in any language compatible with .NET. The previous line of code states that Form1 inherits the functionality of the System.Windows.Forms.Form namespace.

The Inherits directive specifies the class (also known as the base class—in this case Windows.Forms.Form) from which the current class inherits. The Inherits keyword is allowed only in class declarations.

Think about what happens when a new form is added to your project. The form is born knowing how to do all sorts of things. It has its own menu, it knows how to resize itself, respond to events, and host controls, just to name a few. Imagine if you had to write the code to perform all those behaviors. Instead, you simply inherit the functionality of a form base class and modify your form so that it suits your needs. It's pretty obvious that inheriting prebuilt functionality permits your programs not only to be smaller, but also to do more real work.

note

Creating a new Windows form by inheriting from a base form is a handy way to duplicate your best efforts without going through the hassle of entirely re-creating a form every time you require one. You might have a specific look and feel for forms in your company. Simply create the model form once and inherit from it each time it's needed. However, keep in mind that in order for you to inherit from a form, the file or namespace containing that form must have already been built into an executable file or DLL. Of course, a reference to the namespace must be added to the class inheriting the form using the Imports keyword.

Starting Up Our Form1 Class

A class, such as our Form1 class, needs a constructor, a procedure that controls initialization of new objects. In previous versions of Visual Basic, the constructor was hidden from programmers, but it was there all along. Visual Basic .NET provides the Public Sub New constructor event. The Sub New method will run only once—when the class is created. Furthermore, the code in the Sub New method will always run before any other code in a class.

Because we have a constructor that builds the object, having a destructor to tear down the object when its usefulness is finished only seems right. In fact, a Sub Destruct method does exist, but you don't see it in the code. The Destruct method is called automatically by the system when an object is destroyed. In fact, you could not call the method explicitly even if you tried.

The .NET Framework destroys an object when the system determines that the object is no longer needed. When the object is set to Nothing or goes out of scope, Sub Destruct will be called by the system. However, unlike the Sub New method, you cannot determine exactly when the .NET Framework will execute the Sub Destruct method. You can only be sure that eventually the system will call Sub Destruct some time after the .NET Framework determines that the object is no longer needed. Our program will execute the Dispose method, which tells the CLR that the object is no longer needed. However, the object will not be released from memory until the garbage collector makes its rounds, which could be several minutes after the object is flagged for extinction. I'll cover garbage collection in more detail later on. I'll discuss what is called deterministic finalization and garbage collection (taking out used-up objects) in detail in Chapter 4.

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

In previous versions of Visual Basic, you set any references to objects to Nothing—for example, Set MyObject = Nothing—and the underlying COM plumbing would free up all memory and release any resources being used. In Visual Basic .NET, you can still use the Nothing keyword, but the object probably won't be freed at exactly that time. Nothing in Visual Basic .NET serves as an indicator that an object can be freed up when the garbage collector makes its rounds.

In classic Visual Basic, you placed initialization code for a form in the Form_Initialize or Form_Load event procedures. In Visual Basic .NET, the constructor, Sub New, replaces both of these events. When the constructor begins executing, you can be sure that all of the controls have been sited on the form and initialized right after InitializeComponent is called.

In classic Visual Basic, beginners would often run into trouble trying to set a visible property (such as the text in a text box) on a control before it was completely sited and initialized on a form. For example, programmers sometimes would set a visible property of a control, such as txtTextBox.Text = "Hello World", in the Form_Load event. Because the form was still initializing and the txtTextBox control was still being built, the programmer would get the extremely descriptive "Object Not Set" error. The programmer would be left with some head scratching to do because the error didn't provide a clue about what was wrong. With Visual Basic .NET, you can now safely place any initialization code directly after the call to InitializeComponent and be sure that it won't cause problems. Notice that the IDE adds a comment to let you know where you can initialize controls.

Public Sub New()     MyBase.New()     'This call is required by the Windows Form Designer.     InitializeComponent()     'Add any initialization after the     'InitializeComponent() call End Sub

As soon as the form's class constructor starts to execute, the following line actually creates the form object:

MyBase.New()

The MyBase keyword refers to the immediate base class and its inherited members—in this case, the events and properties of the form. It's important to note that the call to the constructor, MyBase.New, must be the first statement in the New class constructor. Of course, this order makes sense because the form would not exist until we created it with the call to MyBase.New.

Public Class Form1

The MyBase.New command is in the Sub New constructor of the Form1 class, which means that the constructor of the class calls the New method of MyBase to create a new object, in this case a form. From now on you can use MyBase from within the class to access public members defined in the base class. MyBase can't be used to access private members in the base class. (I'll describe public and private members shortly.) For our simple program, we really don't need to access the base class, so we won't have to work with MyBase now. MyBase cannot be assigned to a variable, passed to procedures, or used in Is comparisons. Why? MyBase is not a real object; it just acts like one. I'll discuss this type of behavior in detail in Chapter 2, when I describe Visual Basic .NET object-oriented programming.

note

When I saw the keyword MyBase, I started scratching my head. Who named that? Why wasn't it some geek-sounding term like ObjectBase? That would make me feel more technical. But MyBase? All I could figure out is that Microsoft has a propensity to name everything with the prefix My. Take a look at Windows. Right there is My Computer, My Documents, My Network Places, My Files, and so on. I suppose the theme was carried through to My Visual Basic .NET.

Next we have some code that looks like it gets rid of the object but includes the Overrides modifier.

Protected Overloads Overrides _ Sub Dispose(ByVal disposing As Boolean)

Remember that derived classes inherit the methods defined in their base class. Form1 inherited all of the behavior (resizing, responding to clicks, a menu) from the base form class. Usually, most of the standard methods in the base class will be fine for your purposes. Using the Overrides keyword in a derived class lets you define a new implementation of an inherited method. In other words, overriding permits you to modify the inherited behavior of the base class. In this case, when the Dispose method is called, it alerts the system garbage collector that the object is fair game to be eliminated.

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

The IDE included the overridden Dispose method so that we could dispose of additional items instead of just the default form. The Dispose method is called on MyBase, and the Dispose method is also called on the components object. In our simple program, the Dispose method is called (if necessary) when the form is dismissed. Essentially, when this method is called, the form frees all system resources it may have allocated, releases references to any other objects, and renders itself unusable. It's now officially an ex-form.

Warning! Don't Fiddle with the Designer's Code

Yes, this sounds ominous, but it's really self-defense for the Windows Form designer to ensure that it can read what it wrote without some pesky programmer mucking things up. This area should be hands off for programmers. However, if you have ever used any of the wizards in classic Visual Basic, you have already seen how they put a hands off notice on code they write and will need to read again. This code gets parsed by the wizard and must be left in the way it was written.

Earlier I described the region of code that was added automatically for the Windows Form designer. You should not fiddle with this code because anything you need to change can be accessed from the Properties window. The IDE will write your changes in this region itself.

'Required by the Windows Form Designer Private components As System.ComponentModel.Container     '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()         '         'Form1         '         Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)         Me.ClientSize = New System.Drawing.Size(292, 266)         Me.Name = "Form1"         Me.StartPosition = _             System.Windows.Forms.FormStartPosition.CenterParent         Me.Text = "Visual Basic .NET - Our First Form"     End Sub

The first line of code creates the variable components and declares it to be of type System.ComponentModel.Container. The components object will store all of the changes that you make to the form, such as the title change, and permits the changes to persist. The InitializeComponent procedure that follows contains the code you should not modify with the code editor.

In a real program, you would change various properties of the form, such as the text (the caption), size, its position on the screen, color, and so forth. Anything you need to modify in the InitializeComponent subroutine can be changed directly in the Properties window for the form. In fact, when you change a property such as the Text or Backcolor property in the Property window, you'll notice that the form in design mode does not change until you either hit Enter or move off the text entry box. The designer wants to be sure that you've finished typing. When it is sure you've finished, it revisits this segment of code and updates it appropriately.

Of course, you want your form to remember these changes when you run it again. In classic Visual Basic, these changes were stored in the form's .frm file, which was plain ASCII. You could open the form's .frm file with Notepad and see all of these settings. When the form was run, the simple text .frm file was read and the form was created. Each form was stored in a separate .frm file. If images or other non-ASCII data had to be stored on the form, this data was saved in a .frx file with the same name as the form. Various offsets were stored in the .frm file to let the form know where to place the binary data stored in the .frx files. So this same information was always there, it was just hidden from us. Instead of hiding these properties, Visual Basic .NET uses the Me keyword to expose the properties directly in your code.

    '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()         '         'Form1         '         Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)         Me.ClientSize = New System.Drawing.Size(292, 266)         Me.Name = "Form1"         Me.StartPosition = _             System.Windows.Forms.FormStartPosition.CenterParent         Me.Text = "Visual Basic .NET - Our First Form"     End Sub

If you are new to object-oriented programming, the Me keyword might look a bit weird. Actually, the keyword Me represents a read-only variable referring to the current object. In other words, Me refers to the current instance of an object—the one in which your code is currently running. Use the Me keyword to refer to this current instance. All procedures associated with this particular instance of an object have access to the object referred to as Me. Using Me is particularly useful for passing information about the current instance to a procedure in another module. If you come from C++, you use the this pointer to accomplish the same thing.

The Big Event

Remember that an event is an action to which you can respond. You want to "handle" the event in your code. Event-driven applications execute code in response to an event. Each form and control exposes a predefined set of events that you can program against. If one of these events occurs and the associated event handler contains code, that code is invoked. The types of events raised by an object vary, but many types are common to most controls. For example, every form has a Load event handler that is executed when the form loads. The Forms Designer added the Load event handler for our form. As with any event, we can choose to handle it or not.

Private Sub Form1_Load(ByVal sender As System.Object, _     ByVal e As System.EventArgs) Handles MyBase.Load End Sub

Event handlers were upgraded in Visual Basic .NET. Now we can determine the sender of the event and receive data that is passed in via the System.EventArgs parameter. For example, we might interrogate the sender parameter and find that an event was fired by a mouse click. Then, by looking at EventArgs, we can retrieve additional information such as the X and Y position of the mouse when it was clicked. We will examine events in detail in later chapters. But as you can see, to our object an event handler is just another subroutine.



Coding Techniques for Microsoft Visual Basic. NET
Coding Techniques for Microsoft Visual Basic .NET
ISBN: 0735612544
EAN: 2147483647
Year: 2002
Pages: 123
Authors: John Connell

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