ActiveX Control Related Objects and Property pages



Objects related to ActiveX control
The following are the objects that are involved in the process of creating an ActiveX control.

¨         UserControl object
¨         AmbientProperties object
¨         Extender object
¨         Constituent control objects

UserControl Object
This is the object used to create a single ActiveX control. Every ActiveX control is consisting of one UserControl object and a set of constituent controls. Just like a From, a UserControl object also has a designer, which allows you to place intrinsic control on the UserControl object.

You have properties, methods, and events for UserControl object. They are discussed later in this chapter.

AmbientProperties Object
This is used to get information from container of ActiveX control.  The properties of AmbientProperties object are the ambient properties of the control.  These properties are read-only.  These properties allow you to determine how you adapt your control according to the capabilities of the container.

Not all ambient properties are standard. Some of them are specific to only a particular container.

AmbientChanged event occurs whenever any of the ambient properties (properties in container) changes. This enables programmer to change control according to the container.

AmbientProperties object is not available in Initialize event.

The following is the list of standard ambient properties.


Property
Meaning
Default value if property is not supported by Container.
BackColor
Color that contains the suggested interior color of the contained control.
 &H80000005
DisplayAsDefault
Returns True if  the control is the default control otherwise false.
 false
DisplayName
The name that the control assigned by developer.
 "".
Font
Contains the suggested font information of the contained control.
 MS Sans Serif 8.
ForeColor
Suggested foreground color of the contained control.
 0x80000008: the system color for window text.
LocaleID
Specifies the language and country of the user
 System locale ID.
Palette
Picture object whose palette specifies the suggested palette for the contained control.

RightToLeft
Indicates the text display direction and control visual appearance on a bi-directional system.
 False.
ScaleUnits
The name of the coordinate units being used by the container.
""
TextAlign
Specifies how text is to be aligned.
 0 - General Align.
UserMode
Specifies if the environment is in design mode or end user mode
 True.
 Table 28.1: Ambient properties of a UserControl.

The following code changes the background color of the text box to the background color of the container whenever background color of the container is changed.

Private Sub UserControl_AmbientChanged(PropertyName As String)
 If PropertyName = "BackColor" Then
      txtNumber.BackColor = Ambient.BackColor
 End If
End Sub
Listing 28.1: Changing BackColor property of text box to BackColor property of user Control.

AmbientChanged event of the UserControl object occurs whenever any of the ambient properties is changed. Ambient object provides access to values of ambient properties.

PropertyName parameter of the AmbientChanged event contains the name of the properties that has been changed in the container.

Extender Object
This object holds properties of the control that are actually controlled by the container of the control rather than by the control itself

The properties, methods, and events of Extender object are provided by the container. So there is no guarantee that all these are supported in all platforms.

You can access extender properties using Extender property of UserControl.

The following is the list of extender properties.

Property
Meaning
Name
Contains the user-defined name of the control.
Visible
Specifies if the control is visible or not.
Parent
Represents the container of the control, such as a form in Visual Basic.
Cancel
Indicates that the control is the Cancel button for the container.
Default
Indicates that the control is the default button for the container.
Container
Represents the visual container of the control.
DragIcon
Picture that specifies the icon to use when the control is dragged.
DragMode
Specifies if the control will automatically drag, or if the user of the control must call the Drag method.
Enabled
Specifies if the control is enabled. This is not present unless the control also has an Enabled property.
Height
Specifies the height of the control in the container’s scale units.
HelpContextID
Specifies the context ID to use when F1 key is pressed being in the control.
Index
Specifies the position in a control array that this instance of the control occupies.
Left
Specifies the position of the left edge of the control to the left edge of the container, specified in the container’s scale units.
TabIndex
Specifies the position of the control in the tab order of the controls in the container.
TabStop
Specifies if Tab will stop on the control.
Tag
Contains a user-defined value.
ToolTipText
Contains the text to be displayed when the cursor stays on the control for more than a second.
Top
Specifies the position of the top edge of the control to the top edge of the container, specified in the container’s scale units.
WhatThisHelpID
Specifies the context ID to use when the What’s This pop-up is used on the control.
Width
Specifies the width of the control in the container’s scale units.

Table 28.2: Extender properties.

The following are the methods provided by Extender object.

¨         Drag
¨         Move
¨         SetFocus
¨         ShowWhatsThis
¨         Zorder

The following are the events provided by Extender object

¨         DragOver
¨         DragDrop
¨         GotFocus
¨         LostFocus

Properties of UserControl object
The following are the properties that are specific to user control object.

Property
Meaning
AccessKey
Returns or sets a string that contains the keys that will act as the access keys (or hot keys) for the control.
Ambient
Returns an AmbientProperties object holding the ambient properties of the container.
ContainedControls
Returns a collection of the controls that were added to the control.
EditAtDesignTime
Returns or sets a value determining if a control can become active during the developer design time
EventsFrozen
If it is set to true, then events of usercontrol are ignored by container
Extender
Returns the Extender object for this control that holds the properties of the control that are kept track of by the container.
ParentControls
Returns a collection containing other controls in parent container.
PropertyPages
Is a string array containing the names of the property pages in the project that are associated with this control.
ContainerHwnd
Returns the window handle (hWnd) of a UserControl’s container.
Parent
Returns a reference to the container object on which the control is sited.
CanGetFocus
Determines whether focus should move to this control or not.
Table 28.3: Properties of User Control.

UserControl Events
The following are the various events of usercontrol object and their description.

Event
When does it occur?
AccessKeyPress
Occurs when user presses one of the accesskeys for the control. It passes the key that is pressed by user.
AmbientChanged
Occurs when an ambient property’s value changes. This passes the name of the property as the only parameter
EnterFocus
This event occurs whenever a constituent control receives focus.
ExitFocus
Occurs whenever focus leaves the control.
GotFocus
Occurs in the constituent control when focus enters it. The EnterFocus event is raised before the GotFocus event.
Hide
Occurs when the object’s Visible property changes to False.
InitProperties
Occurs when a new instance of an object is created.
This allows programmer to initialize new control when it is placed on the form.
ReadProperties
Occurs when loading an old instance of an object that has a saved state. This is used to read the values of the properties. Used for property persistence.
Show
Occurs when the object’s Visible property changes
WriteProperties
Occurs when an instance of an object is to be saved.  This is used to save the values of properties.
AsyncReadProgress
Occurs when more data is available as a result of an AsyncRead method.
AsyncReadComplete
Occurs when the container has completed an asynchronous read request.
HitTest
Occurs when the user moves the mouse over a UserControl object. Only occurs when the Windowless property of the UserControl is set to True and the BackStyle property is set to Transparent.
Initialize
Occurs when an application creates an instance of a user control.
Terminate
Occurs when the instance of the control is about to be destroyed.
Table 28.4: Events of user control object.

