Click here to Skip to main content
11,428,497 members (66,310 online)
Click here to Skip to main content

FilesListBox

, 16 Jan 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
Yet another files browser - a simple FilesListBox control derived from the ListBox control.

File Browser in action

Introduction

One of the things that is really missing in the VS controls is a file browser control, like the Explorer control in Windows, to navigate through folders and files, to select files, etc. in a modeless way. The OpenFileDialog , SaveFileDialog, and the FolderBrowserDialog are good for selecting files in a dialog, but what if I need a form that has a file browser on the left side, and some control that handles file selection when they occurred, on the right side? Let's say, some FTP application? Well, it doesn't help... So, I've decided to create a simple control so anyone can just copy this class to his\her project and use it.

Quick Start (for the ones that don’t have time)

  1. Copy the class FilesListBox to your project.
  2. It will appear in your tool box, so drag it to your form.
  3. Set the SelectedPath to the startup folder.
  4. That's it; you have a file browser control on your form…

Getting started

In order to create our control, we will need a ListBox extension. The ListBox control already contains most of the features we need from the file browser, so all we have to do is to extend it a little bit. Deriving from controls is usually the best practice in cases like this, why reinvent the wheel if we can just tweak it a bit?

First Step - Creating the control

Create a new class, derived from ListBox, and set the initial properties in the ctor.

/// <summary>
/// Represents a ListBox control with file names as items.
/// </summary>
public class FilesListBox : ListBox
{
    ...
    ...

    //// <summary>
    /// Intializes a new instance of the FilesListBox class, to view a list of
    /// files inside a ListBox control.
    /// </summary>
    public FilesListBox()
    {
            SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
            DrawMode = DrawMode.OwnerDrawFixed;
     }

    ....
    ....
}

The default SelectionMode for the control is multi selection, but can be changed to whatever you want. We use DrawMode.OwnerDrawFixed to draw our list items ourselves, this will be discussed later on in the article.

Second Step - The Events

/// <summary>
/// Occures whenever a file is selected by a double click on the control.
/// </summary>
public event FileSelectedEventHandler FileSelected;

The FileSelected event occurs when an item is double clicked. The event delegate contains the FileSelectedEventArgs object that contains the file name that was selected. Note that when a directory is selected, the event will not be fired, but will go to the selected directory instead.

Third Step - The properties

// Gets or sets the directory name that the files should relate to 
public string DirectoryName { get; set; }
 
// Gets or sets a value indicating wheater
// to show directories on the control
public bool ShowDirectories { get; set; }

// Gets or sets a value indicating wheater to show the back
// directory icon  on the control
// (when the IsToShowDirectories property is true)      
public bool ShowBackIcon { get; set; }

// Gets an array containting the currently selected files
// (without directories) in the FilesListBox.
[Browsable(false)]             
public string[] SelectedFiles { get; set; }

// Gets the currently selected file in the FilesListBox
[Browsable(false)]  
public string SelectedFile { get; set; }

/ Gets or sets the icon size, this value also sets the item heigth
public IconSize FileIconSize { get; set; }

The properties are pretty self explanatory and you can add lots of properties such as SelectedDirectoy, etc. We want a simple class, so we will stay with only these properties for now.

Fourth Step - Populating the ListBox with files

The PopulatingItems() method is called after setting the DirectoryName property or after double clicking on a directory item in the list box itself.

/// <summary>
/// Populate the list box with files and directories according to the 
/// directoryName property
/// </summary>
private void PopulatingItems()
{
            // Ignore when in desing mode
            if (DesignMode)
                return;

            this.Items.Clear();
            // Shows the back directory item (            
            if (_showBackIcon && _directoryName.Length > 3)
            {
                Items.Add("..");
            }
            try
            {
                // Fills all directory items
                if (_showDirectories)
                {
                    string[] dirNames = Directory.GetDirectories(_directoryName);
                    foreach (string dir in dirNames)
                    {
                        string realDir = Path.GetFileName(dir);
                        Items.Add(realDir);
                    }
                }
                // Fills all list items
                string[] fileNames = Directory.GetFiles(_directoryName);
                foreach (string file in fileNames)
                {
                    string fileName = Path.GetFileName(file);
                    Items.Add(fileName);
                }
            }
            catch
            {
                // eat this - back is still optional
            }
            Refresh();
}

