Implementing the CD Form

Team-Fly    

 
eMbedded Visual Basic: Windows CE and Pocket PC Mobile Applications
By Chris Tacke, Timothy Bassett
Table of Contents
Chapter 7.  Storing and Retrieving Data with ActiveX Data Objects CE


Now, build the CD form that you added at the beginning of the project. The CD form allows the user to edit an existing CD record or add a new CD record.

Designing the CD Form

The CD form (frmCD) has the following controls and nondefault property values:

Control Property Setting(s)
Label Caption = "Artist"
ComboBox Name = "cboArtist"
Label Caption = " Genre "
ComboBox Name = "cboGenre"
Label Caption = "CD Name"
Textbox Name = "txtCDName", MaxLength = 64
Label Caption = "Year Released"
Textbox Name = "txtYear", MaxLength = 4
Label Caption = "Price"
Textbox Name = "txtPrice"
Menu Name = "MenuBar1", NewButton = True (default value, but ensure)

Visually design the CD form to look similar to Figure 7.5.

Figure 7.5. The CD form (frmCD) has a control for each user-editable column in the CD table. The menu control is added to allow the creation of a new CD record.

graphics/07fig05.gif

Setting Up frmCD

The CD form (frmCD) uses two module-level variables :

 Dim mlngCDId As Long      'stores the current CD primary key Dim mlngArtistId As Long  'stores the current Artist primary key 

Implementing CDOpen: The Entry Point to frmCD

Because the only function called from the main form (frmMain) is CDOpen, implement it first (see Listing 7.21).

Listing 7.21 Opening the CD Form
 Public Function CDOpen(_     ByVal lngCDId As Long, _     ByVal lngArtistId As Long, _     lngFormMode As Long) As Boolean     On Error Resume Next     ' set the default error return     CDOpen = False     ' check to see if a CDId was received     If IsNumeric(lngCDId) Then         ' set the module variable         mlngCDId = lngCDId     End If     ' check to see if an artist was received     If IsNumeric(lngArtistId) Then         ' set the module variable         mlngArtistId = lngArtistId     End If     ' which mode are we in?     Select Case lngFormMode         Case CDFORM_MODE_EDIT             ' Edit Mode             ' Close this up so we can get an             ' updatable version of just this record             If gobjCD.State = adStateOpen Then                 gobjCD.Close             End If             ' get the record             gobjCD.Open _                 "SELECT * FROM cd WHERE CDId = " & mlngCDId, _                 gobjConnection, _                 adOpenForwardOnly, _                 adLockOptimistic             ' did we find it?             If gobjCD.EOF Then                 Exit Function             End If             ' let's refresh the form             If Not RefreshFormCD() Then                 ' something went wrong                 MsgBox "Error refreshing form"                 Exit Function             End If         Case CDFORM_MODE_NEW             ' New CD             If Not CdNew() Then                 MsgBox "Can not create a new CD."                 Exit Function             End If     End Select     ' show the form     Me.Show End Function 

CDOpen does the usual setup, and then checks the value of the CDId parameter (lngCDId). If a numeric value was passed, it sets the module variable to it. This value is used to retrieve and save the record.

 ' check to see if a CDId was received If IsNumeric(lngCDId) Then     ' set the module variable     mlngCDId = lngCDId End If 

A similar action is taken with the contents of the ArtistId parameter (lngArtistId). If the New button on the Menu is tapped, the new CD record will default to this artist.

 ' check to see if an artist was received If IsNumeric(lngArtistId) Then     ' set the module variable     mlngArtistId = lngArtistId End If 

A decision is then made via a Select Case statement as to whether the form should behave in "edit" or "add new" mode. Remember, the Const CDFORM_MODE_EDIT and CDFORM_MODE_NEW are defined in modGlobal.

 ' which mode are we in? Select Case lngFormMode     Case CDFORM_MODE_EDIT         ' Edit Mode         ' Close this up so we can get an         ' updatable version of just this record         If gobjCD.State = adStateOpen Then             gobjCD.Close         End If         ' get the record         gobjCD.Open _             "SELECT * FROM cd WHERE CDId = " & mlngCDId, _             gobjConnection, _             adOpenForwardOnly, _             adLockReadOnly         ' did we find it?         If gobjCD.EOF Then             Exit Function         End If         ' let's refresh the form         If Not RefreshFormCD() Then             ' something went wrong             MsgBox "Error refreshing form"             Exit Function         End If     Case CDFORM_MODE_NEW         ' New CD         If Not CdNew() Then             MsgBox "Can not create a new CD."             Exit Function         End If End Select 