Property Pages
Before we started creating ActiveX Control, we had already used a few ActiveX controls.  All of them have Property pages that allow you to change properties of the control.  Now let us create two property pages for our Number control. First one contains a text box to take number from user and changes Value property, Second one contains two text boxes Maximum Length and Minimum Length properties.  A developer using Number ActiveX Control can invoke property pages and change properties.

The best way of creating a property page is using Property Page Wizard. Now having decided how many property pages to have and what to have in each of these property pages, we are ready to use Property Page Wizard.

To invoke property page wizard:

1.      First make Property Page Wizard available to Visual Basic project by selecting  Add-Ins menu and then select Add-In Manager option.
2.      In Add-In Manager dialog box double click on VB 6 Property Page Wizard. You should see Loaded message in Load Behavior column.
3.      Click on Ok.
4.      Then select Add-Ins menu and Property Page Wizard. You will see a series of windows prompting for required information.

The following are the steps to create two property pages and to place Value property in first property page and MinLength and MaxLength properties on the second property page.

1.      When Property Page Wizard is displayed, it first displays Introduction screen.
2.      Click on Next button to move to select the Property Pages page.
3.      Click on Add button.
4.      Enter  ppValue as the name of the page.
5.      Click on Add button again and enter ppLength as the name of second property page.
6.      Click on  Next button to move to Add Properties page.
7.      Available Properties list contains the list of available properties.
8.      Make sure ppValue tab is selected in Available  Property Pages.
9.      Select Value property  and click on > to move the property to ppValue property.
10.  In the same way select ppLength tab and click on >> to place  MinLength and MaxLength properties on ppLength property page.
11.  Click on Finish button to start building property pages.
12.  Invoke ppValue property page and change Caption property to “Value”
13.  Invoke ppLength property page and change Caption property to  “Length”.

Property Page Wizard has created two property pages ( ppValue and ppLength, shown in figure 28.3, and  28.4).

The code that Property Page Wizard has written for ppValue property page is as follows.

Private Sub txtValue_Change()
    Changed = True
End Sub

Private Sub PropertyPage_ApplyChanges()
    SelectedControls(0).Value = txtValue.Text
End Sub

Private Sub PropertyPage_SelectionChanged()
    txtValue.Text = SelectedControls(0).Value
End Sub
Listing  28.1: Code written by property page wizard.
Let us understand the code written by Property Page Wizard. But before we try to do that, we have to understand properties, events of property page.

Changed Property
When this property is set to true, Apply button in the property page will be enabled.  In addition to that, setting it to true calls ApplyChanges event whenever you click on Ok button or move to a different property page.

SelectedControls property
This is a collection that contains the controls that are currently selected on the form. SelectedControls (0) references the control that is currently selected. This is used to get the values for properties of the currently selected instance of the ActiveX control for which property page belongs.

The code written by Property Page Wizard, uses SelectedControls (0) (first selected control) only. If you want to handle all selected controls, you have to modify the code written by wizard.

SelectionChanged Event
This is fired whenever an instance of the ActiveX control is selected for editing properties through property pages.  This event is used to get the values of the properties from selected control (SelectedControls (0)) and assign those values to controls in property pages to enable user to change them.

ApplyChanges Event
This event is fired whenever user is selecting Apply button, selecting Ok button, closing page or shifting to a different page.

The event occurs only when Changed property is set to true,

Now, if you look at the code written by Property Page Wizard, you should be able to understand the code. The code uses all the properties and events that we have discussed. The following is the summary of the code.

¨         Sets Changed property to True, whenever user changes values in txtValue text box, which is meant for Value property.
¨         SelectionChanged event is used to get the value of Value property of the currently selected control (SelectedControls(0)) and put that value in txtValue textbox.
¨         ApplyChanges event is used to write value entered in txtValue textbox into Value property of the currently selected control (SelectedControls (0)).

Code for ppLength property page
The code written by Property Page Wizard for ppLength property page is as follows.

Private Sub txtMaxLength_Change()
    Changed = True
End Sub

Private Sub txtMinLength_Change()
    Changed = True
End Sub

Private Sub PropertyPage_ApplyChanges()
    SelectedControls(0).MaxLength = txtMaxLength.Text
    SelectedControls(0).MinLength = txtMinLength.Text
End Sub

Private Sub PropertyPage_SelectionChanged()
    txtMaxLength.Text = SelectedControls(0).MaxLength
    txtMinLength.Text = SelectedControls(0).MinLength
End Sub
Listing 28.2: Code for ppLength property page.

This code needs no explanation, as it doesn’t differ from the previous code.

Using property pages at the time of designing
Let us see how a developer who is using Number ActiveX control can use Property Pages of Number control.  Here are the steps to test it:

1.      Open testing project (tstNumctrl) project
2.      Invoke Form designer
3.      Select Number1 control and click right button
4.      You should see a new option in popup menu – Properties.
5.      Select Properties option to invoke Property pages.
6.      Property pages window is displayed with two tabs at the top, one for Value property page and another for Length property page.
7.      In Value property page, you will see the value you assigned to Value property of the selected control. As shown in figure 28.5 , the value assigned to Value property is 1000.  So initially you will see 1000.
8.      Change the value to 2000 in property page. It will enable Apply button of the property  page. At this stage, your property Page should be identical to figure 28.5.
9.      Click on Apply to make Value property of Number1 control. Click on Length tab to move to Length property page.

Note: Pressing F4 on the control will invoke Properties Pallette. And selecting Popup Menu -> Properties option will invoke Property pages. This is same for all ActiveX controls.

Data Bound ActiveX Control and Data Repeater



ActiveX Control Interface Wizard
Each ActiveX Control contains an interface – properties, methods, and events.  ActiveX Control Interface Wizard is used to assist the author (creator) of ActiveX Control in creating properties, methods and events.

ActiveX Control interface Wizard can do the following:

¨         Create property procedures for user-defined properties
¨         Map user-defined properties to standard properties of Constituent controls.
¨         Take care of property persistence using ReadProperties and WriteProperties events.

Let us create a new project to understand how to create interface for Number control using ActiveX Control Interface Wizard. Let us call this control as WizNumber.

Here are the steps to create WizNumber, which is same as Number control but built using ActiveX Control Interface Wizard:

1.      Start a new project and select ActiveX Control as the type of the project.
2.      Change Name of the UserControl to WizNumber.
3.      Place a textbox on UserControl

Note: We concentrate on how to use ActiveX Control Interface Wizard and not on how to write code to accomplish the task. So I do not explain how to write code for WizNumber control (because I have already done with Number control in the previous chapters and there is no need to do that again) instead we will understand how we can use Wizard to create interface.

4.      Invoke ActiveX Control Interface Wizard from Add-Ins Menu.  If it is not available, use Add-In Manger to load the Wizard into Visual Basic IDE. Please see the section “Loading Property Page Wizard” in chapter 28 for detail regarding how to add an Add-in into Visual Basic IDE.
5.      Click on Next to skip the Introduction screen.
It pre-selects a list of standard properties, methods, and events that are commonly used. If you do not want them, you can unselect them by selecting unwanted names and clicking < (less than) button.
If you want to select some more from the Available Names, select the name that you want to add and click on > (greater than) button.
6.      Click on Next without unselecting or selecting anything.
7.      Wizard displays Create Custom Interface Members page.
8.      Click on New button to add a member.(Figure 29.1)
9.      In Add Custom Member dialog enter the name of the member and type of the member.
10.  Repeat the process to enter the following members.

