Using VSView Reporting Edition > Advanced Topics > Custom Data Sources > Implementing Custom Recordsets in Visual Basic |
To implement a custom recordset in Visual Basic, follow these steps (for a complete example, see the CustomData project in the Samples/VB directory):
Create a new project (or open an existing one) and add a VSReport8 and a VSPrinter8 control to the main form.
Create a Class Module using the Project menu and selecting Add Class Module. Use the property window to give the class a meaningful name (such as MyReportDataSource).
Open the code window and add the following code to the new class:
Example Title |
Copy Code
|
---|---|
Option Explicit Implements IVSReportRecordset Private m_sData(5) As String Private m_lCursor As Long Private Sub Class_Initialize() InitData m_lCursor = 0 End Sub Private Sub InitData() m_sData(0) = "Alice Mutton|Meat/Poultry|20 - 1 kg tins|0" m_sData(1) = "Aniseed Syrup|Condiments|12 - 550 ml bottles|13" m_sData(2) = "Boston Crab Meat|Seafood|24 - 4 oz tins|123" m_sData(3) = "Camembert Pierrot|Dairy Products|15 - 300 g rounds|19" m_sData(4) = "Carnarvon Tigers|Seafood|16 kg pkg.|42" m_sData(5) = "Chai|Beverages|10 boxes x 20 bags|39" End Sub |
The Implements statement is important. It means this class promises to implement all the methods in the IVSReportRecordset, described above. Without this statement, the class would not qualify as a valid recordset for VSReport8, and trying to assign an instance of it to the Recordset property would raise an error.
The m_sData() and m_lCursor are the variables that will hold the actual data and the cursor position for our new class. They are both initialized in response to the Class_Initialize event. In this example, there are only five records, each consisting of a string with field values separated by pipes ("|").
Select the IVSReportRecordset_GetFieldCount routine on the code editor (note that VB created a stub automatically based on the Implements statement) and add the following implementation:
Example Title |
Copy Code
|
---|---|
Private Function IVSReportRecordset_GetFieldCount() As Long IVSReportRecordset_GetFieldCount = 4 End Function |
This function returns the number of fields in the recordset. In this case, each record contains four fields: product name, category name, quantity per unit, and units in stock.
Follow the same steps to implement the remaining field information routines:
Example Title |
Copy Code
|
---|---|
Private Function IVSReportRecordset_GetFieldName_ (ByVal Index As Long) As String Dim s$ Select Case Index Case 0: s = "ProductName" Case 1: s = "CategoryName" Case 2: s = "QuantityPerUnit" Case 3: s = "UnitsInStock" Case Else Err.Raise 666, , "Invalid Index" End Select IVSReportRecordset_GetFieldName = s End Function |
This function returns the name of a field based on its index. The field names are important because they are used by VSReport8 when evaluating the expressions contained in calculated report fields.
Example Title |
Copy Code
|
---|---|
Private Function IVSReportRecordset_GetFieldType_
(ByVal Index As Long) As Long
IVSReportRecordset_GetFieldType = 8 ' string
End Function
Private Function IVSReportRecordset_GetFieldSize_
(ByVal Index As Long) As Long
IVSReportRecordset_GetFieldSize = 50
End Function
|
These functions return each field's type and size. They are not used by VSReport8 except to give it back to the user in case he requests it using the FieldInfo property.
Example Title |
Copy Code
|
---|---|
Private Function IVSReportRecordset_GetFieldValue
(ByVal Index As Long) As Variant
Dim v
v = Split(m_sData(m_lCursor), "|")
IVSReportRecordset_GetFieldValue = v(Index)
End Function
|
This function returns the value for a specific field in the current record. In this example, the function splits the current record string at the pipes using VB's Split function and returns the desired value.
Implement the cursor management functions:
Example Title |
Copy Code
|
---|---|
Private Sub IVSReportRecordset_MoveFirst() m_lCursor = 0 End Sub Private Sub IVSReportRecordset_MoveLast() m_lCursor = UBound(m_sData) End Sub Private Sub IVSReportRecordset_MovePrevious() If m_lCursor > 0 Then m_lCursor = m_lCursor - 1 End Sub Private Sub IVSReportRecordset_MoveNext() If m_lCursor < UBound(m_sData) Then m_lCursor = m_lCursor + 1 End Sub Private Function IVSReportRecordset_BegOfFile() As Boolean IVSReportRecordset_BegOfFile = (m_lCursor = 0) End Function Private Function IVSReportRecordset_EndOfFile() As Boolean IVSReportRecordset_EndOfFile = (m_lCursor >= UBound(m_sData)) End Function |
These functions move the cursor and inform the caller (VSReport8) whether the cursor has reached the end of the recordset. The functions are simple and generic, and you should be able to use them whenever your data is stored in arrays.
Example Title |
Copy Code
|
---|---|
Private Function IVSReportRecordset_GetBookmark() As Variant
IVSReportRecordset_GetBookmark = m_lCursor
End Function
Private Sub IVSReportRecordset_SetBookmark(newVal As Variant)
If newVal < 0 Or newVal > UBound(m_sData) Then
Err.Raise 666, , "Invalid Bookmark"
Else
m_lCursor = newVal
End If
End Sub
|
The bookmark functions allow the caller (VSReport8) to save and restore its current position in the recordset. This is necessary when calculating aggregate expressions.
Implement the filtering and sorting functions:
Example Title |
Copy Code
|
---|---|
Private Sub IVSReportRecordset_ApplyFilter(ByVal Filter As String) Debug.Print "Ignoring filter: "; Filter End Sub Private Sub IVSReportRecordset_ApplySort(ByVal Sort As String) Debug.Print "Ignoring sort: "; Sort End Sub |
As you can see, these are dummy implementations. They don't need to do anything, but they need to be there so the class qualifies as a bona-fide IVSReportRecordset.
Instantiate and use the custom recordset as you would use an ADO or DAO recordset. For example, add a button and the following code to the form:
Example Title |
Copy Code
|
---|---|
Private Sub Command2_Click()
' create the custom recordset object
Dim rs As New MyReportDataSource
With VSReport1
.DataSource.Recordset = rs
.Render VSPrinter1
End With
End Sub
|