Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C# ПІДРУЧНИКИ / c# / Manning - Windows.forms.programming.with.c#.pdf
Скачиваний:
108
Добавлен:
12.02.2016
Размер:
14.98 Mб
Скачать

8.2THE FORM.CLOSE METHOD

In this section we pick up the thread of our previous discussion on the CloseCurrentAlbum method by discussing the Close and Dispose methods. You may think this is a little off-topic from dialog boxes, but in fact it is quite relevant. One of the key issues for C# programming in .NET is when to call the Dispose method to clean up window handlers and other nonmemory resources. This section will discuss this topic as it relates to dialog boxes, and introduce the Closing event as a way to intercept a user’s request to close a form.

8.2.1The relationship between Close and Dispose

Before we return to the topic of calling CloseCurrentAlbum when our application exits, let’s look at the relationship between Close and Dispose in .NET. It’s actually quite simple: they are the same. For all classes in the .NET Framework, a call to Close is equivalent to calling the Dispose method, and a call to Dispose is equiv-

alent to calling the Close method. The term “close” traditionally applies to objects like files and windows, and .NET has preserved this terminology. When you are finished with a form or a file, it seems silly to require a call to both Close and Dispose, so it makes sense to merge these two concepts together. The .NET design team could have chosen to use a common name for all classes, but programmers naturally expect to close objects such as forms and files, and closing objects like arrays or drawing objects seems a bit odd. Instead, the designers chose to use both methods and define them to be equivalent.

For Form objects, the behavior of the form itself varies depending on whether the object is displayed as a modal or modeless window. For a modeless window, displayed with the Form.Show method, the nonmemory resources are automatically cleaned up when the form is closed. This makes life much easier for us programmers, since we do not have to remember anything in this case. You cannot use a modeless Form after it is closed since all of its resources are gone. The Hide method should be used if you simply want to remove a Form from the desktop and display it later via the Show method. We will see this in chapter 13 when we use a tool bar button to hide the modeless dialog created in section 8.4 of this chapter.

For modal windows, displayed with the Form.ShowDialog method, there is a problem in that the dialog is typically accessed after the window disappears. As a result, a modal dialog must call Dispose explicitly to release its nonmemory resources. Typically, a modal dialog is created and destroyed in the same block of code. For example:

{

MyModalDialog dlg = new MyModalDialog();

// Initialize any dlg settings

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

{

// Use dlg settings to do something

THE FORM.CLOSE METHOD

233

My ModalDialog

}

dlg.Dispose()

}

In this code, if the resources for the dlg variable disappeared after the ShowDialog method returned, you could not access any of its settings. For this reason, .NET only calls the Hide method after a user responds to a modal dialog, so that the dialog settings may still be accessed. This can be a little confusing since we still say the user closes the dialog, even though the dialog’s Close method is not actually called.

Fortunately, modal dialog boxes tend to have deterministic scope, meaning that you can predict when the dialog will be created and destroyed. The application waits until the user responds to a modal dialog, so it’s clear where the Dispose method must be called. We have already seen this method used with OpenFileDialog and SaveFileDialog objects in chapter 6, both of which are modal dialogs.

The C# language provides a using statement to call Dispose on our behalf in deterministic situations such as this. We have seen how the using directive defines an alias or shortcut for an object or members of a namespace. The using statement defines the scope in which a given object should exist. The syntax is as follows:

using (object)

{

// Do something with object

}

At the end of the block of code associated with the statement, the identified object is automatically disposed. For example, the previous code for the

object can be written as follows to cause Dispose to be called automatically at the end of the block:

{

using (MyModalDialog dlg = new MyModalDialog)

{

// Initialize any dlg settings

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

{

// Use dlg settings to do something

}

}

}

As another example, here is how our menuSaveAs_Click handler looks with this statement. The changes from our current implementation are shown in bold.

private void menuSaveAs_Click(object sender, System.EventArgs e)