Property          Value
MinLength
                        MaxLength
Method                        Clear

Event               InvalidChar

                        InvalidLength


After you have added all members, the Wizard should look like the following.

11.  Click on Next button to move to Set Mapping page, shown in figure 29.3.
Mapping enables user-defined properties to be mapped to standard properties.  Let us map MaxLength property to MaxLength property of textbox. 
12.  Select MaxLength property in Public Name and select Text1 as control and MaxLength as Member.
13.  Repeat the process for Value property. Map it to Text property of textbox. See figure 29.3.
14.  Once mapping is over click on Next to move to Set Attributes page.
15.  Select MinLength property and change the remaining as shown in figure 29.4.
16.  Click on Next button and then click on Finish.

The code written by ActiveX Control Interface Wizard is given in listing 29.1 without any editing. Particularly concentrate on the following:

¨         InitProperties Event
¨         ReadProperties Event
¨         WritePropeties Event
¨         Property Procedures for user-defined properties

'Default Property Values:
Const m_def_BackColor = 0
Const m_def_ForeColor = 0
Const m_def_Enabled = 0
Const m_def_BackStyle = 0
Const m_def_BorderStyle = 0
Const m_def_MinLength = 0
'Property Variables:
Dim m_BackColor As Long
Dim m_ForeColor As Long
Dim m_Enabled As Boolean
Dim m_Font As Font
Dim m_BackStyle As Integer
Dim m_BorderStyle As Integer
Dim m_MinLength As Integer
'Event Declarations:
Event Click()
Event DblClick()
Event KeyDown(KeyCode As Integer, Shift As Integer)
Event KeyPress(KeyAscii As Integer)
Event KeyUp(KeyCode As Integer, Shift As Integer)
Event MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Event MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Event MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Event InvalidChar()
Event InvalidLenth()

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=8,0,0,0
Public Property Get BackColor() As Long
    BackColor = m_BackColor
End Property

Public Property Let BackColor(ByVal New_BackColor As Long)
    m_BackColor = New_BackColor
    PropertyChanged "BackColor"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=8,0,0,0
Public Property Get ForeColor() As Long
    ForeColor = m_ForeColor
End Property

Public Property Let ForeColor(ByVal New_ForeColor As Long)
    m_ForeColor = New_ForeColor
    PropertyChanged "ForeColor"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=0,0,0,0
Public Property Get Enabled() As Boolean
    Enabled = m_Enabled
End Property

Public Property Let Enabled(ByVal New_Enabled As Boolean)
    m_Enabled = New_Enabled
    PropertyChanged "Enabled"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=6,0,0,0
Public Property Get Font() As Font
    Set Font = m_Font
End Property

Public Property Set Font(ByVal New_Font As Font)
    Set m_Font = New_Font
    PropertyChanged "Font"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=7,0,0,0
Public Property Get BackStyle() As Integer
    BackStyle = m_BackStyle
End Property

Public Property Let BackStyle(ByVal New_BackStyle As Integer)
    m_BackStyle = New_BackStyle
    PropertyChanged "BackStyle"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=7,0,0,0
Public Property Get BorderStyle() As Integer
    BorderStyle = m_BorderStyle
End Property

Public Property Let BorderStyle(ByVal New_BorderStyle As Integer)
    m_BorderStyle = New_BorderStyle
    PropertyChanged "BorderStyle"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=5
Public Sub Refresh()
    
End Sub

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=Text1,Text1,-1,Text
Public Property Get Value() As String
    Value = Text1.Text
End Property

Public Property Let Value(ByVal New_Value As String)
    Text1.Text() = New_Value
    PropertyChanged "Value"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=7,0,0,0
Public Property Get MinLength() As Integer
    MinLength = m_MinLength
End Property

Public Property Let MinLength(ByVal New_MinLength As Integer)
    m_MinLength = New_MinLength
    PropertyChanged "MinLength"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=Text1,Text1,-1,MaxLength
Public Property Get MaxLength() As Long
    MaxLength = Text1.MaxLength
End Property

Public Property Let MaxLength(ByVal New_MaxLength As Long)
    Text1.MaxLength() = New_MaxLength
    PropertyChanged "MaxLength"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=14
Public Function Clear() As Variant

End Function

'Initialize Properties for User Control
Private Sub UserControl_InitProperties()
    m_BackColor = m_def_BackColor
    m_ForeColor = m_def_ForeColor
    m_Enabled = m_def_Enabled
    Set m_Font = Ambient.Font
    m_BackStyle = m_def_BackStyle
    m_BorderStyle = m_def_BorderStyle
    m_MinLength = m_def_MinLength
End Sub

'Load property values from storage
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)

    m_BackColor = PropBag.ReadProperty("BackColor", m_def_BackColor)
    m_ForeColor = PropBag.ReadProperty("ForeColor", m_def_ForeColor)
    m_Enabled = PropBag.ReadProperty("Enabled", m_def_Enabled)
    Set m_Font = PropBag.ReadProperty("Font", Ambient.Font)
    m_BackStyle = PropBag.ReadProperty("BackStyle", m_def_BackStyle)
    m_BorderStyle = PropBag.ReadProperty("BorderStyle", m_def_BorderStyle)
    Text1.Text = PropBag.ReadProperty("Value", "Text1")
    m_MinLength = PropBag.ReadProperty("MinLength", m_def_MinLength)
    Text1.MaxLength = PropBag.ReadProperty("MaxLength", 0)
End Sub

'Write property values to storage
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)

    Call PropBag.WriteProperty("BackColor", m_BackColor, m_def_BackColor)
    Call PropBag.WriteProperty("ForeColor", m_ForeColor, m_def_ForeColor)
    Call PropBag.WriteProperty("Enabled", m_Enabled, m_def_Enabled)
    Call PropBag.WriteProperty("Font", m_Font, Ambient.Font)
    Call PropBag.WriteProperty("BackStyle", m_BackStyle, m_def_BackStyle)
    Call PropBag.WriteProperty("BorderStyle", m_BorderStyle, m_def_BorderStyle)
    Call PropBag.WriteProperty("Value", Text1.Text, "Text1")
    Call PropBag.WriteProperty("MinLength", m_MinLength, m_def_MinLength)
    Call PropBag.WriteProperty("MaxLength", Text1.MaxLength, 0)
End Sub
Listing  29.1: Code written by ActiveX Control Interface Wizard.

You can customize the code written by a Active Control Interface Wizard. The code written by the wizard is a good starting point to start creating an ActiveX control.

