Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
1,95 MB
Nội dung
516 CHAPTER 15 TREE VIEWS As we mentioned at the start of this section, we will not spend much time discussing these changes, since they leverage concepts and features we have seen before. Let’s move on to editing a tree node’s label. 15.5.2 S UPPORTING LABEL EDITS Tree nodes can be edited in a manner similar to list items. There is a BeginEdit method in the TreeNode class to initiate a label edit programmatically, and Befor- eLabelEdit and AfterLabelEdit events in the TreeView class that occur before and after the user edits the label. Event handlers for these events receive the NodeLa- belEditEventArgs class for the event parameter. This class is summarized in .NET Table 15.5, and is manipulated in much the same way as we saw for the LabelEditEventArgs class when handling label events for the ListView class. 5 Update the AfterSelect event handler to use the new DisplayPhoto method to ensure the proper control is visible. private void treeViewMain_AfterSelect(. . .) { . . . if (node.Parent == null) { // Bad tag or top-level node. LoadAlbumData(fileName); DisplayPhoto(null); } else if (Path.GetExtension(fileName) . . .) { // Album node selected PhotoAlbum album = OpenTreeAlbum(. . .); LoadPhotoData(album); DisplayPhoto(null); } else // must be a photograph { // Clear the list and display the photo listViewMain.Clear(); DisplayPhoto(node); } } 6 Add a Resize event handler for the PictureBox control to force the control to redraw the entire image when it is resized. private void pictureBoxMain_Resize (object sender, System.EventArgs e) { // Force the entire control to repaint pictureBoxMain.Invalidate(); } DISPLAY PHOTOGRAPH IN A PICTUREBOX CONTROL (continued) Action Result FUN WITH TREE VIEWS 517 In our application, we will permit nodes to be edited using the menuEditLabel menu item, or by pressing the F2 key when a tree node is selected and the tree view has the focus. The following table details the steps required for this change: .NET Table 15.5 NodeLabelEditEventArgs class The NodeLabelEditEventArgs class represents the event data associated with the Befor- eLabelEdit and AfterLabelEdit events in the TreeView class. This class is part of the System.Windows.Forms namespace, and inherits from the System.EventArgs class. Public Properties CancelEdit Gets or sets whether the edit operation should be cancelled. This property can be set both before and after the node is edited. Label Gets the new text to assign to the label of the indicated node. Node Gets the TreeNode object being edited. SUPPORT EDITING OF TREE NODE LABELS Action Result 1 Set the LabelEdit property for the TreeView control to true in the MainForm.cs [Design] window. Tree node labels may now be edited. 2 Handle the KeyDown event for the TreeView control to initiate a label edit when the F2 key is pressed in the tree control. private void treeViewMain_KeyDown (object sender, System.Windows. Forms.KeyEventArgs e) { if (e.KeyCode == Keys.F2) { if (treeViewMain.SelectedNode != null) { treeViewMain.SelectedNode.BeginEdit(); e.Handled = true; } } } 3 Update the menuEdit_Popup event handler to use the text “Node” for the menuEditLabel menu when the TreeView has the focus. How-to Use the Focused property for the TreeView class. private void menuEdit_Popup (object sender, System.EventArgs e) { if (treeViewMain.Focused) { menuEditLabel.Enabled = (treeViewMain.SelectedNode != null); menuEditLabel.Text = "&Node"; } else // assume ListView has focus { menuEditLabel.Enabled = (listViewMain.SelectedItems.Count > 0); if (this._albumsShown) menuEditLabel.Text = "&Name"; else menuEditLabel.Text = "&Caption"; } } 518 CHAPTER 15 TREE VIEWS 4 Update the menuEdit- Label_Click event handler to edit the appropriate item based on the current focus. private void menuEditLabel_Click (object sender, System.EventArgs e) { if (treeViewMain.Focused) { if (treeViewMain.SelectedNode != null) treeViewMain.SelectedNode.BeginEdit(); } else if (listViewMain.SelectedItems.Count > 0) listViewMain.SelectedItems[0].BeginEdit(); } 5 Handle the AfterLabelEdit event for the TreeView control. Note: We permit the user to edit the root node here to alter a top-level name in the tree, even though this change is dis- carded when the application exits. A more robust solution might be to prevent this from occurring, or to save the change in a configuration file. private void treeViewMain_AfterLabelEdit (object sender, System.Windows. Forms.NodeLabelEditEventArgs e) { if (e.Label == null) { // Edit cancelled by the user e.CancelEdit = true; return; } // No changes required for root node if (e.Node.Parent == null) return; string fileName = e.Node.Tag as string; if (Path.GetExtension(fileName) == ".abm") e.CancelEdit = !UpdateAlbumName(e.Label, e.Node); else e.CancelEdit = !UpdatePhotoCaption(e.Label, e.Node); } 6 Rewrite the UpdateAlbum- Name method to accommodate both list items and tree nodes. private bool UpdateAlbumName (string newName, object obj) { ListViewItem item = obj as ListViewItem; TreeNode node = obj as TreeNode; // Determine the file name string fileName = null; if (item != null) { fileName = item.Tag as string; node = FindNode(fileName, false); } else if (node != null) fileName = node.Tag as string; Note: Recall that the list view’s AfterLabelEdit event handler from chapter 14 provides a ListView- Item object when calling this method. This invocation is still valid and is properly dealt with by this code. SUPPORT EDITING OF TREE NODE LABELS (continued) Action Result How-to a. Cancel the edit if the new text is null. b. Do nothing if the node is a root node. c. For an album node, use the UpdateAlbumName.method. d. For a photograph node, use the UpdatePhotoCaption method. How-to a. Change the second parame- ter to an object rather than a ListViewItem. b. Convert the given object to both a list item and a tree node. c. Determine the file name for the appropriate object. d. If the object is a list view item, also find the node cor- responding to this item. FUN WITH TREE VIEWS 519 7 Rename the file. How-to Use the RenameFile method from chapter 14. // Rename the file string newFileName = null; if (fileName != null) { newFileName = RenameFile(fileName, newName, ".abm"); } if (newFileName == null) { MessageBox.Show("Unable to rename album " + "to this name."); return false; } 8 Update the Tag property for the appropriate object. Note: When the object is a list item, this updates the corre- sponding node as well. // Update the appropriate Tag property if (item != null) { item.Tag = newFileName; if (node != null) node.Text = newName; } else if (node != null) node.Tag = newFileName; return true; } 9 Rewrite the UpdatePhoto- Caption method to accom- modate both list items and tree nodes. private bool UpdatePhotoCaption (string caption, object obj) { ListViewItem item = obj as ListViewItem; TreeNode node = obj as TreeNode; // Determine the album index int index = -1; if ((item != null) && (item.Tag is int)) { index = (int)item.Tag; node = FindNode(_album[index].FileName, false); } else if (node != null) { index = node.Index; } 10 Return false if the caption cannot be updated. if ((caption.Length == 0) || (index < 0)) { MessageBox.Show("Invalid caption value."); return false; } SUPPORT EDITING OF TREE NODE LABELS (continued) Action Result How-to a. Change the second param- eter to an object rather than a ListViewItem. b. Convert the given object to both a list item and a tree node. c. Determine the album index for the appropriate object. d. If the object is a list view item, also find the node corresponding to this item. 520 CHAPTER 15 TREE VIEWS Our program now permits editing of nodes in the TreeView and items in the List- View . Editing is initiated with the menuLabelEdit menu or the F2 key, and is based on which control currently has the focus. In both update methods, note how the as keyword is used to convert the given object into both a TreeView and a ListView, as is shown in the following excerpt. The remainder of each method executes the appropriate statements based on which type of control is provided. ListViewItem item = obj as ListViewItem; TreeNode node = obj as TreeNode; Also of note is our use of the FindNode method created earlier in the chapter as part of section 15.4.2. As you may recall, we included a parameter to this method that indicated whether to expand the selected node. We set this second parameter to false here to ensure that the contents of the tree view control are not altered. Our final change is to support the display of our album and photograph property dialogs from the TreeView control. 15.5.3 U PDATING THE PROPERTIES MENU In chapter 14 we created a Properties menu. We handled the Click event for this menu in a menuProperties_Click method, and created the DisplayAlbumProp- erties and DisplayPhotoProperties methods to display the two types of dialogs required. Here we would like to change the behavior of this menu to the following: • When the TreeView has the focus, display the appropriate properties dialog if an album node or a photograph node is selected. • When the ListView has the focus, display the appropriate properties dialog for the selected item. • When the PictureBox has the focus, display the photograph properties dia- log associated with the displayed image. To make this change, we will modify our Display methods to accept either a List- ViewItem or a TreeNode object. The following table details the changes required. 11 Update the photograph’s caption, and save the changes to the album. Note: When the object is a list item, this updates the corre- sponding node as well. // Update caption _album[index].Caption = caption; if (item != null && node != null) { // Update node text as well node.Text = caption; } // Save the changes to the album . . . } SUPPORT EDITING OF TREE NODE LABELS (continued) Action Result FUN WITH TREE VIEWS 521 UPDATE PROPERTIES MENU TO HANDLE TREE NODES Action Result 1 In the MainForm.cs code window, update the menuProperties_Click event handler to accommodate the three controls that might have the focus. private void menuProperties_Click (object sender, System.EventArgs e) { if (treeViewMain.Focused) { TreeNode node = treeViewMain.SelectedNode; string file = node.Tag as string; if (node == null || node.Parent == null || file == null) return; // do nothing if (Path.GetExtension(file) == ".abm") DisplayAlbumProperties(node); else DisplayPhotoProperties(node); } else if (pictureBoxMain.Focused) { // Display photograph for this image TreeNode node = treeViewMain.SelectedNode; if (node != null) DisplayPhotoProperties(node); } else if (listViewMain.SelectedItems.Count > 0) { ListViewItem item = listViewMain.SelectedItems[0]; if (this._albumsShown) DisplayAlbumProperties(item); else DisplayPhotoProperties(item); } } 2 Rewrite the DisplayAlbum- Properties method to accept an object instance. private void DisplayAlbumProperties (object obj) { ListViewItem item = obj as ListViewItem; TreeNode node = obj as TreeNode; // Open the album as appropriate PhotoAlbum album = null; if (item != null) { string fileName = item.Tag as string; if (fileName != null) album = this.OpenAlbum(fileName); } else if (node != null) { album = OpenTreeAlbum(node); } if (album == null) . . . // as in chapter 14 How-to a. For the TreeView control, ignore the parent node and call the appropriate Proper- ties method based on the node type. b. For the PictureBox control, call the DisplayPhoto- Properties method on the selected photo node. c. For the ListView control, the code is the same as in chapter 14. How-to a. Convert the given object to a ListViewItem and a TreeNode instance. b. Open the PhotoAlbum using whichever object is not null. c. If the album could not be opened, display an error message. 522 CHAPTER 15 TREE VIEWS 3 When displaying the album edit dialog, only update the list item settings if the given item is a list view item. Note: If the given item is a tree node, then photographs are dis- played in the list view, and these settings should not be updated. using (AlbumEditDlg dlg = new AlbumEditDlg(album)) { if (dlg.ShowDialog() == DialogResult.OK) { // Save changes made by the user . . . // Update item settings if (item != null) { item.SubItems[MainForm. AlbumTitleColumn].Text = album.Title; bool hasPwd = (album.Password != null) && (album.Password.Length > 0); item.SubItems[MainForm. AlbumPwdColumn].Text = (hasPwd ? "y" : "n"); } } } album.Dispose(); } 4 Modify the DisplayPhotoProperties method to accept an object instance. How-to This is similar, at least in spirit, to the DisplayAlbumProperties method. private void DisplayPhotoProperties (object obj) { ListViewItem item = obj as ListViewItem; TreeNode node = obj as TreeNode; int index = 0; if (item != null && (item.Tag is int)) { index = item.Tag; } else if (node != null) { index = node.Index; } _album.CurrentPosition = index; UPDATE PROPERTIES MENU TO HANDLE TREE NODES (continued) Action Result FUN WITH TREE VIEWS 523 As you can see, the display methods use the as keyword to convert a given object into both a ListViewItem and a TreeNode instance. Whichever instance is non- null indicates how to display the property dialog. TRY IT! As a further change to our TreeView control, add a context menu to this control to perform the following tasks. 1 An “Add Directory” menu item that permits a new album directory to be added to the tree. This should prompt for a directory name and add a top-level node to the tree for each album discovered in that directory. 2 A “Properties” menu item that displays the properties dialog for the nearest node. This should select the nearby node, and then call the PerformClick method for the menuProperties menu. 3 A “Delete” menu item that deletes a node from the tree. This should delete the album file from the file system or the Photograph from the containing album for the given node. You should prompt the user to make sure they really wish to do this. You will need to use the GetNodeAt method to locate the TreeNode instance at a given pixel position, so that the action applies to the specific tree node located at the current mouse position. 5 After displaying the dialog, update the list or node with any modified photograph settings. Note: Recall that our photo edit dialog permits all photographs in an album to be updated. As a result, when the photographs are shown in the tree node, the label for each related node must be updated as well. This is true regardless of the type object given. using (PhotoEditDlg dlg = new PhotoEditDlg(_album)) { if (dlg.ShowDialog() == DialogResult.OK) { // Save any changes made . . . // Update controls with new settings TreeNode baseNode = null; if (item != null) { LoadPhotoData(_album); baseNode = treeViewMain.SelectedNode; } else if (node != null) { baseNode = node.Parent; } if (baseNode != null) { // Update all child labels foreach (TreeNode n in baseNode.Nodes) { n.Text = _album[n.Index].Caption; } } } } } UPDATE PROPERTIES MENU TO HANDLE TREE NODES (continued) Action Result 524 CHAPTER 15 TREE VIEWS You could also implement these items within the ListView control as well. This completes our discussion on the TreeView class. Before we move on, let’s do a quick recap of what we covered in this chapter. 15.6 RECAP In this chapter we extended the MyAlbumExplorer project built in chapter 14 to add a TreeView control. We divided our main window using the Splitter class in order to create a classic explorer window such as that used in the Windows operating system for browsing the file system. A tree view contains a hierarchy of TreeNode objects, and we created a tree dis- playing our album files and the photos in each album. We discussed common oper- ations within a tree view such as expand, collapse, selection, and label editing. During the course of the chapter, the ListView and TreeView controls were integrated to display a common interface, with changes to one control reflected in the other control. We also added a PictureBox control in order to display the image associated with a selected photograph node in the tree. The explorer interface we saw in these last two chapters is one of three kinds of standard Windows interfaces. In part 2 of this book we built what is called a single document interface. In the next chapter we will look at another kind of interface, namely the multiple document interface. 525 CHAPTER 16 Multiple document interfaces 16.1 Interface styles 526 16.2 MDI forms 530 16.3 Merged menus 535 16.4 MDI children 543 16.5 MDI child window management 557 16.6 Recap 563 The ListView and TreeView classes discussed in chapters 14 and 15 present a col- lection of objects within a single list or tree control. These are especially useful when creating an explorer-style interface such as our MyAlbumExplorer application, or the common Windows Explorer application. Another kind of interface is the multiple document interface, also called an MDI (normally pronounced em-dee-eye). An MDI application presents a collection of forms within a single application window. We will discuss MDI applications through the following discussion areas: • Understanding various interface styles. • Creating an MDI container window. • Converting an SDI application into an MDI application. • Using MDI-related class members of various controls. • Merging two menus into a single merged menu. • Managing menus and forms in an MDI application. These topics will be covered as we progress through the chapter, beginning with the concept of interface styles. [...]... in which the Form class in general and MDI support in particular is integrated into the Windows Forms hierarchy As we discussed in chapter 7, a Form object is a Control instance that happens to display an application window For MDI applications, Form controls are contained by a parent Form Of course, the contained forms can be resized and moved within their container, and can still display menus, toolbars,... still display menus, toolbars, status bars, and other controls As we shall see, the relationship between MDI parent and child forms is different than the relationship between control containers and controls 528 CHAPTER 16 MULTIPLE DOCUMENT INTERFACES 16.1.4 SUPPORT IN WINDOWS FORMS To provide some insight and perhaps some perspective on MDI applications, the following table lists a number of class members... through the list of child windows for one that displays the selected album The MdiChildren property in the Form class retrieves the collection of child forms assigned to an MDI container form This property can be treated like any other array to search for a matching form This property is useful whenever a specific form is desired, as we do here It can also be used to see if any child forms are present in... STYLES 527 Also note that Visual Studio NET, while providing an MDI-like interface, uses more of a TabControl look and feel for the set of displayed windows, or what might be called a Multiple Tabbed Documents Interface, or MTDI In this style, multiple sets of windows are displayed as horizontal or vertical groups of tabs Both the MSDI and MTDI approaches can be created using the NET Framework as an alternative...16.1 INTERFACE STYLES Before we discuss exactly how multiple document interfaces are created, let’s take a step back and consider the various types of application interfaces used for Windows applications Most Windows applications fall into one of three interface categories: • Single document interfaces • Explorer interfaces • Multiple document interfaces We will discuss each type of interface separately... Alternate information may appear on the list side of the window as well, such as the photographic image we displayed in chapter 15 for a selected photograph in the MyAlbumExplorer application In Windows, of course, the Windows Explorer application is another example of this style Figure 16.2 16.1.3 Our explorer interface presents the collection of photo albums in list form MULTIPLE DOCUMENT INTERFACES A multiple... Gets the MenuItem object contained by this menu that displays a list of MDI child forms for the associated form object 16.5.2 Methods MergeMenu Merges the MenuItem objects in a given menu with those contained by this menu 16.3 Properties MdiList Gets or sets whether this menu should be populated with a list of MDI child forms contained by the associated form 16.5.2 MergeOrder Gets or sets the relative... support a multiple document interface We begin with the MDI container form 16.2 MDI FORMS So let’s convert our existing MyPhotos application into an MDI application This initial work is not as difficult as you might think Generally, we need one Form to act as the top-level container, and the ability to create other forms as children within this container Here, we will do this via the following tasks:... often referred to as a parent form, since it acts as the parent for one or more MDI child forms The following table details the steps required for this task Set the version number of the MyPhotos application to 16.2 CREATE A NEW FORM AS AN MDI CONTAINER Action Result 1 In the Solution Explorer window, add a new Windows Form to the application called ParentForm The new file appears in the Solution Explorer... class This background contains the MDI child forms, and is always last in the z-order As a result, any controls added to the form will appear above this background, and therefore in front of any MDI children Typically, controls added to an MDI container are docked to one edge of the parent form The code generated for our ParentForm class is much like other forms we have seen in this book The InitializeComponent . Befor- eLabelEdit and AfterLabelEdit events in the TreeView class. This class is part of the System .Windows. Forms namespace, and inherits from the System.EventArgs class. Public Properties CancelEdit. is pressed in the tree control. private void treeViewMain_KeyDown (object sender, System .Windows. Forms. KeyEventArgs e) { if (e.KeyCode == Keys.F2) { if (treeViewMain.SelectedNode != null) . in a configuration file. private void treeViewMain_AfterLabelEdit (object sender, System .Windows. Forms. NodeLabelEditEventArgs e) { if (e.Label == null) { // Edit cancelled by the user