(Print this page)

A combo box displaying drives
Published date: Saturday, March 14, 2009
On: Moer and Éric Moreau's web site

Every once in a while, I need to display the computer drives into a combo box to let the user pick one. In the previous era (namely VB6), this control was known as the DriveListBox control.

Recently, a friend asked me how he could display a drive list box in a .Net application. After a quick Live Search session (or Google session if you prefer), I discovered a couple of interesting (new) ways of doing it.

I will demonstrate 3 ways of providing that list to the user. The first method uses a plain old regular combo. The second way is to use a class provided by .Net Framework 2.0. The last one uses a specialized combo displaying images.

Downloadable example

The code you can download for this article was created using Visual Studio 2008 SP1. One of the examples is using LINQ. If you are still using VS2005, all examples would also work fine (except the LINQ version of the first solution).

Lucky are C# developers. Once again I have added semi-colons to the end of the lines and have crafted a C# version of the demo application. While the code shown in this article is all VB (except one very special line of code), the downloadable solution contains both a VB and a C# version.

Figure 1: The demo application in action

Enumerating logical drives

Before thinking of displaying the logical drives into a control, we need to find a way to retrieve them. The System.IO namespace provides a Directory class that provides the GetLogicalDrives shared (or static) method. At least the first (The poor man solution) and the third solution (Yet another solution) are using this method to populate the control. I really doubt that the second solution (The VisualBasic.Compatibility solution) uses that method because this control is a wrapper over and old Windows object.

This method returns a collection of strings representing all logical drives on your computer (floppies, hard drives, CD/DVD drives, external hard drives, USB keys, lan drives, ...).

The Poor man solution

Sometimes, the easiest solution is simply better!

The first solution I am showing you is using a plain old ComboBox that we will manually populate. I will show you how to populate it the traditional way and also using a LINQ method (which will only works with the .Net Framework 3.5).

The traditional method of displaying the list of available drives uses the strings collection returned by the GetLogicalDrives method. It loops through the collection to add the drive letters to a ComboBox. This is exactly what this code is doing:

'Remove the binding set by the LINQ method 
'otherwise, you may get an exception
cboPoorMan.DataSource = Nothing

'Clear items already in the list
cboPoorMan.Items.Clear()

'Loop through the available drives
For Each d As String In Directory.GetLogicalDrives
    cboPoorMan.Items.Add(d.Trim.Replace("\", ""))
Next

'Select the first item
cboPoorMan.SelectedIndex = 0
Instead of looping through the collection of strings, you could directly assign it to the DataSource property of ComboBox control like this (but you then lose some validation/formatting possibilities):
cboPoorMan.DataSource = Directory.GetLogicalDrives
The second method does exactly the same thing but instead of using a For...Each statement, it is using a LINQ-to-Object query and set the DataSource property of the ComboBox directly:
'Remove the binding set by the LINQ method 
'otherwise, you may get an exception
cboPoorMan.DataSource = Nothing

'Clear items already in the list
cboPoorMan.Items.Clear()

'Create a LINQ query and set it to the combobox
cboPoorMan.DataSource = (From d In Directory.GetLogicalDrives _
                         Select d.Trim.Replace("\", "")).ToArray

'Select the first item
cboPoorMan.SelectedIndex = 0
If you already have made the move to Visual Studio 2008, you should really think about using LINQ whenever and wherever it is possible. The task we have to do here is trivial and the For...Each loop was sufficient enough but in many cases where you need to filter or sort the collection, LINQ is by far more efficient.

The VisualBasic.Compatibility solution

Those who used VB6 before surely remember 3 great controls (at least they were great when we needed them at this time!): the DriveListBox, the DirListBox, and the FileListBox. I don’t know if I should announce it as good or as a bad news, but none the less, those controls are still available to .Net applications (starting with the .Net Framework 2.0). In fact, those controls are provided by Windows itself and the .Net Framework just expose a wrapper over them.

I just want to warn you that they look as ugly as they used to be 10 years ago. They still have the Windows 3.1 look (if you are old enough to remember what they looked like). But they still work as expected.

To be able to add those controls on a form, you first need to add a reference to the Microsoft.VisualBasic.Compatibility component. Once you have referenced it, you can now click the “Choose items” menu item (that you can get by right-clicking the toolbox) and select the 3 controls. There is nothing bad to add a reference to this component even if you are programming C#. The name comes from the team who built that component.

When you add a DriveListBox control to a form, there is no code to write to populate it. This control is a specialized one that knows what it has to do so it does it automatically when the form loads. I could have stop to be only using the DriveListBox but I will show you how to use the 3 controls working together. To bind them, you need to handle 2 events (if you just want the DriveListBox, you have absolutely no code to write).

If you have a DirListBox and you want to synchronize it when you select a drive in the DriveListBox, you need to handle the SelectedIndexChanged event of the DriveListBox. A single line of code is required to refresh the content of the DirListBox:

DirListBox1.Path = DriveListBox1.Drive
Now if you also want to refresh the content of the FileListBox, you need to handle the SelectedIndexChanged event of the DirListBox control with this other single line of code:
FileListBox1.Path = DirListBox1.DirList(DirListBox1.DirListIndex)
Normally, when you convert to C#, you just have to add a semi-colon (in this very simple demo, it is almost true!) at the end of the line and you are done but this is not the case with the previous line! The DirList property of the DirListBox control is not available to C# programmers (don’t ask me why)! Instead, you have to use the get_DirList method as shown here:
FileListBox1.Path = DirListBox1.get_DirList(DirListBox1.DirListIndex);
I have tried a couple of other properties of the DirListBox (like Path and SelectedValue) before finally using the DirList property but none seemed to be really in sync with the selection I was doing!

Yet another solution

To be honest, I cannot take any credit for this last solution I will demonstrate you here. The full credit goes to Michael B. Hansen who has posted this control on CodeProject who in turn has to give credit to Niels Penneman for the ImageCombo also posted on CodeProject.

I have simply added control from the FastDriveCombo project to my demo solution. It is a C# project. There is no added value for me to translate this to VB (and I really hope that other VB programmers are not shy of adding a C# project to their solution).

After that the DriveComboBox project has been added to the solution, it should appear right at the top of your toolbox, ready to be added to any form. Because the constructor of the DriveComboBox calls the BuildDriveList method (which is surprisingly using Directory.GetLogicalDrives), you have absolutely no code to write to populate it, it is already all done for you.

In addition to the drive letter, this control also shows you a small icon representing your drive type and a description of the drive type. That makes this control nicer for the user.

Conclusion

Very often, there is more than one solution to a single problem. The best solution is not always the one that requires the greatest numbers of line of code!

So the next time you will need to let the user pick a drive letter, remember this column.


(Print this page)