Although the open file dialog is a good tool for picking files, sometimes its the desire of the programmer to have a dialog that chooses a directory. This simple directory picker should get you started on this useful windows function. I wrote a previous article on this topic for Beta 1, but wanted to redo it for Beta 2. This Directory Picker in this article is also a bit different because it uses the "Large Icon" view of the ListView to traverse through directories. It also has a nice back button to bring you to the parent directory. The UML design of the directory picker dialog and test application is shown below:
This design was reverse engineered using the WithClass 2000 UML Design Tool for C#.
As seen from the design, The Directory Picker Dialog consists of 2 controls: a User Control that contains the ListView and toolbar for traversing directories and a Windows Form Dialog that contains the User Control. The User Control takes advantage of the Directory class in the System.IO namespace. Below are some of the properties and methods of the Directory class. All of these methods are static, so you don't need to create an instance when using them.
Properties and Methods of Directory clas |
Description |
CreateDirectory(string path) |
Creates a directory from the path and subpaths string |
string GetCurrentDirectory |
Returns the current directory path |
bool Exists(string path) |
Returns true if the directory path exists |
Delete(string path) |
Deletes an empty directory from the disk |
string[] Directories(string path) |
Gets a list of directories contained in the specified path |
string[] Files(string path, string filter) |
Gets a list of files contained in the specified path and with the specified filter (e.g. "*.gif") |
string[] GetLogicalDrives() |
Gets a list of the logical drives such as "C:\\", "G:\\" |
DirectoryInfo GetParent(string path) |
Gets the parent directory of the specified path in the form of the DirectoryInfo structure. |
GetDirectoryRoot(string path) |
Gets the root of the specified path |
The DirectoryInfo class is often useful for accessing different parts of the directory path you are interested in. Below are the properties of this class:
DirectoryInfo Properties |
Description |
FullName |
Full directory path of the directory or file (string) |
Name |
Just the name of the directory or file (string) |
Parent |
Parent Directory DirectoryInfo |
Root |
Root Directory DirectoryInfo |
The directory picker utilizes the functions of the Directory class to traverse the different levels of directories and also invents some of its own directory functions through simple string manipulation. Below is the method that populates the ListView with Directories in the User Control.
public void PopulateView()
{
// set the label to the current directory
this.label1.Text = m_CurrentDirectory;
// use the Directory class to get a list of directories in the current directory (filter is *.*)
string[] dirs = Directory.GetDirectories(m_CurrentDirectory, m_CurrentFilter);
if (dirs.Length == 0)
{
return; // precondition
}
// Sort the list of directories in alphabetical order
this.listView1.Clear();
IComparer comparer = null;
Array.Sort(dirs, comparer);
// place each directory in the directory list into the ListView
// Also store the full qualified path name in the tag of the ListViewItem
foreach (string s in dirs)
{
string s_name = GetFileNameFromPath(s); // This strips the name of the directory from the path
ListViewItem nextItem = this.listView1.Items.Add(s_name, CLOSED_INDEX);
nextItem.Tag = s;
}
this.listView1.ArrangeIcons();
}
The code takes advantage of the ListViewItems Tag property to store the fully qualified path of the directory. You could actually store any class instance you like in this Tag.
When you double click on a folder in the ListView, it traverses to the directory you click on. Below is the event handler for double clicking on a ListViewItem. It simply cycles through the collection of selected items (which should only be one selected item, since we turned off multiselect in this ListView) and assigns the current directory to the fully qualified path in the item's Tag property. Then the PopulateView is called to update the ListView:
private void listView1_DoubleClick(object sender, System.EventArgs e)
{
// Cycle through each item (actually 1 item) in the ListView that is selected
foreach (ListViewItem item in this.listView1.SelectedItems)
{
item.ImageIndex = OPENED_INDEX;
// Assign the fully qualified path hidden in the Tag of the ListViewItem to the CurrentDirectory
m_CurrentDirectory = (string)item.Tag;
// Update the ListView with the new Current Directory.
PopulateView();
}
}
Instead of using the fancy functions in the Directory class, the Back button does a little bit of string manipulation to get to the parent directory. Below is the code for addressing the pressing of the Back toolbar button:
private void toolBar1_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
switch (e.Button.Text)
{
case "Back":
if (m_CurrentDirectory.Length > 3) // make sure we are not at the root drive c:\
{
// strip the terminating backslash, if it exists
if (m_CurrentDirectory[m_CurrentDirectory.Length - 1] == '\\' )
{
m_CurrentDirectory = m_CurrentDirectory.Substring(0, m_CurrentDirectory.Length - 1);
}
// get the parent directory by finding the previous backslash
m_CurrentDirectory = m_CurrentDirectory.Substring(0, m_CurrentDirectory.LastIndexOf("\\") + 1);
// Refresh the ListView with the Parent Directory
PopulateView();
}
break;
}
}
So far we talked about the internals of the Directory Picker Dialog, but you may be more interested in how to use this dialog. Below is the code that brings up the dialog for use when the browse button is hit in our sample form application:
private void button1_Click(object sender, System.EventArgs e)
{
if (ThePickerDialog.ShowDialog() == DialogResult.OK)
{
PopulateFiles();
}
}
ThePickerDialog has a property TheDirectory which contains the fully qualified path of the Directory when the OK Button is pressed. TheDirectory Path in the dialog is populated from the user control's CurrentDirectory property. The code for PopulateFiles in our sample application is shown below:
public void PopulateFiles()
{
// Use the Directory Class and the directory returned from the Directory Picker Dialog
// to get all the files in the chosen directories and add them to a ListBox in our sample app.
string[] AllFiles = Directory.GetFiles(ThePickerDialog.TheDirectory, "*.*");
listBox1.Items.Clear();
foreach (string aFile in AllFiles)
{
string aFileName = GetFileNameFromPath(aFile);
this.listBox1.Items.Add(aFileName);
}
}
Improvements
This control could be improved by adding a detail view that shows the directory name and modified date. Also, I thought it might be nice to have a My Document Directory button in the toolbar that takes you right to the documents directory.