This chapter will introduce some of the basic anatomy of the program.
Namespace
Every DotNet program is called an assembly (irrespective if it is a WinForm application, Console Application or even a .DLL library). All DotNet codes are arranged in Namespaces. Even if your code does not declare a namespace, it is automatically placed into a default namespace. Namespace provides a way for you to declare classes and modules and without needing to make sure that the name has not been previously used (unless it will be in the same namespace). For example, you have buttons in Web Forms (System.Web.UI.WebControls.Button) ; you have also buttons in Windows Forms (System.Windows.Forms.Button). Without namespaces, this would not be possible.
In our examples of “Hello World”, we use System.Console.WriteLine to write the “Hello World” at the console.
Module Hello
Sub Main
System.Console.writeline("Hello World")
End Sub
End Module
It would be tedious to do that for every single code. Alternatively, the namespace can be imported, as shown below. However, if two classes (from different namespace) with the same name are used and both namespaces were imported, the fully qualified name must be used to avoid confusion. (Just as you would if you have two John in the room, you need a way to tell which John you are referring to).
Imports System
Module Hello
Sub Main
Console.writeline("Hello World")
End Sub
End Module
Modules and Classes
Module is a special type of class that cannot be instantiated – meaning all references to the members in the module refers to the same instance. All members (subroutine, variables, functions etc) of a module are implicitly shared. Also, you cannot inherit a module nor can you derive a class from a module. Therefore, if you have a change the value of a variable in the module, all codes that refer to the variable will see the same value. This is very important to remember especially if you are going to write in ASP.NET or any multiuser application. When more than one person access it, you will encounter strange results and error.
One way to overcome this is to pass the values as parameters to your functions and subroutines (as you would in shared subroutines and functions).
For classes, you can have multiple instances of a class. Variables within each instance are independent of other instances. As shown in the example below:
'
' Module and Class Sample
' User: Strovek
' Date: 8/28/2005
'
' ========================================
Imports System
Namespace PJ
Module Mod1
Dim vNumVar1 As Integer = 10
Public Property pIntVal As Integer
Get
Return vNumVar1
End Get
Set (Value As Integer)
vNumVar1 = Value
End Set
End Property
End Module
Module Mod2
Sub Main
Console.WriteLine("test program")
pIntVal = 5
Console.WriteLine("Mod1 integer value is {0}.", pIntVal)
Dim ObjC1 As New cls1
Dim ObjC2 As New cls1
Console.WriteLine("Obj 1 integer value is {0}.", ObjC1.pIntVal2)
Console.WriteLine("Obj 2 integer value is {0}.", ObjC2.pIntVal2)
ObjC1.pIntVal2 = 9
ObjC2.pIntVal2 = 20
Console.WriteLine("Obj 1 integer2 value is {0}.", ObjC1.pIntVal2)
Console.WriteLine("Obj 2 integer2 value is {0}.", ObjC2.pIntVal2)
Console.WriteLine("Obj 1 integer3 value is {0}.", ObjC1.pIntVal3)
Console.WriteLine("Obj 2 integer3 value is {0}.", ObjC2.pIntVal3)
End Sub
End Module
Public Class cls1
Dim vNumVar1 As Integer = 10
Public Sub New()
End Sub
Public Property pIntVal2 As Integer
Get
Return vNumVar1
End Get
Set (Value As Integer)
vNumVar1 = Value
End Set
End Property
Public Function pIntVal3 As Integer
return pIntVal
End Function
End Class
End Namespace
The output is as follows:
The following lines of code will produce the same output:
Console.WriteLine("Obj 1 integer value is {0}.", ObjC1.pIntVal2)
Console.WriteLine("Obj 1 integer value is " & ObjC1.pIntVal2 & ".")
exit
Setting and getting values of Variables within Classes
If you have some variables in a class, which you want to be able to obtain values as well as change the values. There are a few ways of doing it:
1. Declare the variable as public.
2. Have a Subroutine to set the value and have a function to return the value.
3. Create a property for setting and getting the value.
Option 1 is the easiest method but there are several problems with it. You have no control on how the values are set and neither do any classes that inherit from this class.
Option 2 and 3 provides much better flexibility. You can:
1. Add additional logic to control values you can set for the variable.
2. Allow the derived class to change the logic.
3. Make the variable read only from the outside by not declaring the subroutine for setting the value or the property for setting the value (while still allow the value to be changed during initializing, or by other subroutines or functions within the class).
The following is a sample of the above:
'
' Module and Classes Sample
' User: Strovek
' Date: 8/28/2005
'
' ========================================
Imports System
Namespace PJ
Module Mod1
Dim vNumVar1 As Integer = 10
Public Property pIntVal As Integer
Get
Return vNumVar1
End Get
Set (Value As Integer)
vNumVar1 = Value
End Set
End Property
End Module
Module Mod2
Sub Main
Console.WriteLine("test program")
pIntVal = 5
Console.WriteLine("Mod1 integer value is {0}.", pIntVal)
Dim ObjC1 As New cls1
Dim ObjC2 As New cls1
Console.WriteLine("Obj 1 integer value is {0}.", ObjC1.pIntVal2)
Console.WriteLine("Obj 2 integer value is {0}.", ObjC2.pIntVal2)
ObjC1.pIntVal2 = 9
ObjC2.pIntVal2 = 20
Console.WriteLine("Obj 1 integer2 value is {0}.", ObjC1.pIntVal2)
Console.WriteLine("Obj 2 integer2 value is {0}.", ObjC2.pIntVal2)
Console.WriteLine("Obj 1 integer3 value is {0}.", ObjC1.pIntVal3)
Console.WriteLine("Obj 2 integer3 value is {0}.", ObjC2.pIntVal3)
End Sub
End Module
Public Class cls1
Dim vNumVar1 As Integer = 10
Public Sub New()
End Sub
Public Property pIntVal2 As Integer
Get
Return vNumVar1
End Get
Set (Value As Integer)
vNumVar1 = Value
End Set
End Property
Public Function pIntVal3 As Integer
return pIntVal
End Function
End Class
End Namespace
The output is as follows:
In Sub Var3 and Property Var4, if the value passed is more than 50, set the value to –1.
Constants
Constants can (declared at the top of the program and) be used to provide a fixed value that can be used in various parts of the program. This will ease maintenance by allowing single point of modification when the value changes. It can also be used to make the code more readable by replacing numeric code with a readable name for example example vbNewLine to represent a CrLf, ConnectionState.Open is easier to understand than the numeric code it represents.
Classes Inheritance and Overriding
VB.Net is an Object Oriented Programming Language. As such, it supports inheritance.
A subroutine or function can be overwritten only if it has the keyword Overridable – the new class can then declare the new subroutine and function (with the same name) using the keyword Overrides.
Constants must be declared as Friends before it can be visible to the derived class. If the derived class wishes to overrides the value of the constant, then the new constant needs to be declared as Shadows.
The following is an example:
' Inheritance Sample
' User: Strovek
' Date: 8/28/2005
'
' ========================================
Imports System
Namespace PJ
Public Class clsOr
Friend Const preFixStr As String = "Sub Routine"
Public Overridable Function dispSub1 As String
return preFixStr & " 1"
End function
Public Overridable Function constVal As String
Return preFixStr
End Function
Public Sub New()
End Sub
End Class
Public Class clsNew
Inherits PJ.clsOr
Public Overrides Function dispSub1 As String
Return preFixStr & " 1 - Changed"
End Function
End Class
Public Class cls2ndGen
Inherits clsNew
Shadows Const preFixStr As String = "Another Value"
Public Overrides Function dispSub1 As String
Return "Unrelated value"
End Function
End Class
Public Class cls3rdGen
Inherits cls2ndGen
Shadows Const preFixStr As String = "New Value"
Public Overrides Function dispSub1 As String
Return "Unrelated value 2"
End Function
Public Overrides Function constVal As String
Return preFixStr
End Function
End Class
Module Mod1
Public Sub Main
Console.WriteLine("Program Start")
Dim Obj1 As New clsOr
Dim Obj2 As New clsNew
Dim Obj3 As New cls2ndGen
Dim Obj4 As New cls3rdGen
Console.WriteLine("Obj 1 constVal is {0}", obj1.constVal)
Console.WriteLine("Obj 2 constVal is {0}", obj2.constVal)
Console.WriteLine("Obj 3 constVal is {0}", obj3.constVal)
Console.WriteLine("Obj 4 constVal is {0}", obj4.constVal)
Console.WriteLine("Obj 1 sub 1 is {0}", obj1.dispSub1)
Console.WriteLine("Obj 2 sub 1 is {0}", obj2.dispSub1)
Console.WriteLine("Obj 3 sub 1 is {0}", obj3.dispSub1)
Console.WriteLine("Obj 4 sub 1 is {0}", obj4.dispSub1)
End Sub
End Module
End Namespace
In cls2ndGen class, even though the value of constVal was changed to “preFixStr”, the constVal still displays the original value. This is because we are using the constVal inherited from clsOr (the original class). When writing Windows Form, Web Services and ASP.Net applications; inheriting the appropriate classes will make programming much easier.
Inheriting a class provides the option to override existing methods (subroutine or functions) or using the original implementation. That is the true power of inheritance – allowing building on the existing code (instead of starting from scratch).
Main Subroutine
When writing a console program, one shared subroutine called main is necessary. Adding the (args() as String) parameter will allow the program to accept runtime parameters.
'
' Program with Parameters
' User: Strovek
' Date: 8/30/2005
'
' ========================================
Imports System
Module PrgWithParam
Sub Main(args() As String)
Console.Writeline("Start Program")
Console.WriteLine("Total Paramater is {0}.", args.Length)
Dim loopCnt As Integer
For loopCnt = 0 To args.Length-1
Console.WriteLine("Arg {0} is {1}.", loopCnt, args(loopCnt))
Next
End Sub
End Module
The output is as follows:
When writing a Windows Form, a main subroutine is optional. However, a Windows Form application must:
1. Inherit from a System.Windows.Forms (or another derived class). So you cannot use a module to create program.
2. Import System.Drawing (since we will be using a lot of graphics – which we did not need when we wrote a text based (console) application.
3. Perform a System.Windows.Forms.Application.Run the form object.
The following sample will create a blank window:
'
' Simple Windows Form
' User: Strovek
' Date: 8/30/2005
'
' ========================================
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Namespace PJ
Public Class wForm
Inherits Form
Public Shared Sub Main()
Dim winObj As New wForm
application.Run(winObj)
End Sub
End Class
End Namespace
The output is as follows:
For the windows form, the shared main subroutine is optional. If you leave out the shared main subroutine is not available, the main class must be specified using /main:
The modified code is as follows (the output is identical with the code above) – I added the namespace to illustrate that the class needs to be a fully qualified class, if no namespace is there then you specify /main:wForm.
'
' Simple Windows Form
' User: Strovek
' Date: 8/30/2005
'
' ========================================
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Namespace PJ
Public Class wForm
Inherits Form
End Class
End Namespace
The compile the above program, we need to type the following (all in one line):
\WINDOWS\Microsoft.NET\Framework\v1.1.4322\vbc /t:winexe SampleWindowForm2.vb /main:PJ.wForm /r:System.Windows.Forms.dll,System.dll,System.Drawing.dll
The following is how the process looks like:
Events
In Window Form and ASP.Net application, majority of the work is done through event handling. Most of the controls have built in events (e.g. Buttons have Click, Form contains load etc).
There are two ways of handling events:
1. Create a subroutine and specify that it “handles the event”.
2. Adding the handler to the event
In the samples below, you will notice that all subroutines handling the events have to be declared with an object and also an eventargs as parameters. This is because the event will pass both these parameters to the event handler subroutine.
Note that you can have more than one subroutine handle a specific event and a subroutine handle multiple events.
Direct event handling
In this approach, just add the keyword “WithEvents” to the object declaration as in:
WithEvents Private btnSubmit2 As System.Windows.Forms.Button
Then declare the subroutine as handling the event as follows:
Private Sub BtnSubmitClick(sender As System.Object, _
e As System.EventArgs) handles btnSubmit.Click
MsgBox("Button Clicked")
End Sub
Adding the handler to the event
In this approach, the “WithEvents” keyword is optional in the object declaration:
Private btnSubmit2 As System.Windows.Forms.Button
Add the handler to the event using AddressOf creates a procedure delegate instance that references the specific procedure. It is a pointer associated to the procedure:
AddHandler Me.btnSubmit2.Click, AddressOf Me.BtnSubmit2Click
Once done, it is not necessary to specify the event in the subroutine declaration, as shown below:
Private Sub BtnSubmit2Click(sender As System.Object, e As System.EventArgs)
The following code illustrates the above concept. There are three buttons – two buttons are declared with “WithEvents” keyword. btnSubmit and btnSubmit3 have two handlers. Subroutine MultiHandler handles two events. The sender can be converted to the original control using CType Function, (otherwise gettype will return the type). In this case, we know that the sender is a button control, so it can be converted back to its original control in order to obtain the name of the sender.
'
' Sample Windows Form Events
' User: Strovek
' Date: 8/26/2005
'
' ========================================
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports Microsoft.VisualBasic
Namespace TestWinform
Public Class MainForm
Inherits System.Windows.Forms.Form
WithEvents Private btnSubmit As System.Windows.Forms.Button
WithEvents Private btnSubmit3 As System.Windows.Forms.Button
Private btnSubmit2 As System.Windows.Forms.Button
Public Shared Sub Main
Dim fMainForm As New MainForm
fMainForm.ShowDialog()
End Sub
Public Sub New()
MyBase.New
'
' The Me.InitializeComponent call is required for
' Windows Forms designer support.
'
Me.InitializeComponent
'
' TODO : Add constructor code after InitializeComponents
'
End Sub
#Region " Windows Forms Designer generated code "
' This method is required for Windows Forms designer support.
' Do not change the method contents inside the source code
' editor. The Forms designer might
' not be able to load this method if it was changed manually.
Private Sub InitializeComponent()
Me.btnSubmit2 = New System.Windows.Forms.Button
Me.btnSubmit3 = New System.Windows.Forms.Button
Me.btnSubmit = New System.Windows.Forms.Button
Me.SuspendLayout
'
'btnSubmit2
'
Me.btnSubmit2.Location = New System.Drawing.Point(104, 88)
Me.btnSubmit2.Name = "btnSubmit2"
Me.btnSubmit2.TabIndex = 1
Me.btnSubmit2.Text = "Submit2"
AddHandler Me.btnSubmit2.Click, _
AddressOf Me.BtnSubmit2Click
'
'btnSubmit3
'
Me.btnSubmit3.Location = New _
System.Drawing.Point(104, 200)
Me.btnSubmit3.Name = "btnSubmit3"
Me.btnSubmit3.TabIndex = 2
Me.btnSubmit3.Text = "Submit3"
AddHandler Me.btnSubmit3.Click, _
AddressOf Me.BtnSubmit3Click
'
'btnSubmit
'
Me.btnSubmit.Location = New System.Drawing.Point(104, 144)
Me.btnSubmit.Name = "btnSubmit"
Me.btnSubmit.TabIndex = 0
Me.btnSubmit.Text = "Submit"
'
'MainForm
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Controls.Add(Me.btnSubmit3)
Me.Controls.Add(Me.btnSubmit2)
Me.Controls.Add(Me.btnSubmit)
Me.Name = "MainForm"
Me.Text = "MainForm"
Me.ResumeLayout(false)
End Sub
#End Region
Private Sub BtnSubmitClick(sender As System.Object, _
e As System.EventArgs) handles btnSubmit.Click
MsgBox("Button Clicked")
End Sub
Private Sub BtnSubmit2Click(sender As System.Object, _
e As System.EventArgs)
msgbox("Button 2 Clicked")
End Sub
Private Sub BtnSubmit3Click(sender As System.Object, _
e As System.EventArgs)
MsgBox("Button 3 Clicked")
End Sub
Private Sub MultiHandler(sender As System.Object, _
e As System.EventArgs) _
Handles btnSubmit.Click, btnSubmit3.Click
MsgBox("Button 1 or 3 has been clicked")
msgbox(sender.ToString & " sent this event:" & e.ToString)
Dim tmpBtn as System.Windows.Forms.Button = _
Ctype(sender, System.Windows.Forms.Button)
msgbox("the name is " & tmpbtn.Text)
End Sub
End Class
End Namespace
No comments:
Post a Comment