Creating Your First Class Library

To see how to build your first class library, start Visual Studio .NET and from the Start Page, click Create New Project. From the New Project dialog box, choose Visual Basic Projects in the Project Types list box, and then choose Class Library in the Templates list box. Name the project Healthcare and click the OK button.

At this point, a new class is created for you. The first thing you might notice is that the class does not have a designer, which is the “form” on which you can drop controls. This lack of a designer makes the class different from most other VB .NET file types, such as Forms, Web Forms, and even a Web Service. Instead, you start with basically the same thing you had in VB6: an empty class. You don't even have a block of code generated by Visual Studio .NET, as you do in most of the other file types.

Right now, you have one class, named Class1. Here is where things start to diverge from VB6. In VB6, you had one class per class module, and these were compiled into a single component. VB6 class modules had a .CLS extension. In VB .NET, your module has a .VB extension, and a single .VB source code file can contain more than one class. You can create a new class at any time using the Class...End Class block. Finally, one or more source code files can be compiled into an assembly.

In the code window, change the class definition line to name the class Patient. In other words, change this line:

Public Class Class1

to this:

Public Class Patient

You have now changed the class name, but if you look in the Solution Explorer window, or just look at the tab on the current code window, you see the filename is still Class1.vb.

Right-click on the Class1.vb icon in the Solution Explorer and choose Rename. Name the file Healthcare.vb. You should see the tab in the main code window change to reflect the new filename. What you have done is change the name of the file that holds one or more classes.

Adding a “Souped-Up” Class

You already have your first class, which was created for you when you created the class library. This class is now called Patient, but it does not have a constructor (Public Sub New) as most new files in VB .NET do. You can add your own constructor if you want your class to have one.

Not only doesn't this class have a constructor already built for you, neither does it have a designer. It is possible to create a new class that comes with a designer and a constructor already created. In the Solution Explorer, right-click on the project name, choose Add, and then choose Add Component. From the dialog that opens, choose Component class and click Open. This adds a new file to the project, which has only a class in it. This class, however, includes a designer, as shown in Figure 4.1.

Figure 4.1. A new class created with a designer and a constructor already created.


The new class includes a designer, so you can perform actions such as dragging database connections to the designer to make it easier to create data components.

Double-clicking on the designer opens the code window. You can see that there is more code in this class than in the class that was created with the class library project. If you examine the code, you'll notice the following line:

Inherits System.ComponentModel.Component

This line makes the class inherit from the base Component class in System.ComponentModel. If you added that line to your Healthcare class, you would have access to the designer there.

For now, you'll return to the generic Healthcare class you created earlier.

Creating Properties

You can now start adding properties to your class, but be aware that the syntax for creating properties has changed.

Add a FirstName property by first creating a private variable. Inside the class, add the following code:

Dim msFirstName as String

Now, add the following code. Realize that as soon as you type the first line, most of the rest of the code will be filled in for you by the IDE. You'll still have to add the Return and the assignment.

Public Property FirstName() As String
    Get
        Return msFirstName
    End Get
    Set(ByVal Value As String)
        msFirstName = Value
    End Set
End Property

Notice the new syntax for creating properties. No longer do you create matching Public Property Get/Public Property Let procedures. Instead, you create a Public Property block and then add a Get and a Set section to it. There is no Let anymore, which makes life easier.

Also notice that you do not have to add an argument to the definition of the property, as you have to do in the Public Property Let in VB6. This means that you no longer have to specifically create an argument to accept the incoming value; instead, if the user passes in a value, it is put in the Value variable automatically.

Building a Test Client

Now, it is time to test this class. True, it has only one property, but you need to see how to call this class in a client application. From the File menu, choose New and then Project. This time, add a Windows Application. Name it HealthcareClient, but before you click OK, make sure that you select the Add to Solution radio button. The default is to close the current solution and open a new one. By choosing to add this new project to the current solution, you have the equivalent of a VB6 group.

After you click the OK button, the new project is loaded into the Solution Explorer, as shown in Figure 4.2. As in VB6, the project name that appears in bold in the Solution Explorer is the project that will start when you start the application. Simply right-click on the HealthcareClient project and choose Set as StartUp Project from the pop-up menu.

Figure 4.2. The Solution Explorer showing two projects loaded at once.


In the Solution Explorer, right-click on the References node for the HealthcareClient project and choose Add Reference. The Add Reference dialog box will appear. Click on the Projects tab and you should see your Healthcare project. It is already highlighted, but the OK button is disabled, as you can see in Figure 4.3. Click the Select button to move Healthcare into the Selected Components box, and then click the OK button.

Figure 4.3. The Add Reference dialog box.


Now, on the form in HealthcareClient, add a button. Double-click the button to get to the code window, and enter the following code for the Button1_Click event procedure:

Protected Sub button1_Click(ByVal sender As Object, _
  ByVal e As System.EventArgs) Handles button1.Click
    Dim myPatient As New Healthcare.Patient()
    myPatient.FirstName = "Bob"
    MsgBox(myPatient.FirstName)
