• No results found

g Once all of the controls are created and initialized, they can be added to the form Visual Studio adds the controls in one statement using the AddRange method avail-

I MPLEMENT A C LICK HANDLER FOR THE BTN L OAD BUTTON

2.3.2 Exception handling

You may well be familiar with exception handling, since a number of C++ develop- ment environments, including earlier Microsoft environments, support this feature. Newer languages such as Java also support exceptions. Exception handling came into existence as a common way to deal with errors in a program. In our application, we expect the user to select a JPEG or other image file that can be opened as a Bitmap

object. Most of the time, no error occurs. However, if a corrupted or invalid JPEG file is selected, or if the operating system is low on memory, then this creates an exceptional condition where it may not be possible to create our Bitmap. Since such

situations will certainly occur, a way to recognize such errors is required.

Since some C++ programmers may not be familiar with exception handling, we will look at some alternative approaches before discussing exceptions in .NET. As one approach, we could use static creation methods that include an error field. For exam- ple, our code might look like the following:

Figure 2.5 The Visual Studio Options dialog box can be used to en- able or disable the statement comple- tion feature.

LOADINGFILES 59

// Wrong way #1 to support error handling int err = 0;

Bitmap bm = Bitmap.CreateObject(dlg.OpenFile(), err); if (err != 0) {

// An error occurred

if (err == bad_file_error) {

// Indicate to the user that the file could not be loaded. }

else if (err == memory_error) {

// Indicate that memory is running low. }

return; // on error abort the event handler }

// Assign the newly created Bitmap to our PictureBox pbxPhoto.Image = bm;

This code would certainly work, but it requires extra variables and the programmer must check for errors every time a bitmap is created. This might be problematic if the programmer forgets or a new error is added which is not handled by the code. Then our design is for naught and bad things will happen. In critical production code, the mishandling of errors can lead to serious problems such as corrupted database infor- mation, unexpected stock trades, or other actions that a user or a program would not normally allow to happen. So this solution does not provide the best guarantees for program and data stability.

A second way to handle errors is to provide a global GetLastErrorfunction.

This solution was used by Microsoft prior to the MFC environment, and is still used in some cases within MFC. It looks something like this:

// Wrong way #2 to support error handler Bitmap bm = new Bitmap(dlg.OpenFile()); int err = GetLastError();

if (err != 0) {

// Handle error values much like the above code }

This is more elegant than the previous method, but has all the same problems. Pro- grammers may forget to use it, and error codes change from release to release.

Exceptions provide a solution to these problems by forcing a programmer to deal with them, and provide guarantees that the program will exit if they do not. When an exception is not caught by a program, the program will exit. A forced exit is much safer than continuing to run in an error state and risk compromising critical data.

More formally, an exception is an unexpected error, or exceptional condition, that may occur in a program. Code that creates such a condition is said to throw the excep- tion, and code that processes the condition is said to catch the exception. In .NET,

exceptions are implemented as classes. Almost all exceptions inherit from the Sys- tem.Exception class.

One problem with exceptions in other languages is that they are expensive to sup- port. Modern languages like Java and C# have done away with this problem by designing exceptions into the language so that compilers can handle them cheaply and gracefully. The format used to process exceptions is the well-known try-catch blocks used

in distributed computing interfaces and C++ development environments for many years. A portion of code where exceptions may be caught is enclosed in a try block,

and the portion of code that handles an exception is enclosed in a catch block. We

will discuss this syntax in more detail in a moment. First, let’s add such a block to the code where we create the Bitmap object. Here is our existing code:

if (dlg.ShowDialog() == DialogResult.OK) {

imgPhoto.Image = new Bitmap(dlg.OpenFile()); }

The following table details how to catch exceptions in this code. CATCHEXCEPTIONSINTHEBTNLOAD_CLICKMETHOD

Action Result

1 Edit the MainForm.cs source file and locate the

btnLoad_Click method.

Note: You can search this file by hand, or use the drop- down box in the top portion of the source code window to select this method explicitly.

2 Insert a try block around the

Bitmap creation code.

The changes to the existing code are shown in bold.

if (dlg.ShowDialog() == DialogResult.OK) {

try {

imgPhoto.Image = new Bitmap(dlg.OpenFile()); }

}

3 Add a catch block to catch any exceptions that may occur in the try block.

if (dlg.ShowDialog() == DialogResult.OK) {

try {

imgPhoto.Image = new Bitmap(dlg.OpenFile()); }

catch (Exception ex) {

// Handle exception }

}

Note: Event handlers in Visual Studio .NET tend to use an “e” parameter for the event parameter to the call. To ensure we avoid a conflict, we will use ex as a standard variable name for an Exception object.

RESIZINGFORMS 61 In C#, the catch clause takes an exception class name, and a variable to use in refer-

ring to this class. The block is executed if one of the statements in the try block

throws this class as an exception. The catch clause can leave this class name out to

catch any exception. Here, we catch all Exception class objects, which is generally

all exceptions in .NET. For example, the OpenFileDialog.OpenFile method can

throw a file I/O exception using the IOException class. Since this class derives from

the Exception class, it will be caught by our handler. Other exceptions such as OutOfMemoryException may also occur, and are caught by our block as well.3

This code uses a class we have not seen before: the MessageBox class. This class is

used to display a simple dialog box. We discuss this class in detail in chapter 8. For now, just copy the code and trust me.

The Message property for the ex variable is used in our dialog to insert the mes-

sage string describing the exception provided by the Exception object. This and

other members of the Exception class are summarized in .NET Table 2.1.

We will use exceptions throughout the book to handle errors in a similar manner. Other concepts associated with exceptions will be presented as they are required by our sample program.

Our MyPhotos application is now in line with our MyForm application from sec- tion 1.3, with the slight improvement of handling any exception that occurs while opening the file. Our last task in this chapter is to enable the form to resize gracefully using the Anchor property.

2.4

Resizing forms

Our final task in this chapter is to set the behavior for resizing using the Anchor

property for our controls, and establish a minimum size for the form so that our

PictureBox control does not disappear. This will finish our duplication of the

application created in chapter 1. The remainder of this book will use Visual Studio .NET when discussing applications changes, so we will carry the MyPhotos applica- tion into chapter 3 and beyond.

3 A more formal discussion of exceptions and the exception handling syntax appears in appendix A. HANDLEEXCEPTIONSINTHEBTNLOAD_CLICKMETHOD

Action Results and Comments

4 Handle the exception by displaying a message to the user.

Note: In this case, we return to the caller without loading an image.

One way to do this is as follows:

catch (Exception ex) {

// Handle exception MessageBox.Show(

"Unable to load file: " + ex.Message); }

Figure 2.6

The application is resized here via the Picture- Box.Anchor property.

.NET Table 2.1 Exception class

The Exception class represents a generic exceptional condition, and serves as the base class for all exception classes in .NET. This class is part of the Systemnamespace, and pro- vides information required to raise (throw) and process (catch) exceptions. Note that it is possible for unmanaged code to throw exceptions that will not be seen as Exception

objects. These exceptions can be caught using an empty catch clause.

Public Properties

HelpLink Gets a link to help information associated with this exception.

InnerException Gets the inner (nested) exception associated with this object, if any.

Message Gets the message text assigned to the exception.

Source Gets or sets a string containing the source of the exception, such as the name of the application or object that generated the error.

StackTrace Gets the stack trace as a string. By default, the stack is captured just before the exception is thrown.

TargetSite Gets the MethodBase object for the method that threw this exception.

Public Methods

GetBaseException Returns the original Exception that caused the current exception to be thrown. Useful when a chain of nested exceptions is received.

SetHelpLink Sets the string returned by the HelpLinkproperty. ToString

(overridden from

Object)

Returns the fully qualified name of the exception, and possibly other information such as the message text, the name of the inner exception, and a stack trace.

RESIZINGFORMS 63