First of all, we check that we are not in DesignMode, in this case, we ignore the populate method.

The next step is to add the 'back' directory (..) if specified, and all directories in the DirectoryName. I used the static method Directory.GetDirectories(string path) for that.

Note that I only take the folder name for the display and not the full path using Path.GetFileName(string path).

The next step required is to add all the files in the DirectoryName in a similar manner to the directories adding step. When done populating, I refresh the control so it will repaint again with the new values.

Fifth Step - Painting file icons and names

As mentioned above, we handle the listbox drawing in OwnerDrawFixed. This means that the control should draw each listbox item by itself and not the OS, as default. To do this, we override the OnDrawItem(DrawItemEventArgs e) method and paint the object:

protected override void OnDrawItem(DrawItemEventArgs e)
{
    e.DrawBackground();
    e.DrawFocusRectangle();
    Rectangle bounds = e.Bounds;
    if (e.Index > -1 && e.Index < Items.Count)
    {
        Size imageSize;
        string fileNameOnly = Items[e.Index].ToString();
        string fullFileName = GetFullName(fileNameOnly);
        Icon fileIcon = null;
        Rectangle imageRectangle = new Rectangle( bounds.Left + 1, 
                   bounds.Top +1 , ItemHeight - 2,ItemHeight - 2);
        if (fileNameOnly.Equals(".."))
        {                    
            // When .. is the string - draws directory icon                    
            fileIcon =
                IconExtractor.GetFileIcon(Application.StartupPath, _fileIconSize);
            e.Graphics.DrawIcon(fileIcon,imageRectangle);                    
        }
        else
        {
            fileIcon =
                IconExtractor.GetFileIcon(fullFileName, _fileIconSize);
                // Icon.ExtractAssociatedIcon(item);
            e.Graphics.DrawIcon(fileIcon,imageRectangle);
        }
        imageSize = imageRectangle.Size;
        fileIcon.Dispose();

        Rectangle fileNameRec = new Rectangle(bounds.Left + 
                  imageSize.Width + 3, bounds.Top, 
                  bounds.Width - imageSize.Width - 3, bounds.Height);
        StringFormat format = new StringFormat();
        format.LineAlignment = StringAlignment.Center;
        e.Graphics.DrawString(fileNameOnly, e.Font, new SolidBrush(e.ForeColor),
            fileNameRec, format);
            //bounds.Left + imageSize.Width + 3, bounds.Top + 2);
    }
    
    base.OnDrawItem(e);
}
  1. Using the OS, we draw the focus and the background for the item.
  2. Finds out the full file name for the drawing item by contacting the DirectoryName property.
  3. Draws the icon using the included IconExtractor utility class. This class extracts the icon from a file/directory/logical driver.
  4. When the item is the 'back' directory, we draw a directory icon by calling the IconExtractor with the application start up folder.
  5. Draws the file name itself.

Remark: In .NET 2.0, you can extract a file icon by using the method:

Icon.ExtractAssociatedIcon(string filePath);

But this method knows to extract only file icons. The extractor uses API calls, but I will not go there, you can use it 'as-is' or learn more on a related article on that class on the CodeProject.

Sixth Step - Handling File/Directory selection

File/Directory selection occurs when an item is double-clicked. This is obtained by overriding the MouseDoubleClick event of the ListBox control:

protected override void OnMouseDoubleClick(System.Windows.Forms.MouseEventArgs e)
{   
    string selectedFile = _directoryName + SelectedItem.ToString();
    // .. ---> go back one level
    if (selectedFile.EndsWith(".."))
    {
        // Removes the \ in the end, so that the parent will return the real parent.
        if (_directoryName.EndsWith("\\"))
            _directoryName = _directoryName.Remove(_directoryName.Length - 1, 1);
        _directoryName =  Directory.GetParent(_directoryName).FullName;
        PopulatingItems();
    }
    // go inside the directory
    else if (Directory.Exists(selectedFile))
    {
        _directoryName = selectedFile + "\\";
        PopulatingItems();
    }
    else
    {
        OnFileSelected(new FileSelectEventArgs(selectedFile));
    }
    base.OnMouseDoubleClick(e);
}
  1. When the selected file is the 'back' directory - get the parent directory of the current folder and populate the list with that folder's files.
  2. Else, check whether a directory is selected by checking if such a directory exists, and if so, populate that directory's files to the listbox.
  3. Else, a file has been selected, so raise the FileSelected event for the control owner to handle if it wishes to.

