Properties

Let us think for a moment about our student class... How will the objects of this class be identified? Our class must have the capability to handle Student ID, Name, Age, etc.

The solution is simple, we can create public variables in the class to store these properties of a student. 

Public Class cStudent
    
Public Age As 
Byte
    .
    .
End Class 
To set the age we will do something like this:

Dim objStudent1 As New cStudent()
objStudent1.Age = 20

Fine. Now consider the following:

Dim objStudent1 As New cStudent()
objStudent1.Age = 200

or

objStudent1.Age = 2000

We would not want the users of our class to be able to set wrong data or invalid data. But there is no way to control this if we allow the users to access the variables directly. So, what is the best solution for this? The answer is Properties.

To store data of our object we would definitely require variables. These variables are called instance variables because they are created for each instance of the class. But, instead of giving direct access to instance variables, we will provide properties to the users of our class to access data. This way we will be able to check and control the value which is assigned.

Therefore, we will make our instance variables private so that they can not be accessed from outside the class: Private iAge As Byte

See, I have used the prefix 'i' before the variable name. I use this to differentiate instance variables from other elements.

Our next step is to create a public property for Age:

Public Property Age() As Byte
    Get
        Return
 iAge
    
End Get

    
Set(ByVal Value As Byte)
        
If Value <= 12 Or Value >= 30 Then
            
MsgBox("We do not accept students below 12 years and above 30 years", MsgBoxStyle.Exclamation, "Age not set")
        
Else
            
iAge = Value
        
End If
    
End Set
End Property
To access this property, we will use this code...
    Line 1: Set property - Age
    Line 2: Get property - Age

Dim objStudent1 As New cStudent()
objStudent1.Age = 16 

MsgBox("The present age is: " & objStudent1.Age)

A property has two parts: Get and Set.

The get part of a property is accessed when the value of property is read like in line 3 above. Therefore, we need to return a value (which we want our users to read) when get is invoked. In this case, we return the value of iAge.

Set part of the property is called when the user assigns some value to the property. The assigned value is passed to the Set code. Now see, we have decided to store the age in iAge variable. However, we do not want the users to set any age they want. Therefore, we have defined the criterion and applied it in the property. The value which users assign to the property is accessible to us through Value parameter. We can check the value and decide if we really want to assign it to iAge (as we have done above). This way we can maintain the integrity of our class.

One more thing. We have used Public and Private in our instance variable declaration to make it accessible or inaccessible to the code outside the class. Public and private are access types or access specifiers which define the scope of a variable. Please check the following to see the available access types and the scope defined for each one.

Private - available only to the code within our class
Friend - available only to the code within the project 
Protected - available only to classes that inherit from our class
Public - available to code inside and outside our class or project

Let's return back to properties. We have already learned how to create a property. What if you do not want the user to set or change a property but want to allow him/her to be able to get/see it. Yes, I am talking about readonly properties.

ReadOnly and WriteOnly Properties
To understand this, let us assume that there is a property called TotalCreditsEarned and it is calculated by some complex method and users are not allowed to change its value directly. However, users can check/read the TotalCreditsEarned property. Let us assume that TotalCreditsEarned is calculated by some method and is stored in a private variable called iTCE. Using this information, we can write a read only property: Public ReadOnly Property TotalCreditsEarned()As Int16
    
Get
        Return
 iTCE
    
End Get
End
 
Property

Please note in the above code that to make a property read only, we use the ReadOnly keyword in property declaration and remove the set part of the property (we do not need this anyway in a read only property).

Simple? Similarly, we can make a property write only by using the keyword WriteOnly instead of readonly and defining only the set portion.

Public WriteOnly Property WOP() As DataType
    
Set(ByVal Value As DataType)
        
'do something
    
End Set
End
 
Property
Parameterized Properties

Now let us take one example. Suppose each student is evaluated on the basis of marks in VB, ASP and Java. To get or set these marks, we will have to create three private variables and three properties. Right?

