![]() |
Desktop Development »
Selection Controls »
General
Intermediate
License: The Code Project Open License (CPOL)
FilesListBoxBy Eli GazitYet another files browser - a simple FilesListBox control derived from the ListBox control. |
C#.NET 1.1, .NET 2.0, Win2KVS.NET2003, VS2005, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
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.
FilesListBox to your project.
SelectedPath to the startup folder.
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?
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.
/// <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.
// 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.
false)>
public string[] SelectedFiles { get; set; }
// Gets the currently selected file in the FilesListBox
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.
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.
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);
}
DirectoryName property.
IconExtractor utility class. This class extracts the icon from a file/directory/logical driver.
IconExtractor with the application start up folder.
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.
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);
}
FileSelected event for the control owner to handle if it wishes to. 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�
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 16 Jan 2006 Editor: Smitha Vijayan |
Copyright 2005 by Eli Gazit Everything else Copyright © CodeProject, 1999-2009 Web22 | Advertise on the Code Project |