In edit mode, the CD Recordset (gobjCD) is immediately closed. Then, the particular record being edited is retrieved into the CD recordset.

The recordset LockType is still read-only (via adLockReadOnly enumeration value for the LockType parameter of the Open method). This would seem like an obvious place to open the recordset as an updatable LockType, but, in the SaveCD function, the record is retrieved again before updating.

I have found in my experience with eVB, it's best to count on maintaining the state of as few items as I can. In other words, there is currently no design reason here to not open the record set as updatable (adLockOptimistic). But, knowing eVB's encapsulation limitations, I find that it leads to more robust, maintainable codebase if the application never counts on that recordset to be in the same state when attempting to update the recordset. The recordset objects are constantly being reused. The application design might change in the sense that the CD recordset is manipulated in some manner that's not harmonious to the goals of opening the recordset updatable in the CDOpen function. This is one limitation to the encapsulation model of eVB and using global objects.

 ' Close this up so we can get an ' updatable version of just this record If gobjCD.State = adStateOpen Then     gobjCD.Close End If ' get the record gobjCD.Open _     "SELECT * FROM cd WHERE CDId = " & mlngCDId, _     gobjConnection, _     adOpenForwardOnly, _     adLockReadOnly 

CDOpen verifies the record was retrieved. If not, it exits the function returning an error value. If all is well, the RefreshFormCD function is called.

 ' did we find it? If gobjCD.EOF Then     MsgBox "Error finding CD record."     Exit Function End If ' let's refresh the form If Not RefreshFormCD () Then     ' something went wrong     MsgBox "Error refreshing form"     Exit Function End If 

Implementing the RefreshFormCD Function

RefreshFormCD is generic to handle both an edit of a record and new record (see Listing 7.22). It populates both the Artist and Genre comboboxes . If the artist or genre is known, it sets the combobox to the appropriate record. Then, it populates all the textboxes with the known values.

Listing 7.22 Setting the Values on the CD Form
 Private Function RefreshFormCD() As Boolean     Dim lngIndex As Long     On Error Resume Next     RefreshFormCD = False     ' add all artist records to     ' the artist combobox     PopulateArtistCombo     ' add all genre records to     ' genre combobox     PopulateGenreCombo     ' set the artist combo to no selected item     Me.cboArtist.ListIndex = -1     ' check for valid value     If Not IsNull(gobjCD.Fields("ArtistId").Value) Then         If gobjCD.Fields("ArtistId").Value > 0 Then             ' set the artist combobox             For lngIndex = 0 To Me.cboArtist.ListCount - 1                 ' is this the artist?                 If Me.cboArtist.ItemData(lngIndex) = _                     gobjCD.Fields("ArtistId").Value Then                         ' set the selected item                         Me.cboArtist.ListIndex = lngIndex                         ' get out of here                         Exit For                 End If             Next         End If     End If     ' set the genre combo to no selected item     Me.cboGenre.ListIndex = -1     ' check for valid value     If Not IsNull(gobjCD.Fields("GenreId").Value) Then         If gobjCD.Fields("GenreId").Value > 0 Then             ' set the genre combobox             For lngIndex = 0 To Me.cboGenre.ListCount - 1                 If Me.cboGenre.ItemData(lngIndex) = _                     gobjCD.Fields("GenreId").Value Then                             Me.cboGenre.ListIndex = lngIndex                             Exit For                 End If             Next         End If     End If     ' clear the textboxes     Me.txtCDName.Text = ""     Me.txtYear.Text = ""     Me.txtPrice.Text = ""     ' do we have a CD name?     If Not IsNull(gobjCD.Fields("CDName").Value) Then         ' set the name         Me.txtCDName.Text = gobjCD.Fields("CDName").Value     End If     ' do we have a valid year?     If Not IsNull(gobjCD.Fields("Year").Value) Then         If gobjCD.Fields("Year").Value <> 0 Then             ' set the year             Me.txtYear.Text = gobjCD.Fields("Year").Value         End If     End If     ' valid price     If Not IsNull(gobjCD.Fields("Price").Value <> 0) Then         If gobjCD.Fields("Price").Value <> 0 Then             ' set the price             Me.txtPrice.Text = gobjCD.Fields("Price").Value         End If     End If     If Err.Number = 0 Then         RefreshFormCD = True     End If End Function 

