The UserControl Properties

Each and every ActiveX control already has some built in properties. Open the code window in your control and select UserControl from the drop-down window. Notice the various event procedures on the left drop-down box. We will add some code to a few of these now to get our control set up.

Try It Out - Coding the UserControl Properties

1.  Please add the following code to the predefined UserControl_Initialize event procedure:

Private Sub UserControl_Initialize()
   editStatus = nowStatic
End Sub

We want to initialize the current editStatus of our control whenever it is initialized. The initialize event fires whenever our control either goes into design-time or run-time.

2.  Now add this piece of code in the UserControl_InitProperties event:

Private Sub UserControl_InitProperties()
   m_recordSource = m_def_recordSource
   m_connectionString = m_def_connectionString
End Sub

The InitProperties event is fired only once - when the ActiveX control is first drawn on the host form. When it is drawn, the default properties for the RecordSource and ConnectionString are set to the default values, which we earlier fixed as "". At this point, the user of our control has a new instance and can set these properties to open any table desired.

3.  Here's the next chunk of code – please add it to UserControl_Resize event:

Private Sub UserControl_Resize()
   Width = UserControl.ScaleX(m_def_Width, vbPixels, vbTwips)
   Height = UserControl.ScaleX(m_def_Height, vbPixels, vbTwips)
   Set m_form = UserControl.Parent
End Sub

Our control gets resized whenever it is drawn on the host form, or whenever the user attempts to physically resize it by stretching or shrinking the sizing handles. By setting the Width and Height properties of our control to our size constants we set up in the general area of the control, this is an exercise in futility for the user. If the user attempts to stretch or shrink our control, it snaps right back to the size we defined. This is also a perfect place to Set our m_form object variable to the name of the parent - which is the host of our control. Remember that since this is an object variable, we must use Set, because we are setting a reference to the object variable. A simple assignment of m_form = UserControl.Parent will generate our friend, the Run-time error '91':

Remember, when using objects, we must always set a reference to them.

4.  Another built-in event procedure is the Terminate event. When the user closes the form that is hosting our ActiveX control, this event gets fired. It is good practice to Set the references to both our adoRecordset and adoConnection to Nothing. This ensures that all memory is freed up. In reality, this will occur without us having to explicitly do this, but again, we don't want to rely on the default behavior of VB 6.0. It's much better to do this ourselves.

To achieve this, add the following code to the UserControl_Terminate event:

Private Sub UserControl_Terminate()
On Error Resume Next
If Not adoRecordset Is Nothing Then
  Set adoRecordset = Nothing
End If

If Not adoConnection Is Nothing Then
  Set adoConnection = Nothing
End If

End Sub

The last two built in properties we will add code to are the ReadProperties and WriteProperties.  These are critical to the operation of our control. When a control is initialized, the ReadProperties event is fired. This is what initializes our internal control variables. VB takes care of actually storing and retrieving the information for us. We simply must tell VB which properties to read and write, and it does the rest for us.

5.  Add the following code to the UserControl_ReadProperties event:

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
   m_recordSource = PropBag.ReadProperty("RecordSource", _
   m_connectionString = PropBag.ReadProperty _
   ("ConnectionString", m_def_connectionString)
End Sub

The ReadProperties event attempts to read the value stored in the name of the property. So in our code we are setting the private variable m_recordSource. The property is stored with the name "RecordSource". If a value has been previously set for this, it is read and assigned to m_recordSource. If the property has not yet been set, as in a new control that is drawn on a form, the default value is read. So if a value is present, it is retrieved and assigned to our variable, otherwise the default value we defined in the general section is assigned.

The reciprocal event is the WriteProperties event. Whenever a property gets changed, this event is called and the new value is stored in the PropertyBag for us. These two events, ReadProperties and WriteProperties are responsible for making the properties of our ActiveX control persistent. So when a programmer adds a value for a RecordSource, it is written to the PropertyBag. Then when the program is run, the control is destroyed and recreated in the running program. As it gets initialized, the RecordSource property is read from the property bag and assigned to our internal variable. This is how the magic of property persistence occurs, even though our control is constantly getting destroyed and brought back to life through the cycle of design and run.

6.  Add the code below to the UserControl_WriteProperties event:

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
     Call PropBag.WriteProperty("RecordSource", _
   m_recordSource, m_def_recordSource)
     Call PropBag.WriteProperty("ConnectionString", _
   m_connectionString, m_def_connectionString)
End Sub

The first parameter is the property to be written. This property is in quotation marks. If there is a value for the property, it gets written as the value. Otherwise, the default value gets written. So in the first example, if the user has defined a record source and it is different from the default value, this gets written as the current value. Otherwise, the default value gets written.

For optimization purposes, VB compares both the value of the variable (such as m_recordSource) and the default value (such as m_def_recordSource). If they have the same value, the property does not get written. If they are different, VB knows that the value has been changed. In our example, it means the user entered a RecordSource for our control. In this case, the new value gets written and it is now persistent.

7.  Now take a minute and add two final properties, RecordSource and ConnectionString. These will be the only two properties that the user must enter to use our control. Choose Tools-Add Procedure from the main VB  menu. Ensure the properties are Public so the user can access them from outside of our control:

8.  Adding the properties will just add templates to your control. You will have to do some tailoring of both the parameters and return values. Add the following code and please take special care that the parameters and return values are exactly as shown below:

Public Property Get RecordSource() As String
   RecordSource = m_recordSource
End Property

Public Property Let RecordSource(ByVal New_RecordSource As String)
    m_recordSource = New_RecordSource
    PropertyChanged "RecordSource"
End Property

9.  Now add a ConnectionString property to our class. Please add the following code:

Public Property Get ConnectionString() As String
   ConnectionString = m_connectionString
End Property

Public Property Let ConnectionString(ByVal New_ConnectionString As String)
   m_connectionString = New_ConnectionString
   PropertyChanged "ConnectionString"
End Property

The Let part of the property is fired when the user changes the value. So when the user changes the RecordSource property, the Let_RecordSource event gets fired. The new entry is passed in as the parameter New_RecordSource and is assigned to the internal variable m_recordSource. However, since this property has changed, we must inform VB so that it gets written to the PropertyBag. We simply add **PropertyChanged "RecordSource" **and it will be taken care of for us. Take care to ensure the name of the property, in this case "RecordSource" is spelled the same in the Let, ReadProperties, and WriteProperties event procedures. This is the string literal that VB uses to identify this specific property for reading and writing.

OK, now let's add some finesse to our property pages.

© 1998 by Wrox Press. All rights reserved.