{

using (SaveFileDialog dlg = new SaveFileDialog())

{

234

CHAPTER 8 DIALOG BOXES

dlg.Title = "Save Album"; dlg.DefaultExt = "abm";

dlg.Filter = "abm files (*.abm)|*.abm"; dlg.InitialDirectory = PhotoAlbum.DefaultDir; dlg.RestoreDirectory = true;

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

{

// Record the new album name _album.FileName = dlg.FileName;

// Use Save handler to store the album menuSave_Click(sender, e);

//Update title bar to include new name SetTitleBar();

}

}

}

In general, any object that supports the IDisposable interface can be used with the using statement in this manner. In particular, you will recall that we supported this interface in our PhotoAlbum and Photograph classes in chapter 5, so we could use this statement with our album and photo objects.

For the remainder of the book, we will generally employ the using statement in our examples to dispose of nonmemory resources rather than calling the Dispose method explicitly.

8.2.2INTERCEPTING THE FORM.CLOSE METHOD

Let’s get back to our application and the CloseCurrentAlbum method. Since our application is a modeless dialog, Close will be called when the application exits. In fact, we call the Close method explicitly in the Click handler for our Exit menu.

We could certainly use the CloseCurrentAlbum method in our Click event handler. While this would work for the Exit menu, it does not work for the case where

the application exits via the Alt+F4 keyboard shortcut or the Close option on the system menu.2

To handle both situations, the Form class provides a Closing event that occurs whenever the form is about to close. The protected OnClosing method is invoked whenever the Close method is called, and it in turn raises the Closing event by invoking any registered event handlers. The signature for this method is as follows:

protected virtual void OnClosing(CancelEventArgs ce);

2 The system menu, as you may know, is the menu of operating system commands that appears when you click the control box icon in the upper left corner of a window. You can also right-click an application’s title bar or its entry in the task bar to display this menu.

THE FORM.CLOSE METHOD

235

CloseCurrent-

As you can see, this method receives a CancelEventArgs object. This class defines a Cancel property to help determine whether the application will actually exit. If this property is set to true by an override of the OnClosing method or a Closing event handler, then the close operation is cancelled and the application will continue to run. The Cancel property has a default value of false, so that the close operation is not cancelled and the application will exit.

We will override the OnClosing method in our MainForm class to make sure the CloseCurrentAlbum method is called regardless of how the application exits.

Set the version number of the MyPhotos application to 8.2.

 

OVERRIDE THE ONCLOSING METHOD

 

 

 

 

Action

Result

 

 

 

1

Override the OnClosing

protected override void OnClosing

 

method in the

(CancelEventArgs ce)

 

MainForm.cs source

{

 

 

 

window.

 

 

 

 

2

Within this method, call the

if (this.CloseCurrentAlbum() == false)

 

CloseCurrentAlbum

 

 

method to see if the

 

 

current album should be

 

 

saved.

 

 

 

 

3

If the user clicked the

ce.Cancel = true;

 

Cancel button, then cancel

Note: This cancels the Close operation so that the appli-

 

the close operation.

 

cation does not exit.

 

 

 

 

 

4

Otherwise, allow the

else

 

application to close.

ce.Cancel = false;

 

 

Note: Since false is the default value, these lines are

 

 

not strictly required. They are here simply to illustrate the

 

 

setting when the application is permitted to exit.

 

 

 

5

Remember to call

base.OnClosing(ce);

 

OnClosing in the base

}

 

class.

Note: This call ensures that logic internal to the Form

 

 

class is performed, and ensures that any Closing event

 

 

handlers for the form are called before the application

 

 

exits. Of course, any registered handler can prevent the

 

 

application from exiting by setting ce.Cancel to true.

 

 

 

Compile and run the application to see this method in action. Add a few photos and try to exit the application using the Exit menu, the Alt+F4 key, and the Close option from the system menu. In all cases, you should be queried by the

Album method with the question dialog for saving the current album. If you select the Cancel button the application will not, in fact, exit.

236

CHAPTER 8 DIALOG BOXES

Соседние файлы в папке c#