Let us see a better way to do so. We will keep 3 variables to store the values (yes, we can use array also), however, we will define only one property to access these variables. But the problem is - how will we know which subject user wants to access? See the code:

I suppose code is quite self explanatory... Note that we have used a parameter (subj as string) to handle this case.

Private iMarksVB As Single
Private iMarksASP As Single
Private iMarksJava As Single

Public Property Marks(ByVal subj As String) AsSingle
    Get
        
Select Case subj
            
Case "VB"
                
Return iMarksVB
            
Case "ASP"
                
Return iMarksASP
            
Case "Java"
                
Return iMarksJava
        
End Select
    
End Get

    Set(ByVal Value As Single)
        
Select Case subj
            
Case "VB"
                iMarksVB = Value
            
Case "ASP"
                iMarksASP = Value
            
Case "Java"
                iMarksJava = Value
        
End Select
    
End Set
End Property

To access this property, we will have to write something like this:
Line 1: Set Property - Marks
Line 2: Get Property - Marks

Dim objStudent1 As New cStudent()
Dim MarksInVB As Single
objStudent1.Marks("VB") = 55.5 'Line 1
MarksInVB = objStudent1.Marks("VB") ' Line 2
Enumeration

There is a problem in above code. User must know that there are three subjects (VB, ASP, Java) and must use strings to represent them. If the spelling or letter case is wrong, then? VB.NET provides a very beautiful construct to handle such cases and I like to use it as much as possible - Enumeration.

Have you ever noticed that while using the MsgBox function a list of all available buttons or icons appear automatically when you need to enter it? If not, then first of all do the following:

Open a project and write - Msgbox "something" - in it and then put a comma (,). Did you see a list of all available buttons.

Wouldn't it be nice if our class user gets a list like this (containing VB, ASP, Java, etc.) when he/she accesses the Marks property? And would you not like that when you are writing code for Get and Set, you also get the list while using Select Case statement?

This reduces chances of error many times and provides a quick and easy interface for us and our users to work.

Please see the code which demonstrates how to provide these features using enumeration.

In the code note the following things:

  • Enumerations are created using the ENum keyword
  • They can be used as type while declaring variables or parameters for methods or properties

Private iMarksVB As Single
Private iMarksASP As Single
Private iMarksJava As Single

Public Enum eMarks
    VB
    ASP
    Java
End Enum

Public Property Marks(ByVal subj As eMarks) AsSingle
    Get
        
Select Case subj
            
Case eMarks.VB
                
Return iMarksVB
            
Case eMarks.ASP
                
Return iMarksASP
            
Case eMarks.Java
                
Return iMarksJava
        
End Select
    
End Get

    Set(ByVal Value As Single)
        
Select Case subj
            
Case eMarks.VB
                iMarksVB = Value
            
Case eMarks.ASP
                iMarksASP = Value
            
Case eMarks.Java
                iMarksJava = Value
        
End Select
    
End Set
End Property

To use this property, see the code given here... (The list of all available subjects comes automatically wherever this parameter is used, for example, while using the property or while defining the property)
Line 1: Set Property - Marks
Line 2: Get Property - Marks
objStudent1.Marks(cStudent.eMarks.VB) = 55.5 
MarksInVB=objStudent1.Marks(cStudent.eMarks.VB)

Write this code and try it out yourself once...

Default Properties

We need to write the following to access Marks property:

objStudent1.Marks(cStudent.eMarks.VB)

If we make Marks property the default property, we will be able to access it like this:

objStudent1(cStudent.eMarks.VB)

Please see the code. Note that we have used Default keyword to make our property default. Simple. So we do not need to do anything to our property, except adding the keyword Default, to make it default property. Just a matter of one word!! Default Public Property Marks(ByVal subj AseMarks) As Single
...
...
End Property

Please note some obvious facts about properties:

  • There can be only one default property in a class.
  • Properties with no required parameters cannot be declared Default. Therefore, the property which we want to make default must have at least one parameter.

This was all about properties. Let us move to methods in detail now.

