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

Album method. The Nodes collection is cleared and the expand operation is cancelled.

2If the album is opened and found to be empty, then the Nodes collection is cleared and the expand operation is cancelled.

3If the album is opened and found to be nonempty, then the existing Nodes collection is replaced with a collection of TreeNode objects based on the photographs in the album.

Note that we once again use the Tag property to hold the file path, this time for the Photograph object’s file name. This will come in useful when we look at node selection in the next section.

Compile and run the program to exercise our new event handler. Try to reproduce each of these three possibilities to see the result. Also note how the icon for the photograph nodes differs when the node is selected.

TRY IT! Handle the AfterCollapse event for the tree to clear the collection contained in an album node. This event handler should again use the Tag property for the node to determine if the node represents an album. When an album node is collapsed, call the Clear method on its Nodes collection and recreate the default “child” node so the album can be expanded later on.

Of course, a more complex tree hierarchy will require nodes at various levels of the tree to expand and collapse depending on their requirements. The code we created here is for a three-level tree, but can be extended to support more complicated structures. Once again it is worth mentioning that the use of the Tag property works well in our application since there are only three types of objects. For a more complex tree view, consider creating one or more new classes based on the TreeNode class.

So far we have not worried about synchronizing the contents of our ListView and TreeView controls. In the next section we finally take up this topic while discussing the selection of tree nodes.

15.4NODE SELECTION

A node in a tree view is selected whenever the user clicks on the node with the mouse. In our application, the tree nodes correspond to albums and photographs that can be displayed in the ListView area of the form. Whenever a user selects a node, the contents of that node should be displayed in the list view.

Such behavior is typical of applications that employ a TreeView control. The nodes in the tree contain or refer to other data that is or can be displayed on the form. Whenever a new tree node is selected, the data displayed must be updated as well. For example, in Windows Explorer, the tree view contains directories,1 while the list view contains files contained in these directories. When the user selects a directory entry from the tree view, the contents of that directory are displayed in the list view of the window. The reverse is also true. When the user double-clicks on a directory in the

NODE SELECTION

505

Select-

list view, that directory is shown in the tree view and its contents are displayed in the list view.

In this section we will look at how to implement this behavior in our MyAlbumExplorer application. This will link up our TreeView and ListView controls so they work together and present a consistent interface to the user.

These changes come in two flavors. First there are changes to ensure that the ListView is properly updated when the TreeView changes. Next there are changes to ensure that the TreeView is properly updated when the ListView changes. All of these updates will be driven by the selection of a tree view node using the

edNode property of the TreeView control. Figure 15.8 shows our application with an album selected in the tree view and the corresponding collection of photographs displayed in the list view.

Figure 15.8 In this figure, the TreeView and ListView controls are finally coordinated.

We will begin these changes by updating our form when a node is selected in our

TreeView control.

15.4.1SUPPORTING NODE SELECTION

As we saw for the expand and collapse operations, there are two events associated with node selection. The BeforeSelect event occurs before the node is selected in the control, and receives a TreeViewCancelEventArgs instance containing the event data. The AfterSelect event occurs after the node has been selected, and receives a TreeViewEventArgs instance.

1It also contains disks, the desktop, the control panel, and other objects. For the purposes of our example, we can pretend that it contains only directories.

506

CHAPTER 15 TREE VIEWS

The BeforeSelect event is useful when you may wish to cancel a selection based on the state or other settings related to a given node. Since we have no need to do this here, we will use the AfterSelect event to update the ListView control based on the selected node. The following table summarizes the types of nodes in our tree, how to identify each type, and what the ListView control should contain for each type.

Contents of ListView for each type of TreeNode

TreeNode Type

How to identify this type

What to show in the ListView

 

 

 

Top-level node

The parent node is null.

The collection of albums.

Album node

The associated file has an album

The collection of photos in this album.

 

file extension.

 

Photograph

The node is not a top-level or an

Nothing for now. Later we will draw the actual

node

album node.

photograph associated with this node.

 

 

 

We can use this information to implement our event handler. The steps required are described by the following table.

Set the version number of the MyAlbumExplorer application to 15.4.

IMPLEMENT A HANDLER FOR THE AFTERSELECT EVENT

 

Action

Result

 

 

 

1

In the MainForm.cs [Design] window,

private void treeViewMain_AfterSelect

 

add an AfterSelect event handler for

(object sender, System.Windows.

 

the TreeView control.

Forms.TreeViewEventArgs e)

 

{

 

 

 

 

 

2

Obtain the file name associated with the

TreeNode node = e.Node;

 

selected node.

string fileName = node.Tag as string;

 

 

 

3

If the file name string is null, throw an

if (fileName == null)

 

exception.

throw new ApplicationException

 

Note: This should not happen, and indi-

("selected tree node has "

 

+ "invalid tag");

 

cates that something is wrong.

 

 

 

 

4

If the node is a top-level node, display

if (node.Parent == null)

 

the albums associated with this node in

{

 

the list view.

// Top-level node

 

LoadAlbumData(fileName);

 

 

 

 

}

 

 

 

5

If the node is an album node, display the

else if (Path.GetExtension(fileName)

 

photographs associated with the album

== ".abm")

 

in the list view.

{

 

// Album node selected

 

 

 

 

PhotoAlbum album

 

 

= OpenTreeAlbum(node);

 

 

LoadPhotoData(album);

 

 

}

 

 

 

6

Otherwise, the node must be a

else // must be a photograph

 

photograph node.

{

 

 

// Just clear the list for now.

 

 

listViewMain.Clear();

 

 

}

 

 

}

 

 

 

NODE SELECTION

507

As you can see, we take advantage of the LoadAlbumData and LoadPhotoData methods implemented in chapter 14. By encapsulating our load functionality in a method, we are able to reuse the methods here with no changes. Both of these methods are based on a file path from which to load the data, and we make use of this fact here to specify the appropriate data associated with the selected tree node. For a toplevel node this is an album directory. For an album node this is an album file which is loaded as a new PhotoAlbum object. For a photograph node, this is the image file, although we do not make use of this fact here.

Astute readers will realize that there is some inefficiency here since we have separated the logic for updating our two views. For instance, when an album node is expanded and selected, we open the album to load the collection of photographs in the treeViewMain_BeforeExpand method, and then open the album again to update the contents of the ListView control from the treeViewMain_AfterSelect method. This is the result, in part, of how we have separated our discussion of the two controls. In a production program, you would likely want to merge these efforts to ensure that an album is only opened one time for each update.

One situation we will fix is the behavior of the OnLoad method. The method performs the following tasks:

1 The InitTreeData method is called, which does the following:

aCreates and selects the top level node,

bCreates tree nodes for each album in the default album directory.

2As a result of selecting the top-level node, the treeViewMain_After-Select event handler is called, which does the following:

a Calls LoadAlbumData to populate the ListView control.

3Back in the OnLoad method, the LoadAlbumData method is called to initialize the ListView control.

Clearly the second call to LoadAlbumData is no longer required, so we can remove it from our program.

UPDATE THE ONLOAD METHOD

 

Action

Result

 

 

 

7

Modify the OnLoad method to

protected override void OnLoad(EventArgs e)

 

only initialize the TreeView

{

 

control.

. . .

 

 

 

 

// Initialize the contents of the form

 

 

InitTreeData();

 

 

}

 

 

 

508

CHAPTER 15 TREE VIEWS

Tree-

This completes the update of the list view as the contents of the tree view are modified. You can compile and run the application to verify that the ListView contents changes as different nodes are selected.

Our next topic is to update the contents of the TreeView control based on user interactions with the list view items.

15.4.2REVISITING THE LIST VIEW

The contents of our ListView control can be modified directly by the user through the control itself and through the menu bar items. There are three actions a user can perform to alter the list contents:

1Select the Albums menu item under the View menu. This invokes a Click event for the menu, and our menuAlbums_Click event handler.

2Select the Photos menu item under the View menu, which can only be done when an item representing an album is selected in the list view. This invokes a Click event for the menu, and our menuPhotos_Click event handler.

3Double-click on an item in order to activate it. This invokes the ItemActivate event, and our listViewMain_ItemActivate event handler.

We will handle each of these actions by selecting the appropriate node in our

View control. This permits the tree view to “be in charge” of ensuring that all controls on the form display the proper information based on the currently selected node. This is a good general mechanism that can be employed in any application.

Let’s take a moment to consider what the behavior should be for each of these actions. These are summarized in the following table.

Result of user actions modifying the ListView control

Action

Result in TreeView

Result in ListView

 

 

 

Select the Albums

The top-level Default Albums node

The collection of albums from the

menu item.

should be selected.

default album directory should be

 

 

displayed.

Select the Photos

The tree node corresponding to the

The collection of photographs for the

menu item.

current album should be selected.

current album should be displayed.

Double-click on an item

The tree node corresponding to the

The contents of the item should be

in the list view.

activated item should be visible and

displayed.

 

selected.

 

 

 

 

As you can see, all three actions should result in the selection of a node in the tree. This will cause the AfterSelect event to occur, which will invoke our treeViewMain_AfterSelect event handler. This handler will, in turn, cause the proper set of items to appear in the ListView control, as described in the previous table.

As a result, we simply need to modify the behavior for these three actions to select the proper tree node, and our existing code will do the rest. We will begin with our Albums menu item.

NODE SELECTION

509

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