Implementing the PopulateArtistCombo Function

The PopulateArtistCombo function closes , then opens the artist table with the artist recordset object (gobjArtist). After clearing the artist combobox (cboArtist), it repopulates it (see Listing 7.23). The artist recordset is scanned, adding an entry to the combobox for each artist record. After adding the record, it sets the appropriate item in the ItemData collection to the primary key value of the artist record.

Listing 7.23 Adding the Choices to the Artist Combobox
 Private Function PopulateArtistCombo() As Boolean     On Error Resume Next     ' set the error state for early exit     PopulateArtistCombo = False     ' close the artist recordset     If gobjArtist.State = adStateOpen Then         gobjArtist.Close     End If     ' open artist     gobjArtist.Open "artist", _         gobjConnection, _         adOpenForwardOnly, _         adLockReadOnly, _         adCmdTableDirect     ' clear the current contents     ' of the combobox     Me.cboArtist.Clear     ' scan the recordset     Do While Not gobjArtist.EOF         ' add the artist         Me.cboArtist.AddItem gobjArtist.Fields("ArtistName").Value         ' set the ItemData to the primary key of the artist record         Me.cboArtist.ItemData(Me.cboArtist.NewIndex) = _             gobjArtist.Fields("ArtistId").Value         ' next record         gobjArtist.MoveNext     Loop     ' check for errors     If Err.Number = 0 Then         PopulateArtistCombo = True     End If End Function 

Implementing the PopulateGenreCombo Function

The PopulateGenreCombo function works exactly like the PopulateArtistCombo function, except it uses the genre table (see Listing 7.24).

Listing 7.24 Adding the Choices to the Genre Combo Box
 Private Function PopulateGenreCombo() As Boolean     On Error Resume Next     ' set the error state for early exit     PopulateGenreCombo = False     ' close the genre recordset     If gobjGenre.State = adStateOpen Then         gobjGenre.Close     End If     ' open genre     gobjGenre.Open "genre", _         gobjConnection, _         adOpenForwardOnly, _         adLockReadOnly, _         adCmdTableDirect     ' clear the current contents     ' of the combobox     Me.cboGenre.Clear     ' scan the recordset     Do While Not gobjGenre.EOF         ' add the artist         Me.cboGenre.AddItem gobjGenre.Fields("genreName").Value         ' set the ItemData to the primary key of the artist record         Me.cboGenre.ItemData(Me.cboGenre.NewIndex) = _             gobjGenre.Fields("genreId").Value         ' next record         gobjGenre.MoveNext     Loop     If Err.Number = 0 Then         PopulateGenreCombo = True     End If End Function 

Viewing the CD

At this point, your CD form should operate minimally . Start the application up and tap a CD record in the grid of the main form (frmMain). Does it bring up the CD form? Are the comboboxes populated ?

Implementing the New Button on the Main Form

At this point, let's take a step back and implement the New button of the menu bar from the main form (frmMain):

 Private Sub MenuBar1_NewClick()     ' open the cd form with the current artist in new mode     frmCD.CDOpen Null, glngArtistId, CDFORM_MODE_NEW End Sub 

Implementing a New CD in the CD Form

In the CDOpen function (refer to Listing 7.21), there was a case of the Select Case block we didn't examine. Part of the functionality of creating a new CD from the main form is implemented in CDOpen within that Case statement:

 Case CDFORM_MODE_NEW     ' New CD     If Not CdNew() Then         MsgBox "Can not create a new CD."         Exit Function     End If 

In the Case CDFORM_MODE_NEW statement, a call is made to the CdNew function, whose duty it is to temporarily append a record to the CD recordset object (see Listing 7.25),. A peculiar looking approach might be to append a new record, canceling it only a few lines later. This is just a "trick" to give RefreshFormCD the ability to generically handle new and edit records.

Listing 7.25 frmCD: Creating a New CD Record
 Private Function CdNew() As Boolean     On Error Resume Next     ' a bit different, since we have     ' cleanup to do, we'll assume no     ' error return value and set it at     ' the end if there is an error     CdNew = True     ' since it's a new record, it has no primary key     mlngCDId = Null     ' if it currently does not adding     ' new records, let's close it, so     ' we can reopen it with AddNew support     If gobjCD.State = adStateOpen Then         If Not gobjCD.Supports(adAddNew) Then             gobjCD.Close         End If     End If              adOpenForwardOnly, adLockOptimistic, adCmdTableDirect     End If     ' add a new record     gobjCD.AddNew     ' set the artist id foreign key     gobjCD.Fields("ArtistId") = mlngArtistId     ' we're going to refresh the form     ' while we have this blank record     ' on hand, this is a good way to     ' keep that RefreshFormCD generic     If Not RefreshFormCD() Then         ' error         CdNew = False     End If     ' now that we refreshed the form, we     ' need to cancel the update     gobjCD.CancelUpdate     ' everything go ok?     If Err.Number <> 0 Then         ' something did not go ok         CdNew = False     End If End Function 

Go Ahead, Make My CD

Your application should be able to not only display a particular record from the CD table, but be able to mimic creating a new one. Start your application and tap the New button on the main form. It should display a blank record, with the exception of setting the artist combobox (cboArtist) to the "current artist."

Implementing the SaveCD Function

The CD Library application saves CD records when users tap the OK button on the top-right of the form. By default, there is an OK button on every eVB form. Typically, on first edit of a form's code, eVB will put template code in the Form.OKClick event to stop execution of the application:

 Private Sub Form_OKClick()     App.End End Sub 

You need to override this behavior in the CD form. The code in Listing 7.26 enables the CD form to call SaveCD on an OKClick event of the form.

Listing 7.26 Saving the CD Record
 Private Sub Form_OKClick()     On Error Resume Next     ' save the cd     If SaveCD() Then         ' it's saved, let's get back         frmMain.Show     Else         ' error - do not close form         MsgBox "Error saving record."     End If End Sub 

The OKClick event in Listing 7.26 calls the SaveCD function in Listing 7.27.

Listing 7.27 Committing the Record
 Private Function SaveCD() As Boolean     Dim lngArtistId As Long     Dim lngGenreId As Long     On Error Resume Next     ' because we may have some cleanup     ' work to do, let's set the     ' default return value to true     SaveCD = True     ' do we have an existing or new genre     If Me.cboGenre.ListIndex >= 0 Then         ' existing genre         ' get the pk value         lngGenreId = Me.cboGenre.ItemData(Me.cboGenre.ListIndex)     Else         ' new genre         ' ask user to add new genre         If MsgBox("Would you like to add the genre: " _             & Me.cboGenre.Text, vbYesNo) = vbYes Then                 ' get a new genre pk value                 lngGenreId = AddGenre(Me.cboGenre.Text)                 ' is it valid?                 If lngGenreId < 0 Then                     ' outta here                     MsgBox "Error adding genre."                     SaveCD = False                     Exit Function                 End If         Else             ' can't save without a genre             SaveCD = False             MsgBox "You can not save a CD without a genre."             Exit Function         End If     End If     ' do we have an existing or new artist     If Me.cboArtist.ListIndex >= 0 Then         ' existing genre         ' get the pk value         lngArtistId = Me.cboArtist.ItemData(Me.cboArtist.ListIndex)     Else         ' new genre         ' ask user to add new genre                 If MsgBox("Would you like to add the artist: " _             & Me.cboArtist.Text, vbYesNo) = vbYes Then              ' get a new artist pk value              lngArtistId = AddArtist(Me.cboArtist.Text, lngGenreId)              ' is it valid?              If lngArtistId < 0 Then                  ' outta here                  SaveCD = False                  MsgBox "Error adding artist."                  Exit Function             End If         Else             ' can't save without a artist             SaveCD = False             MsgBox "You can not save a CD without a artist."             Exit Function         End If     End If     ' close the CD recordset, we're about to update     If gobjCD.State = adStateOpen Then         gobjCD.Close     End If     ' check mode     If Not IsNull(mlngCDId) Then         'edit mode - let's get the record         gobjCD.Open "SELECT * FROM cd WHERE CDId = " _             & mlngCDId, gobjConnection, _             adOpenForwardOnly, adLockOptimistic     Else         ' new mode, no primary key value         gobjCD.Open "cd", gobjConnection, adOpenForwardOnly, _             adLockOptimistic, adCmdTableDirect         ' get a new pk value         mlngCDId = GetNewPK("CD")         ' add the record         gobjCD.AddNew         ' set the pk value         gobjCD.Fields("CDId").Value = mlngCDId     End If     ' are we at the end of the     ' recordset (no record added     ' or no record retrieved)     If gobjCD.EOF Then         Exit Function     End If     ' assign the values     gobjCD.Fields("ArtistID").Value = lngArtistId     gobjCD.Fields("CDName").Value = Me.txtCDName.Text     gobjCD.Fields("Year").Value = CLng(Me.txtYear.Text)     gobjCD.Fields("Price").Value = CCur(Me.txtPrice.Text)     gobjCD.Fields("GenreID").Value = lngGenreId     ' update the recordset     gobjCD.Update     ' check for errors     If Err.Number <> 0 Then         Exit Function     End If     ' everything's cool, return true     SaveCD = True End Function 

Now examine SaveCD. This function determines whether the genre combobox is an existing or new genre. If the current genre combobox displays an existing genre, the ListIndex property of the combobox will be => 0. If ListIndex is < 0, it must be a genre not in the genre table.

If the genre already exists, the primary key value of that genre record is retained from the ItemData collection of the combobox:

 ' do we have an existing or new genre If Me.cboGenre.ListIndex >= 0 Then     ' existing genre     ' get the pk value     lngGenreId = Me.cboGenre.ItemData(Me.cboGenre.ListIndex) Else     ' new genre     ' ask user to add new genre         If MsgBox("Would you like to add the genre: " _             & Me.cboGenre.Text, vbYesNo) = vbYes Then                 ' get a new genre pk value                 lngGenreId = AddGenre(Me.cboGenre.Text)                 ' is it valid?                 If lngGenreId < 0 Then                     ' outta here                     MsgBox "Error adding genre."                     SaveCD = False                     Exit Function                 End If     Else         ' can't save without a genre         SaveCD = False         MsgBox "You can not save a CD without a genre."         Exit Function     End If End If 

If the genre doesn't exist, the user is prompted by a MsgBox to add it. If the user agrees to add the genre, AddGenre is called with the value of the combobox's Text property. The return value of AddGenre (the new primary key value) is retained and checked for validity.

 ' do we have an existing or new genre If Me.cboGenre.ListIndex >= 0 Then     ' existing genre     ' get the pk value     lngGenreId = Me.cboGenre.ItemData(Me.cboGenre.ListIndex) Else     ' new genre     ' ask user to add new genre         If MsgBox("Would you like to add the genre: " _             & Me.cboGenre.Text, vbYesNo) = vbYes Then                 ' get a new genre pk value                 lngGenreId = AddGenre(Me.cboGenre.Text)                 ' is it valid?                 If lngGenreId < 0 Then                     ' outta here                     MsgBox "Error adding genre."                     SaveCD = False                     Exit Function                 End If     Else         ' can't save without a genre         SaveCD = False         MsgBox "You can not save a CD without a genre."         Exit Function     End If End If 

If the genre doesn't exist and the user doesn't choose to add the genre, the return value for the SaveCD function is set to False and the function exits.

 ' do we have an existing or new genre If Me.cboGenre.ListIndex >= 0 Then     ' existing genre     ' get the pk value     lngGenreId = Me.cboGenre.ItemData(Me.cboGenre.ListIndex) Else     ' new genre     ' ask user to add new genre         If MsgBox("Would you like to add the genre: " _             & Me.cboGenre.Text, vbYesNo) = vbYes Then                 ' get a new genre pk value                 lngGenreId = AddGenre(Me.cboGenre.Text)                 ' is it valid?                 If lngGenreId < 0 Then                     ' outta here                     MsgBox "Error adding genre."                     SaveCD = False                     Exit Function                 End If     Else         ' can't save without a genre         SaveCD = False         MsgBox "You can not save a CD without a genre."         Exit Function     End If End If 