Methods
We have already seen how to create a simple method above. Let us consider it again: Public Sub Laugh()
    MsgBox(":)")
End Sub

Note the keyword Public here. It is an access specifier. Public means that the scope of this method is public, that is, we can call it from anywhere. Private access type limits the scope to the class in which the method is defined and Friend limits the access to the project in which the method is defined. I hope this must be clear by now.

Methods can be of two types:

  • Sub-routines: Methods which do not return any value; keyword used to define - Sub
  • Functions: Methods that return some value; keyword used to define - Function
You have already seen how to define and use a sub-routine above. Check out functions now:

Note that we have used the keyword Function to define a function. The return type is specified in the definition itself. To return the result of the function, we use the Return keyword followed by the value we want to return.

Public Function AverageMarks() As Single
    Return
 (iMarksVB + iMarksASP + iMarksJava)/3
End 
Function
If we want to use parameters in functions or sub-routines we can define the method as below:

Public Function FindPercentage(ByVal subj As eMarks) As Single
    
Dim result As Single
    
Select Case subj
        
Case eMarks.VB
            result = iMarksVB * 100 / 150
        
Case eMarks.ASP
            result = iMarksASP * 100 / 150
        
Case eMarks.Java
            result = iMarksJava * 100 / 150
    
End Select
    Return
 result
End Function

Optional Parameters

Look at the function above. We have assumed that the maximum marks for each subject are 150. If we want to give the user a choice to specify the maximum marks and if the user does not want we want to use 150, then what is the solution? Solution is function with optional parameters. Check the code:

Note that in the code we have used an optional parameter MaxMarks. If a parameter is declared optional, the user may or may not enter a value for this. If the value is not specified by the user, default value is taken (150 in our case). It is compulsory to specify the default value for the optional parameters.

A method can have any number of optional parameters, however, it should be noted that optional parameters must be the last in parameter list of a method.

Public Function FindPercentage(ByVal subj AseMarks, Optional ByVal MaxMarks As Single = 150) As Single
    
Dim result As Single
    
Select Case subj
        
Case eMarks.VB
            result = iMarksVB * 100 / MaxMarks
        
Case eMarks.ASP
            result = iMarksASP * 100 / MaxMarks
        
Case eMarks.Java
            result = iMarksJava * 100 / MaxMarks
    
End Select
    Return
 result
End Function
To use this method, we can use following code:
Line 1: Default value of MaxMarks would be taken, that is, MaxMarks=150
Line 2: User specified value is assigned to MaxMarks, that is, MaxMarks=100
objStudent1.FindPercentage(cStudent.eMarks.VB) 
objStudent1.FindPercentage(cStudent.eMarks.VB, 100)
One last thing about methods. We can pass objects as parameters to a method and also a method can return an object. To do this we just need to specify the class name in the method declaration (just as we did for enumeration). 
Shared Members
So far we have seen that the variables defined in a class are created for each instance and hence are called instance variables. Now, if we want to keep track of number of instances created then how can we do so. Here come shared variables. Shared variables are variables which are shared by all instances. In other words, we can say that shared variables belong to the class and not the object.

Similarly there can be properties and methods which do not depend on any object data. These may depend on shared data. Therefore, shared methods and properties cannot access instance variables, but they can use shared variables.

Since shared members belong to the class and not the object, we do not need to create an instance in order to use shared members. We can simply access them as follows:

Class.SharedMember

An example of shared method is MessageBox.Show. Here, Show is the shared member of MessageBoxclass.

Now, how to define shared members. Very simple. Simply put the keyword 'Shared' after the access type while declaring variables, properties, methods and events.

Events
We all have done programming based on events. In this example also, we have used the Click Event of button. What are events? Events are a mechanism through which the creator of class gives an opportunity to the user of class to write code when something (some event) happens.

