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
Private Sub UserControl_InitProperties() m_recordSource = m_def_recordSource m_connectionString = m_def_connectionString End Sub
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
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
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
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
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
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
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 Err.Clear End Sub
The last two built in properties we will add code to are the
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
Private Sub UserControl_ReadProperties(PropBag As PropertyBag) m_recordSource = PropBag.ReadProperty("RecordSource", _ m_def_recordSource) m_connectionString = PropBag.ReadProperty _ ("ConnectionString", m_def_connectionString) End Sub
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,
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
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,
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
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
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.