ActiveX controls created with Visual Basic can support asynchronous downloading of property values, such as Picture properties that may contain bitmaps. Through the Hyperlink property of the UserControl object, they can also request that a browser jump to a URL, or navigate through the history list.
These features are available when the control is placed on a container that provides the necessary support functions, such as Microsoft Internet Explorer.
You may wish to design your control to support both normal loading of property values from a PropertyBag, which is not supported by browsers, and asynchronous downloading of property values.
Note Asynchronous downloading of local files is available in any application. An absolute file path must be used (that is, a path starting from the root directory). Relative file locations will not work.
A control requests asynchronous downloading of a property by calling the AsyncRead method of the UserControl object. This method can be called from any event, method, or property procedure of your control, as long as the control has already been sited on the container.
The call returns immediately, and downloading proceeds in the background, as shown in Figure 9.8a.
Figure 9.8a Starting asynchronous download of a bitmap property
When the container has retrieved the entire property value, the control receives an AsyncReadComplete event that identifies the property whose value has been retrieved. The control can then access the retrieved data and set the property value, as shown in Figure 9.8b.
Figure 9.8b Asynchronous download completes
The example code in this topic follows this scheme to create a simple control that displays a bitmap.
To work through the example, open a new Standard EXE project. Use the Project menu to add a UserControl to the project. Place a PictureBox control on the UserControl, and set the properties as shown in the following table:
Object | Property | Setting |
UserControl | Name | AsyncBitmap |
PictureBox | Name | picBitmap |
AutoSize | True |
The control will have two properties, an ordinary Picture property and a related PictureFromURL property. The Picture property is implemented with all three property procedures, because a Picture object can be assigned with or without the Set statement.
Public Property Get Picture() As Picture
Set Picture = picBitmap.Picture
End Property
Public Property Let Picture(ByVal NewPicture _
As Picture)
Set picBitmap.Picture = NewPicture
PropertyChanged "Picture"
End Property
Public Property Set Picture(ByVal NewPicture _
As Picture)
Set picBitmap.Picture = NewPicture
PropertyChanged "Picture"
End Property
The Picture property of the ActiveX control simply delegates to the Picture property of the picture box, picBitmap
. The picture box does all the work of displaying the bitmap.
The new property overrides the Picture property of the UserControl object. From now on, if you type Picture without qualifying it, you will get the ActiveX control's Picture property, as defined here. To access the Picture property of the UserControl, you must now qualify it by typing UserControl.Picture
.
Note The purpose and importance of PropertyChanged are discussed in "Adding Properties to Controls," later in this chapter.
When a URL string is assigned to the ActiveX control's PictureFromURL property, the Property Let begins a download of the bitmap. When the download is complete, the bitmap is assigned to the Picture property. PictureFromURL is thus an alternate way of assigning a value to the Picture property.
The PictureFromURL property stores the URL string in a private data member, in the Declarations section of the UserControl:
Option Explicit
Private mstrPictureFromURL As String
The Property Get simply returns this string, so the program can discover where the picture was downloaded from. The Property Let does all the work:
Public Property Get PictureFromURL() As String
PictureFromURL = mstrPictureFromURL
End Property
Public Property Let PictureFromURL(ByVal NewString _
As String)
' (Code to validate path or URL omitted.)
mstrPictureFromURL = NewString
If (Ambient.UserMode = True) _
And (NewString <> "") Then
' If program is in run mode, and the URL string
' is not empty, begin the download.
AsyncRead NewString, vbAsyncTypePicture, _
"PictureFromURL"
End If
PropertyChanged "PictureFromURL"
End Property
When a URL string is assigned to the PictureFromURL property, the string is saved in the private variable. If the project the control has been added to is in run mode (which will always be true for a control on an HTML page) and if the URL string is not empty, the Property Let starts an asynchronous download, and then exits.
The asynchronous download is begun by calling the UserControl's AsyncRead method, which has the following syntax:
AsyncRead Target, AsyncType [, Property]
The Target argument specifies the location of the data. This can be a path or a URL. The host determines the correct method to retrieve the data.
The AsyncType argument specifies the form in which the retrieved data will be provided. It has the following possible values:
Constant | Description |
VbAsyncTypePicture | The retrieved data is provided as a Picture object. |
VbAsyncTypeFile | The retrieved data is placed in a file created by Visual Basic. A string containing the path to the file is provided. This is useful when the data contains a large AVI file to be played. The control author can assign the string to the file name property of the appropriate constituent control. |
VbAsyncTypeByteArray | The retrieved data is provided as a byte array. It is assumed that the control author will know how to handle this data. |
The Property argument is a string containing the name of the property whose value is to be downloaded. You can use this to enable multiple simultaneous downloads, because this same string is returned in the AsyncReadComplete event, and can be used in a Select statement.
The value of the Property argument can also be used as the argument of the CancelAsyncRead method, described below.
As each requested download completes, the control receives an AsyncReadComplete event. The argument of the AsyncReadComplete event is a reference to an AsyncProperty object, which can be used to identify the downloaded property and retrieve the downloaded data.
Private Sub UserControl_AsyncReadComplete( _
AsyncProp As VB.AsyncProperty)
On Error Resume Next
Select Case AsyncProp.PropertyName
Case "PictureFromURL"
Set Picture = AsyncProp.Value
Debug.Print "Download complete"
End Select
End Sub
You should place error handling code in this event procedure, because an error condition may have stopped the download. If this was the case, that error will be raised when you access the Value property of the AsyncProperty object.
When the downloaded bitmap is assigned to the Picture property, the control repaints.
Note In addition to the Value property that contains the downloaded data and the PropertyName property that contains the name of the property being downloaded, the AsyncProperty object has an AsyncType property. This contains the same value as the AsyncType argument of the AsyncRead method that started the download.
So far, the example has no way to save a bitmap assigned at design time. That is, there is no code in the InitProperties, ReadProperties, and WriteProperties events. That code is omitted here, because the purpose of the example is to show asynchronous downloading of a local file.
One more bit of code will prove useful, however. The reason for using a picture box to display the bitmap, instead of simply using the Picture property of the UserControl, is to take advantage of the AutoSize property of the picture box. The following code resizes the entire control whenever the picture box is resized by the arrival of a new bitmap.
Private Sub picBitmap_Resize()
' If there's a Picture assigned, resize.
If picBitmap.Picture <> 0 Then
UserControl.Size picBitmap.Width, _
picBitmap.Height
End If
End Sub
The resizing only happens if the picture box actually contains a Picture object. This allows the user to specify the size of the empty picture box while the download is pending. The code is as follows:
Private Sub UserControl_Resize()
If picBitmap.Picture = 0 Then
picBitmap.Move 0, 0, ScaleWidth, ScaleHeight
Else
If (Width <> picBitmap.Width) _
Or (Height <> picBitmap.Height) Then
Size picBitmap.Width, picBitmap.Height
End If
End If
End Sub
If there is no Picture object, the picture box is sized to fill the visible area of the UserControl. If there is a Picture object, and the UserControl is resized, it will snap back to the size of the picture box.
Close the UserControl designer. The control is now running, even though the rest of the project is in design mode. The default control icon on the Toolbox is enabled, so you can add an instance of the control to Form1.
Locate a large bitmap on your computer the larger the better. Note the file name and path to the file. Add the following code to the Declarations section of Form1, substituting the name and path of your bitmap for the one shown here:
Option Explicit
Const DOWNLOADFILE = "file:\windows\forest.bmp"
Make sure the string begins with file:\
so that it's a valid URL for a local file.
Note The URL you pass to the AsyncRead method cannot be a relative URL. That is, you cannot specify relative pathnames for local files.
Place the following code in the form's Load event:
Private Sub Form_Load()
AsyncBitmap1.PictureFromURL = DOWNLOADFILE
DEBUG.PRINT "Load event complete"
End Sub
When the form loads, the URL for the local bitmap file will be assigned to the PictureFromURL property, starting the download.
Press F5 to run the project. In the Immediate window, notice that the first message is "Load event complete," followed by the "Download complete" message from the AsyncReadComplete event.
If the bitmap was large enough, you may also have noticed that Form1 painted while the bitmap was still downloading. Close Form1, to return to design mode.
Run the project again, and this time click the Close button on Form1 as soon as you see it. Because the download is proceeding asynchronously in the background, the form becomes active and can respond to user input before the bitmap has been loaded.
Up to this point, the example only demonstrates downloading of a local file. It can't be used on a Web page, because controls in Standard EXE projects cannot be used by other applications. To use the control in other projects or on Web pages, add the source file to an ActiveX control project and compile it as an .ocx file. You'll need some additional code for example, to save the Picture property, as shown here.
Private Sub UserControl_InitProperties()
' Use Nothing as the default when initializing,
' reading, and writing the Picture property,
' so than an .frx file won't be needed if
' there's no picture.
Set Picture = Nothing
End Sub
Private Sub UserControl_ReadProperties( _
PropBag As PropertyBag)
Set Picture = _
PropBag.ReadProperty("Picture", Nothing)
End Sub
Private Sub UserControl_WriteProperties( _
PropBag As PropertyBag)
PropBag.WriteProperty "Picture", Picture, Nothing
End Sub
You can use the ActiveX Control Interface Wizard to add standard properties, methods, and events such as MouseMove to the control.
You can call the CancelAsyncRead method to cancel an asynchronous data load. CancelAsyncRead takes the property name as an argument; this must match the value of the PropertyName argument in a prior AsyncRead method call.
Only the specified data load is canceled. All others continue normally.
For More Information You can also use the AsyncReadProgress event to monitor the progress of an asynchronous download. The AsynchReadProgress event is discussed in "Downloading Data Asynchronously" in "Building ActiveX Documents."
The Hyperlink object gives your control access to ActiveX hyperlinking functionality. Using the properties and methods of the Hyperlink object, your control can request a hyperlink-aware container, such as Microsoft Internet Explorer, to jump to a given URL or to navigate through the history list.
You can access the Hyperlink object through the Hyperlink property of the UserControl object. The following code fragment assumes that the control's URLText property contains a URL string. Clicking on the control causes it to request that its container navigate to that URL.
Private Sub UserControl_Click()
HyperLink.NavigateTo Target:=URLText
End Sub
If the target is not a valid URL or document, an error occurs. If the control is sited on a container that does not support hyperlinking, an application that is registered as supporting hyperlinking is started to handle the request.
The NavigateTo method accepts an optional Location argument, which specifies a location within the target URL. If a location is not specified, the server will jump to the top of the URL or document.
The NavigateTo method also accepts an optional FrameName argument, which specifies a frame within the target URL.
Note If your control is placed on a container that does not support the IHLink interface, the Hyperlink property of the UserControl object will return Nothing. You should test the property for this value before attempting to use the Hyperlink object.
You can call the GoForward and GoBack methods to navigate through the History list. For example:
Hyperlink.GoForward
If GoForward and GoBack are called when there are no entries in the History list to move forward to, an error occurs. GoForward and GoBack will also raise errors if the container is not hyperlink-aware.
For More Information Details of Internet support for ActiveX controls authored in Visual Basic can be found on the Microsoft Visual Basic Web site.
Information on designing Internet and intranet applications with Visual Basic can be found in Building Internet Applications.