Data Binding Objects (VB6)

Library to Reference

Microsoft Data Binding Collection (../SYSTEM32/MSBIND.DLL)

Description

Apparently, when Microsoft was planning the new release of Visual Basic, they researched how professional developers were using the language. One result which seems to have taken the VB development team by surprise was that very few professional developers use the Data control and data bound controls. The reason for this is quite easy to understand: rightly or wrongly, professional VB developers see the Data control and data bound controls as inflexible and an encroachment on their control over the database. Furthermore, as more and more VB applications follow the n-tier paradigm, in which database access is performed on a remote server, with only properties passed to (or requested by) the client, the usefulness of a Data control was diminishing rapidly.

With this in mind, Microsoft introduced a new object model to give developers control over data mapping without sacrificing the rapid development time offered by more or less central data binding. The binding objects sit between standard form controls and your recordset (which can be wrapped within a class in an ActiveX server), automatically updating the form control as the user navigates through the recordset. Therefore, any form control can now be bound to a database field.

The Binding object model, which is shown in Figure 7.2, consists of a top-level collection to which you add Binding objects, these being the physical binding of data column to form control. The Binding object offers a flexibility that should satisfy most needs. For example, you can bind data to any property on a control, and you can specify at what point the data binding should be updated. A major enhancement over previous data binding technologies is the ability to bind the controls on a form to a VB class object. This can be achieved in both directions; that is to say, a VB class module can now be a data source, or it can be a data consumer.

Figure 7.2. The Data Binding object model

Example

To introduce the objects involved in both data binding and data formatting, this example demonstrates how the objects can bind data from an ActiveX OLE server to standard VB form controls without using a Data control. This example uses the sample SQL Server pubs database, but it can be easily modified to use an Access database or even the computer's own file system as a source of data. What's important is the relationship between the different objects in the Data Binding and Data Formatting object model.

In this example, an ActiveX DLL class object performs the database access and exposes itself as a data source. The form creates a BindingCollection object that binds various controls on the form to database fields in two different recordsets held in the class. The example shows how to:

  • Expose a VB class as a data source.

  • Create a BindingCollection object.

  • Specify the VB class as the data source for the BindingCollection object.

  • Add individual Binding objects to the collection, thereby binding controls to database fields held within the data provider class object.

  • Create DataFormat objects to perform formatting functions on the incoming and outgoing data.

  • Navigate through the recordset.

  • Perform simple validation and confirmation before updating the database.

Data Consumer Form Code

The form includes the following object references, which are selected from the References dialog:

  • Microsoft Data Binding Collection

  • Microsoft Data Formatting Object Library

In addition, if the data source class isn't in the same project as the data consumer form, a reference to the data source class needs to be added.

The form contains the following controls:

Control Name Control Type
chkContract Checkbox
cmdMoveNext Command button
cmdMovePrevious Command button
txtAddress Text box
txtContract Text box
txtFirstName Text box
txtlastName Text box
txtPubDate1 Text box
txtTitle1 Text box

Option Explicit
'declare object variables for the BindingCollection
'objects we'll need and a single Binding object.
Private obcAuthors As BindingCollection
Private obcTitles  As BindingCollection
Private oBind      As Binding

'declare an object variable referencing our
'BindingSource class
Private oSource    As BindingSource

'declare object variables for the DataFormat objects
Private WithEvents fmtF1 As StdDataFormat
Private WithEvents fmtF2 As StdDataFormat
Private WithEvents fmtF3 As StdDataFormat
Private WithEvents fmtF4 As StdDataFormat

