3. WinForms
The Visual Basic.Net compiler
has a large number of options, one of which is the /target option, which
determines how the output should appear. Under Windows, a dll file and an exe
are both similar. The only apparent distinction between the two is that an exe
file can be executed at the command prompt, whereas, a dll cannot. It acts as a
carrier or a reservoir of code. By default, the target output is set to exe.
Now, create the following file called b.vb:
b.vb
public class yyy
sub abc
System.Console.WriteLine("abc")
end sub
end class
The file b.vb is composed into a
dll file, instead of an exe file. To achieve this, the following command is
used:
>vbc /target:library b.vb
The above command creates a file
called b.dll, which carries the code of the class yyy, containing a sub called
abc. The word 'public' mentioned before the name of the class signifies that
the entire world has access to the code in the class. Words such as 'public'
are called access modifiers, which we shall address in a subsequent section. If
we eliminate the 'public' access modifier, the next program would not work
successfully.
a.vb
Public Class zzz
Shared Sub Main()
dim a as yyy
a = new yyy
a.abc
End Sub
End Class
>vbc a.vb /r:b.dll
Output
abc
One of the most vital advantages
of writing code is that the other programmers too can access it. For example,
the file b.dll carries a class yyy, which can contain numerous functions like
abc. Now, any other program can also refer to this code.
On running the Visual Basic.Net
compiler at this stage, an error will be reported, since the compiler is
unaware of the identity of the file that contains the code. Thus, we need to
explicitly inform the compiler about the identity of the dll file that contains
the function.
This is achieved by specifying
the command line option /R, where the R stands for 'reference'. It is followed
by the name of the dll that contains the code. Microsoft also offers its own
set of classes by locating them in multiple dll files. Hence, to access the
code contained in them, we need to use the /R option at the compiler level.
This chapter is primarily
focused on building GUI applications. In the Visual Basic.Net program
stipulated below, the class zzz is derived from the class Form. This implies
that all the code in the class Form is now made available in the class zzz.
a.vb
Imports System.Windows.Forms
Public Class zzz
Inherits Form
Shared Sub Main()
dim a as zzz
a = new zzz()
Application.Run(a)
End Sub
End Class
>vbc a.vb /r:System.Windows.Forms.dll /r:System.dll
|
Screen 3.1 |
On running the above program,
general happiness prevails, since a pretty little window comes into view, as
shown in screen 3.1.
Since the class zzz is derived
from the Form class, all methods and instance variables within the Form class,
are now made available in zzz. This establishes the potency and beauty of the
concept of inheritance.
The Form class belongs to the
namespace of System.Windows.Forms. This explains the presence of the 'imports'
statement, which is provided with the primary aim of evading the use of the
entire namespace before Form, since the class is used very often.
All classes in the .Net world
must belong to a namespace. If we do not specify a namespace for a class, it
will get placed in the global namespace.
In the Main function, first an
object of type zzz is created. It is then passed as a parameter to the Run
function. Abiding by what we have learnt so far, we can safely conclude that
Application is the name of the class, and Run is a shared function. The
Application class also falls under the namespace of System.Windows.Forms.
The final action to be taken is
to furnish the Visual Basic.Net compiler with a reference to the dll,
which contains the code of the Forms
and Application classes. The help text on the above-mentioned classes clearly
reveals that the dll that constitutes the System.Windows.Namespace, is the
System.Windows.Forms dll. This name is passed on to the Visual Basic.Net compiler
using the /R option.
The Run function merely requires
an object derived from Form. Once it gets the custody of this object, it
displays a cool looking window. Never mind how or why!
a.vb
Class zzz
Shared Sub Main
dim a as yyy
a = new yyy
a.i = 10
a.abc
a.pqr
End Sub
End Class
Class yyy
Inherits xxx
sub abc
System.Console.WriteLine("yyy abc {0}" , i)
i = 30
end sub
end class
Class xxx
public dim i as integer
sub pqr
System.Console.WriteLine("xxx pqr {0}", i)
end sub
end class
Output
yyy abc 10
xxx pqr 30
The above program demonstrates a
simple concept. The class xxx has a public instance variable i. Thus, other
classes can now access this variable. The class yyy is derived from the xxx
class, with 'a' as its object. Now, 'a' is allowed access to the variable i.
The golden rule here is that,
whatever an object of class xxx is allowed to do with the members of the class
xxx, the same leeway is granted to an object of the class derived from xxx.
Furthermore, there is only one copy of the variable i. So, any changes made to
it from the sub abc, would be reflected in the sub pqr within the class xxx.
The next program converges
around this concept.
a.vb
Imports System.Windows.Forms
Public Class zzz
Inherits Form
Shared Sub Main()
dim a as zzz
a = new zzz()
Application.Run(a)
End Sub
sub new
myBase.New
Me.Text = "Vijay Mukhi"
end sub
End Class
|
Screen 3.2 |
The above program displays a
window, as seen in screen 3.2, where the title of the window is given as
"Vijay Mukhi".
The program has a constructor
'new', which traditionally calls the original constructor. This is not
mandatory, but we would rather follow the rules laid down by the Big Daddy!
Then, using the keyword 'Me', the variable Text is initialised to "Vijay
Mukhi". The Text member is not created anywhere in the class. So, it is
safe for us to assume that it exists in the class Form.
This initialisation results in a
change in the title of the window. The Run function determines the title of the
window, after ascertaining the contents of the Text variable. The default is a
blank value. We are still at the preliminary stage of customizing the Windows
Forms.
a.vb
Imports System.Windows.Forms
Imports System.Drawing
Public Class zzz
Inherits Form
Dim b as Button
Shared Sub Main()
dim a as zzz
a = new zzz()
Application.Run(a)
End Sub
sub new
myBase.New
Me.Text = "Vijay Mukhi"
b = new Button
b.Text = " sonal"
dim p as Point
p = new Point(10,100)
b.Location = p
Dim c as Control.ControlCollection
c = Controls
c.Add(b)
end sub
End Class
>vbc a.vb /r:System.Windows.Forms.dll /r:System.dll
/r:System.Drawing.dll
This example displays a button
with the name "sonal" in it, as shown in screen 3.3.
|
Screen 3.3 |
We initiate the above example by
creating an object 'b', whose type is Button, and which resides in the System.Windows.Forms
namespace.
The class contains code and
instance variables that are conversant with the role of a button.When the Text
property of the Button object 'b' is set to some text such as
"sonal", this text gets displayed on the Button.
Now, to place the button at a
specific position on our screen, the Point class is used, whose two members
represent a Point on the graphics screen. These two members x and y are
initialised to the values 10 and 100, respectively, through the Point constructor.
The Point class is in the System.Drawing namespace. Therefore, during
compilation, the reference of /r is set to the file System.Drawing.dll.
The Location property of the
Button object is then initialised to this freshly created Point object p. The
most pertinent action at this stage is to inform the Form class that a Control
is being added to the Form.
The Form class has a property
called Controls, whose type is Control.ControlCollection. This property keeps
track of all the controls that are placed on the form.
So, by using the Add function in
the Control.ControlCollection, we can add the button control to the Collection
object, thereby displaying the button on the form. This is how we add a Button
Control to our form.
a.vb
Imports System.Windows.Forms
Imports System.Drawing
Public Class zzz
Inherits Form
Dim b,b1 as Button
Dim t as TextBox
Shared Sub Main()
dim a as zzz
a = new zzz()
Application.Run(a)
End Sub
sub new
myBase.New
Me.Text = "Vijay Mukhi"
b = new Button
b.Text = "sonal"
dim p as Point
p = new Point(10,100)
b.Location = p
b1 = new Button
b1.Text = "VMCI"
p = new Point(40,180)
b1.Location = p
Dim s as Size
s = new Size(50,90)
b1.Size = s
t = new TextBox
t.Text = "Hi"
p = new Point(140,100)
t.Location = p
Dim c as Control.ControlCollection
c = Controls
c.Add(b)
c.Add(t)
c.Add(b1)
end sub
End Class
This example culminates in the
creation of a window with two buttons,
one larger than the other and a textbox containing the value "hi".
This is shown in screen 3.4
|
Screen 3.4 |
One more button is added to the
form in the same manner as before. Thereafter, the new instance of the button
b1 is provided with a Size object. The Size class comprises of the width and
height members, which are to be initialised using the constructor. The Size
property of the Button class determines the size of the control. In case the
dimensions are not mentioned, the default values are taken, as seen in the case
of the Button b.
The TextBox class is used to
place a TextBox control on the form. Here also, the Text property determines
the contents that are to be displayed with the TextBox. Everything else remains
just the same.
This example illustrates how
multiple controls can be placed on a single form. The only impediment here is
that, each time that the Control is to be added to the form, the services of
the Add function have to be exploited. So, if there are 100 controls to be
placed on the form, the Add function will be executed a 100 times! Let us
simplify this process by introducing the concept of Arrays.
a.vb
Public Class zzz
Shared Sub Main()
dim a(2) as integer
a(0) = 1
a(1) = 10
a(2) = 40
System.Console.WriteLine("{0} {1} {2}", a(0), a(1),
a(2))
end sub
End Class
Output
1 10 40
An array is a variable with a
single name, but is equipped to hold multiple values. The above DIM statement
of "a(2) as integer" creates three variables named a(0), a(1) and
a(2). Thus, in a single stroke, multiple variables have been created. These
variables conduct themselves in a manner similar to the normal variables. At
this stage, the only difference that you need to take heed of is, that this
type of variable has a pair of open-close brackets following it.
a.vb
Public Class zzz
Shared Sub Main()
dim a(2) as integer
dim i as integer
i = 0
a(i) = 1
i = 2
a(i) = 10
i = 1
a(i) = 100
System.Console.WriteLine("{0} {1} {2}", a(0) , a(i) ,
a(2))
end sub
End Class
Output
1 100 10
The above example showcases the
most valuable facet of an array.
First, we create an array of
size 3, followed by an integer variable i, which is initialised to a value of
0. Earlier, we had specified a number in round brackets, but here, we specify
the variable i instead. Thus, the line a(i) = 1 will evaluate to a(0) = 1,
since the variable i has a value of 0. On the next line, we change the value of
the variable i to 2. Therefore, the statement a(i) = 10 evaluates to a(2) = 10.
The variable a(1) is initialised in a similar manner.
Hence, in the above example, the
value of the variable i determines the name of the variable. To display the
value of the array variables, similar rules apply. The use of variables in lieu
of constant numbers assists in making the code more generic.
Loops
a.vb
Public Class zzz
Shared Sub Main()
dim i as integer
i = 1
Do while i <= 5
System.Console.Write("{0} " , i)
loop
end sub
End Class
If you run the above program, it
would continue to execute till eternity. So, hold on! Let us appreciate the
code first.
We first create an integer
variable i, and set its value to 1. Then, we come across a 'Do while' statement
containing the condition i <= 5. The 'Do while' statement, including the
condition and the loop, are part and parcel of the looping construct. A loop
construct is pressed into action when the same code needs to be repeated
multiple times.
The condition i <= 5 will
evaluate the value of i. Since it is 1, the condition evaluates to 1<=5,
which is True. Since the condition results in True, all code enclosed within
the 'Do while' and the loop, gets
executed. Presently, it contains only a Write function, which is very similar
to the WriteLine function, except for the 'return' at the end. This Write
function displays the value of the variable i.
On encountering the loop
statement, the control in code execution loops back to the 'Do while'
statement, where the condition is checked again. Since the value of i is still
1, the condition results in True, thereby executing the Write Function and the
loop.
The loop again takes the control
back to the 'Do While' statement, and the whole process iterates itself. This
action will keep repeating itself till eternity, since the condition after the
'Do While' never becomes False. Thus, we are trapped in an incessant loop.
Press Ctrl C to terminate the loop.
a.vb
Public Class zzz
Shared Sub Main()
dim i as integer
i = 1
Do while i <= 5
System.Console.Write("{0} " , i)
i = i + 1
loop
System.Console.Write("..{0} " , i)
end sub
End Class
Output
1 2 3 4 5 ..6
In this program, only one
additional line has been added to the earlier program. This line enhances the
value of the variable i by 1. This amendment results in printing the numbers
from 1 to 5.
This is because, when the value
of the variable i is 1, the condition becomes 1<= 5, which evaluates to
True, and the value of i is printed, using the Write function.
Then, the value is incremented
by 1, making it 2. The condition that is now checked is 2<=5. This too
results in True and the process is reiterated. However, when the value of i
reaches 6, the condition evaluates to 6<=5. The outcome of this is False and
the loop terminates. The control is now passed to the next statement after
loop. The value of i that is 6, is now printed with two dots preceding it. A loop construct is implemented when code
has to be executed repetitively.
a.vb
Public Class zzz
Shared Sub Main()
dim i as integer
i = 1
while i <= 5
System.Console.Write("{0} " , i)
i = i + 1
End while
System.Console.Write(".{0} " , i)
end sub
End Class
Output
1 2 3 4 5 .6
The output of the two programs
remains almost identical, except that the double dots are replaced by a single
dot. This is a sure indication of why programming languages exasperate us! In
place of the 'Do While' loop, we now have the 'While End While' loop. This
amendment in the syntax however does not translate into any change in the
output.
Thus, it is entirely your
decision to use either a 'While End While' or a 'Do While' loop. There are
myriad ways of achieving the same result. However, we would advise you to stick
to just one loop construct under all circumstances.
a.vb
Public Class zzz
Shared Sub Main()
dim i as integer
i = 100
for i = 1 to 5
System.Console.Write("{0} " , i)
next
System.Console.Write(".{0} " , i)
end sub
End Class
Output
1 2 3 4 5 .6
One more variation of the loop
construct is the For Next loop. Here, a variable has to be created, so that it
can be used as a counter. We have created an integer variable i and initialised
it to 100. The next line has the 'for' syntax, "for i = 1 to 5".
Despite the variable being
initialised to 100, the 'for statement resets its value to 1. Since the value
of i falls within the range of 1 to 5, all the code until the Next statement is
executed.
The 'Next' statement is like the
loop statement. It moves the control back to the top of the 'for' loop, but
only after incrementing the value of the counter by 1. The code from the 'for'
upto the 'next' is then executed once again. This process is repeated until the
value of the variable i reaches 6. As soon as i falls out of range, the line
that immediately succeeds the 'for- next' statement, is executed.
The variable i is not required
to be initialised, since the 'for' statement resets its value in any case.
You are bound to feel perplexed
while determining the loop construct to be implemented. You may adopt our
methodology wherein, on Mondays, Wednesdays and Fridays, we use the 'While'
construct, and on Tuesdays, Thursdays and Saturdays, we use the 'For'
construct. Sunday being a rest day, we desist from writing any code. ;-)
a.vb
Public Class zzz
Shared Sub Main()
dim i as integer
dim b(3) as integer
for i = 0 to 3
b(i) = i*10
next
for i = 0 to 3
System.Console.Write(".{0} " , b(i))
next
end sub
End Class
Output
.0 .10 .20 .30
The above example amply
demonstrates how arrays work seamlessly with Loop Constructs. We create an
array 'b' of 4 integers and 1 integer variable named i. In the 'for' statement,
i will have values ranging from 0 to 3.
In the first round, when the
value of the variable i is 0, the name of the variable becomes b(0) and its
value becomes 0*10 = 0. Then, when the value of the variable i becomes 1, the
name of the variable becomes b(1), and its value becomes 1*10 = 10. In this manner,
all the members of the array are initialised to values that are multiplication
factors of 10.
The second 'for' loop is used to
display the values of all the members of the array. This is achieved by using
the Write function. Thus, arrays and the loop mechanism go hand-in-glove. The
combination has been employed extensively in this book. Its use has also been
witnessed in many of the other programming languages.
a.vb
Public Class zzz
Shared Sub Main()
dim i as integer
dim b() as integer = {1,20,40 , 100}
for i = 0 to 3
System.Console.Write(".{0} " , b(i))
next
end sub
End Class
Output
.1 .20 .40 .100
Short forms may be considered as
a bane or a boon. In the above example, we have demonstrated how arrays can be
created and initialised simultaneously.
Using the = sign with DIM,
different array values can be assigned to the members of the array, by placing
the values in a pair of curly brackets {}. The 'for' loop confirms these values
in the array. We could have easily shirked from explaining this concept, but we
thought it prudent to deal with it, since this concept has been encountered on
numerous occasions in various Visual Basic.Net programs.
Failures are considered to be
stepping-stones to success. In the same vein, errors in programming languages
are believed to make a programmer a lot wiser. Therefore, we have sprinkled
this book generously with many of these error messages. Also, in a programming
language, every rule that is not abided by, generates a corresponding error
message.
For example, if we change the
array initialising line to the following:
dim b(3) as integer = {1,20,40 , 100}
the error that is generated is :
Error
c:\il\a.vb(4) : error BC30672: Explicit initialization is not
permitted for arrays declared with explicit bounds.
At the first glance, you may be
astounded by the error message, because so far, we have merely created an array
of 4 variables and initialized each of these array members. However,
programming languages in a sense may be compared to the human behavior,
especially when it comes to being extremely moody and whimsical.
In the Visual Basic.Net
language, it is very clearly stated that when an array is initialised at the
time of creation, the size must not be specified, even though it may be known
in advance. The compiler is of the opinion that we are encroaching on its
prerogative of determining the size of the array. On various occasions, you
will realize that a large number of rules stipulated by the compiler, have
become rigid and redundant. Welcome to the real world !
However, some errors do manage
to dodge detection. Thus, even if the program compiles normally, there is
always a possibility of encountering errors on running the program.
Rectify the above error and
change the 'for' loop to the following:
for i = 0 to 4
By increasing the range from 3
to 4, one more array member can now be accessed. However, the array extends
only from b(0) to b(3).
While the process of scanning
the code is on, the compiler is unable to detect such programming errors.
Therefore, it compiles successfully. However, it is during the execution when
the program tries to access b(4); in other words, when it goes beyond the
bounds of the array, the following exception is thrown:
Unhandled Exception: System.IndexOutOfRangeException: Index
was outside the bounds of the array.
Thus, an exception is an error
that the compiler fails to detect. It occurs only at run time. This is an ample
proof of the fact that, you can never be absolutely positive about whether your
program will run error-free or not, despite having compiled successfully.
a.vb
Public Class zzz
Shared Sub Main()
dim a as aaa
dim b as bbb
a = b
end sub
End Class
class aaa
end class
class bbb
end class
Error
c:\il\a.vb(5) : error BC30311: Value of type 'bbb' cannot be
converted to 'aaa'.
There are great many people in
this world, who are very selective about the people that they associate
themselves with. In all probability, they would have picked up this trait from
programming languages like Visual Basic.Net. ;-)
Both, an 'integer' as well as a
'string', are classes that the Visual Basic.Net complier understands
intrinsically. But, when we create two classes aaa and bbb, they are considered
external entities, since Visual Basic.Net is not clued-up about them.
Therefore, the classes have been created explicitly in the program. Now, when
we try to equate one with the other, we get an error.
The fundamental rule in all
modern programming languages is that, we cannot equate two variables or objects
with each other, unless they belong to the same class, or are of the same data
type. Therefore, an object of class aaa cannot be equated to an object of class
bbb, even though the contents of both may be the same.
a.vb
Public Class zzz
Shared Sub Main()
dim a as aaa
dim b as bbb
a = b
end sub
End Class
class aaa
end class
class bbb
inherits aaa
end class
However, there are always a few
exceptions to every rule. Two different objects can be equated to each other,
provided one derives from the other. Therefore, the only modification that we
have introduced in the above program is that, we have derived the class bbb
from the class aaa. The class bbb now comprises of both aaa and bbb.
The amended rule now reads as
follows: Two different classes can be equated, provided the class on the right
of the 'equal to' sign is a derived class, and the one on the left is the base
class. This is permissible since a derived class contains the base class. This
rule applies wherever a data type is expected, such as, the parameters to a
function, etc. The same rule applies to the members of an array also.
a.vb
Public Class zzz
Shared Sub Main()
dim b(2) as aaa
b(0) = new aaa
b(1) = new bbb
b(2) = new ccc
end sub
End Class
class aaa
end class
class bbb
inherits aaa
end class
class ccc
inherits bbb
end class
In this program, three classes
are created. The class aaa is an independent entity, which does not derive from
any class. The class bbb derives from the class aaa. Finally, the class ccc
derives from the class bbb.
Thus, the class ccc comprises of
classes aaa and bbb, whereas, the class bbb encompasses the class aaa.
Thereafter, an array 'b', of type aaa and size 3, is created.
The member b(0) is initialised
to an aaa object. The array member b(1) is set to a bbb type, and b(2) is
equated to a ccc object. None of the above generates an error, since we can
equate a base class to a derived class, bearing the following rule in mind
that, the object on the right should be larger than the one on the left.
a.vb
Imports System.Windows.Forms
Imports System.Drawing
Public Class zzz
Inherits Form
Dim b,b1 as Button
Dim t as TextBox
Shared Sub Main()
dim a as zzz
a = new zzz()
Application.Run(a)
End Sub
sub new
myBase.New
Me.Text = "Vijay Mukhi"
b = new Button
b.Text = "sonal"
dim p as Point
p = new Point(10,100)
b.Location = p
b1 = new Button
b1.Text = "VMCI"
p = new Point(40,180)
b1.Location = p
Dim s as Size
s = new Size(50,90)
b1.Size = s
t = new TextBox
t.Text = "Hi"
p = new Point(140,100)
t.Location = p
Dim c as Control.ControlCollection
c = Controls
Dim a() as Control = {b,b1,t}
c.AddRange(a)
end sub
End Class
We took a small detour into
certain aspects of the language to simplify the explanation of the above
example. In order to add controls to the form, the Add function from the
Controls collection, was called multiple times. It is easy to desist from this
repetition by using the AddRange function, which accepts an array of Control
objects as a parameter.
So, after creating the
individual controls and setting their properties, we then create an array 'a'
of type Control. The array is initialised to the three control objects at the
time of declaration itself. The values assigned are the two Button types b and
b1 and the TextBox t.
You should be well apprised of
the fact that the array type is Control, and the array members are of type
Button and TextBox. The compiler does not gripe at this approach, since the
Button and TextBox classes are derived from the class Control, thereby making
Control as the base class. Now, when we run the program, the controls get
displayed on the Form Window.
The next step is to activate
some code when the button is clicked upon.
To implement this, we again need to take a break away from the regular
routines, and fathom out the language a little further.
Event Handling
a.vb
Public Class zzz
WithEvents b as yyy
Shared Sub Main()
dim a as zzz
a = new zzz
End Sub
sub new
b = New yyy()
b.pqr
b.abc()
end sub
Sub vijay() Handles b.e
System.Console.WriteLine("Hi")
End Sub
End Class
public class yyy
Event e()
Sub abc()
RaiseEvent e
End Sub
Sub pqr()
System.Console.WriteLine("pqr")
End Sub
end class
Output
pqr
Hi
Let us examine the above program
in small parts.
The class yyy has an entity
called 'e', which is neither a variable nor an object, but an event. The 'event'
keyword is understood intrinsically by Visual Basic.Net.
The entity 'b' is of type yyy,
but since it has the WithEvents keyword associated with it, the class will be
used solely to handle events. We are fully aware that the concept of events has
not been clarified so far.
To initialise the event object
'b', the zzz object has to be created, since it is the constructor or the sub
'new' of zzz, that actually instantiates it. Then, using b, the two functions
pqr and abc are called off the yyy object. At this point in time, the
WithEvents keyword does not prohibit the yyy type from calling the sub pqr and
abc.
The WithEvents keyword aids in
working with events, but b will always remain a yyy object. Thus, this keyword
augments the existing features of the object.
In the function abc, there is a
statement RaiseEvent within which, the name of the event has been specified. As
always, the round brackets placed after the event name, are optional.
This statement performs a
considerable amount of work. It checks for functions in class zzz. These
functions contain the word 'Handles', followed by the object name 'b', and
finally, followed by the event 'e'. It only looks at functions in zzz, because
the function abc has been called from this class.
The function 'vijay' satisfies
both these criteria:
• It contains the Handles keyword and
the object name 'b'
• It also comprises of the name of the
event 'e', which is raised by RaiseEvent.
Just about anything can trigger
off an event, such as a mouse-click, or a key press on the keyboard, or the
shutting of a window.
Here, the event is set by
calling the function abc. The function
calls RaiseEvent, which calls all functions from the class zzz handling this
event object combination. There can be innumerable such functions, which the
event in class yyy is simply unaware of.
a.vb
Public Class zzz
WithEvents b as yyy
Shared Sub Main()
dim a as zzz
a = new zzz
End Sub
sub new
b = New yyy()
b.pqr
b.abc()
end sub
Sub vijay() Handles b.e
System.Console.WriteLine("Hi")
End Sub
Sub mukhi() Handles b.e
System.Console.WriteLine("Hi1")
End Sub
End Class
public class yyy
Event e()
Sub abc()
RaiseEvent e
End Sub
Sub pqr()
System.Console.WriteLine("pqr")
End Sub
end class
Output
pqr
Hi1
Hi
In the above example, the class
zzz has two functions, viz. vijay and mukhi, both of which can handle the event
'e' using the object 'b'. So, when the event 'e' is raised, both the functions
vijay and mukhi get called one after the other. This proves that when the
function abc is called, some code will get triggered off in the class zzz.
a.vb
Public Class zzz
WithEvents b as yyy
WithEvents c as yyy
DIM d as yyy
Shared Sub Main()
dim a as zzz
a = new zzz
End Sub
sub new
b = New yyy()
b.abc()
c = new yyy
System.Console.WriteLine("New Object")
c.abc
d = new yyy
System.Console.WriteLine("New Object1")
d.abc
end sub
Sub vijay() Handles b.e , c.e
System.Console.WriteLine("vijay")
End Sub
Sub mukhi() Handles b.e, c.f, b.f, c.e
System.Console.WriteLine("mukhi")
End Sub
Sub sonal() Handles c.f
System.Console.WriteLine("sonal")
End Sub
End Class
public class yyy
Event e()
Event f
Sub abc()
RaiseEvent e
System.Console.WriteLine("Event")
RaiseEvent f
End Sub
end class
Output
mukhi
vijay
Event
mukhi
New Object
mukhi
vijay
Event
sonal
mukhi
New Object1
Event
The above program is mammoth in
size. So, let us address it in small parts. We have three yyy objects named b,
c and d. Since the WithEvents clause has been used only for the b and c
objects, the d object cannot be used for event handling. As was done in the
earlier program, we create a new yyy object and call the abc function.
In the abc function, we first
raise the event 'e'. On doing so, the Visual Basic.Net system will check all
the functions that handle the event object b.e. Two functions named vijay and
mukhi, which handle this object event, get called. A point to be noted here is
that a sub can handle as many object event combos as is desired. Then, the
Event string is displayed.
Thereafter, another event f is
raised. The system now searches all the functions for the combination of b and
f. The only match found is the function mukhi.
Object c is then initialized to
new yyy and the Write function displays the string New Object.
Now, function abc is called,
using the object c. So, the raise event will check for subs having a combo
object c, and an event e. The subs that correspond to this criterion are Vijay
and Mukhi. And finally, the last RaiseEvent raises the event f, and calls mukhi
and sonal.
The object d also calls the
function abc, thereby raising both the events e and f. Nothing transpires
because there are no subs that can handle the object d, due to the absence of
the keyword 'WithEvents'. The class yyy is equipped to contain multiple events,
such as 'e' and 'f'. The function abc too can raise multiple events.
a.vb
Public Class zzz
WithEvents b as yyy
Shared Sub Main()
dim a as zzz
a = new zzz
End Sub
sub new
b = New yyy()
b.abc(100)
end sub
Sub vijay(i as integer ) Handles b.e
System.Console.WriteLine("vijay {0}" , i)
End Sub
End Class
public class yyy
Event e(i1 as integer)
Sub abc(j as integer)
RaiseEvent e(j)
End Sub
end class
Output
vijay 100
In the above example, the event
e is defined to accept an integer parameter. The brackets are to be provided
for the event entity only, when parameters are to be specified. The name of the
parameter is of no consequence at all.
As an outcome of this
modification, when the event 'e' is raised, an integer has to be specified as
the parameter. The event is passed the parameter j, which has been passed from
the constructor to the function abc.
The other amendment that has
been initiated is with regard to the sub vijay, which now requires an integer
parameter as part of its signature. The Handles and the WithEvents are
oblivious to the changes that occur when parameters are passed to events.
a.vb
Imports System.Windows.Forms
Imports System.Drawing
Imports System
Public Class zzz
Inherits Form
WithEvents b As Button
Shared Sub Main()
dim a as zzz
a = new zzz()
Application.Run(a)
End Sub
sub new
myBase.New
Me.Text = "Vijay Mukhi"
b = new Button
b.Text = "sonal"
dim p as Point
p = new Point(10,100)
b.Location = p
Dim c as Control.ControlCollection
c = Controls
Dim a() as Control = {b}
c.AddRange(a)
end sub
Sub vijay(s As Object,e As EventArgs) Handles b.Click
MessageBox.Show("Hi")
End Sub
End Class
Let us revert back to the
Windows Forms application. Now, when we click on the button, certain code gets
called. The button object b has the WithEvents keyword added to it, due to
which, it could now trap events in the Button object.
|
Screen 3.5 |
Yet another change has been
initiated wherein, the sub vijay accepts two parameters. Also, the keyword
'Handles' has been affixed with the name of the Button object 'b' and with the
Event within the Button object Click. Resultantly, when the button is clicked
upon, code contained within the button class gets called.
The framework checks for an
event called Click within the class, and it calls the command RaiseEvent with
two parameters. This RaiseEvent searches in the class zzz for a sub that has a
Handles, alongwith an object event match b.Click. Since the match is found in
the sub vijay, the code in vijay gets executed.
This is how we can ensure that
our own code gets called, whenever the Click event occurs. The MessageBox is
shown in screen 3.5.
Sub vijay1(s As Object,e As EventArgs) Handles b.Click
MessageBox.Show("Hi1")
End Sub
End Class
For the sake of revision, we add
the above three lines of code, just prior to the End Class statement. The code
merely creates a sub vijay1, and employs the 'Handles' keyword to associate the
event Click and object b with the sub. Thus, each time we click on the button,
both subs vijay and vijay1 will be executed. We can associate as many events as
we like with a sub, as has been demonstrated above.
a.vb
Public Class zzz
WithEvents b as yyy
Shared Sub Main()
end sub
Sub vijay() Handles b.e
End Sub
End Class
public class yyy
Event e()
end class
class aaa
inherits yyy
Sub abc()
RaiseEvent e()
End Sub
end class
Error
c:\il\a.vb(14) : error BC30029: Derived classes cannot raise
base class events.
Earlier, the class yyy had a sub
that raised an event using the statement RaiseEvent, with event e in the same
class. In the above example, the RaiseEvent statement raises an event e defined
in the base class. This is forbidden, as has been indicated by the error
message. Thus, we can only raise events in the very class in which they have
been created.
a.vb
Public Class zzz
Shared Sub Main()
End Sub
Sub vijay() Handles b!e
System.Console.WriteLine("Hi")
End Sub
End Class
Error
c:\il\a.vb(5) : error BC30287: '.' expected.
The ! symbol placed between the
name of the WithEvents object and the name of the event, is invalid. The only
permissible separator is the dot sign.