End Sub

This code should look very familiar to VB6 developers. After adding a reference, you instantiate the object by setting the variable myPatient to a New Healthcare.cPatient. If you are used to VB6, you might be tempted to try this shortcut and type this line of code:

Dim myPatient As New Patient()

If you type the line this way, however, you'll get an error that says User-defined type not defined: Patient. This shows that you need to have the name of the component fully qualified. The word Healthcare in this case is not the assembly name; instead, it is the namespace.

To get around this problem, you can import the namespace containing the Patient class. As you read in Chapter 3, “Major VB .NET Changes,” all projects have a default namespace, and the name of the default namespace is the same as the project. Therefore, if you go to the top of the code module and add an Imports statement, the shortcut reference to the Patient class will work. Your Imports statement must go at the top of the module, and it will look like this:

Imports Healthcare

You might have noticed in the code that you used the New keyword to create the object. In VB6, you could use the New keyword in two ways. Here is the first way:

Dim myPatient as New Healthcare.Patient

In VB6, this code works, but it is not the best way to create objects. When you use this method, the object is not actually created until you call the first property or method. In fact, each call to a property or method requires a check to see whether the object has already been instantiated. To avoid this overhead, you should have been using this method in VB6:

Dim myPatient as Healthcare.Patient
Set myPatient = New Healthcare.Patient

In VB .NET, however, the following two methods are considered equivalent:

Dim myPatient As New Patient()

Dim myPatient As Patient = New Patient()

In both of these lines, the object is created in memory immediately. This means that with VB .NET, you will have the object in memory, and you avoid the overhead of having to check whether the object is in memory. With VB6, this overhead could occur with every call to the object if you instantiated it using the shortcut syntax. With VB .NET, you completely avoid this because VB .NET knows the object is instantiated immediately and does not need to check whether the object exists.

Read-Only and Write-Only Properties

Returning to the class library you are creating, you should notice that the property you created, FirstName, has both a Get and Set section in the Property block. In VB6, to make a property read-only, you simply did not create a Public Property Let statement. To create a write-only property, you did not create the Public Property Get.

You might be tempted to try to create a read-only property by simply leaving out the Set...End Set block. However, VB .NET handles read-only and write-only properties differently: You must add a keyword to the property declaration. To create a read-only property named Age (you can assume that it's calculated from the person's date of birth), your code would look like this:

Public ReadOnly Property Age() As Single
    Get
        'get Date of Birth (DOB)
        'calculate age from DOB
        'return age
    End Get
End Property

Creating a write-only property is equally simple. Just put the keyword WriteOnly in the property declaration, and have only a Set...End Set block in the property procedure.

Parameterized Properties

It is possible to create a parameterized property. Using the example of a patient, consider that a patient is likely to have several physicians attending to him at any one time. Therefore, although your Healthcare class library might have a Physician class, the Patient will likely hold a collection of Physician objects. You would be able to access this collection through a parameterized property and walk through this collection.

Creating a parameterized property is fairly straightforward: You simply add a parameter to the property procedure. If you have a Physicians property that walks through a collection of Physician objects, the code would look something like this:

Dim PhysiciansList As New Collection()
Public ReadOnly Property Physicians(ByVal iIndex As Integer) _
  As Physician
   Get
      Return CType(PhysiciansList(iIndex), Physician)
   End Get
End Property

You might notice several unusual things in this code. First of all, the basic functionality is there, in that you pass in an index value and get back a particular object in a collection. Notice also that even though the PhysiciansList is defined as a Collection data type, Option Strict will prevent an automatic conversion from a Collection type to a Physician type. Therefore, if Option Strict is on, you must run the CType function and pass both the object you want to convert and the type of the class (or object) into which it should be converted. Only then will the return actually succeed.

Default Properties

At the beginning of Chapter 3, you learned that default properties were gone, with the caveat that default properties without parameters were gone. However, if a property has one or more parameters, it can be the default property. Therefore, the Physicians property in Patient could be a default property.

Making a property the default property is as simple as adding the word Default in front of the property declaration. To make the Physicians property the default, your declaration would look like this:

Default Public ReadOnly Property _
  Physicians(ByVal iIndex As Integer) As Physician

Now, in your client program, you could call the default property on the Patient object. The last two lines of this code snippet are equivalent:

Imports Healthcare
...
Dim Patient As New Patient()
Dim Phys As New Physician()
Phys = Patient.Physicians(1)
Phys = Patient(1) 'equivalent to line above

Constructors in Your Classes

The one class you have built so far, Patient, did not come with a constructor; in other words, there was no Sub New available when you first created the class library. Constructors can be quite useful because they allow you to instantiate an object with some values already in it.

For example, assume that you wanted the Patient to allow you to pass in a PatientID when you instantiated the object. That means you could write code that would create the object and, at creation time, read a database and fill in the properties for a particular patient. Your new definition for the Sub New would look like this:

Public Sub New(Optional ByVal iPatientID As Integer = 0)

