When the user draws our ActiveX control on a form, we want it to be a specific size. In other words, we don't want the user to shrink the control so some of the buttons are cut off, or to stretch it so the control takes up more form real estate than is really required. We will set the size to a constant value when the control is resized. This will permit our control to act like the timer control. It is a fixed size and can't be changed:
'-- Keep our control a constant size --
Private Const m_def_Height = 80
Private Const m_def_Width = 452
9. Your mileage may vary on the exact size of the control. Once you have it laid out the way you want, bring up the property box of the control. Set the ScaleMode to 3-Pixel. Then note the ScaleHeight
and ScaleWidth
sizes and set your constants m_def_Height
and m_def_Width
variables to the sizes shown in the property box. The control above has a ScaleHeight
of 80
and a ScaleWidth
of 452
:
Now no matter how much the user tries, whenever the control is first drawn or resized, it will snap back to the size that we have defined:
In the code, we then just have a few additional variables and the now familiar enumerated values for the command buttons. So you already know how they work.
Another thing we must also do is manually track the edit status of the recordset. Why can't we just check the adoRecordset.EditMode
as we normally do? Good question! Since we are really operating in a level of indirection (the bound control actually holds the data field and we don't have any control over what fields will be bound), the EditMode
is not always set when we need it. This can lead to erratic results. In all other cases, we could just read the EditMode
and be done with it - letting ADO do the work. But in our control we must track the current state of the recordset. So the easiest way to accomplish this is to create enumerated constants for each of the three possible states of the recordset:
'—Values for our current edit status
Private Enum editMode
nowStatic = 0
nowEditing = 1
nowAdding = 2
End Enum
To make our life as easy as possible, we define a form level variable, editStatus
of type editMode
. This means that the variable can only hold one of the three states we defined:
Dim editStatus As editMode
One of the really handy features of using enumerated constants is that not only will VB stop us setting it to a wrong value, but it is smart enough to display the 'legal' options available. Since we dimensioned editStatus
as a type editMode
, the three editMode
options are displayed for us:
Neat, eh?
But the workhorses of the control will be the ADO connection object and the ADO recordset object. Our control will create the ADO recordset and use it internally to manage the data requested by the user. So we create two private variables to hold both of these objects:
'Declare our object variables for the ADO connection
'and the recordset used in the control
Private adoConnection As ADODB.Connection
Private adoRecordset As ADODB.RecordSet
We need some way to notify the host when a data operation is taking place. For example, the programmer using our control needs some place to enter data validation code to cater for when the user attempts to save a record. Let's say that the user tries to save a record with a blank field. Well, we will raise the event validateRecord
on certain data events, such as saving a record. The programmer can then cancel the operation if the entries in the text boxes don't meet the specified data validation criteria. So by defining this event, we can raise it within the host form. Just like the normal events on other controls, we now have the ability to raise an event in the host.