Вы находитесь на странице: 1из 64

Windows Programming With Visual Basic .

NET 2005
Short Notes
Chapter 3: Object Oriented Programming with VB.NET
1. Class Basics
A class is one form of data type. In object-oriented design, classes are intended to represent the definition of
real-world objects, such as customer, order, product, etc. The class is only the definition, not an object itself. An
object would be a customer, an order, or a product. A class declaration defines the set of members— fields,
properties, methods, and events— that each object of that class possesses. Together, these members define an
object's state, as well as its functionality. An object is also referred to as an instance of a class. Creating an
object of a certain class is called instantiating an object of the class.

Consider the class definition in the following Example

Eg.1.
Public Class Employee
Public EmployeeID As Integer
Public FIrstName As String
Public LastName As String
Public DateOfBirth As Date
Public Salary As Decimal
Public Function Format( ) As String
Return FirstName & " " & LastName
End Function
End Class

The code in the Example defines a class called Employee. It has five public fields (also known as
data members) for storing state, as well as one member function. The class could be used as shown
in Eg. 2.

Eg. 2. Using a class

Class TestEmployee
Dim emp As New Employee( )
emp.EmployeeID = 10
emp.FirstName = "Lamma"
emp.LastName = "Bekele"
emp.DateOfBirth = #1/28/1965#
emp.Salary = 5000

Public Shared Sub Main ()

Console.WriteLine("Employee Name: " & emp.Format( ))


