"Choose COM; choose OLE Servers using Distributed COM; choose Remote Clients; choose 32-bit Object Orientated Programming with Visual Basic, Choose ActiveX. I chose not to choose ActiveX..." Or so a recent pop song never went. You've heard all this hype from the Microsoft spindoctors about how ActiveX will revolutionise the way we wash our cars. The burning question is: is this true?
Well, it may not quite help us to wash our cars, but it is certainly another great weapon to add to our programming arsenal. In this article, I will take you through the A to X of ActiveX control programming. So without further ado...
The short answer is a class with a graphical front-end. You may or may not have used classes before, but they are a great way to create code that you can easily reuse in a later project. ActiveX controls take this idea one step further, allowing you to write a widget that you can package and reuse in later applications, or even distribute it as the perfect solution to other budding developers' problems.
With ActiveX, you can make a composite control: one control made up of several others. This means that you can take the ordinary VB controls, or any other ActiveX control for that matter, put them in your ActiveX control, write the functionality that you want, all in one reusable component.
Method is just a collective name for the subs and functions of your control. These are just the same as any other functions that you have written in your VB career. You can pass any number of parameters and return a value if you want. In the look method of our body, we want to pass the direction that the eye is looking. This method might be:
Public Sub Look(Direction As Integer)
Select Case Direction
Case 0 '=Left
Case 1 '=Right
Case 2 '=Up
Case 3 '=Down
For all the fancy names, this is all that it is. To return a value, we will use our read method as an example, you must declare it as a function instead of a sub:
Public Function Read() As String
'Do reading stuff
Read = "Hello from VB-World.net"
Isn't all this method stuff easy? If you really can't get the idea sorted in your head, think of it like this: your control is like a machine. You put information in the top, turn the handle, your method, some lights will flash and the machine will start doing things, eventually giving you a final value out the bottom. But wait...what if your machine wants to tell you something? It's a great event when that happens...
An ActiveX control is made up of its members; the properties; the methods; and the events. I think it is time to explain this with a silly analogy. Lets think of the human body as the ActiveX control.
This control will have one property: the eyes open property. In this case, this property can have two values; opened or closed. The developer can tell the body to let this property have a new value, or it can tell the body to get the current value.
Our method will be the look method. When the developer calls this method, specifying where the eyes are to look, the body should make the eyes look there. We will also have another method; this one, the read method, will return what the eyes see before them.
Lastly, the body will also provide a blink event. This will notify the developer of when the eyes blink. All that the developer knows is when this event is fired; they do not know the interval workings of the body and how or why the event was fired.
Back in the wonderful world of VB, our members live on and we must figure out how to code them. Let's go...
Before we get going on properties, we need a new control to play with. Load up VB and start a new ActiveX Control Project. Play around with it a bit. Add some controls, play with some of the properties. To test your new control, close the designer and add a new standard project. You should find a new icon in your toolbox corresponding to your control, which you can use to draw your control like you would any other.
The simplest kind of property is a simple public variable. For example, if you put the following in the declarations section of your usercontrol:
Public EyeOpen As Boolean
You can now set this property to your heart's content. However, it will not do much because the control cannot tell when you are setting this property, and VB will not remember it between one session and the next. To do this, you must use property procedures.
Property procedures are called when a property value is set or retrieved. Lets make one now: open up the code window for your usercontrol and click on Tools|Add Procedure... Type in the name as 'EyeOpen' and the set the type to 'Property'. When you click OK, as if by magic, VB creates the skeleton for the property procedures. Now it is up to you to put the muscles on this skeleton.
As you can see, there are two: the 'Get' and the 'Let' functions (in fact there is also a third type that we will meet later). This may sound complicated, but in fact it is really easy: the 'Get' function is called when the container (the posh name for the form on which the control is placed) tries to get the current value for the property; the 'Let' function is called when the container tries to let the property have a new value.
For a property procedure to work, we must have a temporary variable to store the property's value in. Add the following to the declarations section:
Private m_EyeOpen As Boolean
Note that the 'm_' prefix is the prefix usually used for internal variables of a usercontrol.
Now to put some code in the Property Let procedure... This procedure has one parameter: by default it is called vNewValue, defined as a variant. We want a boolean not a variant because the eye can only be open or shut in our model; so, change this parameter to 'New_EyeOpen As Boolean'. If we want this property to be read only, you could leave this procedure empty. As it is, we want to set the m_EyeOpen to the new value, so add this one line of code, leaving the procedure looking like this:
Public Property Let EyeOpen(New_EyeOpen As Boolean)
m_EyeOpen = New_EyeOpen
'now do stuff to open/close eye as needed
The Property Get procedure is even easier! The Get procedure is similar to a standard function: you return a value by setting the function to equal something:
Public Property Get EyeOpen() As Boolean
EyeOpen = m_EyeOpen
There is just one more thing about properties: how do you get VB to remember the property value between sessions?
When does an ActiveX control keep his properties? In his property bag!
No, seriously! You use the PropertyBag object to store values between sessions, a process known as persisting.
The PropertyBag object sports two methods: one to write values into the bag, and another one to retrieve them. You should write properties to the bag whenever one changes. This is done using the WriteProperties event of the usercontrol. This provides an instance of the PropertyBag object, which you can use to save the value. For example:
PropBag.WriteProperty "EyeOpen", m_EyeOpen, True
This saves the property, under the name of "EyeOpen". The third parameter, in this case set to True, is the default. Use this in conjunction with the default parameter of the ReadProperties method to set a default value. If the property is equal to this value, then it is not actually saved. When it comes to reading the value, the ReadProperty function sees that there is not value in the bag, so returns the default value. This provides a way to reduce the amount of memory required to persist the object.
When the control is restarted, you must reload all the saved values. The ReadProperties event is fired when this must be done. In this event, you must do the opposite to what you did in the WriteProperties event., You should resort all of the values that you stored, making sure that the default values are the same. For example:
m_EyeOpen = PropBag.ReadProperty("EyeOpen", True)
One way to synchronise the default values is to create a constant in the declarations section, so that you can reference it anywhere you need to. For example:
Private Const m_def_EyeOpen = True
Again, the 'm_def_' prefix is used generally for a default value constant.
To make a property have a default value at startup, use the InitProperties event of the usercontrol. This event is only triggered when the control is first placed on a form, then never again at design time. You would probably want something similar to this to achieve the desired effect:
Private Sub UserControl_InitProperties()
m_EyeOpen = m_def_EyeOpen
The last thing to do is to tell the control that your property has changed so that it can save it into the PropertyBag. You do this by calling the "PropertyChanged" method in the Property Let procedure:
Now that I have opened your eyes ('scuse the pun!) to properties, lets move on to the next type of member: methods...
Events are what you use to notify the developer who is using your control that something important has happened that they might want to react to. Examples of events for the ever-popular TextBox control are Change and KeyPress. Events must be declared in the declarations section of your control, then they can be raised at whatever moment you feel fit. It is these events, and not the InitProperties, ReadProperties, WriteProperties, etc. that the developer will see. Our blink event would require this declaration:
Public Event Blink()
Within the parenthesis, you can place any parameters that you want to pass with the event. For a click event, this might be the x and y co-ordinates of the click position. However, since we are only blinking, we don't need any extra parameters.
Surprisingly enough, to raise the event, you use the RaiseEvent method. For our blink event, we will have it connected to a timer, so that it will regularly blink:
Private Sub Blinker_Timer()
And that's all there it is to it! There are no secrets, no subtle twists and no hidden cheats. All our budding developer must do now is to write some code for blinking in the blink event:
Private Sub BodyControl1_Blink()
Debug.Print "Wow! I have just blinked!"
A final word..
Well, that's about it for the first instalment of ActiveX controls. Next time we will be looking at loads more cool features that we can add to the control, including the picture and font properties, an aboutbox, and read-only at runtime properties to mention just a few. You know where to come if you're just craving for some more great ActiveX action. Tune in same time, same place for yet more OCX excitement.