Conclusion

The control described here is just a start, you can add features to it such as - deleting the file when clicking on the Del key, applying context menu commands such as create new folder; the sky is the limit.

The class is light and simple for the purpose - for you to dive in quickly to the code and customize it to your exact needs.

Use it well…

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Eli Gazit
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
Question@Eli: License Conditions Pin
Doc Lobster8-Sep-11 21:59
memberDoc Lobster8-Sep-11 21:59 
AnswerRe: @Eli: License Conditions Pin
eligazit8-Sep-11 22:38
membereligazit8-Sep-11 22:38 
GeneralMemory leak in IconExtractor Pin
krneki4562-Dec-09 4:44
memberkrneki4562-Dec-09 4:44 
QuestionHorizontal scrollBar Pin
Rankor202-Jan-08 4:20
memberRankor202-Jan-08 4:20 
QuestionGood job Pin
junli26-Nov-07 22:25
memberjunli26-Nov-07 22:25 
AnswerRe: Good job Pin
eligazit27-Nov-07 3:58
membereligazit27-Nov-07 3:58 
GeneralExtractAssociatedIcon Pin
The_Mega_ZZTer18-Sep-07 17:56
memberThe_Mega_ZZTer18-Sep-07 17:56 
GeneralRe: ExtractAssociatedIcon Pin
Eli Gazit19-Sep-07 0:15
memberEli Gazit19-Sep-07 0:15 
QuestionHow does it work? Pin
Freedss15-Jan-07 23:33
memberFreedss15-Jan-07 23:33 
AnswerRe: How does it work? Pin
eligazit15-Jan-07 23:43
membereligazit15-Jan-07 23:43 
QuestionPossible bug??? Pin
Sasa Scekic6-Jan-07 8:56
memberSasa Scekic6-Jan-07 8:56 
AnswerRe: Possible bug??? Pin
eligazit6-Jan-07 21:24
membereligazit6-Jan-07 21:24 
GeneralInitial Selected Path Pin
jonberry24-Jun-06 16:56
memberjonberry24-Jun-06 16:56 
GeneralRe: Initial Selected Path Pin
eligazit27-Aug-06 8:36
membereligazit27-Aug-06 8:36 
Generalremove extenson Pin
elraton16-Mar-06 8:09
memberelraton16-Mar-06 8:09 
Generalbig icon problem Pin
elraton14-Mar-06 22:31
memberelraton14-Mar-06 22:31 
GeneralRe: big icon problem Pin
eligazit14-Mar-06 22:34
membereligazit14-Mar-06 22:34 
GeneralRe: big icon problem Pin
elraton16-Mar-06 8:08
memberelraton16-Mar-06 8:08 
GeneralRe: big icon problem Pin
The_Mega_ZZTer18-Sep-07 17:54
memberThe_Mega_ZZTer18-Sep-07 17:54 
GeneralVisual Studio 2003 Pin
Erik Huynh23-Jan-06 6:29
memberErik Huynh23-Jan-06 6:29 
GeneralRe: Visual Studio 2003 Pin
eligazit23-Jan-06 21:32
membereligazit23-Jan-06 21:32 
GeneralRe: Visual Studio 2003 Pin
E. H.24-Jan-06 7:17
memberE. H.24-Jan-06 7:17 
GeneralRe: Visual Studio 2003 Pin
eligazit24-Jan-06 12:59
membereligazit24-Jan-06 12:59 
GeneralRe: Visual Studio 2003 Pin
E. H.25-Jan-06 5:03
memberE. H.25-Jan-06 5:03 
GeneralRe: Visual Studio 2003 Pin
eligazit25-Jan-06 21:22
membereligazit25-Jan-06 21:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150428.2 | Last Updated 16 Jan 2006
Article Copyright 2005 by Eli Gazit
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid