Directory listing of http: uap.unnes.ac.id ebook biblebook Visual Basic 6 com & Library Books

17
C H A P T E R

Building Your
Own Bound
Controls









In This Cha pter
Building class o bjects
Building user co ntro ls

I


n this c hapter, I’ll sho w yo u ho w to build yo ur o wn COM
c o mpo nents that c an be bo und to a data so urc e. I’ll also
c o ver ho w to c reate yo ur o wn data so urc e, whic h c an be used
in plac e o f the ADO Data Co ntro l.

Introducing Data Sources
and Consumers
In the ADO wo rld, everything c an be c lassified into o ne o f
two gro ups: data so urc es and data c o nsumers. A data so urce
pro duc es data that c an be read by a data c o nsumer. A data
co nsume r may update data pro vided by a data so urc e. The
tec hnique used to c o nnec t the data so urc e to the data c o nsumer is kno wn as data binding. This is the same tec hnique
that yo u use to bind a text bo x c o ntro l ( data c o nsumer) to
the ADO Data Co ntro l ( data so urc e) .
Data so urc es and data c o nsumers are just COM o bjec ts that
suppo rt a few spec ial pro perties and events. COM o bjec ts c an
take the fo rm o f Ac tiveX c o ntro ls, Ac tiveX DLLs, and Ac tiveX
EXEs. The fo rm yo u c ho o se depends o n ho w yo u want yo ur
o bjec ts to wo rk. The same princ iples o f binding apply equally
to all three types o f COM c o mpo nents.


Implementing data
binding









350

Part IV ✦ COM + Transactions, and M essage Queues

Data sources
A data so urc e is respo nsible fo r generating an ADO Recordset o bjec t, whic h is
ac c essed by a data c o nsumer. A c o mmo n example o f a data so urc e in Visual Basic is
the ADO Data Co ntro l. While yo u might think that the ADO Data Co ntro l is very c o mplic ated, it really isn’t. I’ll sho w yo u ho w to build o ne later in this c hapter, in the sec tio n c alled “Building a Data So urc e”.

A data so urc e has two key elements: the DataSourceBehavior pro perty and the
GetDataMember event. When the DataSourceBehavior pro perty has a value o f
vbDataSource (1), the o bjec t bec o mes a data so urc e. The GetDataMember event will
be triggered whenever the data so urc e needs an o bjec t po inter to the Recordset
o bjec t. Whenever the c urrent rec o rd in the Recordset o bjec t c hanges, the data c o nsumer will be no tified and it c an update its info rmatio n.
The data so urc e has the o ptio n o f making mo re than o ne rec o rdset available to a
data c o nsumer. The DataMember pro perty is used to identify the spec ific rec o rdset
that the data c o nsumer wants to ac c ess. This value is passed to the o bjec t using
the GetDataMember event. If yo ur data so urc e o nly returns a single Recordset
o bjec t, then this pro perty c an be igno red.

Data consumers
A data c o nsumer rec eives data generated by a data so urc e. It do esn’t deal with the
Recordset o bjec t direc tly, but rather it identifies o ne o r mo re fields o f data that it
wants to ac c ess and the pro perties that will rec eive it. Then, as the c urrent rec o rd
po inter in the Recordset mo ves, the data so urc e will assign the updated data to
the spec ified pro perties in the data c o nsumer.
Data c o nsumers c o me in two flavo rs: simple and c o mplex. A simple data co nsume r
binds o nly a single pro perty to a data so urc e, while a co mple x data co nsume r c an
bind multiple pro perties to a data so urc e. The type o f data c o nsumer is identified by

the DataBindingBehavior pro perty. A value o f vbSimpleBound (1) means that the
o bjec t has o ne pro perty bo und to the data so urc e, while a value o f vbComplexBound
(2) means that the o bjec t has multiple pro perties bo und to the data so urc e.
After selec ting the type o f data c o nsumer, yo u need to adjust the attributes fo r
eac h o f the pro perties yo u want to bind to the data so urc e. This invo lves using the
Pro c edure Attributes dialo g bo x to mark the pro perty as data bo und. If yo u’re no t
familiar with this to o l, see “Setting Pro perty Attributes,” later in this c hapter.
While a simple data c o nsumer c an spec ify the nec essary binding info rmatio n direc tly
in the o bjec t’s pro perties, a c o mplex data c o nsumer c an’t. It uses the DataBindings
c o llec tio n and the DataBinding o bjec t to ho ld the definitio ns. The DataBinding
o bjec t c o ntains all o f the pro perties that wo uld have been used in the o bjec t itself
had the o bjec t been a simple data c o nsumer. Thus, yo u need o ne DataBinding
o bjec t fo r eac h pro perty yo u wish to bind. The DataBindings c o llec tio n ho lds the
set o f DataBinding o bjec ts fo r the data c o nsumer.

Chapter 17 ✦ Building Your Own Bound Controls

A Brief Introduction to COM Components
Many database applic atio ns, whic h are written as a series o f large pro grams, c o uld
benefit fro m rewriting them to use COM (c o mpo nent o bjec t mo del) c o mpo nents.

COM c o mpo nents are ideal fo r iso lating c o mmo nly used func tio ns fro m the pro grams that use them. Yo u c an use them to ho ld yo ur applic atio n lo gic , suc h as ho w
to validate a partic ular data element, o r yo u c an use them to ho ld yo ur database
lo gic , suc h as ho w to retrieve a set o f info rmatio n fro m the database.
By iso lating c o mmo nly used ro utines away fro m yo ur main pro grams, yo u make it
easier to update yo ur applic atio n. Sinc e COM c o mpo nents live in files external to
yo ur pro gram’s EXE file, yo u c an replac e o ne c o mpo nent witho ut nec essarily affec ting the o thers. This will let yo u replac e o ne small file, rather than replac ing all o f
the pro gram files that make up yo ur applic atio n.

What is a COM component?
A COM c o mpo nent is an o bjec t mo dule that c o ntains exec utable c o de that c an be
dynamic ally lo aded into memo ry at runtime. Co mmunic atio n with a COM c o mpo nent fo llo ws a fairly stric t set o f rules, the details o f whic h a Visual Basic pro grammer really do esn’t have to wo rry abo ut. The Visual Basic pro grammer o nly has to
wo rry abo ut pro perties, metho ds, and events that fo rm the interfac e to the COM
c o mpo nent.
Rec all that COM c o mpo nents c o me in three flavo rs: Ac tiveX DLLs, Ac tiveX EXEs,
and Ac tiveX Co ntro ls. Every Visual Basic pro grammer is familiar with Ac tiveX c o ntro ls, whic h are plac ed o n their fo rms to perfo rm vario us func tio ns. Ac tiveX DLLs
(Dynamic Linking Libraries) and Ac tiveX EXEs (Exec utables) are really just a series
o f o ne o r mo re Visual Basic Class mo dules that are c o mpiled into a single file.
The key differenc e between an Ac tiveX c o ntro l and Ac tiveX DLLs and EXEs is that a
c o ntro l has a visible presenc e that c an be inc luded o n a Visual Basic fo rm. Ac tiveX
DLLs and EXEs are built using the Visual Basic Class mo dules, while an Ac tiveX

c o ntro l is built using a UserControl mo dule.

Using class modules
Class mo dules are used to build bo th Ac tiveX DLLs and Ac tiveX EXEs. Whic h o f
these yo u c ho o se depends o n ho w yo u plan to use them. The c o de in an Ac tiveX
DLL runs inside yo ur pro gram’s address spac e and respo nds quic ker to pro c essing
requests than an Ac tiveX EXE. An Ac tiveX EXE runs independently o f yo ur pro gram
and need no t reside o n the same c o mputer. This allo ws yo u to spread yo ur pro c essing o ver multiple c o mputers.
A Class mo dule is just a template fo r an o bjec t. It desc ribes the public pro perties,
metho ds, and events that o ther pro grams will use, and it c o ntains the c o de and lo c al
data sto rage definitio ns that are used to respo nd to vario us pro c essing requests.

351

352

Part IV ✦ COM + Transactions, and M essage Queues

Pro pe rtie s appear to the user as a variable that is part o f the o bjec t. They are implemented as either a public mo dule level variable that is visible to the users o f the
o bjec t o r as a spec ial ro utine that is c alled when yo u want to return o r set a pro perty value. Pro perty values are returned using the Property Get statement, whic h

is equivalent to the Function statement. The Property Set statement is used to
assign o bjec t values to a pro perty, while the Property Let is used to assign values
to all o ther types o f variables. While it is legal to use a set o f parameters with the
Property statements, yo u sho uld make the Pro pertyGet and Let statements have
the same parameter list.
Me tho ds are no rmal func tio ns and subro utines that are used to perfo rm ac tio ns
using info rmatio n in the o bjec t. These ro utines must be dec lared as Public in o rder
to be ac c essed by the o bjec t’s user. Otherwise, they may o nly be c alled by o ther
ro utines in the o bjec t itself.
Eve nts are subro utines external to the o bjec t that c an be c alled fro m within the
o bjec t. The subro utine header must be inc luded in the Class mo dule in o rder to
define the parameters that may be passed to the subro utine, while the ac tual subro utine will be c o ded by the o bjec t’s user and will reside in the user’s pro gram.
Tip

Eventless: Even though you have the ability to use events in your class m odule,
you shouldn’t use them , because they lim it the usefulness of your objects.

Persistable objects
It is o ften desirable to c reate o bjec ts that have a memo ry o f their pro perty values.
This means that while yo u run a pro gram, yo u c an c reate an o bjec t and save its values so that the next time yo u run the pro gram, tho se values will be resto red.

Tip

Queuing for bytes: When using m essage queuing, it is im portant for you to m ake
any objects you send persistent. If you don’t, you w ill lose your data w hen the
receiving program re-creates your object (see Chapter 19 for m ore inform ation
about m essage queuing).

Persistenc e is managed tho ugh the PropertyBag o bjec t. When yo u c reate an
instanc e o f the o bjec t fo r the first time, yo u must pro vide initial values fo r eac h o f
the pro perties. As part o f the pro c ess o f destro ying the o bjec t, yo u c an save the
pro perty values into the PropertyBag o bjec t. Then when the o bjec t is re-c reated,
yo u c an resto re the pro perty values saved in the PropertyBag, whic h means that
the o bjec t has all o f the same values that it had befo re it was destro yed.
Co nsider fo r a mo ment ho w Visual Basic implements Ac tiveX c o ntro ls. While in
design mo de, VB ac tually c reates an instanc e o f the c o ntro l and lets yo u manipulate
its pro perties thro ugh the Pro perties windo w. Then, when yo u go to run the pro gram,
the design time instanc e o f the c o ntro l is destro yed, but befo re it is destro yed, it
saves a c o py o f its pro perties in the PropertyBag.

Chapter 17 ✦ Building Your Own Bound Controls


When yo u run the pro gram, a run-time instanc e o f the c o ntro l is c reated, whic h
reads its pro perty settings fro m the PropertyBag. All o f yo ur design time settings
are present in the new instanc e o f the c o ntro l, so the c o ntro l c an draw itself o n the
fo rm in the pro per lo c atio n, as dic tated by the Left, Top, Width, and Height pro perties. This also means that the rest o f the pro perty values are available so the c o ntro l sho uld behave as per yo ur design.

Class module properties
Table 17-1 lists the internal pro perties fo r a c lass o bjec t. These pro perties determine ho w the o bjec t will behave. No te that these pro perties will no t be visible to
the user, but merely determine so me o f the c apabilities o f yo ur o bjec t.

Table 17-1
Properties for a Class M odule
Property

Description

DataBindingBehavior

An enum erated data type w hich can be vbSimpleBound
(1), m eaning that only a single property can be bound;

vbComplexBound (2), m eaning that m ultiple properties
can be bound; or vbNone (0), m eaning that the object isn’t
a data consum er.

DataSourceBehavior

An enum erated data type w hich can be vbDataSource (1),
m eaning the object w ill act as a data source; or vbNone (0),
m eaning the object isn’t a data source.

Instancing

An enum erated data type w hich describes how an
object w ill be reused. A value of Private (0) m eans that
even though your object m ay have Public m em bers,
no program s outside your current project can access it.
PublicNotCreatable (1) m eans that other program s
can use this object but can’t create it. MultiUse (5)
m eans that other program s can create and use this object.
GlobalMultiUse (6) is identical to MultiUse, but the

properties and m ethods of this class can be used w ithout
explicitly creating an instance of the object first.

Persistable

An enum erated data type that allow s you to keep property
values betw een instances. If you set this property to
Persistable, additional events w ill be available in your
class m odule to initialize, save, and restore property values.
NotPersistable im plies that the object’s properties w ill be
reinitialized each tim e an instance of the object is created.

353

354

Part IV ✦ COM + Transactions, and M essage Queues

Class module property routines
When yo u set the DataBindingBehavior pro perty to vbComplexBound (2), the
fo ur pro perty ro utines desc ribed belo w will auto matic ally be added to yo ur c lass
o bjec t to handle the binding issues.

Public Property Get DataSource( ) As DataSource
The DataSource Propety Get ro utine is used to return the c urrent data so urc e.

Public Property Set DataSource(ByVal objDataSource As DataSource)
The DataSource Property Set ro utine is used to assign a new value to data
so urc e, where objDataSource is an o bjec t referenc e to a data so urc e.

Public Property Get DataM ember( ) As DataM ember
The DataMember Property Get ro utine is used to return the c urrent data member.

Public Property Let DataM ember(ByVal DataM ember As DataM ember)
The DataMember Property Let ro utine is used to assign a new data member to
the o bjec t, where DataMember is an o bjec t referenc e to a data member.

Class module events
By default, a Class mo dule has two events: Initialize and Terminate, whic h are
c alled when the o bjec t is c reated and destro yed. Ho wever, if yo u make the o bjec t a
data so urc e, the GetDataMember event is also inc luded.

Event GetDataM ember(DataM ember As String, Data As Object)
The GetDataMember event is triggered when a user requests a rec o rdset by
spec ifying a value fo r DataMember. No te that this event is present o nly when the
DataSourceBehavior pro perty is set to vbDataSource.

DataMember is a String value that c o ntains the name o f the data member that the
event sho uld return.
Data is an o bjec t referenc e that yo u must return c o ntaining a Recordset o bjec t
asso c iated with the DataMember value spec ified.

Event Initialize( )
The Initialize event is triggered when a new instanc e o f the o bjec t is c reated.
Yo u sho uld initialize yo ur lo c al variables and allo c ate any mo dule level o bjec ts that
yo ur o bjec t will be using.

Chapter 17 ✦ Building Your Own Bound Controls

Event InitProperties( )
The InitProperties event is triggered when a new instanc e o f the o bjec t is c reated.
Yo u sho uld use this ro utine to initialize pro perties, rather than the Initialize
event, to avo id c o nflic ts that may o c c ur when using the Initialize event and the
ReadProperties event.

Event ReadProperties(PropBag As PropertyBag)
The ReadProperties event is triggered when an o ld instanc e o f an o bjec t needs
to resto re its pro perties, where PropBag is an o bjec t referenc e to a PropertyBag
o bjec t, whic h is used to sto re the pro perty values.

Event Terminate( )
The Terminate event is triggered when the o bjec t is abo ut to be destro yed. Yo u
sho uld set all o f the o bjec t variables that still exist to Nothing, so that yo u c an
rec laim the memo ry and o ther reso urc es they are using. If yo u do n’t do this, the
o bjec ts will remain in memo ry until the user pro gram fo r an Ac tiveX DLL o r the
Ac tiveX EXE ends.

Event WriteProperties(PropBag As PropertyBag)
The WriteProperties event is triggered befo re a persistent o bjec t is destro yed. In
this event, yo u must use the PropertyBag o bjec t to save the values o f yo ur pro perties so that later they may be resto red using the ReadProperties event. PropBag
is an o bjec t referenc e to a PropertyBag o bjec t, whic h is used to sto re the pro perty
values.

The PropertyBag object
The PropertyBag o bjec t c o ntains the info rmatio n that needs to be saved between
instanc es o f an o bjec t. It wo rks with the InitProperties, ReadProperties,
and WriteProperties events in the Class mo dule and UserControl mo dule.
The so le pro perty fo r the PropertyBag o bjec t is Contents, whic h is a Byte()
c o ntaining the data that is sto red in the PropertyBag.

Function ReadProperty(Name As String, [DefaultValue]) As Variant
The ReadProperty metho d is used to retrieve a pro perty value fro m the pro perty
bag.

Name is a String c o ntaining the name o f the pro perty value sto red in the pro perty
bag. DefaultValue is a Variant c o ntaining the default value o f the pro perty.

355

356

Part IV ✦ COM + Transactions, and M essage Queues

Sub WriteProperty(Name As String, Value, [DefaultValue])
The WriteProperty metho d is used to sto re a pro perty value in the pro perty bag.

Name is a String c o ntaining the name o f the pro perty value sto red in the pro perty
bag.
Value is a Variant c o ntaining the value o f the pro perty.
DefaultValue is a Variant c o ntaining the default value o f the pro perty.
Caution

Default consistently: You m ust specify the sam e value for DefaultValue in the
ReadProperty and the WriteProperty m ethods, since the property value is
stored only w hen it is different from the specified default value. By doing this,
Microsoft reduces the am ount of data you need to store in the property bag.
How ever, if you’re not careful, you can get different property values each tim e you
save and restore an object.

Building a Data Source
The c lassic data so urc e that everyo ne builds when c reating the first data so urc e is
a c lo ne o f the ADO Data Co ntro l. It’s an ideal c o ntro l to build, sinc e it o ffers a visual
c o mpo nent that the user c an interac t with, and no t muc h c o de is nec essary beyo nd
what is required to manage the DataBindings c o llec tio n. My implementatio n o f
this c o ntro l is c alled the DataSpinner c o ntro l (see Figure 17-1).
The DataSpinner c o ntro l c o nsists o f two c o mmand butto ns and a text bo x. The
c o mmand butto ns are used to sc ro ll fo rward and bac kward thro ugh the data in the
c o ntro l, while the text bo x simply represents a way to display info rmatio n in the
c o ntro l.
Note

UserControls vs. Classes: All of the steps described here apply equally w hen creating a UserControl data source or a Class m odule data source.

Figure 17-1: Designing the
DataSpinner control

Chapter 17 ✦ Building Your Own Bound Controls

M odule-level declarations
Befo re I dig into the c o de fo r the DataSpinner c o ntro l, I want to go o ver the mo dulelevel dec laratio ns (see Listing 17-1). Of the six variables dec lared, fo ur are used to
ho ld pro perty values. The ConnectionString is sto red in cn; Recordsource is
kept in ds; UserName is sto red in us; and Password is sto red in pw. The o ther two
variables ho ld a c o nnec tio n to the database server and the c urrent rec o rdset that
supplies the bo und data.

Listing 17-1: M odule-level declarations in DataSpinner
Private
Private
Private
Private
Private
Private

cn
db
ds
pw
rs
us

As
As
As
As
As
As

String
ADODB.Connection
String
String
ADODB.Recordset
String

Event Click()
Event Scroll()

Two events are also defined. The Click event is triggered whenever so meo ne c lic ks
in the text bo x, while the Scroll event is triggered whenever so meo ne presses
either the prev o r next butto n.

Binding data
Sinc e the DataSpinner c o ntro l is a data so urc e, yo u must set the DataSource
Behavior to vbDataSource (1) in the UserControl pro perties. This will expo se
the names o f the c o lumns retrieved fro m the database and allo w them to be bo und
to the c o ntro l. This info rmatio n is gathered fro m the GetDataMember event (see
Listing 17-2).

Listing 17-2: The UserControl_GetDataM ember Event in
DataSpinner
Private Sub UserControl_GetDataMember _
(DataMember As String, Data As Object)
If db Is Nothing Then
If Len(cn) > 0 And Len(us) > 0 Then
Set db = New ADODB.Connection
Continued

357

358

Part IV ✦ COM + Transactions, and M essage Queues

Listing 17-2 (continued)
db.Open cn, us, pw
Set rs = New ADODB.Recordset
rs.Open ds, db, adOpenStatic, adLockPessimistic
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst
End If
End If
End If
Set Data = rs
End Sub

The GetDataMember event is c alled whenever Visual Basic needs a referenc e to
the underlying Recordset o bjec t. This allo ws the c aller to find o ut the names o f the
c o lumns returned at design time o r to retrieve the c urrent ro w o f info rmatio n to be
displayed in the bo und c o ntro ls.
This event will also be c alled eac h time the DataMember pro perty in the c o ntro l is
c hanged. Typic ally, yo u wo uld return a different Recordset based o n the value o f
DataMember argument: ho wever, in this c ase, I’m always go ing to return the same
Recordset no matter what value is supplied in the DataMember argument.
I start this event by c hec king to see if the mo dule-level variable db is Nothing. If it
is, it means that I haven’t o pened a c o nnec tio n to the database yet. Then I c an verify that so meo ne entered a c o nnec tio n string ( cn) and a user name ( us) befo re
o pening a database c o nnec tio n.
Onc e the c o nnec tio n is o pen, I c an o pen the Recordset o bjec t. In this c ase, I
c ho o se to always spec ify a static c urso r and pessimistic lo c king. Ho wever, I c o uld
have easily c reated pro perties fo r these values also . Then I do a MoveFirst to
ensure that the c urrent rec o rd po inter is po inting to the first rec o rd in the
Recordset.
At the end o f the ro utine, I’ll return an o bjec t po inter to the Recordset o bjec t using
the Data parameter. If I c o uldn’t o pen the Recordset, then the rs will have a value o f
Nothing and the pro gram trying to bind to the c o ntro l will get an erro r. Otherwise,
the info rmatio n c o ntained in rs will be used in the binding pro c ess.

Chapter 17 ✦ Building Your Own Bound Controls

M oving through the recordset
Onc e the c o ntro l has been initialized, yo u write yo ur pro gram just like yo u wo uld
no rmally write a Visual Basic pro gram. Fo r instanc e, in Listing 17-3, the c o de yo u
see wo uld be very typic al o f ro utine to mo ve c urrent rec o rd po inter to the next
rec o rd in a rec o rdset.

Listing 17-3: The Command2_Click event in DataSpinner
Private Sub Command2_Click()
If Not rs Is Nothing Then
rs.MoveNext
If rs.EOF Then
rs.MoveFirst
End If
RaiseEvent Scroll
End If
End Sub

The o nly part o f the c o de that is different is the RaiseEvent statement. In this c ase,
the RaiseEvent statement is used to trigger the Scroll event that was dec lared in
the mo dule-level dec laratio ns. This event allo ws so meo ne using this c o ntro l to
detec t when the c urrent rec o rd po inter has c hanged.

Exporting recordset information
A pro grammer using this c o ntro l might find it useful to lo o k at the underlying
Recordset o bjec t fro m time to time. The easiest way to handle this is to c reate a
Property Get ro utine, like the o ne sho wn in Listing 17-4. This ro utine merely
returns an o bjec t referenc e to rs. Bec ause I do n’t want anyo ne c hanging the o bjec t,
I didn’t inc lude a Property Set ro utine. This makes the Recordset pro perty reado nly, and the pro grammer using the c o ntro l c an’t substitute their rec o rdset fo r the
o ne in the c o ntro l.

359

360

Part IV ✦ COM + Transactions, and M essage Queues

Listing 17-4: The Recordset Property Get routine in
DataSpinner
Public Property Get Recordset() As ADODB.Recordset
Set Recordset = rs
End Property

Using the DataSpinner control
Adding the DataSpinner c o ntro l to yo ur applic atio n is merely a matter o f dragging
the c o ntro l o nto yo ur fo rm and setting a few pro perties. In this c ase, I set the
Connection pro perty to provider=sqloledb;data source=athena;initial
catalog=VB6DB and the RecordSource pro perty to Select * From Customers.
This will return all o f the rec o rds in the Custo mer table.
The Scroll event is a go o d plac e to display the AbsolutePosition pro perty o f
the underlying Recordset (see Listing 17-5). No te that I use the Recordset pro perty desc ribed previo usly in this c hapter under “Expo rting Rec o rdset Info rmatio n”
to ac c ess this info rmatio n.

Listing 17-5: The DataSpinner1_Scroll event in Customer
Viewer
Private Sub DataSpinner1_Scroll()
DataSpinner1.Text = _
FormatNumber(DataSpinner1.Recordset.AbsolutePosition, 0)
End Sub

Building a Data Consumer
To go alo ng with the data so urc e I just built, I c reated a simple data c o nsumer
c alled AddressDisplay (see Figure 17-2). The c o ntro l is c o mpo sed o f six text bo xes
and six label c o ntro ls. Eac h text bo x has its o wn unique pro perty. Assigning a value
to any o f these pro perties simply displays the value in the appro priate text bo x.

Chapter 17 ✦ Building Your Own Bound Controls

Figure 17-2: Designing the
AddressDisplay control

Exposing properties
Eac h text bo x o n the c o ntro l has a Property Get ro utine and Property Let ro utine that manage the info rmatio n asso c iated with eac h c o ntro l. Listing 17-6 sho ws
a typic al Property Get ro utine that retrieves the value fro m the text bo x that is
used to display the Name field fro m the database.

Listing 17-6: The CName Property Get routine in
AddressDisplay
Public Property Get CName() As String
CName = Text1.Text
End Property

Note

What’s in a name: You m ay be w ondering w hy I nam ed this property CName,
rather than calling it Name after the database field. The reason is sim ple. Each
ActiveX control already com es w ith a property called Name, and you can’t override
this property.

Changing a pro perty is so mewhat mo re c o mplic ated than yo u might expec t. In
the CName Property Let ro utine ( see Listing 17-7) , yo u no tic e that I c all the
CanPropertyChange metho d to determine if I c an c hange the value. This prevents erro rs fro m o c c urring if so meo ne c ho o ses to b ind the c o ntro l to a reado nly Recordset.

361

362

Part IV ✦ COM + Transactions, and M essage Queues

Listing 17-7: The CName Property Let routine in
AddressDisplay
Public Property Let CName(s As String)
If CanPropertyChange(“CName”) Then
Text1.Text = s
PropertyChanged “CName”
End If
End Property

I also use the PropertyChanged metho d to no tify the c o ntro l that this pro perty has
c hanged. This is impo rtant, sinc e it ensures that the c o ntro l kno ws when a pro perty
has c hanged. If the c o ntro l isn’t aware that the pro perty has c hanged, it may no t
pro perly save the pro perty values in the Recordset.
Yo u sho uld c lo sely examine yo ur c o de and the o bjec ts o n yo ur UserControl to make
sure that the value o f the pro perty c an’t be c hanged witho ut c alling the Property
Changed metho d. In the c ase o f this c o ntro l, it is po ssible fo r a user to c hange the
c o ntents o f the text bo x o n the c o ntro l. So I need to inc lude a Change event fo r eac h
text bo x to indic ate that the value o f the pro perty has been c hanged (see Listing 17-8).

Listing 17-8: The Text1_Change event in AddressDisplay
Private Sub Text1_Change()
PropertyChanged “CName”
End Sub

Setting property attributes
In o rder to allo w a pro perty to be bo und to a data so urc e, yo u have to identify
the pro perty as data bo und. To set the attribute o n the pro perty, yo u need to
use the Pro c edure Attributes to o l (see Figure 17-3). To start the to o l, c ho o se
To o ls ➪ Pro c edure Attributes fro m the Visual Basic main menu.
To mark a pro perty as data bo und, selec t the name o f the pro perty in the Name dro pdo wn bo x and press the Advanc ed butto n. This will display a windo w similar to the
o ne sho wn in Figure 17-4. At the bo tto m o f the windo w is the Data Binding sec tio n.

Chapter 17 ✦ Building Your Own Bound Controls

Figure 17-3: Setting
property attributes

Figure 17-4: View ing advanced
procedure attributes

In the Data Binding sec tio n, plac e a c hec k mark in the Pro perty is data bo und c hec k
bo x. This will enable the c hec k bo xes belo w it. Then yo u sho uld c hec k Sho w in
DataBindings c o llec tio n at design time and Pro perty will c all CanPro pertyChange
befo re c hanging c hec k bo xes. This will allo w yo u to bind the pro perty to a data
so urc e at design-time and let Visual Basic kno w that yo u are using the CanProperty
Change metho d in the pro perty ro utines.
Yo u do n’t have to c lo se the windo w after selec ting the info rmatio n fo r a single pro perty. Just selec t a different pro perty in the Name dro p-do wn bo x and set the desired
values. Onc e yo u enter all o f this info rmatio n, yo u c an verify it by adding yo ur c o ntro l to a simple pro gram and displaying the Data Bindings windo w (see Figure 17-5).
If yo u c hec k the This pro perty binds to DataField c hec k bo x in the windo w sho wn
in Figure 17-4, yo u c an bind the pro perty to the c o ntro l’s DataField pro perty.
This means that the pro grammer using yo ur c o ntro l do esn’t have to use the Data
Bindings windo w to bind a field in a data so urc e to this pro perty.

363

364

Part IV ✦ COM + Transactions, and M essage Queues

Figure 17-5: Binding
properties in the Data
Bindings w indow

Tip

Data binding and other stuff too: The Procedure Attributes tool perform s m any
useful functions, in addition to allow ing you to m ark a property as data bound.
You can add a description to each property that w ill show up w hen you view the
com ponent in the Object Brow ser w indow. You can m ark a property as hidden,
assign the property to a specific property page (if you im plem ent custom property
w indow s) and you can assign the property to a specific category so that it can be
separated out in the Properties w indow.

Persisting properties
One o f the impo rtant ho usekeeping duties yo u need to wo rry abo ut in an Ac tiveX
c o ntro l is making sure that the values so meo ne assigns to the c o ntro l at designtime are pro perly saved between develo pment sessio ns, and also available at runtime. This is managed by using the PropertyBag o bjec t (intro duc ed earlier in this
c hapter under “Persistable Objec ts”) and the InitProperties, ReadProperties,
and WriteProperties events.

Initializing properties for the first time
The InitProperties event is triggered the first time a c o ntro l ( o r any o ther persistent Ac tiveX c o mpo nent) is instantiated. Yo u sho uld inc lude c o de in this event
to make sure that all o f the pro perty values are pro perly initialized. In this example, I c ho o se to assign desc riptive values fo r eac h o f the fields in the c o ntro l ( see
Listing 17-9) .
While I c o uld have assigned these values direc tly using the Pro perties windo w fo r
eac h o f the c o ntro ls used in this c o ntro l, I wanted to sho w yo u the types o f things
yo u might do in this event.

Chapter 17 ✦ Building Your Own Bound Controls

Listing 17-9: The UserControl_InitProperties event in
AddressDisplay
Private Sub UserControl_InitProperties()
Text1.Text
Text2.Text
Text3.Text
Text4.Text
Text5.Text
Text6.Text

=
=
=
=
=
=

“CName”
“Street”
“City”
“State”
“Zip”
“CustomerId”

End Sub

