ou create an “owner-draw” ListBox or ComboBox when you want to bypass the control’s automatic item display in order to do something special, such as display an image for each item or display a list in which the items aren’t all the same size. The .NET framework makes it simple to create these custom item lists. In this article, you’ll see how to populate list and combobox controls with items you draw yourself.
The only thing you need to do to create an owner-drawn list or combo box is to set the DrawMode property to either OwnerDrawFixed, or OwnerDrawVariable. The DrawMode property has three possible settings: Normal (the default), in which the system handles displaying the items automatically; OwnerDrawFixed, which you should use when you want to draw the items yourself, but they’re all the same height and width; and OwnerDrawVariable, which you use to draw items that vary in height or width. When you select the OwnerDrawFixed setting, you must implement a DrawItem method, which the ListBox calls whenever it needs to draw an item. When you select the OwnerDrawVariable setting, you must implement both the DrawItem and a MeasureItem method. The MeasureItem method lets you set the size of the item to be drawn. When you select the Normal setting, the system does not fire either the MeasureItem or the DrawItem methods.
There are a couple of restrictions. You can’t create variable-height items for multicolumn ListBoxes, and CheckedListBoxes don’t support either of the owner-drawn DrawMode settings.
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.
Example 2: Drawing Items with Variable Width and Height
Here's another example. The items you create don't all have to be the same width and height. To create an owner-drawn list or combo box with variable item heights and widths, set the DrawMode property to OwnerDrawVariable. Then, implement a method that handles the MeasureItem event, which accepts a sender (Object), and a System.Windows.Forms.MeasureItemEventArgs argument. The sample form frmColorListBox displays all the known system colors and their names in a combo box. The items themselves vary between 20 and 40 pixels in height. It's contrived and ugly (see Figure 2), but serves to illustrate the point.
![]() |
Charlie has over a decade of experience in website administration and technology management. As the site admin, he oversees all technical aspects of running a high-traffic online platform, ensuring optimal performance, security, and user experience. Related PostsAbout Our Editorial ProcessAt DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere. See our full editorial policy. ![]() Light Phone Champions Minimal Use Philosophy
Deanna Ritchie
June 23, 2026
3:54 PM
![]() Mexico Edges South Korea, Leads Group A
Rashan Dixon
June 23, 2026
3:12 PM
![]() Securing the Connections Between AI Agents, Tools, and Data
Noah Nguyen
June 23, 2026
1:53 PM
![]() Q-Day Nears As Readiness Lags
Kirstie Sands
June 23, 2026
1:50 PM
![]() New Online Rules Target Youth Safety
Steve Gickling
June 23, 2026
1:22 PM
![]() MIT Launches PATH for AI Workforce
Steve Gickling
June 23, 2026
12:01 PM
![]() Flux Raises $5 Million for Engineering Intelligence
Sumit Kumar
June 23, 2026
11:48 AM
![]() Summer Solstice Arrives This Sunday
Sumit Kumar
June 23, 2026
11:21 AM
AI Safety Shouldn’t Mean Hitting the Kill Switch
Joe Rothwell
June 23, 2026
9:33 AM
![]() Guardrails Launches Populist AI Political Movement
Sumit Kumar
June 22, 2026
4:45 PM
![]() Europe Seeks New Energy and Trade Routes
Steve Gickling
June 22, 2026
3:50 PM
![]() U.S. Entrepreneurs Struggle To Outearn Parents
Deanna Ritchie
June 22, 2026
12:01 PM
Why Big-Battery Phones Finally Make Sense
Joe Rothwell
June 20, 2026
10:37 AM
The State of DevSecOps 2026: Shifting Security Left in the AI Age
Rashan Dixon
June 20, 2026
9:23 AM
![]() Mistral AI Launches Vibe, Targets Industry
Sumit Kumar
June 19, 2026
3:49 PM
![]() Colbert Ends Tenure With Musical Jab
Deanna Ritchie
June 19, 2026
2:31 PM
![]() Stratofortress Crash Kills Eight in California
Kirstie Sands
June 19, 2026
1:08 PM
AI-Native Applications: Designing Software That Learns Continuously
Rashan Dixon
June 19, 2026
11:14 AM
![]() Amazon And Meta Lead Tech Rally
Rashan Dixon
June 19, 2026
10:38 AM
![]() Bear Stalking Prompts Mount Si Closure
Steve Gickling
June 19, 2026
10:21 AM
![]() SpaceX Adds Ex-Sequoia Leader to Board
Sumit Kumar
June 19, 2026
10:03 AM
![]() How Specialized Engineering Talent Helps Modern Tech Companies Build Better Products
Kyle Lewis
June 19, 2026
9:10 AM
Local AI Is Ready—But Not For Everyone
Joe Rothwell
June 19, 2026
6:00 AM
![]() Index Hopes Fuel Pre-Inclusion Stock Surge
Rashan Dixon
June 18, 2026
3:28 PM
![]() New Fix Targets AI Chatbot Freezes
Steve Gickling
June 18, 2026
2:26 PM
|





















