Browse DevX
Sign up for e-mail newsletters from DevX


Create Owner-Draw List and Combo Boxes with .NET  : Page 2

Learn to use the DrawMode settings with ListBoxes and ComboBoxes to create and display customized items.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Example 1: Listing Files and Folders
Suppose you want to list the files and directories in a folder along with the associated system icons appropriate to the type of file. There are several steps required to accomplish the task:

  • Validate the requested directory path
  • Retrieve the files and subfolders from a directory
  • Iterate through them, retrieving their types and names
  • Find the appropriate icon for each file type
  • Draw the items for the ListBox containing the appropriate icon and text

Figure 1: The ListFilesAndFolders form contains an owner-draw ListBox that displays folder and file names, along with their system-associated icons.
Figure 1 depicts a Web form with the finished ListBox control that displays all the files in a specified directory along with their corresponding system icons. To use the example, enter a directory path in the first text field. The form ensures that the entered path is valid, and then follows the steps listed above to fill a ListBox shown in a separate dialog. The user can double-click an item in the list, or select an item and click OK. The constructor for the dialog form (ListFilesAndFolders) requires a path string.

The first step in the application's logic is to validate the path string the user enters into the main form. The System.IO.DirectoryInfo class has an Exists method that returns True if the directory exists:

Dim di As DirectoryInfo di = New DirectoryInfo(Me.txtPath.Text) If Not di.Exists Then txtPath.ForeColor = System.Drawing.Color.Red Beep() End If

The code turns the TextBox text red and plays a warning sound if the entered path is invalid; otherwise, it creates a new instance of the ListFilesAndFolders form, passing the validated path string to its constructor.

Dim frmFiles As New _ ListFilesAndFolders(Me.txtPath.Text)

The ListFilesAndFolders form contains a ListBox, an OK button, and a Cancel button.

The ListFilesAndFolders form constructor calls a FillList method that retrieves the files and folders in the specified path and fills a ListBox control with the icons and names, suspending the control's display until the method completes.

Sub FillList(ByVal aPath As String) Dim fsi As FileSystemInfo lstFiles.BeginUpdate() lstFiles.Items.Clear() files = New DirectoryInfo(aPath).GetFileSystemInfos For Each fsi In files lstFiles.Items.Add(fsi) Next lstFiles.EndUpdate() End Sub

The DirectoryInfo.GetFileSystemInfos method returns an array of FileSystemInfo objects. The code iterates through the returned array and adds each item to the ListBox's Items collection.

The act of adding the items to the ListBox doesn't cause the ListBox to draw them; instead, the ListBox fires a DrawItem event whenever the ListBox needs to display an item. In this case, you want to draw an icon and the name of a FileSystemInfo object that represents a file or folder. Because this is an owner-draw control, you need to create the DrawItem method to create the item display.

Private Sub lstFiles_DrawItem( _ ByVal sender As Object, _ ByVal e As System.Windows.Forms.DrawItemEventArgs) _ Handles lstFiles.DrawItem ' the system sometimes calls this method with ' an index of -1. If that happens, exit. If e.Index < 0 Then e.DrawBackground() e.DrawFocusRectangle() Exit Sub End If ' create a brush Dim aBrush As Brush = System.Drawing.Brushes.Black ' get a reference to the item to be drawn Dim fsi As FileSystemInfo = _ CType(lstFiles.Items(e.Index), FileSystemInfo) ' create an icon object Dim anIcon As Icon ' use a generic string format to draw the filename Dim sFormat As StringFormat = _ StringFormat.GenericTypographic ' get the height of each item Dim itemHeight As Integer = lstFiles.ItemHeight ' call these methods to get items to highlight ' properly e.DrawBackground() e.DrawFocusRectangle() ' retrieve the appropriate icon for this file type anIcon = IconExtractor.GetSmallIcon(fsi) ' draw the icon If Not anIcon Is Nothing Then e.Graphics.DrawIcon(anIcon, 3, _ e.Bounds.Top + ((itemHeight - _ Me.ImageList1.Images(0).Height) \ 2)) anIcon.Dispose() End If ' if the item is selected, ' change the text color to white If (e.State And _ Windows.Forms.DrawItemState.Selected) = _ Windows.Forms.DrawItemState.Selected Then aBrush = System.Drawing.Brushes.White End If sFormat.LineAlignment = StringAlignment.Center e.Graphics.DrawString(fsi.Name, lstFiles.Font, _ aBrush, 22, e.Bounds.Top + _ (e.Bounds.Height \ 2), sFormat) End Sub

In the DrawItem method, the code calls a shared GetSmallIcon method exposed by the IconExtractor class (see Listing 1), which, when passed a FileSystemInfo object, calls the Win32 SHGetFileInfo API to extract the icon for the file type represented by that object. The IconExtractor class exposes two public shared methods, GetLargeIcon and GetSmallIcon, both of which simply call a private GetIcon method that returns the large (32 x 32) and small (16 x 16) icon versions, respectively.

Public Shared Function GetSmallIcon( _ ByVal fsi As FileSystemInfo) As Icon Return IconExtractor.GetIcon _ (fsi, SHGFI_SMALLICON) End Function Public Shared Function GetLargeIcon( _ ByVal fsi As FileSystemInfo) As Icon Return IconExtractor.GetIcon _ (fsi, SHGFI_LARGEICON) End Function Private Shared Function GetIcon( _ ByVal fsi As FileSystemInfo, _ ByVal anIconSize As Integer) As Icon Dim aSHFileInfo As New SHFILEINFO() Dim cbFileInfo As Integer = _ Marshal.SizeOf(aSHFileInfo) Dim uflags As Integer = SHGFI_ICON Or _ SHGFI_USEFILEATTRIBUTES Or anIconSize Try SHGetFileInfo(fsi.FullName, fsi.Attributes, _ aSHFileInfo, cbFileInfo, uflags) Return Icon.FromHandle(aSHFileInfo.hIcon) Catch ex As Exception Return Nothing End Try End Function

The GetSmallIcon and GetLargeIcon methods both accept a FileSystemInfo object. Internally, the GetIcon method uses the FileSystemInfo object to pass the file name and file attributes to the SHGetFileInfo API call. After drawing the icon, the DrawItem event handler calls the Graphics.DrawString method to place the file name on the image next to the icon. The ListBox calls the DrawItem method repeatedly, for each item in its Items collection.

The DrawItemEventArgs argument to the DrawItem event handler exposes an Index property whose value is the index of the item to be drawn. Watch out! The system raises the DrawItem event with an index value of -1 when the Items collection is empty. When that happens you should call the DrawItemEventArgs.DrawBackground() and DrawFocusRectangle() methods and then exit. The purpose of raising the event is to let the control draw a focus rectangle so that users can tell it has the focus, even when there are no items present. The code traps for that condition, calls the two methods, and then exits the handler immediately.

Users can select an item and close the ListFilesAndFolders form either by selecting an item and then clicking the OK button, or by double-clicking an item. Either way, the form sets a public property called SelectedItem, sets another public property called Cancel and then closes. The main form then displays the filename of the selected item in the Result field.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date