Saving property values
When the c o ntro l is destro yed, the WriteProperties event is triggered so yo u c an
save yo ur c urrent pro perty values (see Listing 17-9). A PropertyBag o bjec t is passed
to this event to ho ld all o f the pro perty values. To save the c urrent value o f eac h
pro perty, yo u must c all the WriteProperties event and spec ify the pro perty name,
the pro perty value, and the default value.

Listing 17-9: The UserControl_WriteProperties event
in AddressDisplay
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
PropBag.WriteProperty
PropBag.WriteProperty
PropBag.WriteProperty
PropBag.WriteProperty
PropBag.WriteProperty
PropBag.WriteProperty

“CName”, Text1.Text, “CName”
“Street”, Text2.Text, “Street”
“City”, Text3.Text, “City”
“State”, Text4.Text, “State”
“Zip”, Text5.Text, “Zip”
“CustomerId”, Text6.Text, “CustomerId”

End Sub

If the c urrent value o f the pro perty is different than the default value, it will be
saved in the pro perty bag. Otherwise, the value will be disc arded. While this saves
spac e in the PropertyBag o bjec t, it may c ause pro blems if yo u do n’t use the same
default value c o nsistently.

Reading properties after the first time
The InitProperties event is o nly c alled o nc e, when the c o ntro l is instantiated fo r
the first time. Eac h time after that, the ReadProperties event will be c alled. In this

365

366

Part IV ✦ COM + Transactions, and M essage Queues

event, yo u just need to lo ad the pro perties yo u saved in the WriteProperties
event (see Listing 17-10). As yo u might expec t, yo u need to use the ReadProperty
metho d to retrieve eac h pro perty value fro m the PropertyBag o bjec t.

Listing 17-10: The UserControl_ReadProperties event in
AddressDisplay
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
Text1.Text
Text2.Text
Text3.Text
Text4.Text
Text5.Text
Text6.Text

=
=
=
=
=
=

PropBag.ReadProperty(“CName”, “CName”)
PropBag.ReadProperty(“Street”, “Street”)
PropBag.ReadProperty(“City”, “City”)
PropBag.ReadProperty(“State”, “State”)
PropBag.ReadProperty(“Zip”, “Zip”)
PropBag.ReadProperty(“CustomerId”, “CustomerId”)

End Sub

Note

Initialize ain’t gone: The Initialize event is still present in a persistent com ponent and you should use it to initialize various aspects to the control that need
to be initialized each tim e the control is instantiated. You should save the
ReadProperties and InitProperties events for situations w here you w ant
to keep a m em ory of various property values.

Pulling It All Together
With bo th the Data Spinner and the Address Display c o ntro ls available, it is a simple
matter to c reate a test pro gram (see Figure 17-6). In this c ase, I simply c reated a new
pro gram and added bo th c o ntro ls to the fo rm. I then entered the appro priate values
fo r the Connection, RecordSource, Username, and Password pro perties in the
DataSpinner c o ntro l, and bo und the vario us pro perties o f the AddressDisplay
c o ntro l to the DataSpinner c o ntro l. I also added the c o de fo r the Scroll event to
display the c urrent rec o rd number.

Figure 17-6: Running the Custom er
View er program

Chapter 17 ✦ Building Your Own Bound Controls

Thoughts on Using ActiveX DLLs
Building your ow n COM com ponents isn’t difficult once you have a w orking tem plate to follow. In this chapter I focused on how to create a data source and a data consum er using
ActiveX controls. How ever, the steps I w ent through to expose the properties of a data consum er and returning Recordset inform ation from a data source can be used to build other
types of COM com ponents.
In m any w ays, you’ll find that ActiveX DLLs m ay be even m ore useful in database program m ing than ActiveX controls. After all, ActiveX controls are m uch m ore useful in a regular
Visual Basic program than in an IIS Application. ActiveX DLLs can be used to represent inform ation abstracted from a database rather than just presenting the collection of Fields
from a Recordset object. They also are a convenient place to include application logic that
can be used to validate inform ation in the object or perform useful calculations w ith the
data in the object. ActiveX DLLs are also easy to m igrate to COM+ transactions, a topic that
I’ll explore in Chapter 18.

Summary
In this c hapter yo u learned the fo llo wing:

✦ Yo u c an easily c reate yo ur o wn data so urc es similar to the ADO Data Co ntro l
selec ting the appro priate pro perty values.

✦ Yo u c an build data c o nsumers by c o nfiguring the pro perties o f the o bjec t
using the Pro c edure Attributes windo w.

✦ Yo u c an build COM c o mpo nents using the Visual Basic Class mo dule.
✦ Yo u c an make an Ac tiveX c o ntro l persistable by using the PropertyBag
o bjec t to save and resto re the values fo r eac h pro perty.







367