To understand the application of this concept, let us assume that our class has a Save method which saves some data into a file. When the data is saved we want to notify our class user and allow him/her to perform further action, that is, write code which he/she wants to execute when data is saved. This gives our user great independence in performing whatever action he/she wants when data is saved, like simply showing a message box to the end-user or calling another method or copy the file in which data is saved for backup, etc.

Did you note that there are a number of actions which user might want to perform when data is saved (the list can go up to infinity). Therefore, we cannot assume while designing a class that what action our class user might want to perform on some particular event and so it is wise to expose an event for the user to handle in a way he/she desires.

Creating Events
The first step in creating an event is declaration. See the code. This line defines a public event named Saved. And remember there is no code because we are not going to write it!! If you want to add arguments to the event, you can mention them in the same way as we do for methodd. Pretty simple...  Public Event Saved()
Once an event is declared, the next step is to raise the event or fire the event at appropriate moment. This is done through RaiseEvent statement. Whenever we wish to fire an event, we use this statement. In this example, just after saving the data in Save method of the class. When the user calls the Save method, it saves the data and when data is completely saved, it fires the Saved event which is to be handled by the user. If you have declared event with arguments, pass the appropriate values in the arguments. These arguments will be available to the user of the class in event handler...  Public Sub Save()
    
'code to save the 
    'data
    
RaiseEvent Saved()
End Sub

To use this event, we need to do two things:

  • Use WithEvents keyword while declaring the object of the class (we can instantiate the class in the same line using New keyword). See code...
  • Make the object global, that is, declare the object outside our method directly within the class.
Dim WithEvents objStudent1 As New cStudent()

To write the code to handle the event, we have to write an event procedure. An event procedure is nothing but a method which is called when the event is fired. But how can we associate a method with an event. One way is using Handleskeyword. This is the way the events are normally handled (our click event procedure also uses this way).

Just write the method which you want to execute when event fires. Just add Handles objectName.EventName at the end of method declaration to associate that method with the event. However, this method must have the same number and type of arguments as declared in the event which the method has to handle (if the event has arguments)...

If you want .NET IDE to automatically generate the method declaration, you can select the object from object list and then select the event from the event list, just as you do to write event procedure for other objects like button, textbox, etc.

Private Sub objStudent1_Saved() HandlesobjStudent1.Saved
    
'Do whatever you want when data is saved
    
MsgBox("Data Saved!!!")
End 
Sub
Handling Multiple Events

Now, let us assume that we want to perform the same action when two different events occur. That is, we want to associate the same method with more than one events. Well, this can be done very easily in VB.NET. Just write all the events a method has to handle saparated with comma (,). Keep in mind that the rules of using Handles statement remain the same.

If we want a method handleIt() to handle two events Saved and Loaded of object objStident1, we will use this code.

Private Sub handleIt() HandlesobjStudent1.Saved, objStudent1.Loaded
    
'Do whatever you want when data is saved
    
MsgBox("Data Saved!!!")
End Sub
Event Association at run time

In all the examples above, we have associated a method with some event at design time. There can be situations in which you do not know which method handles which event, or, you create an object at run time and want to associate one of its event with some method. How can this be done? Before explaining this let us consider another case to feel the need to associate at run time.

I have one application which loads the images from a folder at run time and shows them as thumbnails in picture boxes. When user clicks on any of the image a form opens with that particular image in full size. When the user clicks on this new form, the form unloads. Did you understand what I want to say?

Now what I do to show the full view is, I create a form at run time, add picture box to it and show the selected picture in it. Remember all this is done through code at runtime. Now how to associate the method to unload this form with Picturebox's click event...

This is what we are trying to see here. To associate an event with some method at run time, we use AddHandler statement. And to dissociate any event with its handler method at run time, we use RemoveHandler statement.

Suppose we have a method XYZ(). To associate this method with objStudent1 object's Saved method at run time, we will use the following code:

AddHandler objStudent1.Saved, AddressOf XYZ

and to dissociate, we will use following line:

RemoveHandler objStudent1.Saved, AddressOf XYZ

As you can see, the first parameter used above is the event name and second parameter is address of the method.