Private Sub Form_Load()

    'create new instances of the required objects
    'our source class
    Set oSource = New BindingSource
    'and the two BindingCollections
    Set obcAuthors = New BindingCollection
    Set obcTitles = New BindingCollection
    
    'Set up the required Format Objects
    'first to show a short message and automatically
    'handle NULL database values
    Set fmtF1 = New StdDataFormat
    fmtF1.Type = fmtCustom
    fmtF1.NullValue = "No Data Found"
    
    'second to handle 0 and 1 values in the database
    'displaying a string in the text box instead
    Set fmtF2 = New StdDataFormat
    fmtF2.Type = fmtBoolean
    fmtF2.FalseValue = "No Contract"
    fmtF2.TrueValue = "Contract Signed"
    
    'third to switch a checkbox on or off automatically
    'depending on the database value of 0 or 1
    Set fmtF3 = New StdDataFormat
    fmtF3.Type = fmtCheckbox
    
    'last one to format a date field
    Set fmtF4 = New StdDataFormat
    fmtF4.Type = fmtGeneral
    fmtF4.Format = "long date"
    
    'instruct the BindingCollection not to perform
    'an update until the user moves to the next record
    obcAuthors.UpdateMode = vbUpdateWhenRowChanges
    'set the DataMember to the required value - this
    'will be passed to the class to obtain a reference 
    'to the correct recordset
    obcAuthors.DataMember = "Authors"

    'now assign our source class as the datasource for
    'the authors bindings collection
    Set obcAuthors.DataSource = oSource
    'use the add method to create the binding between
    'form controls and database fields
    obcAuthors.Add txtFirstName, "Text", "au_fname", _
                   fmtF1, "fname"
    obcAuthors.Add txtLastName, "Text", "au_lname", _
                   fmtF1, "lname"
    obcAuthors.Add txtContract, "Text", "contract", _
                   fmtF2, "contract"
    obcAuthors.Add chkContract, "Value", "contract", _
                   fmtF3, "chkCont"
    obcAuthors.Add txtAddress, "Text", "address", _
                   fmtF1, "address"
    
    'now do the same for the Titles recordset
    obcTitles.UpdateMode = vbUpdateWhenRowChanges
    obcTitles.DataMember = "Titles"
    Set obcTitles.DataSource = oSource
    obcTitles.Add txtTitle1, "Text", "title", _
                  fmtF1, "title"
    obcTitles.Add txtPubDate1, "Text", "pubdate", _
                  fmtF4, "pubdate"
        
End Sub

Private Sub fmtF1_Format(ByVal DataValue As _
                         StdFormat.StdDataValue)

    'the format event is called when a custom type
    'is about to be formatted. Just for fun let's set
    'the firstname field to uppercase and the
    'lastname field to lowercase
    If DataValue.TargetObject.Name = "txtFirstName" Then
        fmtF1.Format = ">"
    Else
        fmtF1.Format = "<"
    End If
        
End Sub

Private Sub fmtF1_UnFormat(ByVal DataValue As _
                           StdFormat.StdDataValue)

   'the unformat event is only called for custom type
   'formats that are just about to be written back to
   'the database - so lets convert them back to proper
   'case
   DataValue.Value = StrConv(DataValue.Value, _
                             vbProperCase)
    
End Sub

Private Sub cmdMoveNext_Click()

    'the user has finished with the record and wants
    'the next one.
    
    'just check this out first..
    Call CheckForUpdate
    
    'ok now we'll give them the next record by calling
    'the MoveNext method in our source class.
    oSource.MoveNext
    'we need to rebind the titles recordset because
    'it's dynamically built
    Set obcTitles.DataSource = oSource
    
End Sub

Private Sub cmdMovePrev_Click()

    Call CheckForUpdate
    'call the MoveBack method in our source class
    oSource.MoveBack
        
End Sub

Private Function CheckForUpdate() As Boolean

   Dim iResponse As Integer
    
   'before we give them the next record - let's just
   'check whether they made any amendments to the
   'current record.
   'iterate through the Binding objects
   For Each oBind In obcAuthors
      'see if any values have been changed by the user
      If oBind.DataChanged Then
         'indeed they did--was it intentional though?
         iResponse = MsgBox("The data has changed" _
                            & vbCrLf & _
                            "do you wish to update?", _
                            vbYesNo + vbQuestion)
         If iResponse = vbNo Then
            'obviously not - so cancel the update from
            ' being written back to the database
            oBind.DataChanged = False
         End If
         'no point in looking any further...
         Exit For
      End If
   Next