Your client code could now instantiate the object and pass in a value at instantiation. Either of the following lines would allow you to create an instance of the object with a value already set:

Dim Patient As New Patient(1)

Dim Patient As Patient = New Patient(1) 'equivalent to line above

Classes Without Constructors

Obviously, your classes do not have to have constructors. If you just use the Class...End Class block to create a new class, you will not be provided with a Sub New. Whether or not a class has constructors or implements System.ComponentModel.Component, the class can still have properties and methods, and can be created just like any other class. The Physicians class that has been mentioned in previous examples could look something like this:

Public Class Physician
    Dim miPhysID As Integer
    Public Property PhysicianID() As Integer
        Get
            Return miPhysID
        End Get
        Set
            miPhysID = Value
        End Set
    End Property

    Public ReadOnly Property Age() As Single
        Get
            'get Date of Birth (DOB)
            'calculate age from DOB
            'return age
        End Get
    End Property
End Class

Adding Methods to Classes

Adding a method to your class is done the same way it was done in VB6. If you want to create an Admit method in the Patient class, your code might look something like this:

Public Function Admit() As Boolean
    'add patient to database, notify billing, etc.
    Return True
End Function

The call to this from the client is equally simple:

If Patient.Admit Then...

Before you begin thinking that there aren't any changes in methods, understand that there are major changes in defining methods. However, the changes are specific to inheritance, and they will be covered in Chapter 5, “Inheritance with VB .NET.”

Adding Events

To add an event to your class, use the Event keyword. Imagine that you wanted to add an event to the class that notified you when you had pending lab results. You could create the event using code like this inside the class that needs to fire the event:

Event LabResult(ByVal LabType As String)

This just creates the event definition in your code. To actually cause the event to fire, you'll have to add a RaiseEvent statement elsewhere in the code. For example, if you set a PatientID property, you can go check a database for any new lab results for that patient. If there are new lab results, you could raise an event. Your code would look similar to this:

Dim miPatientID As Integer
Public Property PatientID() As Integer
    Get
        Return miPatientID
    End Get
    Set
        miPatientID = Value
        'check labs database for this patient
        'if there are new lab results
        RaiseEvent LabResult("CBC")
    End Set
End Property

If this were a real procedure, you wouldn't hard-code "CBC" into the event, but would instead pull the lab type from the database.

Handling the Event Using WithEvents

You have two options for handling this event in the client. The first way to handle the event is using the WithEvents keyword. The second way is to use the AddHandler statement.

To use the WithEvents keyword, you need to declare the object and include the WithEvents keyword. Notice that if you are using the WithEvents keyword, the declaration cannot be local to a sub or function. Therefore, this code will go outside any sub or function, at the module level in your client:

Dim WithEvents Patient As New Patient

This line assumes that you have imported the HealthCare namespace. This line is at the module level of your class because you cannot use the WithEvents keyword in a declaration inside a procedure. Therefore, you have to declare the object using the WithEvents keyword outside of any procedure.

Now, to add an event procedure, click on the Class Name drop-down list box at the top of the code window and choose Patient. In the Method Name drop-down list box, choose LabResult. This creates an event procedure named Patient_LabResult that looks like this:

Public Sub Patient_LabResult(ByVal LabType As System.String) _
  Handles Patient.LabResult
   ...
End Sub

Handling the Event with AddHandler

The second way to handle events is to use the AddHandler statement. You now do not have to define the class using the WithEvents keyword. Instead, you define it as you did before. You must also have a sub or function that will act as the event procedure.

Next, you use the AddHandler statement to tie a particular event from the object to the procedure you created to handle the event.

For example, assume that you wanted to create an event handler sub called LabHandler. This procedure would be defined as a standard sub. It would have to take as arguments any parameters defined in the LabResult event back in the Patient class. In the example here, the event named LabResult passes along a lab parameter with a data type of string. Therefore, your procedure would have to accept a string as an argument.

When you use AddHandler, you specify the name of the event in the Patient class you want it to handle (LabResult), but you must also refer to the procedure; in this case, LabHandler. However, you don't refer directly to LabHandler; instead, you refer to the address of LabHandler, using the AddressOf operator. Your code to set up event handling with the AddHandler statement would look like this:

Protected Sub Button1_Click(ByVal sender As Object, _
  ByVal e As System.EventArgs) Handles Button1.Click
    Dim Patient As New Patient()
    AddHandler Patient.LabResult, AddressOf Me.LabHandler
    ...
End Sub

Private Sub LabHandler(ByVal LabType As String)
    ...
End Sub

Notice that in the AddHandler, you refer to the object variable (Patient) and the event name (LabResult) using the Object.Event syntax.

Why might you want to use the AddHandler keyword instead of using WithEvents? The advantage of using AddHandler is that you can create one procedure that can handle multiple events, even if the events are being fired from different components. You can also handle events from objects that you create at runtime. For example, you might get a collection of objects passed to you, but still be able to handle their events using the AddHandler keyword.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.52.200