Working with Data Repeater
A DataRepeater is a container of a databound user control. It displays multiple instances of user control and also scrolls the instances, if required.  Each instance of the control represents a single record from the associated recordset.

The following are the major steps in using a DataRepeater.

1.      Create a data bound ActiveX control to deal with the required data.
2.      Load data bound ActiveX Control into the project using Components dialog box.
3.      Place a DataRepeater control into the project.
4.      Change RepeatedControlName property of DataRepater to the required ActiveX Control.
5.      Add a data source, such as the ADO Data Control, to the form, and connect it to a data provider.
6.      Change DataRepeater control's DataSource property to the data source.
7.      Right-click the DataRepeater control and click DataRepeater Properties.
8.      Select RepeaterBindings tab and set the PropertyName to an appropriate DataField, and click the Add button. Repeat the process for each data bound property of ActiveX control.
Let us understand the entire process by creating a DataRepater to display the details of products from PRODUCTS table. Each row of the repeater will display details of one product. User is allowed to view and change the details. The following are the major steps involved in this:

¨         Create an ActiveX Control that displays details of Products using five textboxes (prodno, proddes, qoh, rpu, type). This control contains four databound properties, where each property corresponds to a field in products table.
¨         Create a connection to Products Table of PRODUCTS.MDB database using an ADODC.
¨         Place a DataRepeater control on the form and connect it to ActiveX Control and ADODC.

Creating ActiveX Control – ProductControl
The following are the steps required creating the required ActiveX Control, which is bound to PRODUCTS table of PRODUCT.MDB.

1.      Start a new project and select ActiveX Control as the type of the project.
2.      Invoke UserControl designer and place five text boxes and change the following properties.

Object
Property

Value

UserControl
Name
Productcontrol

BorderStyle
1-fixed single
Text1
Name
TxtProdno

Text
“”
Text2
Name
TxtProddesc

Text
“”
Text3
Name
TxtQoh

Text
“”
Text4
Name
TxtRpu

Text
“”
Text5
Name
TxtPtype

Text
“”

Creating required properties
Invoke  ActiveX Control Interface Wizard to create the following properties.

¨         Prodno
¨         Proddesc
¨         Qoh
¨         Rpu
¨         Ptype

Map each property to text property of the corresponding text box.  Here is the table showing the mapping information. If you are not familiar with using ActiveX Control Interface Wizard, please refer to chapter 28.

Property of the control
Control to map to
Property of mapped control
Prodno
Txtprodno
Text
Prodesc
Txtproddesc
Text
Qoh
Txtqoh
Text
Rate
Txtrate
Text
Ptype
Txtptype
Text


ActiveX Control Interface Wizard adds property procedures (Property Set and Property Get), ReadProperties event procedure and WriteProperties event procedure to the control.

Adding PropertyChanged method
Whenever user changes any of these text boxes, the corresponding property should be marked as changed. For example, if user changed text in txtProdDesc control then the property that is mapped to this text box – ProdDesc – should be marked as changed.

Change event of the text box is used to mark property as changed using PropertyChanged method. The following is the code required for all five properties.

Private Sub txtProdno_Change()
    PropertyChanged "prodno"
End Sub

Private Sub txtproddesc_Change()
    PropertyChanged "proddesc"
End Sub

Private Sub txtPtype_Change()
    PropertyChanged "ptype"
End Sub

Private Sub txtQoh_Change()
    PropertyChanged "qoh"
End Sub

Private Sub txtRpu_Change()
    PropertyChanged "rpu"
End Sub
Listing 29.1: Code for property procedures.

Making properties data bound
The five properties that we have added to ProductControl should be databound. To make these properties data bound, following the procedure given below.

1.      Select Tools -> Procedure Attributes
2.      In Procedure Attributes window select ProdNo from Name dropdown listbox.
3.      Enter  “Returns/sets product number” as the description in Description textbox.
4.      Click on  Advanced>>“ button to expand Procedure Attributes window.
5.      Turn on  Property is data bound check box  in Data Binding group.
6.      Also turn on Show in DataBindings collection at design time.
7.      Then select Proddesc and change all the properties as mentioned above.
8.      Repeat this process for qoh, rate and ptype properties also.
9.      Then click on Ok button in Procedure Attributes window.
10.  Change the following properties of ActiveX control project.
Project name               ProdCtrl         
Project Description      ActiveX Control for Product record by P.Srikanth.

11.  Save the project and UserControl under following names

Project             ProductControl.vbp    
UserControl     ProductControl.ctl

Create ProductContol.ocx by selecting File -> Make ProdcutControl.ocx.

That is the end of creation of ActiveX control for product record. Now let us see how to use it in DataRepeater.

Using ProductControl in DataRepeater
We have so far seen how to create an ActiveX control for datarepeater. Now let us see how to create a project that uses DataRepeater and ProdcutControl controls.

1.      Start a new project and select Standard Exe as the type of the project.
2.      Load the following ActiveX controls using Project-> Components option.

Ø  Microsoft ADO Data Control 6.0 (OLEDB)
Ø  Microsoft DataRepeater Control 6.0 (OLEDB)

3.      Place ADODC and  Data Repeater on the form and arrange them one below the other (see figure 29.7).
4.      Use ADODC to connect to “D:\VBBOOK\PRODCUTS.MDB.”
5.      Change the Type of Record Source to  2- adCmdTable and  select Table or Stored Procedure name to Products.
6.      Change DataSource property of DataRepeater control to ADODC1.
7.      Select RepeatedControlName property and click on down arrow to invoke list of ActiveX controls.
8.      Select ProdCtrl.ProductControl from the list of ActiveX Controls.
9.      Right click on DataRepeater control and select properties from popup menu to invoke property pages.
10.  Select RepeaterBindings  Tab to connect  properties of ActiveX Control ( ProductControl ) to fields of ADODC1.
11.  Select Prodno from Property Name drop down and also select Prodno from DataField  drop down.
12.  Then click on Add button at the buttom.
13.  Then an entry is added to RepeaterBindings listbox.
14.  Do the same for remaining properties. The bindings are as follows.

ProdDesc         proddesc
Qoh                 qoh
Rpu                  Rpu
Ptype               ptype

15.  Once the process is complete then close the property pages of the DataRepeater control.

DataRepeater is used to display multiple occurrences of an ActiveX control. In the above example, DataRepeater displays five instances of ProductControl ActiveX control. You can make changes to the PRODUCTS table by changing data in ProductControl ActiveX control in DataRepeater.

Test Run

1.      Run the project using F5.
As soon as the project starts the form should look like figure 29.7. You can use scrollbar on the right to move up and down. You can also use Data Control to do the same.
2.      Move to product where product number is 6 and change the description to Oracle8i.
The ActiveX control marks ProdDesc property as changed (see code in listing 29.1).
3.      Move to a different record.
This will make the change made to ProdDesc to the underlying table.
4.      To test whether change has really been made, quit the project and restart it. If change is found then everything is working fine.
 

ActiveX Control Related Objects and Property pages



Objects related to ActiveX control
The following are the objects that are involved in the process of creating an ActiveX control.

¨         UserControl object
¨         AmbientProperties object
¨         Extender object
¨         Constituent control objects

UserControl Object
This is the object used to create a single ActiveX control. Every ActiveX control is consisting of one UserControl object and a set of constituent controls. Just like a From, a UserControl object also has a designer, which allows you to place intrinsic control on the UserControl object.

You have properties, methods, and events for UserControl object. They are discussed later in this chapter.

AmbientProperties Object
This is used to get information from container of ActiveX control.  The properties of AmbientProperties object are the ambient properties of the control.  These properties are read-only.  These properties allow you to determine how you adapt your control according to the capabilities of the container.

Not all ambient properties are standard. Some of them are specific to only a particular container.

AmbientChanged event occurs whenever any of the ambient properties (properties in container) changes. This enables programmer to change control according to the container.

AmbientProperties object is not available in Initialize event.

The following is the list of standard ambient properties.


Property
Meaning
Default value if property is not supported by Container.
BackColor
Color that contains the suggested interior color of the contained control.
 &H80000005
DisplayAsDefault
Returns True if  the control is the default control otherwise false.
 false
DisplayName
The name that the control assigned by developer.
 "".
Font
Contains the suggested font information of the contained control.
 MS Sans Serif 8.
ForeColor
Suggested foreground color of the contained control.
 0x80000008: the system color for window text.
LocaleID
Specifies the language and country of the user
 System locale ID.
Palette
Picture object whose palette specifies the suggested palette for the contained control.

RightToLeft
Indicates the text display direction and control visual appearance on a bi-directional system.
 False.
ScaleUnits
The name of the coordinate units being used by the container.
""
TextAlign
Specifies how text is to be aligned.
 0 - General Align.
UserMode
Specifies if the environment is in design mode or end user mode
 True.
 Table 28.1: Ambient properties of a UserControl.

The following code changes the background color of the text box to the background color of the container whenever background color of the container is changed.

Private Sub UserControl_AmbientChanged(PropertyName As String)
 If PropertyName = "BackColor" Then
      txtNumber.BackColor = Ambient.BackColor
 End If
End Sub
Listing 28.1: Changing BackColor property of text box to BackColor property of user Control.

AmbientChanged event of the UserControl object occurs whenever any of the ambient properties is changed. Ambient object provides access to values of ambient properties.

PropertyName parameter of the AmbientChanged event contains the name of the properties that has been changed in the container.

Extender Object
This object holds properties of the control that are actually controlled by the container of the control rather than by the control itself

The properties, methods, and events of Extender object are provided by the container. So there is no guarantee that all these are supported in all platforms.

You can access extender properties using Extender property of UserControl.

The following is the list of extender properties.

Property
Meaning
Name
Contains the user-defined name of the control.
Visible
Specifies if the control is visible or not.
Parent
Represents the container of the control, such as a form in Visual Basic.
Cancel
Indicates that the control is the Cancel button for the container.
Default
Indicates that the control is the default button for the container.
Container
Represents the visual container of the control.
DragIcon
Picture that specifies the icon to use when the control is dragged.
DragMode
Specifies if the control will automatically drag, or if the user of the control must call the Drag method.
Enabled
Specifies if the control is enabled. This is not present unless the control also has an Enabled property.
Height
Specifies the height of the control in the container’s scale units.
HelpContextID
Specifies the context ID to use when F1 key is pressed being in the control.
Index
Specifies the position in a control array that this instance of the control occupies.
Left
Specifies the position of the left edge of the control to the left edge of the container, specified in the container’s scale units.
TabIndex
Specifies the position of the control in the tab order of the controls in the container.
TabStop
Specifies if Tab will stop on the control.
Tag
Contains a user-defined value.
ToolTipText
Contains the text to be displayed when the cursor stays on the control for more than a second.
Top
Specifies the position of the top edge of the control to the top edge of the container, specified in the container’s scale units.
WhatThisHelpID
Specifies the context ID to use when the What’s This pop-up is used on the control.
Width
Specifies the width of the control in the container’s scale units.

Table 28.2: Extender properties.

The following are the methods provided by Extender object.

¨         Drag
¨         Move
¨         SetFocus
¨         ShowWhatsThis
¨         Zorder

The following are the events provided by Extender object

¨         DragOver
¨         DragDrop
¨         GotFocus
¨         LostFocus

Properties of UserControl object
The following are the properties that are specific to user control object.

Property
Meaning
AccessKey
Returns or sets a string that contains the keys that will act as the access keys (or hot keys) for the control.
Ambient
Returns an AmbientProperties object holding the ambient properties of the container.
ContainedControls
Returns a collection of the controls that were added to the control.
EditAtDesignTime
Returns or sets a value determining if a control can become active during the developer design time
EventsFrozen
If it is set to true, then events of usercontrol are ignored by container
Extender
Returns the Extender object for this control that holds the properties of the control that are kept track of by the container.
ParentControls
Returns a collection containing other controls in parent container.
PropertyPages
Is a string array containing the names of the property pages in the project that are associated with this control.
ContainerHwnd
Returns the window handle (hWnd) of a UserControl’s container.
Parent
Returns a reference to the container object on which the control is sited.
CanGetFocus
Determines whether focus should move to this control or not.
Table 28.3: Properties of User Control.

UserControl Events
The following are the various events of usercontrol object and their description.

Event
When does it occur?
AccessKeyPress
Occurs when user presses one of the accesskeys for the control. It passes the key that is pressed by user.
AmbientChanged
Occurs when an ambient property’s value changes. This passes the name of the property as the only parameter
EnterFocus
This event occurs whenever a constituent control receives focus.
ExitFocus
Occurs whenever focus leaves the control.
GotFocus
Occurs in the constituent control when focus enters it. The EnterFocus event is raised before the GotFocus event.
Hide
Occurs when the object’s Visible property changes to False.
InitProperties
Occurs when a new instance of an object is created.
This allows programmer to initialize new control when it is placed on the form.
ReadProperties
Occurs when loading an old instance of an object that has a saved state. This is used to read the values of the properties. Used for property persistence.
Show
Occurs when the object’s Visible property changes
WriteProperties
Occurs when an instance of an object is to be saved.  This is used to save the values of properties.
AsyncReadProgress
Occurs when more data is available as a result of an AsyncRead method.
AsyncReadComplete
Occurs when the container has completed an asynchronous read request.
HitTest
Occurs when the user moves the mouse over a UserControl object. Only occurs when the Windowless property of the UserControl is set to True and the BackStyle property is set to Transparent.
Initialize
Occurs when an application creates an instance of a user control.
Terminate
Occurs when the instance of the control is about to be destroyed.
Table 28.4: Events of user control object.

Property Pages
Before we started creating ActiveX Control, we had already used a few ActiveX controls.  All of them have Property pages that allow you to change properties of the control.  Now let us create two property pages for our Number control. First one contains a text box to take number from user and changes Value property, Second one contains two text boxes Maximum Length and Minimum Length properties.  A developer using Number ActiveX Control can invoke property pages and change properties.

The best way of creating a property page is using Property Page Wizard. Now having decided how many property pages to have and what to have in each of these property pages, we are ready to use Property Page Wizard.

To invoke property page wizard:

1.      First make Property Page Wizard available to Visual Basic project by selecting  Add-Ins menu and then select Add-In Manager option.
2.      In Add-In Manager dialog box double click on VB 6 Property Page Wizard. You should see Loaded message in Load Behavior column.
3.      Click on Ok.
4.      Then select Add-Ins menu and Property Page Wizard. You will see a series of windows prompting for required information.

The following are the steps to create two property pages and to place Value property in first property page and MinLength and MaxLength properties on the second property page.

1.      When Property Page Wizard is displayed, it first displays Introduction screen.
2.      Click on Next button to move to select the Property Pages page.
3.      Click on Add button.
4.      Enter  ppValue as the name of the page.
5.      Click on Add button again and enter ppLength as the name of second property page.
6.      Click on  Next button to move to Add Properties page.
7.      Available Properties list contains the list of available properties.
8.      Make sure ppValue tab is selected in Available  Property Pages.
9.      Select Value property  and click on > to move the property to ppValue property.
10.  In the same way select ppLength tab and click on >> to place  MinLength and MaxLength properties on ppLength property page.
11.  Click on Finish button to start building property pages.
12.  Invoke ppValue property page and change Caption property to “Value”
13.  Invoke ppLength property page and change Caption property to  “Length”.

Property Page Wizard has created two property pages ( ppValue and ppLength, shown in figure 28.3, and  28.4).

The code that Property Page Wizard has written for ppValue property page is as follows.

Private Sub txtValue_Change()
    Changed = True
End Sub

Private Sub PropertyPage_ApplyChanges()
    SelectedControls(0).Value = txtValue.Text
End Sub

Private Sub PropertyPage_SelectionChanged()
    txtValue.Text = SelectedControls(0).Value
End Sub
Listing  28.1: Code written by property page wizard.
Let us understand the code written by Property Page Wizard. But before we try to do that, we have to understand properties, events of property page.

Changed Property
When this property is set to true, Apply button in the property page will be enabled.  In addition to that, setting it to true calls ApplyChanges event whenever you click on Ok button or move to a different property page.

SelectedControls property
This is a collection that contains the controls that are currently selected on the form. SelectedControls (0) references the control that is currently selected. This is used to get the values for properties of the currently selected instance of the ActiveX control for which property page belongs.

The code written by Property Page Wizard, uses SelectedControls (0) (first selected control) only. If you want to handle all selected controls, you have to modify the code written by wizard.

SelectionChanged Event
This is fired whenever an instance of the ActiveX control is selected for editing properties through property pages.  This event is used to get the values of the properties from selected control (SelectedControls (0)) and assign those values to controls in property pages to enable user to change them.

ApplyChanges Event
This event is fired whenever user is selecting Apply button, selecting Ok button, closing page or shifting to a different page.

The event occurs only when Changed property is set to true,

Now, if you look at the code written by Property Page Wizard, you should be able to understand the code. The code uses all the properties and events that we have discussed. The following is the summary of the code.

¨         Sets Changed property to True, whenever user changes values in txtValue text box, which is meant for Value property.
¨         SelectionChanged event is used to get the value of Value property of the currently selected control (SelectedControls(0)) and put that value in txtValue textbox.
¨         ApplyChanges event is used to write value entered in txtValue textbox into Value property of the currently selected control (SelectedControls (0)).

Code for ppLength property page
The code written by Property Page Wizard for ppLength property page is as follows.

Private Sub txtMaxLength_Change()
    Changed = True
End Sub

Private Sub txtMinLength_Change()
    Changed = True
End Sub

Private Sub PropertyPage_ApplyChanges()
    SelectedControls(0).MaxLength = txtMaxLength.Text
    SelectedControls(0).MinLength = txtMinLength.Text
End Sub

Private Sub PropertyPage_SelectionChanged()
    txtMaxLength.Text = SelectedControls(0).MaxLength
    txtMinLength.Text = SelectedControls(0).MinLength
End Sub
Listing 28.2: Code for ppLength property page.

This code needs no explanation, as it doesn’t differ from the previous code.

Using property pages at the time of designing
Let us see how a developer who is using Number ActiveX control can use Property Pages of Number control.  Here are the steps to test it:

1.      Open testing project (tstNumctrl) project
2.      Invoke Form designer
3.      Select Number1 control and click right button
4.      You should see a new option in popup menu – Properties.
5.      Select Properties option to invoke Property pages.
6.      Property pages window is displayed with two tabs at the top, one for Value property page and another for Length property page.
7.      In Value property page, you will see the value you assigned to Value property of the selected control. As shown in figure 28.5 , the value assigned to Value property is 1000.  So initially you will see 1000.
8.      Change the value to 2000 in property page. It will enable Apply button of the property  page. At this stage, your property Page should be identical to figure 28.5.
9.      Click on Apply to make Value property of Number1 control. Click on Length tab to move to Length property page.

Note: Pressing F4 on the control will invoke Properties Pallette. And selecting Popup Menu -> Properties option will invoke Property pages. This is same for all ActiveX controls.

Data Bound ActiveX Control and Data Repeater



ActiveX Control Interface Wizard
Each ActiveX Control contains an interface – properties, methods, and events.  ActiveX Control Interface Wizard is used to assist the author (creator) of ActiveX Control in creating properties, methods and events.

ActiveX Control interface Wizard can do the following:

¨         Create property procedures for user-defined properties
¨         Map user-defined properties to standard properties of Constituent controls.
¨         Take care of property persistence using ReadProperties and WriteProperties events.

Let us create a new project to understand how to create interface for Number control using ActiveX Control Interface Wizard. Let us call this control as WizNumber.

Here are the steps to create WizNumber, which is same as Number control but built using ActiveX Control Interface Wizard:

1.      Start a new project and select ActiveX Control as the type of the project.
2.      Change Name of the UserControl to WizNumber.
3.      Place a textbox on UserControl

Note: We concentrate on how to use ActiveX Control Interface Wizard and not on how to write code to accomplish the task. So I do not explain how to write code for WizNumber control (because I have already done with Number control in the previous chapters and there is no need to do that again) instead we will understand how we can use Wizard to create interface.

4.      Invoke ActiveX Control Interface Wizard from Add-Ins Menu.  If it is not available, use Add-In Manger to load the Wizard into Visual Basic IDE. Please see the section “Loading Property Page Wizard” in chapter 28 for detail regarding how to add an Add-in into Visual Basic IDE.
5.      Click on Next to skip the Introduction screen.
It pre-selects a list of standard properties, methods, and events that are commonly used. If you do not want them, you can unselect them by selecting unwanted names and clicking < (less than) button.
If you want to select some more from the Available Names, select the name that you want to add and click on > (greater than) button.
6.      Click on Next without unselecting or selecting anything.
7.      Wizard displays Create Custom Interface Members page.
8.      Click on New button to add a member.(Figure 29.1)
9.      In Add Custom Member dialog enter the name of the member and type of the member.
10.  Repeat the process to enter the following members.

Property          Value
MinLength
                        MaxLength
Method                        Clear

Event               InvalidChar

                        InvalidLength


After you have added all members, the Wizard should look like the following.

11.  Click on Next button to move to Set Mapping page, shown in figure 29.3.
Mapping enables user-defined properties to be mapped to standard properties.  Let us map MaxLength property to MaxLength property of textbox. 
12.  Select MaxLength property in Public Name and select Text1 as control and MaxLength as Member.
13.  Repeat the process for Value property. Map it to Text property of textbox. See figure 29.3.
14.  Once mapping is over click on Next to move to Set Attributes page.
15.  Select MinLength property and change the remaining as shown in figure 29.4.
16.  Click on Next button and then click on Finish.

The code written by ActiveX Control Interface Wizard is given in listing 29.1 without any editing. Particularly concentrate on the following:

¨         InitProperties Event
¨         ReadProperties Event
¨         WritePropeties Event
¨         Property Procedures for user-defined properties

'Default Property Values:
Const m_def_BackColor = 0
Const m_def_ForeColor = 0
Const m_def_Enabled = 0
Const m_def_BackStyle = 0
Const m_def_BorderStyle = 0
Const m_def_MinLength = 0
'Property Variables:
Dim m_BackColor As Long
Dim m_ForeColor As Long
Dim m_Enabled As Boolean
Dim m_Font As Font
Dim m_BackStyle As Integer
Dim m_BorderStyle As Integer
Dim m_MinLength As Integer
'Event Declarations:
Event Click()
Event DblClick()
Event KeyDown(KeyCode As Integer, Shift As Integer)
Event KeyPress(KeyAscii As Integer)
Event KeyUp(KeyCode As Integer, Shift As Integer)
Event MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Event MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Event MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Event InvalidChar()
Event InvalidLenth()

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=8,0,0,0
Public Property Get BackColor() As Long
    BackColor = m_BackColor
End Property

Public Property Let BackColor(ByVal New_BackColor As Long)
    m_BackColor = New_BackColor
    PropertyChanged "BackColor"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=8,0,0,0
Public Property Get ForeColor() As Long
    ForeColor = m_ForeColor
End Property

Public Property Let ForeColor(ByVal New_ForeColor As Long)
    m_ForeColor = New_ForeColor
    PropertyChanged "ForeColor"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=0,0,0,0
Public Property Get Enabled() As Boolean
    Enabled = m_Enabled
End Property

Public Property Let Enabled(ByVal New_Enabled As Boolean)
    m_Enabled = New_Enabled
    PropertyChanged "Enabled"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=6,0,0,0
Public Property Get Font() As Font
    Set Font = m_Font
End Property

Public Property Set Font(ByVal New_Font As Font)
    Set m_Font = New_Font
    PropertyChanged "Font"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=7,0,0,0
Public Property Get BackStyle() As Integer
    BackStyle = m_BackStyle
End Property

Public Property Let BackStyle(ByVal New_BackStyle As Integer)
    m_BackStyle = New_BackStyle
    PropertyChanged "BackStyle"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=7,0,0,0
Public Property Get BorderStyle() As Integer
    BorderStyle = m_BorderStyle
End Property

Public Property Let BorderStyle(ByVal New_BorderStyle As Integer)
    m_BorderStyle = New_BorderStyle
    PropertyChanged "BorderStyle"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=5
Public Sub Refresh()
    
End Sub

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=Text1,Text1,-1,Text
Public Property Get Value() As String
    Value = Text1.Text
End Property

Public Property Let Value(ByVal New_Value As String)
    Text1.Text() = New_Value
    PropertyChanged "Value"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=7,0,0,0
Public Property Get MinLength() As Integer
    MinLength = m_MinLength
End Property

Public Property Let MinLength(ByVal New_MinLength As Integer)
    m_MinLength = New_MinLength
    PropertyChanged "MinLength"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MappingInfo=Text1,Text1,-1,MaxLength
Public Property Get MaxLength() As Long
    MaxLength = Text1.MaxLength
End Property

Public Property Let MaxLength(ByVal New_MaxLength As Long)
    Text1.MaxLength() = New_MaxLength
    PropertyChanged "MaxLength"
End Property

'WARNING! DO NOT REMOVE OR MODIFY THE FOLLOWING COMMENTED LINES!
'MemberInfo=14
Public Function Clear() As Variant

End Function

'Initialize Properties for User Control
Private Sub UserControl_InitProperties()
    m_BackColor = m_def_BackColor
    m_ForeColor = m_def_ForeColor
    m_Enabled = m_def_Enabled
    Set m_Font = Ambient.Font
    m_BackStyle = m_def_BackStyle
    m_BorderStyle = m_def_BorderStyle
    m_MinLength = m_def_MinLength
End Sub

'Load property values from storage
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)

    m_BackColor = PropBag.ReadProperty("BackColor", m_def_BackColor)
    m_ForeColor = PropBag.ReadProperty("ForeColor", m_def_ForeColor)
    m_Enabled = PropBag.ReadProperty("Enabled", m_def_Enabled)
    Set m_Font = PropBag.ReadProperty("Font", Ambient.Font)
    m_BackStyle = PropBag.ReadProperty("BackStyle", m_def_BackStyle)
    m_BorderStyle = PropBag.ReadProperty("BorderStyle", m_def_BorderStyle)
    Text1.Text = PropBag.ReadProperty("Value", "Text1")
    m_MinLength = PropBag.ReadProperty("MinLength", m_def_MinLength)
    Text1.MaxLength = PropBag.ReadProperty("MaxLength", 0)
End Sub

'Write property values to storage
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)

    Call PropBag.WriteProperty("BackColor", m_BackColor, m_def_BackColor)
    Call PropBag.WriteProperty("ForeColor", m_ForeColor, m_def_ForeColor)
    Call PropBag.WriteProperty("Enabled", m_Enabled, m_def_Enabled)
    Call PropBag.WriteProperty("Font", m_Font, Ambient.Font)
    Call PropBag.WriteProperty("BackStyle", m_BackStyle, m_def_BackStyle)
    Call PropBag.WriteProperty("BorderStyle", m_BorderStyle, m_def_BorderStyle)
    Call PropBag.WriteProperty("Value", Text1.Text, "Text1")
    Call PropBag.WriteProperty("MinLength", m_MinLength, m_def_MinLength)
    Call PropBag.WriteProperty("MaxLength", Text1.MaxLength, 0)
End Sub
Listing  29.1: Code written by ActiveX Control Interface Wizard.

You can customize the code written by a Active Control Interface Wizard. The code written by the wizard is a good starting point to start creating an ActiveX control.

Working with Data Repeater
A DataRepeater is a container of a databound user control. It displays multiple instances of user control and also scrolls the instances, if required.  Each instance of the control represents a single record from the associated recordset.

The following are the major steps in using a DataRepeater.

1.      Create a data bound ActiveX control to deal with the required data.
2.      Load data bound ActiveX Control into the project using Components dialog box.
3.      Place a DataRepeater control into the project.
4.      Change RepeatedControlName property of DataRepater to the required ActiveX Control.
5.      Add a data source, such as the ADO Data Control, to the form, and connect it to a data provider.
6.      Change DataRepeater control's DataSource property to the data source.
7.      Right-click the DataRepeater control and click DataRepeater Properties.
8.      Select RepeaterBindings tab and set the PropertyName to an appropriate DataField, and click the Add button. Repeat the process for each data bound property of ActiveX control.
Let us understand the entire process by creating a DataRepater to display the details of products from PRODUCTS table. Each row of the repeater will display details of one product. User is allowed to view and change the details. The following are the major steps involved in this:

¨         Create an ActiveX Control that displays details of Products using five textboxes (prodno, proddes, qoh, rpu, type). This control contains four databound properties, where each property corresponds to a field in products table.
¨         Create a connection to Products Table of PRODUCTS.MDB database using an ADODC.
¨         Place a DataRepeater control on the form and connect it to ActiveX Control and ADODC.

Creating ActiveX Control – ProductControl
The following are the steps required creating the required ActiveX Control, which is bound to PRODUCTS table of PRODUCT.MDB.

1.      Start a new project and select ActiveX Control as the type of the project.
2.      Invoke UserControl designer and place five text boxes and change the following properties.

Object
Property

Value

UserControl
Name
Productcontrol

BorderStyle
1-fixed single
Text1
Name
TxtProdno

Text
“”
Text2
Name
TxtProddesc

Text
“”
Text3
Name
TxtQoh

Text
“”
Text4
Name
TxtRpu

Text
“”
Text5
Name
TxtPtype

Text
“”

Creating required properties
Invoke  ActiveX Control Interface Wizard to create the following properties.

¨         Prodno
¨         Proddesc
¨         Qoh
¨         Rpu
¨         Ptype

Map each property to text property of the corresponding text box.  Here is the table showing the mapping information. If you are not familiar with using ActiveX Control Interface Wizard, please refer to chapter 28.

Property of the control
Control to map to
Property of mapped control
Prodno
Txtprodno
Text
Prodesc
Txtproddesc
Text
Qoh
Txtqoh
Text
Rate
Txtrate
Text
Ptype
Txtptype
Text


ActiveX Control Interface Wizard adds property procedures (Property Set and Property Get), ReadProperties event procedure and WriteProperties event procedure to the control.

Adding PropertyChanged method
Whenever user changes any of these text boxes, the corresponding property should be marked as changed. For example, if user changed text in txtProdDesc control then the property that is mapped to this text box – ProdDesc – should be marked as changed.

Change event of the text box is used to mark property as changed using PropertyChanged method. The following is the code required for all five properties.

Private Sub txtProdno_Change()
    PropertyChanged "prodno"
End Sub

Private Sub txtproddesc_Change()
    PropertyChanged "proddesc"
End Sub

Private Sub txtPtype_Change()
    PropertyChanged "ptype"
End Sub

Private Sub txtQoh_Change()
    PropertyChanged "qoh"
End Sub

Private Sub txtRpu_Change()
    PropertyChanged "rpu"
End Sub
Listing 29.1: Code for property procedures.

Making properties data bound
The five properties that we have added to ProductControl should be databound. To make these properties data bound, following the procedure given below.

1.      Select Tools -> Procedure Attributes
2.      In Procedure Attributes window select ProdNo from Name dropdown listbox.
3.      Enter  “Returns/sets product number” as the description in Description textbox.
4.      Click on  Advanced>>“ button to expand Procedure Attributes window.
5.      Turn on  Property is data bound check box  in Data Binding group.
6.      Also turn on Show in DataBindings collection at design time.
7.      Then select Proddesc and change all the properties as mentioned above.
8.      Repeat this process for qoh, rate and ptype properties also.
9.      Then click on Ok button in Procedure Attributes window.
10.  Change the following properties of ActiveX control project.
Project name               ProdCtrl         
Project Description      ActiveX Control for Product record by P.Srikanth.

11.  Save the project and UserControl under following names

Project             ProductControl.vbp    
UserControl     ProductControl.ctl

Create ProductContol.ocx by selecting File -> Make ProdcutControl.ocx.

That is the end of creation of ActiveX control for product record. Now let us see how to use it in DataRepeater.

Using ProductControl in DataRepeater
We have so far seen how to create an ActiveX control for datarepeater. Now let us see how to create a project that uses DataRepeater and ProdcutControl controls.

1.      Start a new project and select Standard Exe as the type of the project.
2.      Load the following ActiveX controls using Project-> Components option.

Ø  Microsoft ADO Data Control 6.0 (OLEDB)
Ø  Microsoft DataRepeater Control 6.0 (OLEDB)

3.      Place ADODC and  Data Repeater on the form and arrange them one below the other (see figure 29.7).
4.      Use ADODC to connect to “D:\VBBOOK\PRODCUTS.MDB.”
5.      Change the Type of Record Source to  2- adCmdTable and  select Table or Stored Procedure name to Products.
6.      Change DataSource property of DataRepeater control to ADODC1.
7.      Select RepeatedControlName property and click on down arrow to invoke list of ActiveX controls.
8.      Select ProdCtrl.ProductControl from the list of ActiveX Controls.
9.      Right click on DataRepeater control and select properties from popup menu to invoke property pages.
10.  Select RepeaterBindings  Tab to connect  properties of ActiveX Control ( ProductControl ) to fields of ADODC1.
11.  Select Prodno from Property Name drop down and also select Prodno from DataField  drop down.
12.  Then click on Add button at the buttom.
13.  Then an entry is added to RepeaterBindings listbox.
14.  Do the same for remaining properties. The bindings are as follows.

ProdDesc         proddesc
Qoh                 qoh
Rpu                  Rpu
Ptype               ptype

15.  Once the process is complete then close the property pages of the DataRepeater control.

DataRepeater is used to display multiple occurrences of an ActiveX control. In the above example, DataRepeater displays five instances of ProductControl ActiveX control. You can make changes to the PRODUCTS table by changing data in ProductControl ActiveX control in DataRepeater.

Test Run

1.      Run the project using F5.
As soon as the project starts the form should look like figure 29.7. You can use scrollbar on the right to move up and down. You can also use Data Control to do the same.
2.      Move to product where product number is 6 and change the description to Oracle8i.
The ActiveX control marks ProdDesc property as changed (see code in listing 29.1).
3.      Move to a different record.
This will make the change made to ProdDesc to the underlying table.
4.      To test whether change has really been made, quit the project and restart it. If change is found then everything is working fine.