End Function

Notes

  • This form is set as the project's startup object.

  • In the Form_Load event, a reference to the data source class is assigned to the BindingCollection.DataSource property, firing the data source class's GetDataMember event. The GetDataMember event handler assigns a reference to the recordset specified in the BindingCollection.DataMember property to the BindingCollection.

  • The Binding object's DataChanged property gives you control first, to interrogate the binding and determine if the value has been changed by the user, and second, to prevent the update from being written back to the database.

  • See the Data Format Objects entry for more information about the stdDataFormat object.

Data Source Class Code

The class references the Microsoft ActiveX Data Objects 2.0 Library, selected from the References dialog. The class also has its DataSourceBehavior property set to vbDataSource.

Option Explicit
'declare the ADO objects
Private cn As ADODB.Connection
Private WithEvents rsAuthors As ADODB.Recordset
Private WithEvents rsTitles As ADODB.Recordset

Private Sub Class_GetDataMember(DataMember As String, _
                                Data As Object)
    'this event is called as the datasource is assigned
    'to the BindingCollection object.
    If DataMember = "Authors" Then
        'this class provides two data members
        'the first is authors, the other is titles
        'assign the required recordset back to the
        'BindingCollection object
        Set Data = rsAuthors
    Else
        Set Data = rsTitles
    End If
End Sub

Private Sub Class_Initialize()
    Dim sSQL
    
    'create an instance of the ADO Recordset to use
    'for the Titles recordset later
    Set rsTitles = New ADODB.Recordset
    
    'create the connection object
    Set cn = New ADODB.Connection
        'there is a DNS called Test on this machine
        'pointing to the Pubs database
        cn.ConnectionString = "Test"
        cn.Open
        
    'peform the query to return the data from Authors
    sSQL = "SELECT * FROM authors"
    Set rsAuthors = New ADODB.Recordset
    rsAuthors.Open sSQL, cn, adOpenKeyset, adLockOptimistic
        
    'force the Titles recordset to be created
    rsAuthors.MoveFirst
    
End Sub

Public Sub MoveNext()
    'move to the next record
    rsAuthors.MoveNext
    If rsAuthors.EOF Then
        rsAuthors.MoveFirst
    End If
End Sub

Public Sub MoveBack()
    'move to the previous record
    rsAuthors.MovePrevious
    If rsAuthors.BOF Then
        rsAuthors.MoveLast
    End If
End Sub

Private Sub rsAuthors_MoveComplete(ByVal adReason As _
                        ADODB.EventReasonEnum, _
                        ByVal pError As ADODB.Error, _
                        adStatus As ADODB.EventStatusEnum, _
                        ByVal pRecordset As ADODB.Recordset)
    
    'Move_Complete is an event from the ADO Recordset
    'This code allows us to keep the two recordsets
    'in synch.
    Dim sSQL As String
        
    sSQL = "SELECT titles.title, titles.pubdate" & vbCrLf _
         & "  FROM titles, titleauthor" & vbCrLf _
         & " WHERE titleauthor.au_id = '" _
         & rsAuthors("au_id") & "'" & vbCrLf _
         & "   AND titles.title_id = titleauthor.title_id"
    
    If rsTitles.State = adStateOpen Then
        rsTitles.Close
    End If
    
    'you'll need to rebind this recordset - see code in form
    rsTitles.Open sSQL, cn, adOpenKeyset, adLockOptimistic
            
End Sub

Notes

  • The Class_GetDataMember event handler is automatically placed in the class for you when you set the class's DataSourceBehavior property to vbDataSource.

  • By declaring the ADO recordset object as WithEvents, you can access all the events in the recordset object (such as WillChangeField, which allows you to perform validation and cancellation prior to updating, if you wish).

See Also

BindingCollection Object, Binding Object
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.110.235