Console.WriteLine("Employee Number: " & emp.EmployeeID)
Console.WriteLine("Date of Birth: " & emp.DateOfBirth.ToString()
Console.WriteLine("Salary: " & emp.Salary.ToString()

P age |1
The resulting output is:

Employee Name: Lemma Bekele


Employee Number: 10
Date of Birth: Thursday, January 28, 1965
Salary: $5,000.00

To taste the avove example in using visual studio. Start a new console application and type the entire code (both classes in
Eg.1. and Eg. 2 ) by deleting the default module block. After you finish writing the code change the project start up object
to TestEmployee. Finally, run the application.

Object Instantiation and New


Object instantiation is done using the New keyword. The result of the operation is a reference to a newly created object of
the given type. There are several variations of using new. Consider the following:

Dim emp as new Employee() ‘dynam ic initialization


Dim emp1 as Employee
….
Em p = N ew Em ployee()‘form alinstantiation

The Dim statement declares a variable that is capable of holding a reference to an object of type Employee, but it
doesn't actually create the object. You must use the New operator in either of the two ways shown above.

2. Fields
Fields, also known as data members, hold the internal state of an object. Their declarations appear only within class
declarations. Field declarations include an access modifier, which determines how visible the field is from code outside
the containing class definition. The value stored in a field is specific to a particular object instance. Two instances can
have different values in their corresponding fields. For example:
Dim emp1 As New Employee( )
Dim emp2 As New Employee( )
emp1.EmployeeID = 10
emp2.EmployeeID= 20 'this doesn't affect emp1.
Sometimes it is desirable to share a single value among all instances of a particular class. Declaring a
field using the Shared keyword does this, as shown here:
Public Class Sample
Public Shared Val As Integer
End Class
Changing the field value through one instance affects what all other instances see. For example:


Dim Smp1 As New Sample( )
Dim Smp2 As New Sample( )
Samp1.Val = 10
Samp2.Val = 20
Console.WriteLine(Samp1.VaL) ' Writes 20, not 10.

P age |2
One important characteristic of Shared is that they are also accessible through the class name. This is because their
scope is indirectly the entire class instead of an instance. For example the following statement is correct.
Console.WriteLine(Sample.Val)

3. Methods
Methods are members that contain code. They are either subroutines (which don't have a return value) or functions
(which do have a return value).
Subroutine definitions look like this:
[method_modifiers ] Sub [ attribute_list ] _
method_name ( [ parameter_list ] ) [ handles_or_implements ]
[ method_body ]
End Sub
Function definitions look like this:
[method_modifiers] Function [ attribute_list ] _
method_name ( [ parameter_list ] ) [ As type_name ] _
[ handles_or_implements ]
[ method_body ]
End Function
The elements of method definitions are:
Access modifiers : Public, Protected, Friend, Protected Friend, or Private. If no access-modifier keyword is given, Public
is assumed.
Shared keyword specifies that this method does not access object state. That means that the method does not access
any nonshared members.
Sub or Function keyword
Specifies whether this method is a subroutine or a function.
method_name The name of the method.
parameter_list an optional list of formal parameters for the method.
As type_name for functions only, the data type of the value returned from this function. If Option Strict is off, the As
type_name clause is optional; otherwise, it is required. If it is omitted, the function's return type defaults to Object.
Subroutine declarations do not have an As type_name clause. handles_or_implements Either the Handles keyword
followed by a list of events from the enclosing class's data members, or the Implements keyword followed by a list of
methods from an interface implemented by the enclosing class
method_body :Visual Basic .NET statements.
End Sub or End Function keywords Indicates the end of the method definition.
Method parameters
Methods can be defined to take arguments. As already shown, method definitions can take an optional
parameter list. A parameter list looks like this:
parameter { , parameter }
That is, a parameter list is one or more parameters separated by commas. Each parameter in the list is of the form:
[ Optional ] [ ParamArray ] [ ByRef | ByVal ] [ attribute_list ] _
parameter_name [ As type_name ] [ = constant_expression ]
The elements of each parameter declaration are:
Optional keyword
Specifies that an actual argument may be omitted for this parameter in a call to this method. If Optional is specified, the
= constant_expression, which defines the default value of an omitted argument, must also be specified. Nonoptional

P age |3
parameters can't follow optional parameters in a parameter list. Optional and ParamArray parameters can't appear in
the same parameter list ParamArray keyword Specifies that the caller can provide a variable number of arguments. The
actual arguments are passed to the method in an array. Only the last parameter in a list may have the ParamArray
keyword attached to it. Optional and ParamArray parameters can't appear in the same parameter list.
ByRef or ByVal keyword Specifies whether the actual argument will be passed to the method by reference or by value.
When an argument is passed by reference, the address of the argument is passed to the routine; as a result,
assignments to the parameter within the method affect the argument in the calling environment. When an argument is
passed by value, a copy of the argument is passed to the routine; as a result, assignments to the parameter within the
method do not affect the argument in the calling environment. Consider this code:
Public Sub TestByRef(ByRef MyParameter As Integer)
MyParameter += 1
End Sub
Public Sub TestByVal(ByVal MyParameter As Integer)
MyParameter += 1
End Sub
Public Shared Sub DoTest( )
Dim x As Integer = 1
TestByRef(x)
Console.WriteLine("x = " & x)
Dim y As Integer = 1
TestByVal(y)
Console.WriteLine("y = " & y)
End Sub
The output of the DoTest method is:
x=2
y=1
The TestByRef and TestByVal methods both increment the values of the arguments passed to them by one. However,
because the parameter of the TestByRef method is ByRef, the new value is written back to the argument in the caller (in
this case, the variable x in the DoTest method). In contrast, the TestByVal method's parameter is ByVal, so the
assignment to the parameter doesn't affect the caller. Be aware of the effects of ByRef and ByVal on arguments that are
reference types. ByRef means that a reference to the reference is being passed; ByVal means that the reference itself is
being passed. That means that inside the method, the reference could be used to modify the state of the object in the
calling environment.

Passing arrays as parameters


To declare a parameter as able to receive an array, include parentheses after the parameter name in the declaration.
The caller leaves off the parentheses when naming the actual argument. For example:

Public Shared Sub SomeMethod(ByVal x( ) As String)


Dim str As String
For Each str In x
Console.WriteLine(str)
Next
End Sub
Public Shared Sub TestSomeMethod( )
Dim a(5) As String

P age |4
a(0) = "First"
a(1) = "Second"
a(2) = "Third"
a(3) = "Fourth"
a(4) = "Fifth"
SomeMethod(a)
End Sub
In the SomeMethod method, parameter x represents an array of String objects. In the TestSomeMethod method, a
String array is allocated, its elements are assigned, and the array as a whole is passed to the SomeMethod method,
which then prints the array's contents. All array types are reference types. That means that when passing an array as a
parameter, only a reference to the array is passed. Because the target method receives a reference to the array, the
array elements can be changed by the method, even if the array reference was passed by value. If the array reference is
passed by reference, the array reference itself can be changed by the method. For example, the method could allocate a
new array and return it through the ByRef parameter, like this:

Main method
When an executable application is compiled, some code must be identified as the startup routine. This portion is what is
executed when the application is run. The Visual Basic .NET compiler looks for a method named Main to fulfill this need.
In .NET, all code exists as methods within classes, even the Main method. To make it accessible without having to
instantiate a class, the Main method must be declared as shared. For example:
Public Class App
Public Shared Sub Main( )
' ...
End Sub
End Class
The name of the class is not important. At compile time, the Visual Basic .NET compiler looks for a public shared
subroutine named Main somewhere in the code. If more than one class has such a method, the developer must specify
which one to use by setting the startup object in the Project Properties dialog box. A program's Main method can also
appear within a Visual Basic .NET module (not to be confused
with .NET modules. Because Visual Basic .NET modules are classes wherein everything is shared, the Shared keyword is
not used in such a declaration:
Module App
Public Sub Main( )
' ...
End Sub
End Module

4. Properties
In Visual Basic .NET a property is similar to a field but a property is more encapsulated than a field. First, a property data
is stored as private. Second, two property procedures will be written for accessing the property. These procedures are
Get and Set procedures. This is important if you want to protect data from unwanted modifications and access from
outside the class. The property procedures are written within the Property… End Property block, which defines the
property’s nam e,its type,and its argum ent signature.
Inside the Property block,you w rite a G et… End G et block,w hich defines w hat value the property returns,and a Set… End
Set block, which defines how values are assigned to the property. In most cases, a property simply maps to a Private
Field, so the code for these two blocks often looks like this:

P age |5
Eg. 4.
Class PropSample
‘You can define variables anyw here in a class or m odule.
Dim m_BirthDate As Date
Property BirthDate() As Date
Get
Return m_BirthDate
End Get
Set(ByVal Value As Date) ‘this procedure can validate the value
If value <= Date.Now Then
m_BirthDate = Value
Else
M_BirthDate= Date.Now
End If
End Set
End Property

End Class

Alternatively, the Get block can return the value by assigning the variables value to the Property method.
Property BirthDate() As Date
Get
‘Another w ay to return a value
BirthDate = m_BirthDate
End Get
End Property
The Set… End Set block alw ays receives a Value argum ent that stands for the value being assigned to the property itself.
This argument must be of the same type as the type defined in the Property statement and must be declared using
ByVal. If you happen to have a field named Value, you can distinguish between the field and the Value
A User of the above class can work with it as if the there is a public or shared member is used.
Class TestPropSample
Dim Ps as New PropSample
Public Function SetBirthdate( dt as Date)
Ps.BirthDate = dt
Console.WriteLine(Ps.BirthDate)
End function
End Class

To access a data member or field from within the class, you can prefix it with the Me keyword
‘A class that has a Value field
Class ValueClass
Private Value As Double
‘A property that uses the Value field
Property DoubleValue() As Double
Get

P age |6
Return Me.Value * 2
End Get
Set(ByVal newValue As Double)
Me.Value = newValue / 2
End Set
End Property
End Class
Note that Me.Value is a legal syntax, even if the Value field is private.

Read only and Write only Properties


You can make a property read only by declaring it using the ReadOnly keyword to explicitly state that you mean to
create a Read-only property. Additionally, you avoid the Set block in the property procedure.
‘The Age property is read-only.
ReadOnly Property Age() As Integer
Get
Return Year(Now) - Year(m _BirthD ate)‘Sim plistic age calculation
End Get
End Property

Similarly, you can create a write-only property by om itting the G et… End G et block and using the WriteOnly keyword in
the Property block:
‘LoginD ate is a w rite-only property.
WriteOnly Property LoginDate() As Date
Set(ByVal Value As Date)
m_LoginDate = Value
End Set
End Property
WriteOnly properties are can not be read where as ReadOnly properties can not be written to by and user class

5. Constructors
When a class is instantiated, some initialization often might be performed before the type can be used as it contains
several fields and methods that may require initial values. To provide such initialization, a class may define a
constructor. A constructor is a special kind of method. It is automatically run whenever an object of the class is
instantiated. Constructor declarations use the same syntax as regular method declarations, except that in place of a
method name, the constructor declaration uses the keyword New with in the class. For example:

Public Class SomeClass


Public Sub New( )
' Do any necessary initialization of the object here.
Console.writeline(“ Iam just initialized!!!”)
End Sub
End Class

To invoke the constructor, a new object must be instantiated:


Dim obj As New SomeClass( )

The message – I am just Initalized !!! – will be displayed when this line executes.

P age |7
Note the parentheses (( )) following the name of the class. Until you get used to it, this method-style syntax following a
class name may appear odd. However, the empty parentheses indicate that the class's constructor takes no arguments.

Constructors can take arguments, if they are necessary for the initialization of the object such constructors are called
parameterized constructors:

Public Class SomeClass


Dim m_value As Integer ‘private data m em ber (field)ofthe class
Public Sub New(ByVal InitialValue As Integer)
m_value = InitialValue
End Sub
End Class

When objects of this class are instantiated, a value must be provided for the constructor's argument:
Eg. Dim obj As New SomeClass(27)
This behavior leads us to the possibility that more than one constructor may be used in a class which is called
overloading. Constructors can be overloaded, if desired. For example:

Public Class SomeClass


Dim m_value As Integer
Public Sub New( ) ‘called the default constructor
m_value = Date.Today.Day ' for example
End Sub
Public Sub New(ByVal InitialValue As Integer)
m_value = InitialValue
End Sub
End Class
The constructor that is called depends on the arguments that are provided when the class is
instantiated, as shown here:
Dim obj1 As New SomeClass( ) ' calls parameterless constructor
Dim obj2 As New SomeClass(100) ' calls parameterized constructor
Constructors are usually marked Public.
If a class has shared fields that must be initialized before access, and that initialization can't be performed by initializers
in the fields' declarations, a shared constructor may be written to initialize the fields, as shown here:
Public Class SomeClass
Public Shared SomeStaticField As Integer
Public Shared Sub New( )
SomeStaticField = Date.Today.Day
End Sub
End Class

The shared constructor is guaranteed to run sometime before any members of the type are referenced.
If any shared fields have initializers in their declarations, the initializers are assigned to the fields
before the shared constructor is run. Shared constructors may not be overloaded, nor may they have access modifiers
(Public, Private, etc.). Neither feature is meaningful in the context of shared constructors.

P age |8
6. An Example
The following class diagram shows a sample relationship between the classes of a very simple grading application. The
Grade class generally is the user of the Student and the Course Classes. Hence, every instance of the Grade class must
also instantiate objects of the other two classes.

Student Grade Course


StudentID Stud: Student CourseID
FirstName Cour: Course CourseName
LastName Sem CreditHours
BirthDate SYear …
GetAge() Grade GetPoints()
GetFullName () GetPoints() …
… SetStudentRec ()
..

The Classes are implemented as follows. Start a console application and write the following code to test the application.
The application is concerned with storing a grade. But it requires objects that store the course and the Student
Information.

Eg. 5.
Namespace Grading ‘ this namespase is optional

Public Class Student


Dim m_StudentID As String
Dim m_firstName As String
Dim m_LastName As String
Dim m_BirthDate As Date

Property StudentID() As String


Get
Return m_StudentID
End Get
Set(ByVal value As String)
If Convert.ToInt32(value) <> 0 Then
m_StudentID = value
Else
Console.WriteLine("Wrong ID!!")
End If
End Set
End Property

Property BirthDate() As Date


Get
Return m_BirthDate
End Get
Set(ByVal value As Date)
If value <= Date.Today Then
m_BirthDate = value
Else
Console.WriteLine("Wrong Date Value!!")
End If
End Set
End Property

P age |9
Public Function GetAge() As Integer
Return Date.Today.Year - m_BirthDate.Year
End Function

' Continue with other methods here


End Class

Class Course
Dim m_CourseID As String
Dim m_CourseName As String
Dim m_CreditHours As Byte

Property CourseId() As String


Get
Return m_CourseID
End Get
Set(ByVal value As String)
m_CourseID = value
End Set
End Property

Property CreditHOurs() As Byte


Get
Return m_CreditHours
End Get
Set(ByVal value As Byte)
If value > 0 And value < 5 Then
m_CreditHours = value
Else
Console.WriteLine("Credit hrs must be between 1 and 4!!")
End If
End Set
End Property
End Class

Class Grade
Dim Stud As New Student
Dim Cour As New Course
Dim m_sem As String
Dim m_sYear As String
Dim m_Grade As String
Dim ValidGrades As String = "A A+ A- B B+ B- C C+ C- D D+ D- F"

Property Grade() As String


Get
Return m_Grade
End Get
Set(ByVal value As String)
If ValidGrades.Contains(value) Then
m_Grade = value
Else
Console.WriteLine("Wrong Grade value!!")
End If
End Set
End Property

'** ADD SIMILAR PROPERTY PROCEDURS FOR THE OTHERS

Public Sub SetStudentRec(ByVal sID As String, ByVal CID As String, ByVal Gr As


String)

P a g e | 10
Stud.StudentID = sID
' Stud.BirthDate = ....
Cour.CourseId = CID
'Cour.CreditHOurs ....
Me.Grade = Gr
End Sub

Public Function GetPoints() As Integer


Dim pts As Integer
Select Case m_Grade
Case Is >= "A" ' A A+ A-
pts = 4
Case Is >= "B"
pts = 3
Case Is >= "C"
pts = 2
Case Is >= "D"
pts = 1
Case Else
pts = 0
End Select

Return pts ' or GetPoints = pts

End Function

Public Sub DisplyInfo()


Console.WriteLine("Student ID = " & Stud.StudentID)
Console.WriteLine("Course ID = " & Cour.CourseId)
Console.WriteLine("Grade = " & m_Grade)
End Sub

End Class
____________________________________________________________________________
Public Class GradeUser ' This implements the grade class and the others
Public Shared Sub Main()
Dim StudGrade As New Grade()
StudGrade.SetStudentRec("001", "CS-235", "A+")
Console.WriteLine("Points for " & StudGrade.Grade & ": " &
StudGrade.GetPoints())
Console.WriteLine()
Console.WriteLine("Here is the student information")
Console.WriteLine()
StudGrade.DisplyInfo()
Console.ReadLine()
End Sub
End Class
End Namespace

P a g e | 11
Windows Programming with Visual Basic .NET
Worksheet I
1. Create a console application in Visual Basic .NET that accepts a list of Numbers of any size and then displays the
following report on the numbers.
a. The largest value
b. The smallest Value
c. The Sum
d. The average
e. The number of negative values
f. The Number of positive values
2. Write a console application that implements a simple payroll processing. The program displays a menu for
performing the following tasks
a. Accept a new employee information (ID, Name, Salary values)
b. Display existing information ( a Tabular output)
c. Display information about a given employee
d. Display a paryroll by calculating and including the Tax, and Net Pay ( in a tabula format) .
[ use the Ethiopian Tax rule to calculate the Tax)

Output sample
ID Name Salary Tax NetPay
001 Abebe M. 500 50 450
034 Hirut S. 600 60 540

3. Implement a simple library application that contains about four interacting objects roughly shown below.

Book Loan
BookNo LBook: Book Member
Title LMember: Member MemberID
Author IssuDate FullName
Publisher DueDate Phone
… GetOverDue () …
SetNewLoanRec () GetAddress ()
.. …

Publisher
PublisherID
PubName
City
Country

P a g e | 12
7. Inheritance
Inheritance is implemented in visual basic using the Inherits keyword. The following diagram shows a
typical class inheritance hierarchy.

Person

Employee BusinessPerson

The Class Person is called the Base Class and the other two are called Derived Classes. The derived
classes inherit all inheritable elements of the Base Class and add their own new members. A derived
class also can extend methods defined in the base class by overloading or overriding.

Note that in terms of class inheritance VB.NET supports only Single Inheritance and its extensions. A
derived class can not inherit from more than one class.

Syntax for inheritance


Class <DerivedClassName>
Inherits <BaseClassName>
‘Base class m em bers (Fields,Properties and m ethods… )

End Class
The following example shows the inheritance relationship between the Person and Employee Classes

Class Person

' Fields visible from outside the class


' You can avoid using such fields and use properties instead
Public FirstName As String
Public LastName As String

' address for this person,


Public Address As String

' an overridable method


Function CompleteName(Optional ByVal title As String = "") As String
' Use the title, if provided.
If title <> "" Then CompleteName = title & " "
' Append first and last name.
CompleteName &= FirstName & " " & LastName
End Function

' the BirthDate property


Dim m_BirthDate As Date

P a g e | 13
Property BirthDate() As Date
Get
Return m_BirthDate
End Get
Set(ByVal Value As Date)
m_BirthDate = Value
End Set
End Property

' the Spouse property

Private m_Spouse As Person

Property Spouse() As Person


Get
Return m_Spouse
End Get
Set(ByVal Value As Person)
m_Spouse = Value
End Set
End Property

' The Age property is read-only.

ReadOnly Property Age() As Integer


Get
Return Year(Now) - Year(m_BirthDate)
End Get
End Property

End Class

Class Employee
Inherits Person

' a new public field


Public OverTimeHours As Single

' a private member for the property


Private m_Salary As Single

' A new property


Property Salary() As Single
Get
Return m_Salary
End Get
Set(ByVal Value As Single)
m_Salary = Value
End Set
End Property

Public Function GetOverTimePay(ByVal OT_Rate As Single) As Single

Return OverTimeHours * OT_Rate

End Function

P a g e | 14
End Class

Class EmpTest

Shared Sub Main()


Dim emp As New Employee
Dim otRate As Single ' OT rate is required as a parameter

Console.WriteLine("Enter Employee Information:")


Console.Write("First Name: ")
emp.FirstName = Console.ReadLine()
Console.Write("Last Name: ")
emp.LastName = Console.ReadLine()
Console.Write("Birth Date: ")
emp.BirthDate = Convert.ToDateTime(Console.ReadLine)
Console.Write("Salary: ")
emp.Salary = Convert.ToSingle(Console.ReadLine())
Console.Write("Overtime Hours: ")
emp.OverTimeHours = Convert.ToSingle(Console.ReadLine())
Console.Write("Overtime Rate: ")
otRate = Convert.ToSingle(Console.ReadLine())

Dim Sp As New Person


Console.WriteLine("Enter Spouse Information for Employee:")
Console.Write("First Name: ")
Sp.FirstName = Console.ReadLine()
Console.Write("Last Name: ")
Sp.LastName = Console.ReadLine()
Console.Write("Address: ")
Sp.Address = Console.ReadLine()
Console.Write("Birth Date: ")
Sp.BirthDate = Convert.ToDateTime(Console.ReadLine)

Console.WriteLine("**************************")
Console.WriteLine() 'Empty line

' link Spause with Employee object


emp.Spouse = Sp
'Display Employee information
Console.WriteLine("Employee information")
Console.WriteLine(emp.CompleteName())
Console.WriteLine(emp.Salary)
Console.WriteLine("Age: " & emp.Age)
Console.WriteLine("Overtime Pay: " & emp.GetOverTimePay(otRate))
Console.WriteLine("Total Pay: " & emp.GetOverTimePay(otRate) +
emp.Salary)

Console.WriteLine() 'Empty line

Console.WriteLine("Spouse information")

Console.WriteLine(emp.Spouse.CompleteName)
Console.WriteLine("Address: " & emp.Spouse.Address)
Console.WriteLine("Birth Date: " & String.Format("{0:d}",
emp.Spouse.BirthDate)) ' Short date format
Console.ReadLine()

End Sub
End Class

P a g e | 15
Overriding Base Cass Methods
Methods can be defined with the same name in both the base class and the derived class. In this case,
the base class must allow the derived class to override its definition by declaring the method using the
Overridable keyword. Otherwise, the two functions will be considered as different for the two classes.
In general there are four basic types of method declarations concerning how the method will be treated
by derived classes. They are summarized as follows:

Usage Keyword Description Example


In Base Overidable The method can be redefined in derived Public Overidable Function F1()
Classes classes …
End Function
NotOverridable Prohibits a method from being redefined in Public NotOveridable Sub F1()
derived classes ….
End sub

MustOverride Enforces that the function must be redefined. Protected Must Override Sub Add()
In this case the method will not have a body
in the base class
In derived Overrides Indicates that this the method overrides Public Overrides Function F1()
Classes another one in its base class … ..
End Function

Constructors in Derived Classes


Constructors can be defined in both a base class and a derived class. If the derived class having a constructor is
instantiated, then it can pass parameters to its base class constructor by using the MyBase Keyword. This
statement must be the first statement in the derived class constructor. Eg. 7. Shows the Overridable methods and
the MyBase keyword.

Eg. 7. Overriding Example


Class Person

' Fields visible from outside the class


Public FirstName As String
Public LastName As String

Public Sub New(ByVal FName As String, ByVal LName As String)


FirstName = FName
LastName = LName
End Sub

Overridable Function CompleteName(Optional ByVal title As String = "") As


String
' Use the title, if provided.
If title <> "" Then CompleteName = title & " "
' Append first and last name.
CompleteName &= FirstName & " " & LastName
End Function

End Class

P a g e | 16
' This second version of the Person class demonstrates overloaded
constructors,

Class Employee
Inherits Person

Public Title As String ' A new field

' two overloaded constructors

Sub New(ByVal firstName As String, ByVal lastName As String)


' The first executable statement *must* be a call
' to the constructor in the base class.
MyBase.New(firstName, lastName)
' You can continue with the initialization step here.
' ...
End Sub

Sub New(ByVal firstName As String, ByVal lastName As String, ByVal title


As String)
' The first executable statement *must* be a call
' to the constructor in the base class.
MyBase.New(firstName, lastName)
' set the new field
Me.Title = title
End Sub

Overrides Function CompleteName(Optional ByVal Title As String = "") As


String
If Title <> "" Then CompleteName = Title & " "
CompleteName &= MyBase.CompleteName()
End Function
End Class

Public Class Tester


Shared Sub Main()
Dim Emp As New Employee("Abebe", "Lemma", "Ato")

' output the values


Console.WriteLine()
Console.WriteLine(Emp.CompleteName())
Console.ReadLine()
End Sub

End Class

Inheritable Member Access Modifiers


Public: Inheritable, but also accesible from outside
Protected: Inheriteable but not accesible from outside the classes (ie, the base and the derived
classses). The derived classes must be in the same project.
Protected Friend: similar to protected but here the derived claseses can be any where.

Below is an example class containing all inheritable types

P a g e | 17
Class Base
Protected ID As Integer
Protected Friend PhoneNumber As String
Private Password As String
Public FullName As String

...

End Class

8. Garbage Collection (Object Destruction)


In visual basic there are no direct destructors as in the case of C++. In general object destruction is done
automatically perfomed by a tool in the .NET framework called the Garbage Collector. Technically, a garbage is an
object which is no more wanted by a running application. For example, an object whose all references have
become out of scope. The Garbage Collector reclaims all the system resources occupied by such objects when ever
it is activated. It will be upto the .NET framework to decide when the G.C. is activated.
However, there is a method called Finalize() which is called by the G.C. just before an object is destroyed from
memory. You can add any cleanup code in this method so that your objects will not leave some resources still open
but unusable. This method is originally defined in the Object class as Overridable and with Protected scope. Hence,
your class must use the keyword Overrides Protected to define the finalize method as follows.
Class MySampleClass
Inherits Object
Protected ID As Integer
Private Password As String
'......
Protected Overrides Sub Finalize()
Console.WriteLine("Object is being distroyed")
End Sub
End Class
Exersise: Test the folowing code as a new console application. It demonstrates how objects are created and
destroyed.
Class MySampleClass
'......
Public Sub New()
Console.WriteLine("An instance is created!!!")
End Sub

Protected Overrides Sub Finalize()


Console.WriteLine("Object is being distroyed!!!")
End Sub
End Class

Public Class Tester


Shared Sub main()
Dim i As Integer = 1
Do While i > 0 ' an infinite loop to create the objects
Dim mySampleObj As New MySampleClass()
Loop
End Sub
'Note that there is no code necessry to destroy the object
End Class

P a g e | 18
9. Interfaces
Interfaces are special programming language constructs used to implement several things such us polymorphism
and multiple inheritance(at least partially). An interface is a code block that contains constant declarattions and
method prototypes. Interfaces can not be instantiated. An interface must be implemented by a class inorder to be
used. Instances can be created from the class that implemts an interface. A class must implement the methods of
the interface it implements.
There are two types of interfaces. .NET interfaces and Custom interfaces. .NET interfaces are predefined with in
the .NET framewrok. Where as Custom interfaces are user defined.

Using .NET interfaces


Two most commonly used example interfaces defined in the .NET framework are listed below:
IComparable: this interface contains a method called CompareTo() which is used to compare two objects of the
same type and return whether they are equal, or greater than each other using the values 0 , +1, or
-1. A class implementing it will define an appropriate code for the CompareTo method.
This method has the following prototype:
Function CompareTo (Obj as Object) as Integer ‘Obj is a reference to an other instance

IClonable: this interface also contains one method called Clone() which is used to create a duplicate copy of an
object (instance) so that it can be assined to an other reference.
Function Clone () as Object
Note that different classes can implement an interface using their own way which is an indication of polimorphic
behavior implemetntation.

Implementing IComparable interface


Public Class Employee
Implements IComparable

Public EmployeeID As Integer


Public FirstName As String
'...

Public Function CompareTo(ByVal obj As Object) As Integer Implements


IComparable.CompareTo
Dim emp As Employee
emp = CType(obj, Employee)
If Me.EmployeeID = emp.EmployeeID Then
Return 0
ElseIf Me.EmployeeID > emp.EmployeeID Then
Return 1
Else
Return -1
End If
End Function
End Class

Public Class Tester


Shared Sub main()
Dim emp1, emp2 As New Employee
emp1.EmployeeID = 122
emp2.EmployeeID = 737
Console.WriteLine("Comparison Result: " & emp2.CompareTo(emp1))
End Sub

End Class

P a g e | 19
Implementing multiple interfaces
A class can implement multiple interfaces but can inherit from only one class. As an example the above class
Employee can be modified as follows. The complete version is left as an exercice.

Public Class Person


Public FirstName As String
‘…
End Class

Public Class Employee


Inherits Person
Implements IComparable, ICloneable
‘…

End Class

Defining Custom Interfaces


You can define your ow n interfaces using the Interface… End Interface block. The follow ing block defines an
Example interface called IAsset. Note that only Methods, Properties or Events can be used in interfaces.
Constants and variables are not allowed.

Interface IAsset
Property Division() As String
Function GetID() As Integer
End Interface

Class Computer
Implements IAsset

Private divisionValue As String


Private IDValue As Integer

Public Property Division() As String _


Implements IAsset.Division

Get
Return divisionValue
End Get
Set(ByVal value As String)
divisionValue = value
End Set
End Property

Public Function GetID() As Integer Implements IAsset.GetID

Return IDValue
End Function

Public Sub New(ByVal Division As String, ByVal ID As Integer)


Me.divisionValue = Division
Me.IDValue = ID
End Sub
End Class

P a g e | 20
Interface IPerson 'IPerson interface definition
Property LastName( ) As String
Sub Display( )
End Interface
Class Employee 'Employee class definition
Implements IPerson 'Implements IPerson interface
Private strName As String
Private strCompany As String
'This method is public but also implements IPerson.Display
Public Sub Display( ) Implements IPerson.Display
MsgBox(LastName & " " & Company,, "Employee")
End Sub
'This property is private but implements IPerson.LastName
Private Property LastName( ) As String _
Implements IPerson.LastName
Get
Return strName
End Get
Set (ByVal Value As String)
...
End Property
Public Property Company( ) As String
...
End Property
End Class

P a g e | 21
Chapter 4: Working with Windows Forms (Visual Design)
1. Windows Programming Basics
One of the most important features of microsoft .NET is its inherent ablity to design applications for the
windows opertating system. Such applications will provide visual ( Graphical ) user interfaces to their
users. The basis for Graphical User Interface (GUI) based applications is called a Windows Form. All
windows that you work with are built from a form. Hence, the development of such applications
requires two related tasks from a developer. First the Window layout of the application must be
designed ( Visual design). Second, the code that makes the applications work must be written in relation
to user actions on the application’s w inddw such as cliking a button or a menu command. Such user
actions are called Events. The code you write to interact with events is called an Event Handler. Such
applications are often called Event Driven Applications. You usually create such applications using .NET.
The following diagram shows an example of a windows application. It has a form which conatins a
textbox and a botton. When a user clicks on the button the click event will be fired, in resoponse the
coder written as an event handler executes and displays “H ello U ser?!” on the text box.

Figure 4.1: A typical Widows forms structure


The most common contents you add on a form are called controls. Both forms and controls are defined
as classes that expose methods and properties. Most of the properties of forms and controls can be set
at design type in the Form Designer window. You can add controls using the Toolbox. The tool box can
be displayed by using View -> ToolBox menu command.

To create the above application


1. Start a new windows application
The form Designer window opens with a form added to you by default. You can add other forms
if you want by using the Project -> Add Windows Form or Project-> Add New Item menu
commands
2. Resize the for to reduce its default size.

P a g e | 22
3. Add the two controls, i.e., the TextBox and the Button.
To add a control to the form, Select it from the Tool Box and Draw it on the form.
4. Change the text displayed on the Button. To do so, use the Property sheet that is usually
displayed at the right side of the Form Designer.
a. Select the button
b. Go to the Text property and set it to “H ello”
5. Add the Event Handler procedure that displays the text “H ello U ser?!” on the text box
a. Doubleclick the botton
The code editer with the event handler template opens
b. Then add the following code;
Textbox.Text = “H ello U ser?!”

The complete code will be the following:


Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles Button1.Click

TextBox1.Text = "Hello User?!"

End Sub
End Class

A partial view of the toolbox A partial view of the Property Sheet with a form
selected

Controls

Other
Control
Categories

Figure 4.2: The ToolBox(left) where you select controls and the PropertySheet(right) where you set design time
Propertis of your controls and forms.

P a g e | 23
Common properties of forms and controls
Name: The name of the form. You use it for programatically accesing the the objects ( Form1, Textbox1,
Button1, etc are default names in VB.Net.
VB.NET naming conventions
Microsoft recommends are the following prefixes be used in naming your visual interface objects.
Object Sample Object Description Prefix Example
Form Serves as a container window for applications frm frmHelloSample
TextBox Displays text editable by users txt txtHelloMessage

Button Accepts a mouse click action btn btnHello

Label Displays non editable information lbl lblFirstName

Checkbox Displays a check mark for yes/no values chk chkPayed


ListBox Displays a list of Items for single or multiple lst lstItems
selection

Combobox Displays a list of items for single selection. It is Cbo cboDepartment


also editable ( new text can be typed in it)
RadioButton Displayes an option among which only one can rd, optRed, rdRed
be selected. opt
GroupBox Used to Group conntrols on a form grp grpColors

NumericUP- Used to hold numeric values that can be


Down incremented and decreamened easly with up
and down buttons
PictureBox Used to display images on a form pic picPhoto

MenuStrip, Used to build a menu for an applicationwindow. mnu mnuStandard


Created at the top of a window/Form
MainMenu

ToolStrip Used to build a Toolbar tbr tbrBasic

Text: is the visible text displayed on objects (a form ’s title,a botton’s text,value ofa TextBox,etc)

P a g e | 24
Size: difines the actual width and heith of several objects such as forms and listboxes, etc
ForColor:defines the forgrown color of an object (Eg. text color ofa TextBox,color ofa botton’s text)
BackColor: defined the background color of the object(Eg.Color ofthe form ,TextBox itself,… )
Reading Assignment: Study other common controls that you may use in your applications. Some are
listed below:
ListView
MaskedTextbox
RichTextbox
Timer
MonthCalander
DateTimePicker
Scrollbars (VScrollBar, HScrollBar)
ProgressBar
TrackBar
ErrorProvider
Panel
StatusStrip/StatusBar
Treeview
TabControl
Windows dialobox controls
OpenFileDialog
SaveFileDialog
ColorDialog
PrintDialog
FontDialog

Event Handling on forms


As discribed earlier, an event handler is a procedure in your code that determines what actions
are performed when an event occurs, such as when the user clicks a button. When an event is
raised, the event handler or handlers that receive the event are executed. Events can be assigned
to multiple handlers, and the methods that handle particular events can be changed dynamically.
Each event handler provides two parameters that allow you to handle the event properly. The
following example shows an event handler for a Button control's Click event.
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click

TextBox1.Text = "Hello User?!"


End Sub
The first parameter, sender, provides a reference to the object that raised the event. The second
parameter, e, in the example above, passes an object specific to the event that is being handled.
By referencing the object's properties (and, sometimes, its methods), you can obtain information
such as the location of the mouse for mouse events or data being transferred in drag-and-drop
events.
Typically each event produces an event handler with a different event-object type for the second
parameter. Some event handlers, such as those for the MouseDown and MouseUp events, have

P a g e | 25
the same object type for their second parameter. For these types of events, you can use the same
event handler to handle both events.
You can also use the same event handler to handle the same event for different controls. For
example, if you have a group of RadioButton controls on a form, you could create a single event
handler for the Click event and have each control's Click event bound to the single event handler.
Observe the phrase starting with the Handles keyword in the above example.
The above example can be modified to handle click events of three buttons as follows:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click, Button2.Click,
Button3.Click
TextBox1.Text = "Hello User?!"
End Sub
You can also write multiple handlers for the same event. For example, the following two handlers
are related to the same event ( the click event of the a check box named chkPaid). The effect is
that when the the check box is clicked both handlers will execute in response.
An other way of associating one or events with one or more handlers is by using deligates. The
details of deligates is left as an exercice.

Private Sub chkPaid_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles chkPaid.Click

' handler’s code code here


End Sub

Private Sub Handler(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles chkPaid.Click

' handler’s code code here


End Sub
How to view evetns of objects
The events fired by an object can be viewed in the code editer window using the two boxes at the
top of the code area. The following diagram shows the two boxes:
If you want to write handlers for other types of events of objects
1. Select the object you want from the Object /Class Box
Eg: TextBox1
2. Select the Event you want from the Event/Method box
Eg: TextChanged, (fired when you type something in the textbox)
3. You will get a template for the event like this, then you write the event code afterwards.
Private Sub TextBox1_TextChanged(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles TextBox1.TextChanged

' Add event Handler

End Sub

P a g e | 26
Object
or Class
box
Event or
Method
box

Figure 4.3: the code editer with the object box listing all available objects on the current form

Form Inheritance
Traditionally, you will have a number of forms for different aspects of tasks in the same
application. M ost ofthem m ay have a sim ilar layout though.H ence,you don’t need to either
recreate the same layout and code for each form or Copy and rename your forms to get other
forms. You can create the most common layout and code in one form and then derive the other
forms from it. The only thing you do is Create and save the base form you want first. Then use the
following command to add an Inherited form.
1. Project -> Add Windows Form
2. Select Inherited Form
3. Then Give the name of the Base form , and Click Ok
You will get a form containing all inherited from the base class. All inherited elements
including code and object propeties must be changed in the base form. You can only add
new controls and code on the inherited forms.
However, if you have a plan of modifiying the properties, methods, and events of the base form
and its controls change the Modifiers property of each element to Public in the base form.

Figure 4.4: A typical view of a form inherited from an other form ( inherited cotrols appear different showing that
thy are inherited)

P a g e | 27
The Windows Forms Class Hierarchy
The classes in the System.Windows.Forms namespace make up a fairly complex hierarchy, at the
root of which is the System.Windows.Forms.Control class (see Figure 4.5). The Control class
inherits from the system.ComponentModel.Component class, which represents an object that
can be placed on a container. This means that forms and controls we have seen so far inherit
their common properties, methods, and events from the control class. You can explore the
Control class to get the details.

Figure 4.5: A partial view of the windows forms class hierarchy.

A typical Hierarchy of a combobox is shown below


System.Object
System.MarshalByRefObject
System.ComponentModel.Component
System.Windows.Forms.Control
System.Windows.Forms.ListControl
System.Windows.Forms.ComboBox

Using a Dialog to Display a Message


In a windows application the Messagebox() or the MsgBox() functions enable you to display a
message for the user. The messages can be informative or error messages. You can format the
message dialog according to the type of message it contains.
Syntax:
MessageBox.Show ( text to be displayed, title of the box, Botton, Icon)

Form example the following text shows the message dialog in figure 5.
Private Sub btnConvert_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnConvert.Click
If txtDollars.Text = "" Then
MessageBox.Show("You must a Dollar value first", _
"Dollar Entry Error", MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
Else
Dim brVal As Single
brVal = Convert.ToSingle(txtDollars.Text) * 8.75
txtBirr.Text = brVal.ToString
End If
End Sub

P a g e | 28
Figure 5. Message box demo
Other Messagebox

MessageBoxButtons Constants Description


MessageBoxButtons.OK OK Button. Allows the user to acknowledge a
message.
MessageBoxButtons.OKCancel OK and Cancel Buttons. Allow the user to either
continue or cancel an operation.
MessageBoxButtons.YesNo Yes and No Buttons. Allow the user to respond to a
question.
MessageBoxButtons.YesNoCancel Yes, No and Cancel Buttons. Allow the user to
respond to a question or cancel an operation.
MessageBoxButtons. RetryCancel Retry and Cancel Buttons. Typically used to allow
the user either to retry or to cancel an operation that
has failed.
MessageBoxButtons.AbortRetryIgnore Abort, Retry and Ignore Buttons. When one of a
series of operations has failed, these Buttons allow the
user to abort the entire sequence, retry the failed
operation or ignore the failed operation and continue.
MessegeBox Return Values.
Note that a messagebox returns a value corresponding to the button clicked by the user (such as OK,
Cancel, Abort). You may use these return values to perform some actions. The following code runs when a
form is closed. Depending on the return value (in this case No clicked), the form closing action may be
canceled by the code.

Private Sub frmMessgeDemo_FormClosing(ByVal sender As Object, ByVal e As


System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Dim ret As Integer

ret = MessageBox.Show("Are you sure ?? ", "Confirm close",


MessageBoxButtons.YesNo, MessageBoxIcon.Question)

If ret = vbNo Then


e.Cancel = True
End If

End Sub

P a g e | 29
Figure 6. Messge displayed by the above code ( Form_Closing event Handler)

All other return value constants are prefixed by vb ( vbYes, vbAbort, vbCancel, vbRetry, vbIgnore,… )

Other Messagebox Icons

MessageBoxIcon Icon Description


Constants
MessageBoxIcon.Exclamation Icon containing an exclamation point. Typically
used to caution the user against potential
problems.
MessageBoxIcon.Information Ico n co ntaining the letter “i.” T yp ically used to
display information about the state of the
application.
MessageBoxIcon.Error Icon containing an x in a red circle. Typically
used to alert the user of errors or critical
situations.
MessageBoxIcon.Question Icon containing a question mark. Typically used
to ask the user a question.

Using the InputBox


In a windows application, some typed inputs may be taken from users using the InputBox()
function. The inputbox function like the message box function shows a dialog but with a text box
where the user specifies input. It has three important parameters. Title and DefaultResposnse
values can be omitted.
Syntax:
InputBox( Prompt, Title, DefaultResponse) As String
The code in the following example accepts a date value and displays the weekday using a
message box.

Private Sub btnWeekDay_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnWeekDay.Click

Dim Days() As String = {"Sunday", "Monday", "Tuesday", "Wednesdey",


"Thursday", "Friday", "Saturday"}
Dim dt As Date

dt = InputBox("Enter a date:", "Week day", Date.Now)

MessageBox.Show(Days(dt.DayOfWeek()))
' DayOfWeek returns values 0 to 6 ( 0 for Sunday, 6 for Saturday)
End Sub

P a g e | 30
WorkSheet II
Create Windows forms Applications for the following Applications

1. Problem statement: A payroll company calculates the gross earnings per week of employees from
the number of hours they worked and their hourly wages. Create an application that takes this
inform ation and calculates the gross earnings by m ultiplying the em ployee’s hourly w ages by the
number of hours worked. The application assumes a standard work week of 40 hours. Any hours
worked over 40 hours in a week are considered and the earning will be one and one-half times
the hourly wage. Use a procedure to determine whether the employee has earned overtime pay.
Salary for time and a half is calculated by multiplying the em ployee’s hourly w age by 1.5 and
multiplying the result of that calculation by the number of overtime hours worked. This value is
then added to the user’s earnings for the regular 40 hours of w ork to calculate the totalearnings
for that week. Use another procedure to display the user’s pay.You can use the following figure as
a sample layout, but it is better to use your own.

2. Problem Statement: An organization is hosting a fund raiser to collect donations. A portion of


each donation is used to cover the operating expenses of the organization; the rest of the
donation goes to the charity. Create an application that allows the organization to keep track of
the total amount of money raised. The application should deduct 17% of each donation for
operating costs; the remaining 83% is given to the charity. The application should display the
amount of each donation after the 17% operating expenses are deducted; it also should display
the total amount raised for the charity (that is, the total amount donated less all operating costs)
for all donations up to that point. You can use the following layout as a sample.

Current
Donation

Current
Donation after Total donations
expenses Donation after
expenses

P a g e | 31
3. A certain Instructor wants to calculate the grades of each student in his class. Assume that he has
60 students scoring values out of 100 for the subject. Create a an application for the Instructor
that uses a multicolumn list box to display the Name, Mark and Grade of each student side by
side. Use the following Grading rule to calculate the grades after inputting the name and mark of
each student.

Mark Grade
90-100 A
75-90 B
55-75 C
40-55 D
0-40 F
The layout of the form of this application is left as an exercise.

MDI Windows
Most applications use multiple documents windows for work. Such applications have one Parent Window
(form) and many child widows or forms. Any of your forms can be parents. The parent form ’s
isMdicontainer property must be set to True. You set it at in the forms designer (at design time).

When the child forms are opened or shown you must set the mdIParent property of a form with the name
of its parent form.

frmOrders.MdiParrent = frmMain ‘this can be added in the form s load event procedure.

Figure 6. A typical MDI Application with two child windows opened.

P a g e | 32
Chapter 5: Database Programming with ADO.NET
Data access and ADO.NET
Most applications are database related. A databse is usually maitained and managed by a specific
DBMS. This makes the application development and the Database development two related but
different aspects of contemporary applications. While the application (usually termed as the
Front End) is implemented using a programming environment such as VB.NET, the corresponding
database (usually termed as the Back End) is designed and implemented using some DBMS ( such
as Microsoft Access, SQL server or Oracle). Since these two are deferent environments that are
incompatible to each other, some intermidiary component called data access component will be
useed by the appliction in order to get access to the database stored in a specific DBMS. Such an
intermediary tool is called a Data Access Tool. One example is ADO.NET.
ADO.NET (pronounced as ActiveX Data Objects.NET) is a set of objects (classes) that allow such
communication a data source and a .NET application.

 Provide User
interface and Data Applications
to Users
 Send Updates,
 Connect to Database
Inserts and Delete
 Send application
operations by users
requests fro Apps
to ADO Data Access Tools(ADO.NET)  Return results from
DBMS

DBMS
Data Source
 Store Data
Database
 Maintain Security,
Integrity, Recovery

Figure 5.1. A typical data access methodology

The ADO Architecture and Object Model


The ADO.NET components have been designed to provide data access and data manipulation. There are
two central components of ADO.NET that accomplish this: the DataSet, and the .NET Data Provider, which
is a set of components including the Connection, Command, DataReader, and DataAdapter objects.

P a g e | 33
Figure 5.2. ADO Data Access techniques and Objects

ADO provides data access in both connected (online) or disconnected (offline) architectures. But the most
functional is the latter one. The DataReader is the core component in the connected architecture while
the DataSet is the core component of the disconnected architecture of ADO.NET. The Connection object
provides connectivity to a data source in both the architectures.
The other core element of the ADO.NET architecture is the .NET data provider, whose components are
explicitly designed for Data Manipulation and fast, forward-only, read-only access to data.
The .NET Framework includes two .NET data providers:

 The SQL Server .NET Data Provider: which works for only for SQL Server,
 The OLE DB .NET Data Provider: w hich w orks for all other D BM S’s such as M icrosoft
Access.
The Command object enables access to database commands to return data, modify data, run stored
procedures, and send or retrieve parameter information. The DataReader provides a high-performance
stream of data from the data source. Finally, the DataAdapter provides the bridge between the DataSet
object and the data source.

Figure 5.3 . The two typical data providers for ADO.NET

P a g e | 34
The Data Adapter
Interaction with data sources is controlled through the DataAdapter. Each .NET data provider included
with the .NET Framework has a DataAdapter object: the OLE DB .NET Data Provider includes an
OleDbDataAdapter object and the SQL Server .NET Data Provider includes a OledbDataAdapter object. A
DataAdapter is used to retrieve data from a data source and populate tables within a DataSet. The
DataAdapter also resolves changes made to the DataSet back to the data source. Here, you have to note
that changes by users are saved in memory only in the dataset until they are sent back to the database
whenever the application requires. The DataAdapter uses the Connection object of the particular .NET
data provider to connect to a data source, and Command objects to retrieve data from and resolve
changes to the data source. The DataAdapter uses Command objects to execute SQL commands at the
data source to both load the DataSet with data, and reconcile changes made to the data in the DataSet
back to the data source.
The DataSet Object in Depth
The central component of any software solution using ADO.NET is the DataSet. A DataSet is an in-memory
copy of database data. A DataSet can contain data from any number of database tables or views. The
DataSet constitutes a disconnected view of the database data because it exists in memory without an
active connection to a database containing the corresponding tables or views. This disconnected
architecture enables greater scalability by only using database server resources when reading or writing
from the database.

The biggest advantage of using a DataSet is that it provides a view of the database with multiple tables
and their relations, all without having an active connection to the database. You can think of a DataSet as
a miniature relational database in memory. A DataSet is usually created and populated programmatically.
It contains any number of tables, each of which corresponds to a database table or view.

DataSet
Tables
DataTable
Rows
DataRow
Columns
DataColumn
Figure 5.4. A partial view of the DataSet Object Model

An ADO.NET DataSet contains a collection of zero or more tables represented by DataTable objects. The
DataTableCollection contains all the DataTable objects in a DataSet. A DataTable is defined in the
System.Data namespace and represents a single table of memory-resident data. It contains a collection of
columns represented by a DataColumnCollection, and constraints represented by a ConstraintCollection
(not shown), which together define the schema of the table. A DataTable also contains a collection of rows
represented by the DataRowCollection, which contains the data in the table. Along with its current state, a
DataRow retains both its current and original versions to identify changes to the values stored in the row.

P a g e | 35
ADO Usage Mechanisms and Connection Lifetime

The following diagram concisely shows the usage styles of ADO objects both the connected and the
disconnected architectures.

Application

DataSet
Slow, Updatable,
Scrollable
DataReader
Fast, ReadOnly,
ForwardOnly DataAdapter
SelectCommand()
InsertCommand()
UpdatteCommand()
DeleteCommand()

Command
ExecuteReader()
ExecuteScalar()
ExecuteNonQuerry()

Connection

Data Source
OLEDB
SQL Server

Figure 5.5. The ADO life time

P a g e | 36
Working with ADO (Connected Architecture)
Now that you have got the architectural components of ADO.NET. In this section, we will see how we can
actually work with ADO connected style. This style requires the connection to be open throughout the
over all activity. How ever,this style doesn’t allow alloperations.It only allow s Reading in one direction
(forward only). Updates, Deletes and Inserts are not allowed. Its advantage is that it provides the fastest
navigation in cases where only reading is required. If you want to allow users to make changes, then you
will have to use the second style ( i.e., the Connected Style). You will use a Connection, Command and a
DataReader object for this case. Here are the basic steps used to create a connected style database access:
1. Create a connection to the Database
 Create an instance of the appropriate Connection (SqlConnection, oledbConnection)
 Set the ConnectionString Property of the connection instance
 Open the connection ( use Open method)
2. Create a Command Object to fetch data from the database
 Create an instance of the corresponding command (sqlCommand, oledbCommand)
 Set the Connection property of the Command Object to the Open connection
 Set the CommandType property to either of three settings ( Text, StoredProcedure)
 Set The CommandText to the appropriate Command string depending on the type
Type Setting
CommandType.Text An appropriate Select statement
CommandType.StoredProcedure A call to a stored procedure with appropriate input parameters
CommandType.TableDirect A correct Table or View name in the database
3. Create the DataReader Object
 Create a DataReader referece
 Use one of the Executexxx() methods of the DataReader object to create the Datareader.
Method What it Returns
comObj.ExecuteReader() A Reader that containing a group of records (ResultSet)
comObj.ExecuteSecalar() A Reader that returns a single value(in case the SQL text returns only one
value – aggregate values for example – Sum ,Count,… )

4. Use the RataReader to navigate through the data


 You get access to each column using their names or ordinal values
 You can go to subsequent rows using the Read () method of the data reader.

Example:
The following example code connects to a sample Microsoft Access Database named NWIND.MDB hypothetically
stored in the root folder of drive D. You must modify it if to the correct path in your case.
Class DataRead
Public conn As New OleDbConnection()
Public Ds As New DataSet
Public com As New OleDbCommand
Public Dr As OleDbDataReader

Public Sub ConnectAndCreatDS()


' Specify the connection String ( What Provider, Which Database)
conn.ConnectionString = _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\NWIND.MDB"

P a g e | 37
conn.Open()
' Create The Command Object
com.CommandType = CommandType.Text
com.Connection = conn
com.CommandText = _
"Select EmployeeID,FirstName,LastName From Employees"
'then create the datareader
Dr = com.ExecuteReader() ' this is the only method that creates a
datareader containing many records
End Sub
End Class

Other Classes can be created as users of the above class so that they can use the Dr Public field of the
object to navigate through the records. Below is one such class.

The following example shows a form that displays data retrieved by an object of the above class on a form

Eg. 5.1.
Imports System.Data.OleDb

Public Class frmDataRead


Dim dbObj As New DataRead()
Dim myDr As OleDbDataReader

Public Sub Display()

myDr = dbObj.Dr

If myDr.Read() Then
txtID.Text = myDr.GetInt32(0).ToString
txtFName.Text = myDr.GetString(1) Only next is used (Why??)
txtLName.Text = myDr.GetString(2)
End If

End Sub

Private Sub frmDataRead_Load(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles MyBase.Load
dbObj.ConnectAndCreatDS()
Display()
End Sub

Private Sub btnNxt_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnNxt.Click
Display()
End Sub
End Class

P a g e | 38
Working with ADO (Disconnected)

Now that you have got the architectural components of ADO.NET. In this section, we will see how we can
actually work with ado. Here are the base steps:
1. Create a connection to the Database
 Create an instance of the appropriate Connection (SqlConnection, oledbConnection)
 Set the ConnectionString Property of the connection instance
 Open the connection ( use Open method)
2. Create a DataAdapter to fetch data from the database
 Create an instance of the corresponding data adapter (oledbDataAdapter, oledbDataAdapter)
 You must use an open connection instance to create the data adapter
3. Create the Dataset
 Create a data set instance
 You must use the Fill method of the DataAdapter object to populate the DataSet object
 At this point you can close the connection using its Close() method.
4. Use the Dataset to navigate through the data
 Use Instances of DataTable class to access a data table in the dataset
 Use instances of DataColumn class to access columns of a data table
 Use instances of the DataRow class to navigate through each row of a data table
 You get access to each table, column or row using their respective collections

The following example code connects to a sample Microsoft Access Database named NWIND.MDB hypothetically
stored in the root folder of drive D. You must modify it if to the correct path in your case. The code connects to the
table named Employees and then displays the records on the screen. Implement it using a console application to test
the code.
Eg. 5.2.
'Imports System.Data.SqlClient
Imports System.Data.OleDb

Class ADOClass
Dim conn As New OleDbConnection()
Dim Ds As New DataSet
Dim Da As OleDbDataAdapter
Dim col As DataColumn

Public Sub ConnectAndCreatDS()


conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=D:\NWIND.MDB"
conn.Open()
' Create the addapter
Da = New OleDbDataAdapter("Select EmployeeID,FirstName,LastName From
Employees", conn)
'then create the dataset
Da.Fill(Ds, "Employees") ' here Employees is the name of the Datatable
End Sub

Public Sub Display()

' Navigate each column to display the column name


' Tables(0) is the first and the only table in the dataset

For Each col In Ds.Tables(0).Columns

P a g e | 39
Console.Write(col.ColumnName & " ")
Next

Console.WriteLine()

' Navigate through each row to get access to records and


' display the entries in each field of the rows
For Each dr As DataRow In Ds.Tables(0).Rows
For i As Integer = 0 To Ds.Tables(0).Columns.Count - 1
Console.Write(dr(i) & Space(5))
Next
Console.WriteLine() 'go to a new line after each row is completed
Next

' Then the total number of records in the table


Console.WriteLine(vbCrLf & "There are " & Ds.Tables(0).Rows.Count & "
Rows")

End Sub

End Class

Class Tester
Shared Sub Main()

Dim dbtest As New ADOClass()

dbtest.ConnectAndCreatDS() ' create the dataset


dbtest.Display() ' diplay the records

Console.ReadLine()

End Sub
End Class

Data Binding with Windows Forms and ADO.NET


One Definition describes Data Binding as follows:
“The programming task of retrieving data from a data source, gluing it to a user
interface control, allowing manipulation, including sorting and paging, and optionally
changing the data and the synchronization of such changes with the original data
source. All of this is accomplished with minimal code creation on the part of the
developer”

The Basics of Data Binding and Windows Forms


In essence, data binding refers to the process of automatically setting properties of one or more
form controls at run time from a structure that contains data. Microsoft Windows Forms use
Microsoft ADO.NET under the covers to implement data binding. With data binding, you do not
need to explicitly write the code that instantiates a connection and creates a dataset (as you would
with an unbound form). The Wizards associated with Windows Forms write the necessary
ADO.NET code for you.

P a g e | 40
Windows Forms allow you to bind easily to almost any structure that contains data. This means
that you can use ADO.NET to bind to traditional data stores, such as data stored in a Microsoft
Access or Microsoft SQL Server table or other DBMSs.

After you have bound a form to data, you can then bind controls on the form to specific elements
of the data. The most traditional data binding involves binding the Text property of a text box
control to a column of a datasource. You can also bind the graphic of an Image control, the
background of a control, or any other property of any control on a form.

Two types of data binding are available for Windows Forms:


 Simple Data Binding and
 Complex Data Binding.
Each method offers different advantages.

Simple data binding allows you to bind a control to a single data element. The most common use
of simple data binding involves binding a single data element, such as the value of a column in a
table, to a control on a form. You use this type of data binding for controls that show only one
value. Uses of simple data binding include binding data to text boxes and labels.

Complex data binding allows you to bind more than one data element to a control. Using the
column example, complex data binding involves binding more than one column or row from the
underlying record source. Controls that support complex data binding include data grid controls,
combo boxes, and list boxes.

Building a Simple Data-Bound Windows Form


The most basic use of data binding available in the .NET environment displays the contents of a
table in a grid. The example below involves the following basic steps (without details):

1. Build a Windows Form.


2. Create and configure the dataset to which you wish to bind the form.
3. Add a Data Grid control to the form and bind it to the data.
A Data Grid control provides a tabular view of data that comes from a data source.
its main data source is a data table in a dataset.

An example of a form resulting from this process appears in Figure 5.6.

P a g e | 41
Figure 5.6. The result of creating a simple data-bound Windows Form

Building the Sample Form

The following are the detailed steps required to build the above sample form (fig 5.6).

1. Click File, click New, and then click Project. The New Project dialog box appears.
2. Select the Project Type from the tree-view in the left-hand side of the dialog. For this
example, select Visual Basic Projects.
3. Select Windows Application from the list of templates on the right side of the dialog.
4. Supply a name and location for the project you wish to create. Click OK to create the
project.
5. Right click on the form and select Properties to display the properties for the form.
Change the Name property of the form to frmCustomers.
6. Change the Text property to Customer Information.

Creating and Configuring the Dataset

Once you create the project and form, you are ready to create and configure the dataset underlying
the form. A dataset is an in-memory cache consisting of tables, relations, and constraints. Each
table in the dataset has a collection of columns and rows. Because datasets are aware of both their
original and current state, they can track the changes that occur. The data in a dataset is considered
updateable.

First, create a Data Adapter that contains the SQL statement that you will use to populate the
dataset. To create the data connection and data adapter:

1. In the Toolbox, on the Data tab, select a oledbDataAdapter. Drag-and-drop it to the form.
The Data Adapter Configuration Wizard appears. Click Next.

P a g e | 42
2. Click New Connection to create a data connection that the data adapter will use.
3. C lick change and S elect “Microsoft Access Database File” then click Ok
4. In the Add New Connection dialog box, click Browse and locate your access database,
then click Open.
5. Click Test Connection to confirm that connection to the database is successful.

Source
Database

Figure 5.7 . The Add Connection dialog box allows you to specify connection information for the
data underlying the bound form

6. Click OK to return to the wizard, and then click Next.


7. The wizard allows you to designate the Query Type as in Figure 3. Select Use SQL
statements and click Next.

P a g e | 43
Figure 5.8 . Designate the type of query on which the bound form will be based

8. Type a SQL statement or click Query Builder to have the wizard build the SQL statement
for you. For this example, type the following SQL statement:

SELECT CustomerID, CompanyName, ContactName,


ContactTitle, Country FROM Customers

9. Click Next and then click Finish to complete the process. Notice that an oledbConnection
object named oledbConnection1 and a oledbDataAdapter object named
oledbDataAdapter1 appear in the Tray of the form.

The oledbConnection1 object contains information about how to access the selected
database. The oledbDataAdapter1 object contains a query defining the tables and columns
in the database that you want to access.

Note: We are using the more generic oledbDataAdapter on the Toolbox because
we are using Microsoft Access. If you want to use SQL Server as a data source,
you must select and configure the more specific oledbDataAdapter.

Generating the Dataset Class


The next step is to have Microsoft Visual Studio generate a dataset class based on the query
selected during the creation of the data adapter. To generate the dataset class, you can use the
Smart Task feature of the oledbDataAdapter1 object created earlier. The smart task feature of a
control is activated by clicking the Arrow button it the top right that appears when the control is
selected. A smart task list can also by activated by right clicking the control.

P a g e | 44
The tray of
Activating a a form
smart task

Figure 5.9. Activating the Smart Task feature of a data adapter.

1. Click the Generate Dataset option from the smart task list. The Generate Dataset dialog
box appears as in Figure 4.

Figure 5.10 The Generate Dataset dialog box allows you to specify the name and other attributes
of the dataset that you are generating

2. Enter dsCustomers for the name of the New dataset you are creating. Make sure that you
select the Add This Dataset to the Designer option. Click OK. This generates the dataset.

P a g e | 45
After this step completes, you will see a new control, dsCustomers1, in the Tray for this form. This
new control is a reference to the dsCustomers.xsd file that was also added to your Solution
Explorer window. dsCustomers.xsd is an XML schema definition of the SQL statement that you
typed in earlier. There is a class is shown in the solution Explorer window. Then you can click on
the plus sign that appears behind the dsCustomers.xsd file to see the dsCustomers.vb file, as shown
in Figure 5.11. You can open the XSD file to see what it contains.

Figure 5.11. An XML schema definition (XSD) file has a class module containing the code that loads the
dataset into memory

Adding a Data Grid Control to Display the Data

You are now ready to create a form to display the data contained in the dataset. In this example,
you will add a single data grid control to the form. The data grid control will display the data
contained in the dataset. Here's what's involved:

1. At the top of the window, click the tab to display the frmCustomers form.
2. On the Windows Forms tab of the Toolbox, drag a data grid control onto the form. Size
the control as appropriate.
3. Display the control properties.
4. For the DataSource property, select dsCustomers1.
5. For the DataMember property, select Customers. This is the data table name inside the
dataset whose data will be displayed on the grid.

The steps you just completed have now bound the dataset to the data grid control. There is just one
more step to complete to see the data appear in the data grid control.

Populating the Data Grid Control With Data

Although the data grid control is bound to the dataset, the dataset is not automatically populated
when the form is loaded. Use the form's Load event procedure to populate the data grid control
with data as the form is loaded.

Private Sub frmCustomers_Load(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles MyBase.Load

' Load the Data Grid Control


DsCustomers1.Clear()

P a g e | 46
oledbDataAdapter1.Fill(DsCustomers1, "Customers")

End Sub

In the Load event procedure, you first clear the dataset and then fill the dataset using the Fill
method of the oledbDataAdapter1 object you created earlier. You need to pass in the name of the
table to the second parameter, as this is used by the data grid control to retrieve the correct
DataMember (Customers) that you specified earlier in the DataMember property.

Run the Application

At this point, you are ready to see the data from the Customers table displayed in the data grid
control. There is one more step to complete before you can run this form. Because you changed the
name of the form, you need to inform the project what the Startup form for this project will be.

1. In the Solution Explorer window, click your project name.


2. Right-click it and choose Properties from the shortcut menu.
3. Click the Startup Object combo box and choose frmCustomers from the list.
4. Click OK.
5. Press F5 to run this project, and if you have done everything correctly, you should now see
customer data within the data grid control similar to that shown in Figure 5.6.

Working With Combo Boxes and List Boxes


The example you just created is fine for small result sets, but would not be very efficient if the
table of customers had thousands of records. The problem is that it retrieves all customers from the
Customers table and displays them in the data grid control. Although great for a demonstration,
this technique is not practical in a production application.

A database server is optimized to process large volumes of data, but you should only return small
result sets. The example shown in the previous section would be much more efficient if the user
were to first limit the data by selecting a particular country from a combo box, and then display
only those customers for the selected country. This section shows you how to create the data-
bound combo box. The next section shows you how to use the combo box to limit the data
displayed in the data grid control. The example involves the following basic steps:

1. Add a second data adapter to the form.


2. Generate a second dataset.
3. Add a combo box to the form.
4. Bind the combo box to the second data adapter.
5. Populate the combo box with data from the second data adapter.

Adding a Second Data Adapter to the Form

Before you add a combo box to the form, first add a second data adapter to the form. You will use
this data adapter to generate a dataset containing a unique list of countries from the Customers
table. To add the second data adapter:

P a g e | 47
1. In the Toolbox, from the Data tab, select a oledbDataAdapter. Drag-and-drop it to the
form. The Data Adapter Configuration Wizard appears. Click Next.
2. Select the connection to the Northwind database that you created in the previous example.
Click Next.
3. Select Use SQL Statements and click Next.
4. Enter the following SQL statement:

SELECT DISTINCT Country FROM Customers

5. Click the Advanced Options button on this dialog.


6. Clear the options for Generate Insert, Update, and Delete statements as shown in Figure
5.12. These statements are not necessary for a dataset used solely to populate a combo box.
Click OK to close this dialog box.
7. Click Finish to generate the oledbDataAdapter.

There will now be an object named oledbDataAdapter2 added to the Tray of your form.

Figure 5.12. Do not choose Generate Insert, Update and Delete Statement when creating a dataset used
to bind to a combo box

Generating a Second Dataset

The next step is to generate a dataset class and XSD file for this new oledbDataAdapter containing
the unique list of countries. Here are the steps involved:

1. Right click on the second adapter, and then click Generate Dataset. The Generate
Dataset dialog box appears.
2. Make sure Customers (oledbDataAdapter2) is selected in the list box of tables.
3. Click New, and enter the name dsCountries. Make sure that you select the Add This
Dataset to the Designer option. Click OK. This generates the dataset.

P a g e | 48
You have added a new object to the Tray named dsCountries1, and a new XSD file to the Solution
Explorer named dsCountries.xsd. These two items together create the dataset class and are used to
do the data binding on the combo box you are about to create.

Adding a Combo Box to the Form

You are now ready to add the combo box to the form. You need to increase the height of the form,
and move the data grid control down to make some room for this new combo box. After doing this,
in the Toolbox, you can drag-and-drop a combo box from the Windows Forms tab onto the form.
Place it above the data grid control, as shown in Figure 5.13.

Figure 5.13. Form containing data grid control and combo box

Binding the Combo Box to the Data Adapter

The combo box that you added is not bound to any data. To bind the combo box to the dsCountries
dataset:

1. Select the combo box.


2. Change the name to cboCountry.
3. Set the DataSource property to dsCountries1. This specifies that this is the data source
from which to populate this data grid control.
4. Change the DropDownStyle property to DropDownList.
5. Set the DisplayMember property to Customers.Country. You will need to click the drop-
down list in the DisplayMember property, and then expand the Customers to display the
list of columns that you can use. This step designates the column in the data source that is
used to populate the data grid control.
6. Set the ValueMember property of the combo box to Customers.Country. The
ValueMember property is used to designate the actual value used when an item is selected.

P a g e | 49
Populating the Combo Box With Data

As with the data grid control, you must write some code to populate the combo box with data. The
code is added to the Load event procedure just under the code you used to load the data grid
control.

Private Sub frmCustomers_Load(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles MyBase.Load

' Load the data grid control


DsCustomers1.Clear()
OledbDataAdapter1.Fill(DsCustomers1, "Customers")

' Load the Combo Box


DsCountries1.Clear()
OledbDataAdapter2.Fill(DsCountries1, "Customers")

End Sub
The code shown in bold above is the code you will add to load the combo box. It is very similar to
the code you used to load the data grid control. You are now loading the second DataAdapter
control that you created.
Run the Application
Run this code to see if the countries are being loaded.
1. Press F5 to run this form.
2. Click the Countries drop-down combo box to see if there are countries loaded into the list.
If you have done everything correctly, they should be there and your screen may look
something like Figure 5.14.

Figure 5.14. Using a drill-down combo box to display a lesser amount of data in a data grid can
improve performance

Displaying Data Based on a Parameterized Query


Now that you have the combo box loaded with countries, it is time to use the country selected from
the combo box to select the customers to load in the data grid control. The basic steps are:

P a g e | 50
1. Remove the code that populates the data grid control as the form is loaded.
2. Modify the oledbDataAdapter1 o bject’s SelectCommand property so that it accepts a
parameter for the country whose data you wish to display.
3. Add code that executes when the user selects an item in the combo box.

Remove the Code That Populates the Control as the Form Is Loaded

Now that the data grid control is populated based on the country selected in the combo box, you no
longer want it to load when the form is loaded. Remove the following code from the Load event
procedure of the form:
DsCustomers1.Clear()
OledbDataAdapter1.Fill(DsCustomers1, "Customers")

Modify the SelectCommand Property


The next step is to modify the data adapter's SelectCommand property so that it is based on a
parameterized query. The steps are:

1. In the Tray of the form, click the OledbDataAdapter1 object.


2. Open the Properties window.
3. Next to the SelectCommand property, click the plus sign to expand the list of sub-
properties.
4. Click the CommandText property. Click B u ild (… ) to display the Query Builder dialog
box. (See Figure 9.)
5. Add a WHERE clause so that the SQL statement looks like this:

SELECT CustomerID, CompanyName, ContactName, Country


FROM Customers
WHERE Country = @CountryParam
6. Click OK to accept this change.
7. Click the oledbDataAdapter1 object.
8. Right click oledbDataAdapter1 and select Generate Dataset, and then click OK to
regenerate the existing dataset.

P a g e | 51
Figure 5.15. The Query Builder dialog helps you build SQL statements for your data adapters

Add Code That Executes When the User Selects an Item in the Combo Box

The final piece of required code repopulates the data grid control when a country is selected in the
cboCountry combo box. The basic steps to accomplish this are:
1. Respond to the SelectedIndexChanged event.
2. Set the parameter in the dataset with the data retrieved from the selected item in the combo
box.
3. Fill the dataset using this parameter.

Follow these steps to add the code and make this work.
1. Open the form in design mode.
2. Double-click the cboCountry combo box to display the SelectedIndexChanged event
procedure. This is the event that fires when you choose a new item from the combo box.
3. Write the following code within this procedure.

Private Sub cboCountry_SelectedIndexChanged(ByVal sender As


System.Object, _
ByVal e As System.EventArgs) Handles cboCountry.SelectedIndexChanged

' Get the Parameter object and Set value

OledbDataAdapter1.SelectCommand.Parameters.Item("@CountryParam").Value _
= cboCountry.SelectedValue

' Clear the dataset


DsCustomers1.Clear()
' Load the dataset using the parameter value
OledbDataAdapter1.Fill(DsCustomers1, "Customers")

P a g e | 52
End Sub

Y o u need to use the data adapter’s SelectCommand object to retrieve the specified Parameter
object. You can then set the Value property of this parameter to the SelectedValue property of the
combo box. The SelectedValue property is filled in with the Country name selected in the combo
box because you set the ValueMember property of the combo box to use the Country field from
the dataset. Once you fill in this value, you can fill in the customer dataset and it will automatically
repopulate the data grid control with just the customers for that selected country. An olternative for
the SelcetedValue property of a Combo Box is its Text Property.

Run the Application

At this point, you can run the application again to see how this works.

1. Press F5 to run the application.


2. Select a country from the combo box and you should see customers displayed in the data
grid control.
3. Select a different country to see a different set of customers.

Binding to Text Boxes


The previous examples all displayed data in a data grid control. In building applications, it is also
necessary to display individual columns in text boxes on a form for editing. Although you won't
learn how to edit data in this document, you will learn to display data in text boxes. The mains
steps are as follows:

1. Build a Windows Form that looks like Figure 5.16.


2. Create and configure the dataset to which you wish to bind the form.
3. Add controls to the form and bind them to the dataset.
4. Add command buttons that allow the user to navigate from row to row.

Follow the steps outlined in the sections above, titled Building the Sample Form, Creating and
Configuring the Dataset, and Generating the Dataset Class. These sections create a dataset based
on the Customers table. When adding the oledbDataAdapter to the form, select the existing
connection to the NorthWind database and build a SQL statement that includes the CustomerID,
CompanyName, ContactName, and ContactTitle fields from the Customers table. You are now
ready to add controls to the form and bind them to the dataset.

P a g e | 53
Figure 5.16. A simple data entry form

Adding Controls to the Form and Binding Them to the Dataset

Add controls to the form and set their properties as designated in Table 1.

Table 1. Controls Used to Build Forms (as shown in Figure 10)

Control Type Property Value


Label Name Label1
Text CustomerID
TextBox Name txtCustomerID
Text Blank
Label Name Label2
Text Company Name
TextBox Name txtCompanyName
Text Blank
Label Name Label3
Text Contact Name
TextBox Name txtContactName
Text Blank
Label Name Label4
Text Contact Title
TextBox Name txtContactTitle
Text Blank
CommandButton Name btnPrevious
Text <
CommandButton Name btnNext
Text >

P a g e | 54
You must now bind each text box to a column in the dataset. To do this:

1. Select the text box that you want to bind.


2. Open the Properties window.
3. Click to expand the DataBindings properties.
4. Under DataBindings, select the Text property.
5. Open the combo box and bind each text box to the appropriate field. For example, to bind
the txtCustomerID text box to the CustomerID field, click the plus sign for
DsCustomers1, the plus sign for Customers, and then select the CustomerID field.

Although each field is bound, as with the data grid co ntro l exam p le, do n’t need to w rite the
code to populate such type of binding is made automatically by visual basic.

Adding Command Buttons to Navigate from Row to Row

The final step is to add code that allows the user to navigate from row to row. The code behind the
previous button appears as follows:

Private Sub btnPrevious_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles btnPrevious.Click
Me.BindingContext(DsCustomers1, "Customers").Position -= 1
End Sub

The code uses the BindingContext method of the form to decrement the record pointer in the
dataset. The BindingContext tracks the current item for each datasource being used on the form.
The code behind the next button looks like this:

Private Sub btnNext_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles btnNext.Click
Me.BindingContext(DsCustomers1, "Customers").Position += 1
End Sub

The code behind the next button uses the BindingContext method of the form to increment the
record pointer in the dataset. The resulting form should look like that shown in Figure 5.16.

Note As with the data grid control example, in a production environment you should limit the
data displayed on the form. You could, for example, add a combo box to the top of the form and
allow the user to select only customers in a specific country. The navigation buttons would then
take the user from row to row for the customers in that country.
Exercise: Try to study and use the BindingNavigator Control. It provides another way of
navigating through a datasource of a data bound form.

P a g e | 55
The BindingNavigator
Control

Updating Data with ADO.NET


Generally speaking, an update operation is an operation that transforms the target database from
one state to another in terms of data records. An update means an Insert, Update, or Delete
operation on records. There are two ways in which you may send update instructions from you
applications to the target database.
A) Using the Command Object
You can use a command object that accepts either an Insert, Update or Delete statement in its
CommandText property. And then use the ExecuteNonQuery Method of the command to send the
Update operation.
Example:
The form below shows an application with textboxes and grid that are bound to a single dataset.
The code below shows an update operation that will be sent to the database using a command
object. This code for insert and delete is similar and is left as an exercise.

P a g e | 56
Change any of these
An values, and
AutoNumber Click …
field Update Using Command

See Next
Exam ple’s
code for this
button

Figure 5.17: Update Example


Public Class frmUpdate

Dim comm As New OleDbCommand

Private Sub btnUpdateCommand_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles
btnUpdateCommand.Click

'Open the connection if it is not open yet


If Me.OleDbConnection1.State <> ConnectionState.Open Then
Me.OleDbConnection1.Open()
End If

'Construct the SQL Statement as a string


Dim sql As String

sql = "Update Employees Set FirstName = '" & txtFName.Text _


& "',LastName = '" & txtLName.Text & "', Title ='" & txtTitle.Text _
& "' where EmployeeID = " & Convert.ToInt32(txtEmpId.Text)

'Some connstuct the command


comm.Connection = Me.OleDbConnection1 'Some connection should be used
comm.CommandType = CommandType.Text
comm.CommandText = sql

comm.ExecuteNonQuery()

End Sub

P a g e | 57
Note that comm has been at the class level in the F o rm ’s C lass m o du le.
B) Using the dataset Object
The most common and interactive way of database updates is performed using the DataAdapter
object. As described earlier, applications (users) make inserts, updates, and deletes on a on each
DataRow of Dataset object. But these changes must be sent to the database using the
D ataA dapter’s U pdate m etho d. A ll changes o n the dataset w ill be pro pagated to the database using
this method. Any changes made to any of the tables in the dataset will be saved in the database.
Example:
Private Sub btnUpdateDS_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnUpdateDS.Click

'First update the changes


OleDbDataAdapter1.Update(DsEmployees1)

'then refresh the dataset with the new records (Optional)


OleDbDataAdapter1.Fill(DsEmployees1)

End Sub
This code is part of the same form module shown above.

How a DataAdapter updates changes from a dataset to the database


A data adapter object intelligently monitors changes made to eh dataset and generate appropriate
commands for the three types of operations. The following figure shows this

Figure 5.17: How a data adapter saves changes to target databases

Managing Transactions
Transactions are a feature offered by most databases for ensuring data integrity when data is
modified. A successful transaction must pass the "ACID" test, that is, it must be:

 Atomic – All statements in the transaction either completed successfully or they were all rolled
back. The task that the set of operations represents is either accomplished or not, but in any case
not left half-done, to the detriment of your data.
 Consistent – All data touched by the transaction is left in a logically consistent state. For example,
if inventory numbers were decremented in one table, there has to be a related order that
consumed that inventory. The inventory can't just disappear.
 Isolated – The transaction must affect data without interfering with other concurrent
transactions, or being interfered with by them. This prevents transactions from making changes to
data based on uncommitted information, for example changes to a record that are subsequently
rolled back. Most databases use locking to maintain transaction isolation.

P a g e | 58
 Durable – The data changes enacted by the transaction are permanent, and will persist through a
system failure.

The classic example is submitting an order to an order entry system— you have to check the
customer's credit level, create an order record, create order line item records, decrement the order
items from inventory, create a ship request, and more. If one or more of those steps fail but the rest
succeed, you can end up with inconsistent data in the form of orphaned records, unreliable
inventory numbers, and so forth. Using transactions appropriately prevents this kind of thing from
happening.

Structure of an ADO.NET Transaction


A transaction at its most basic level consists of two required steps— Begin, and then either
Commit or Rollback. The Begin call defines the start of the transaction boundary, and the call to
either Commit or Rollback defines the end of it. Within the transaction boundary, all of the
statements executed are considered to be part of a unit for accomplishing the given task, and must
succeed or fail as one. Commit (as the name suggests) commits the data modifications if
everything was successful, and Rollback undoes the data modifications if an error occurs. All of
the .NET data providers provide similar classes and methods to accomplish these operations.

The ADO.NET data providers offer transaction functionality through the Connection, Command,
and Transaction classes. A typical transaction would follow a process similar to this:

1. Open the transaction using Connection.BeginTransaction().


2. Enlist statements or stored procedure calls in the transaction by setting the
Command.Transaction property of the Command objects associated with them.
3. Commit or roll back the transaction using Transaction.Commit() or Transaction.Rollback().

OLE DB Transactions

All provider specific connections have their own transaction handling variations. In this section,
we will see the case of an OLE DB connection. The OLE DB data provider provides transaction
functionality through the following classes and members:

Class Member Function


OleDbConnection BeginTransaction Open a new transaction.
OleDbCommand Transaction Enlist the command associated with the object in an
open transaction.
OleDbTransaction Begin Create a nested transaction, to enable a partial
rollback.
OleDbTransaction Rollback Roll back a transaction.
OleDbTransaction Commit Commit a Transaction

P a g e | 59
The OLE DB data provider has a Begin() method on the OleDbTransaction object. This allows to
perform multiple transactions on a single connection, but you must remember to explicitly commit
or rollback each one.

Example:
The following code snippet shows a sample transaction based on an OLEDB provider. The
complete version of the code is left as an exercise.
Private Sub btnUpdateCommand_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnUpdateCommand.Click

If Me.OleDbConnection1.State <> ConnectionState.Open Then


Me.OleDbConnection1.Open()
End If

Dim tr As OleDbTransaction

Try
' Start a transaction.
tr = OleDbConnection1.BeginTransaction()

' Insert here database processing code.


comm.Connection = Me.OleDbConnection1 'Some connection should be ‘
used
Dim sql As String

sql = "Update Employees Set FirstName = '" & txtFName.Text _


& "',LastName = '" & txtLName.Text & "', Title ='" & _
txtTitle.Text & "' where EmployeeID = " & _
Convert.ToInt32(txtEmpId.Text)

'.... continue with other commands

comm.CommandType = CommandType.Text
comm.CommandText = sql
comm.ExecuteNonQuery()

' If we get here, we can confirm all changes.


tr.Commit()
Catch ex As Exception
' Display an error message, and roll back all changes.
tr.Rollback()
MessageBox.Show(ex.Message)
End Try

'...
End Sub

P a g e | 60
Concurrency control and Conflict Resolution (Data Validation)
Concurrency control
In VB.NET, the basic mechanism by which you control update conflicts is by using Isolation
Levels on transactions.Isolation levels are used by transactions to determine how restrictive the
transaction is in regards to its isolation behavior. The more restrictive the isolation level, the more
stringently the data affected by the transaction is isolated from other transactions. Most databases
enforce isolation by means of locking; you should double-check what method your targeted DBMS
uses. The tradeoff is between performance and concurrency— the more locks the system has to
maintain, the more likely it is that there will be conflicts and slowdowns as different processes try
to access the same resources.
The following is a list of the isolation levels supported in ADO.NET, which are commonly used.
The isolation levels are listed from least restrictive to most restrictive. They are defined in the
IsolatioLevel Enumerated type.
Property Name Description

Unspecified A different isolation level than the one specified is being used, but the
level cannot be determined.

ReadUncommitted A dirty read is possible, meaning that no shared locks are issued and no
exclusive locks are honored.

ReadCommitted Shared locks are held while the data is being read to avoid dirty reads,
but the data can be changed before the end of the transaction, resulting
in non-repeatable reads or phantom data.

RepeatableRead Locks are placed on all data that is used in a query, preventing other
users from updating the data. Prevents non-repeatable reads but
phantom rows are still possible. Phantom rows are new rows added by
other transactions satisfying the query applied by some transaction
previously.

Serializable A range lock is placed on the data set, preventing other users from
updating or inserting rows into the dataset until the transaction is
complete.

The SQL Server, Oracle, and OLE DB data providers all default to the ReadCommitted isolation
level. If you think ReadCommitted will not provide the isolation level you want for a given
transaction, you can use the Transaction.IsolationLevel property to specify a different level. You
should think very carefully about changing this setting, though, and perform adequate testing to
ensure that the change gives you the behavior that you want without negative side effects like data
inconsistency on one hand or concurrency issues on the other.

Example: the following example issues a Serializable Isolation Level

Dim tr As OleDbTransaction

P a g e | 61
Try
' Start a transaction.
tr = cn.BeginTransaction(IsolationLevel.Serializable)
' Insert here database processing code.
' If we get here, we can confirm all changes.
tr.Commit()
Catch ex As Exception
' Display an error message, and roll back all changes.
tr.Rollback()
MessageBox.Show(ex.Message)
End Try

Resolving Update Conflicts (Validation)


In this section, we will see how you can resolve the unavoidable conflicts that occur in all multiuser
systems. If records are locked by certain users, updates issued by other users may not be fully
successful. However, there might be some rows that could be successfully updated. On the rows that
cou ld n’t be updated a conflict inform ation can be retrieved using the associated D ataA dapter and
DataSet(DataTab le + D ataR ow ) ob jects. B y d efau lt, if an U pdate com m and finds a conflict and can’t
process a row, it throws an exception, skipping all the remaining rows. This means that you should
alw ays protect an U pdate com m and w ith a T ry… E nd T ry b lock:
Try
da.Update(ds, "Employee")
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try

This default behavior makes little sense because you might end up with some rows (all those preceding
the conflicting one) sent to the database correctly and others (those that follow the conflicting one) that
aren’t sent, even if they w ou ld n’t raise any conflict. In m ost cases, you w ant to try the update operation
on all the rows in the DataTable instead of stopping the operation at the first row that fails to update.
Y ou can d o this b y sim p ly setting the D ataA dapter’s C ontinu eU pdateO nE rror prop erty to T ru e. In this
case, you can test w hether one or m ore row s failed to update b y checking the D ataS et’s HasChanges
property:

da.ContinueUpdateOnError = True
da.Update(ds, "Authors")
If ds.HasChanges() Then
' One or more rows failed to update.
End If
You can get more granular control over what happens when an update is attempted by trapping the
RowUpdated event. This event lets you detect the conflict and decide to continue the update operation
with the remaining rows if possible.

Handling the RowUpdated Event


When an Update command is issued, the DataAdapter object fires an event called RowUpdated, when
an inserted, modified, or deleted row in the table being updated.
Private Sub OleDbDataAdapter1_RowUpdated(ByVal sender As System.Object, _
ByVal e As System.Data.OleDb.OleDbRowUpdatedEventArgs) Handles _
OleDbDataAdapter1.RowUpdated
… …
End Sub
The object passed as the second argument (e) of the RowUpdated event exposes the following
properties:

P a g e | 62
 StatementType (an enumerated type that specifies the type of command: insert, delete, or
update);
 Command (the ADO.NET Command object sent to the database);
 Row (the DataRow being updated); TableMapping (the DataTableMapping object used for the
update operation);
 RecordsAffected (the number of records affected by the update operation);
 Errors (the collection of errors generated by the .NET Data Provider during the update
operation); and
 Status (an enumerated value that specified how to handle the current row; can be Continue,
ErrorsOccurred, SkipCurrentRow, or SkipAll- RemainingRows).
The key value to test from inside the handler of the RowUpdated event is the RecordsAffected property.
Any value less than 1 in this property means that the command failed and that there is an update conflict.
This is the usual sequence of operations you perform inside a RowUpdated event handler:
1. If the Status property is equal to Continue and the value of the RecordsAffected property is 1, the
update operation was successful. In most cases, you have little else to do, and you can exit the event
handler.
2. If the Status property is equal to ErrorsOccurred, you can check the Errors property to understand
what went wrong. Frequent causes of errors are violations of database constraints or referential integrity
rules, such as a duplicated valu e in a prim ary key or a uniqu e colu m n or a foreign key that doesn’t point
to any row in the parent table.
3. If you get a System.Data.DBConcurrencyException exception, it means that the WHERE clause in
the SQL command failed to locate the row in the data source. What you do next depends on your
application’s business logic. Typically, you test the StatementType property to determine whether it
was an insert, delete, or update operation; in the last two cases, the conflict is likely caused by another
user w ho deleted or m odified the record you’re trying to delete or update.
4. In all cases, you must decide whether the update operation should continue. You can set the Status
property to Continue or SkipCurrentRow to ignore the conflict for now, or SkipAllRemainingRows
to end the update operation without raising an error in the application. You can also leave the value set
to ErrorsOccurred, in which case the Update method is terminated right away and an exception is
thrown to the main application.

Displaying Conflicting Rows


In the first strategy for managing conflicts, you don’t even try to reconcile them and lim it your actions to
just displaying the records that failed the update operation. This strategy can be implemented quite simply,
as this code demonstrates: (Consider that the LastName field is set by a constraint not to be NULL)

Private Sub btnUpdateDS_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles btnUpdateDS.Click

' Ensure that conflicting rows don’t throw an exception.


OleDbDataAdapter1.ContinueUpdateOnError = True
'First update the changes
OleDbDataAdapter1.Update(DsEmployees1)
'then check for conflicts and desplay them on the grid
CheckConflicts()

End Sub

Sub CheckConflicts()
' Send changes to the database, exit if no update conflicts.
OleDbDataAdapter1.Update(DsEmployees1, "Employees")

P a g e | 63
If Not DsEmployees1.HasChanges Then Exit Sub
' If we get here, there’s at least one conflicting row.
Dim dt As DataTable = DsEmployees1.Tables("Employees")
' Here’s a simple way to evaluate the number of conflicting rows.
Dim rowCount As Integer = dt.GetChanges().Rows.Count
MessageBox.Show(rowCount & " rows failed to update correctly")
' Mark all conflicting rows with the proper error message.
For Each dr As DataRow In dt.Rows
If dr.RowState = DataRowState.Added Then
dr.RowError = "Failed INSERT operation"
ElseIf dr.RowState = DataRowState.Modified Then
dr.RowError = "Failed UPDATE operation"
ElseIf dr.RowState = DataRowState.Deleted Then
dr.RowError = "Failed DELETE operation"
' Undelete this record, else it wouldn’t show in the table.
dr.RejectChanges() 'by default AcceptChanges is invoked
End If
Next

DataGrid1.DataSource = dt

End Sub

Figure 5.18. Marking conflicting rows with an error message

P a g e | 64

Вам также может понравиться