The same structure of checking the combobox values and prompting the user takes place for the artist combobox:

 ' do we have an existing or new artist If Me.cboArtist.ListIndex >= 0 Then     ' existing genre     ' get the pk value     lngArtistId = Me.cboArtist.ItemData(Me.cboArtist.ListIndex) Else     ' new genre     ' ask user to add new genre         If MsgBox("Would you like to add the artist: " _             & Me.cboArtist.Text, vbYesNo) = vbYes Then              ' get a new artist pk value              lngArtistId = AddArtist(Me.cboArtist.Text, lngGenreId)              ' is it valid?              If lngArtistId < 0 Then                  ' outta here                  SaveCD = False                  MsgBox "Error adding artist."                  Exit Function             End If     Else         ' can't save without a artist         SaveCD = False         MsgBox "You can not save a CD without a artist."         Exit Function     End If End If 

Now, SaveCD should have all the values needed to save the CD record. The CD recordset object is closed.

 ' close the CD recordset, we're about to update If gobjCD.State = adStateOpen Then     gobjCD.Close End If 

The check of mlngCDId for Null determines whether the record to save is a new CD record or a CD record edit. If the value of mlngCDId is Not Null, the record being saved is an edit, otherwise it's a new record.

 ' check mode If Not IsNull(mlngCDId) Then         'edit mode - let's get the record         gobjCD.Open "SELECT * FROM cd WHERE CDId = " _             & mlngCDId, gobjConnection, _             adOpenForwardOnly, adLockOptimistic Else         ' new mode, no primary key value         gobjCD.Open "cd", gobjConnection, adOpenForwardOnly, _             adLockOptimistic, adCmdTableDirect         ' get a new pk value         mlngCDId = GetNewPK("CD")         ' add the record         gobjCD.AddNew         ' set the pk value         gobjCD.Fields("CDId").Value = mlngCDId End If 

If the record is an edit, the CD recordset object is opened via a SQL statement. The table is filtered down to one record using the WHERE clause and the value of mlngCDId. The LockType is adLockOptimistic.

 'edit mode - let's get the record gobjCD.Open "SELECT * FROM cd WHERE CDId = " _         & mlngCDId, gobjConnection, _         adOpenForwardOnly, adLockOptimistic 

If the record is a new record, the CD table is opened directly, again using LockType of adLockOptimistic. Also, notice the optional parameter of adCmdTableDirect. This is why the source is only the table name.

 ' new mode, no primary key value gobjCD.Open "cd", gobjConnection, adOpenForwardOnly, _         adLockOptimistic, adCmdTableDirect 

Because this is new CD record, it needs a primary key value. GetNewPK provides this new primary key value:

 ' get a new pk value mlngCDId = GetNewPK("CD") 

A new record is added:

 ' add the record gobjCD.AddNew 

Set the primary key value on this new record:

 ' set the pk value gobjCD.Fields("CDId").Value = mlngCDId 

Now that the different actions have been taken for a new or edited CD record, the rest of the function to save the record is the same, for both Add and Edit.

A check is made to ensure you have a record, whether that record should be an appended record (for new) or a single record (for an edit):

 ' are we at the end of the ' recordset (no record added ' or no record retrieved) If gobjCD.EOF Then     Exit Function End If 

The values are assigned to the Field objects of the Fields collection:

 ' assign the values gobjCD.Fields("ArtistID").Value = lngArtistId gobjCD.Fields("CDName").Value = Me.txtCDName.Text gobjCD.Fields("Year").Value = CLng(Me.txtYear.Text) gobjCD.Fields("Price").Value = CCur(Me.txtPrice.Text) gobjCD.Fields("GenreID").Value = lngGenreId 

The recordset object is updated, sending the data back to the data store. A check for errors and SaveCD is done:

 ' update the recordset gobjCD.Update ' check for errors If Err.Number <> 0 Then     Exit Function End If ' everything's cool, return true SaveCD = True 

Team-Fly    
Top
 


eMbedded Visual BasicR. WindowsR CE and Pocket PC Mobile Applications
eMbedded Visual BasicR. WindowsR CE and Pocket PC Mobile Applications
ISBN: N/A
EAN: N/A
Year: 2001
Pages: 108

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net