1.6 TakeCareofErrorHandlingwithBoundControls When dealing with database tasks, you are going to get runtime errors. In .NET, we call the various types of errors you can get exceptions. This How-To shows examples of what exceptions could occur and how to handle them using the Try, Catch, and Finally statements. Adding and deleting records is fine, but what happens if an error occurs? You tried to delete an existing company, and got the screen that appears in Figure 1.10. Figure 1.10. This is an unhandled error, called an exception in .NET. How do you make it so errors are handled gracefully within the application using bound controls? Technique Errorhandling is one of the most important aspects of working with data, between when a user is entering data and updating the server. If you don't have proper error handling, your system will, in the best situation, give an ugly error message, and in the worst, blow up and put bad data in your system. In Visual Studio .NET, errors are classes called exceptions. Many different (inherited) types of exceptions exist. Run-time exceptions can occur in just about any part of your application. They can be handled by using Try .Catch .Finally or they can be unhandled, where you will see the error in Figure 1.11. Figure 1.11. This error was thrown up from one subroutine to the one that called it. Take a look at a common way to trap exceptions shown in Listing 1.15. Listing 1.15 Standard Code for Handling Exceptions Private Sub MySub() Try '-Code to be handled here Catch dataException as Exception MessageBox.Show(dataException.Message) Finally '-Code that will occur regardless of if an error occurs. End Try End Sub Following are some basic points to help you when working with exceptions and Try .Catch .Finally blocks: • The name of the exception object can be whatever you want it to be. dataException was just used as an example. • Specific types of exceptions inherit from the base class of System.Exception. OleDbException is one of those classes, and you will see an example of using this class in the following steps. • You can use the Throw statement within a Catch statement to throw the exception back up to a calling subroutine. • You can use the When clause on the Catch statement to trap for specific exceptions. • When multiple Catch statements are used, each one is executed unless an End Try or End Sub is placed within a Catch block, as in this How-To. • You can use multiple Catch statements to handle various possible exceptions that can occur. You will see an example of these bullets in the following steps. Steps Taking the form with which you have been working, you are going to modify it to trap exceptions when the record is being saved (either for additions or editing) and when the record is deleted. You will also add some code in the event when closing the form. 1. Modify the code in the Click event of the command button called btnSave. You will surround the SaveRecord routine call with a Try .Catch .End Try block. If an exception occurs, the Show method of the MessageBox class is called, passing the Message property of the Exception object called saveException. Next, the subroutine is exited. If no errors occur, then life goes on, and so does the subroutine. Listing 1.16 frmHowTo1_6.vb: Code Added to btnSave Click Event to Trap Save Exceptions Private Sub btnSave_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnSave.Click Try '- Save the information SaveRecord() Catch saveException As Exception MessageBox.Show("The following error has occurred: " & _ saveException.Message, "Error Saving Record") Exit Sub End Try '- Disable the text boxes ActivateEditing(False) If mbAddNew Then LoadList() RefreshIndividual() mbAddNew = False End If End Sub 2. Modify the SaveRecord routine to "throw" the exception up to the btnSave_Click subroutine, or whatever happens to have called the SaveRecord routine. Following is the SaveRecord subroutine with the new Try .Catch .End Try block added, along with the Throw statement. Listing 1.17 frmHowTo1_6.vb: Pass the Exception Back Up to the Calling Routine Private Sub SaveRecord() Try '- Use the BindingContext class to end the current editing so ' that we can update the server. Me.BindingContext(Me.dsCustomerIndividual, _ "Customers").EndCurrentEdit() '- Perform the requested task at the dataset ' level using the data adapter odaCustomerIndividual.Update(dsCustomerIndividual, "Customers") '- By accepting the changes, the data gets sent back to the server dsCustomerIndividual.AcceptChanges() Catch saveException As Exception Throw saveException End Try End Sub 3. Now it's time to deal with adding exception handling to the btnDelete Click event, as seen next. The Try statement is used to wrap the code that performs deletion of the data. The code then uses a Catch statement to check whether the exception that occurs is a specific OleDbException, 3621, which is an error having to do with trying to delete a record when related records exist in another table. Note that you could-and in fact should-assign this to a constant value. Because delException has been caught as an OleDbException, you can look at the NativeError property of the first error in the Errors collection to get the actual OleDb error number. If the error is not 3621, then the exception is trapped with the next Catch statement, and a messagebox is displayed. If errors occur, then the subroutine is exited before the final lines of code are executed. Listing 1.18 frmHowTo1_6.vb: Catching Exceptions When You're Deleting a Record Private Sub btnDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDelete.Click Try '- Mark the row for deletion using the RemoveAt ' method of the BindingContext Me.BindingContext(Me.dsCustomerIndividual, "Customers").RemoveAt(Me.BindingContext(Me.dsCustomerIndividual, "Customers").Position) '- Perform the requested task at the dataset ' level using the data adapter odaCustomerIndividual.Update(dsCustomerIndividual, "Customers") '- By accepting the changes, the data gets sent back to the server dsCustomerIndividual.AcceptChanges() Catch delException As System.Data.OleDb.OleDbException _ When delException.Errors(0).NativeError = 3621 MessageBox.Show("An error occurred because of related order records.", "Error Deleting Customer", _ MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Exit Sub Catch delException As Exception MessageBox.Show(delException.Message, "Error Deleting Customer", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Exit Sub End Try '- Reload the list LoadList() '- Display the first record RefreshIndividual() '- Disable the text boxes ActivateEditing(False) End Sub How It Works When an exception occurs within the Try .Catch .End Try block, the Catch statements are compared when a When clause is used or when the code is simply executed. If a Throw statement is used, then an execution is thrown back up a level to the Try .Catch .End Try block containing the call to the routine where the Throw statement occurred. You can see an example of this in Figure 1.11. Comments Microsoft has gone to great length to let you control how you handle exceptions in .NET with the various languages. You can be as creative as you need to by using the Try .Catch .End Try block with all the clauses available. Exceptions bring back plenty of information so that you can create pretty slick error handling. You can use exceptions to create a centralized routine that logs errors, or even one that e-mails exception information to you from your applications. . 1.6 Take Care of Error Handling with Bound Controls When dealing with database tasks, you are going to get runtime errors. In .NET, we. so errors are handled gracefully within the application using bound controls? Technique Error handling is one of the most important aspects of working with