![]() | |
|
|
|
To access the contents, click the chapter and section titles.
Advanced Visual Basic Techniques
DataModified is fairly straightforward. It is true when there are pending changes to the document and false when there are no new changes to save. When the user successfully opens or saves a file, ExpenseReporter sets DataModified to false. The program uses Change events to set DataModified to true whenever the user changes data in a text box. For example, when the user types text into the Name field, the NameText_Change event handler executes code similar to the following:
Private Sub NameText_Change()
DataModified = True
End Sub
IgnoreModifyIn practice, using DataModified is not quite this simple. Occasionally the application needs to modify the controls that represent a document. This sort of modification does not represent a user-made change to the document. One example occurs when the user loads a file. When ExpenseReporter loads an existing expense report, it fills in all the text fields with values loaded from the file. This generates change events for every text box, but this does not mean the data has been modified. The file is simply being loaded, and initial values are being assigned to the fields. ExpenseReporter prevents confusion in this case by resetting DataModified to false after it has loaded the document and filled in all of the fields. A trickier problem occurs when the program reformats data but does not change its value. For instance, before printing a report, ExpenseReporter makes sure that all dollar amount fields display two places beyond the decimal point. If the user enters 12.1 in the Prepaid field, ExpenseReporter changes the value to 12.10 before it prints the document. At this point the PrepaidText controls Change event handler will detect the change and set DataModified to true even though the fields value has not really changed. If the user opens an expense report, prints it, and then tries to exit from ExpenseReporter, the program will ask if it should save the changes. The user may rightfully be annoyed and confused because he or she has made no changes.
Even trickier problems can occur in control management code. Suppose the user loads an existing expense report and the first expense has Category value Meals. The values presented by the Description combo box depend on the value of an expenses Category. Because the program now knows the Category of this expense, it must update the list of Description choices, which will cause the Description combo box to receive a Change event even though the data has not actually changed. A simple solution to these problems is to create a new Boolean variable IgnoreModify. Whenever the application needs to make a change that does not represent a user-made change to the documents data, it sets IgnoreModify to true. Change events then check this value to see if they should ignore the change or flag the document as modified. The following code shows the new Change event handler for the Name field.
Private Sub NameText_Change()
If Not IgnoreModify Then DataModified = True
End Sub
After the program has made its nonmodifying changes, it must be sure to restore IgnoreModify to false. Otherwise, the program will never know if the document is later altered by the user. This workaround can be particularly tricky if a routine that changes IgnoreModify is called by another routine that also sets IgnoreModify. The inner routine must not set IgnoreModify to false before it returns because the calling routine may still need the value to be true. If there is any doubt about whether one of these routines will be called by another, the routine should save the original value of IgnoreModify and restore it before returning. The SetDescrComboChoices subroutine that follows uses this technique to set the Description combo box choices based on an expense rows Category.
Sub SetDescrComboChoices(Index As Integer)
Dim txt As String
Dim old_ignore As Boolean
old_ignore = IgnoreModify
IgnoreModify = True
Save the current DescrCombo value.
txt = DescrCombo(Index).Text
Remove the old choices.
DescrCombo(Index).Clear
Create the appropriate choices.
Select Case CategoryCombo(Index).Text
Case Travel
DescrCombo(Index).AddItem Bus
DescrCombo(Index).AddItem Car Mileage
DescrCombo(Index).AddItem Car Rental
DescrCombo(Index).AddItem Plane
DescrCombo(Index).AddItem Taxi
DescrCombo(Index).AddItem Train
Case Meal
DescrCombo(Index).AddItem Breakfast
DescrCombo(Index).AddItem Lunch
DescrCombo(Index).AddItem Dinner
Case Hotel
DescrCombo(Index).AddItem Room
Case Else
DescrCombo(Index).AddItem Gasoline
DescrCombo(Index).AddItem Parking
DescrCombo(Index).AddItem Toll
End Select
Restore the previously selected value.
DescrCombo(Index).Text = txt
Restore IgnoreModify.
IgnoreModify = old_ignore
End Sub
One final way in which IgnoreModify can cause trouble occurs if a routine exits early. For whatever reason, a routine may finish early using an Exit Sub statement. A subroutine also might catch an error using an On Error GoTo statement and then error-handling code might execute an Exit Sub statement. In these cases, the subroutine must be certain it resets IgnoreModify to its previous value before exiting. It should always reset IgnoreModify before any Exit Sub statement and before the subroutine ends normally using End Sub. An even trickier situation occurs if the routine is called by another subroutine that contains an On Error statement. If the inner routine generates an error, control will pass immediately back to the calling subroutine. The inner routine will not have the chance to reset IgnoreModify to its original value. To handle this situation the inner routine should use its On Error GoTo statement to catch errors. The error-handling code should reset IgnoreModify and then use the Err objects Raise method to raise the error again so the calling routine can handle it.
Sub ChangeField()
Dim old_ignore As Boolean
old_ignore = IgnoreModify Save IgnoreModify.
IgnoreModify = True
On Error GoTo ResetIgnore Set the error trap.
Modify field values, etc.
:
If all is well, the program gets here.
IgnoreModify = old_ignore Restore IgnoreModify.
Exit Sub Exit Normally.
ResetIgnore:
Error. Restore IgnoreModify and reraise the error.
IgnoreModify = old_ignore
Err.Raise Err.Number, Err.Source, Err.Description
End Sub
|
||||||||||||||||||||||
|
Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.
|