Click here to Skip to main content
15,884,388 members
Articles / Programming Languages / C#

Implementing a common File system browser with a ListView

Rate me:
Please Sign up or sign in to vote.
4.10/5 (22 votes)
24 Sep 2003 217.4K   4.7K   62  
A ListView Control like the one used in Windows Explorer
/* ****************************************************************************
	Windows Forms File-System List View control for .NET
	Version 0.9, posted Sept-25-2003
	(c)Copyright 2003 Jonathan Gauthier (jg72@videotron.ca). All rights reserved.
	Free for any use, so long as copyright is acknowledged.
	
	Credits:
	The SystemImageList classes were developped by Steve McMahon and taken from the
	site vbAccelerator. http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects/SysImageList/article.asp
	His work was very helpful in order to make this component fast. Thank you.
	
	Some portions were inspired from the work of Furty (furty74@yahoo.com) in his 
	Folder Tree View control v1.1 . Thanks for his works.	
	
	If you improve this control, please email me the updated source, and if you have any 
	comments or suggestions, please post your thoughts in the feedback section on the 
	codeproject.com page for this control.	 
 **************************************************************************** */
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Globalization;
using LivingObjects.Windows.Interop;

namespace LivingObjects.Windows.Forms
{	
	#region ExplorerListViewItem
	public class ExplorerListViewItem: BaseExplorerListViewItem
	{			
		public ExplorerListViewItem(Shell32.FolderItem folderItem):base(folderItem.Name, folderItem.Type)
		{
			SubItems[0].Text = folderItem.Name;			
			SubItems[2].Text = folderItem.Type;			

			//Dummy condition fo the final else ... don'T bother
			if(folderItem.IsFolder && !folderItem.IsFileSystem)
			{
			}
			else if(folderItem.IsFolder && folderItem.IsFileSystem && folderItem.ModifyDate.Year != 1899)
			{
				SubItems[3].Text = folderItem.ModifyDate.ToShortDateString() + " " + 
					folderItem.ModifyDate.ToLongTimeString();							
			}
			else
			{				
				SubItems[1].Text = (folderItem.Size / 1024).ToString("#,0") + " KB";	
			
				if(folderItem.ModifyDate.Year != 1899)
					SubItems[3].Text = folderItem.ModifyDate.ToShortDateString() + " " + 
						folderItem.ModifyDate.ToLongTimeString();				
			}

			Tag = folderItem;
		}			
		
		public Shell32.FolderItem FolderItem
		{
			get
			{
				return (Shell32.FolderItem)Tag;
			}
			set
			{
				Tag = value;
			}
		}

		public bool IsFile
		{
			get
			{
				return !FolderItem.IsFolder;
			}
		}
		
		public FileInfo FileInfo
		{
			get
			{
				if(IsFile)
					return new FileInfo(FolderItem.Path);
				else
					return null;
			}
		}
	}
	#endregion

	/// <summary>
	/// This class is a basic File System ListView allowing to browse drives and folders. 	
	/// Each items Tag property contains the corresponding DirectoryInfo or FileInfo object.
	/// </summary>
	/// <remarks>Special folders and other shell items are not implemented except 
	/// "My Documents" and "Desktop" System folders.</remarks>
	[ToolboxItem(true)]
	public class FileSystemListView : BaseExplorerListView
	{		
		#region Fields
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		protected Shell32.FolderItem _currentFolder;
		private SystemImageList _smallImageList;
		private SystemImageList _largeImageList;
		private bool _enableParentFolderSelection = true;
		#endregion
		
		#region Constructors
		public FileSystemListView(): base()
		{			
			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();

			//Plug in the System Image List
			_smallImageList = new SystemImageList(SystemImageListSize.SmallIcons);
			_largeImageList = new SystemImageList(SystemImageListSize.LargeIcons);						
			SystemImageListHelper.SetListViewImageList(this, _largeImageList, false);
			SystemImageListHelper.SetListViewImageList(this, _smallImageList, false);
							
			this.DoubleClick += new System.EventHandler(this.FileSystemListView_DoubleClick);						
		}
		#endregion

		#region Implementation		
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if( components != null )
					components.Dispose();
			}
			base.Dispose( disposing );
		}

		private void FileSystemListView_DoubleClick(object sender, System.EventArgs e)
		{			
			Shell32.FolderItem folderItem = ((Shell32.FolderItem)this.SelectedItems[0].Tag);								
			_currentFolder = folderItem;
			if(folderItem.IsFolder)
			{
				Cursor.Current = Cursors.WaitCursor; 
				
				Shell32.Folder folder = (Shell32.Folder)folderItem.GetFolder;				
				SetListViewItems(folder);

				Cursor.Current = Cursors.Default;
			}
		}
	
		private void SetListViewItems(Shell32.Folder folder)
		{			
			//This arrays allows us to display folder before files in the list.
			ArrayList folders = new ArrayList();
			ArrayList files = new ArrayList();

			Items.Clear();
			this.BeginUpdate();
						
			if(AllowParentFolderSelection)
				AddParentItem(folder);
			
			if(folder.Title == "Desktop")
			{
				Shell32.Shell shell32 = new Shell32.ShellClass();
				folder = shell32.NameSpace(Win32API.ShellFolder.Desktop);
			}
			
			Shell32.FolderItems folderItems = folder.Items(); 
			foreach(Shell32.FolderItem folderItem in folderItems)	
			{
				//Don't display not selectable item like "Outlook" icon etc...
				//Remove this condition will make the control work but these objects
				//are not needed...
				if((folderItem.IsFileSystem || folderItem.IsFolder) && !folderItem.IsBrowsable)
				{
					if(folderItem.IsFolder)
						folders.Add(folderItem);
					else
						files.Add(folderItem);
				}
			}

			//Add folders in the list
			IEnumerator enumeration = folders.GetEnumerator();
			while(enumeration.MoveNext())
				AddItem((Shell32.FolderItem)enumeration.Current);

			//Add files in the list
			enumeration = files.GetEnumerator();
			while(enumeration.MoveNext())
				AddItem((Shell32.FolderItem)enumeration.Current);

			this.EndUpdate();
		}

		private void AddParentItem(Shell32.Folder folder)
		{
			Shell32.FolderItems folderItems;

			if(folder.Title != "Desktop")
			{
				//Add item to get the parent folder
				if(folder.ParentFolder != null)
				{
					//The parent of the current folder exist
					if(folder.ParentFolder.ParentFolder != null)
					{	
						folderItems = folder.ParentFolder.ParentFolder.Items();
						foreach(Shell32.FolderItem folderItem in folderItems)
						{
							if(folderItem.Name == folder.ParentFolder.Title)
							{
								AddItem(folderItem);
								Items[Items.Count - 1].Text = ".. (" + folderItem.Name + ")";								
								Items[Items.Count - 1].SubItems[2].Text = "Parent Folder";
								Items[Items.Count - 1].SubItems[3].Text = "";
								break;
							}
						}				
					}
					else //The parent is the desktop
					{
						Shell32.Shell shell32 = new Shell32.ShellClass();
						Shell32.Folder desktopFolder = shell32.NameSpace(Win32API.ShellFolder.DesktopDirectory);
					
						folderItems = desktopFolder.ParentFolder.Items();
						foreach(Shell32.FolderItem folderItem in folderItems)
						{
							if(folderItem.Name == desktopFolder.Title)
							{
								AddItem(folderItem);
								Items[Items.Count - 1].Text = ".. (" + folderItem.Name + ")";															
								Items[Items.Count - 1].SubItems[2].Text = "Parent Folder";
								Items[Items.Count - 1].SubItems[3].Text = "";
								break;
							}
						}					
					}
				}
			}			
		}

		private void AddItem(Shell32.FolderItem folderItem)
		{			
			Items.Add(new ExplorerListViewItem(folderItem));	

			//Set the index of the last item added in the System Image list
			Items[Items.Count - 1].ImageIndex = _smallImageList.IconIndex(folderItem.Path, true);									
		}
		#endregion

		#region Properties
		public Shell32.FolderItem CurrentShellFolder
		{
			get
			{
				return _currentFolder;
			}
		}

		[Browsable(false),
		 EditorBrowsable(EditorBrowsableState.Never)]
		public new ImageList SmallImageList
		{
			get
			{
				return base.SmallImageList;
			}
			set
			{
				base.SmallImageList = value;
			}
		}

		[Browsable(false),
		 EditorBrowsable(EditorBrowsableState.Never)]
		public new ImageList LargeImageList
		{
			get
			{
				return base.LargeImageList;
			}
			set
			{
				base.LargeImageList = value;
			}
		}

		[Browsable(false),
		 EditorBrowsable(EditorBrowsableState.Never)]
		public new ImageList StateImageList
		{
			get
			{				
				return base.StateImageList;
			}
			set
			{
				base.StateImageList = value;				
			}
		}		

		/// <summary>
		/// Returns the number of selected items corresponding to files.
		/// </summary>
		[Browsable(false)]
		public int SelectedFileCount
		{
			get
			{				
				return SelectedFileItems.Length;
			}
		}			

		/// <summary>
		/// Return the selected items that are files
		/// </summary>
		[Browsable(false)]
		public ListViewItem[] SelectedFileItems
		{
			get
			{
				ListViewItem[] list;

				if(this.SelectedItems.Count == 0)
					list = new ListViewItem[0];
				else
				{
					int count = 0;

					//Count items that contains SuperFileInfo instance
					foreach(ListViewItem item in this.SelectedItems)
						//if(item.Tag is System.IO.FileInfo)
						if(!((Shell32.FolderItem)(item.Tag)).IsFolder)

							count++;

					list = new ListViewItem[count];					

					//Build the list
					int j = 0;
					foreach(ListViewItem item in this.SelectedItems)
					{
						//if(item.Tag is System.IO.FileInfo)
						if(!((Shell32.FolderItem)(item.Tag)).IsFolder)
						{
							list[j] = item;
							j++;
						}
					}
				}

				return list;
			}
		}


		[Category("Behavior")]
		public bool AllowParentFolderSelection
		{
			get
			{
				return _enableParentFolderSelection;
			}
			set
			{
				_enableParentFolderSelection = value;
			}
		}
		#endregion

		#region Methods
		public void Initialize()
		{			
			//Get the desktop root and add his children items
			Shell32.Shell shell32 = new Shell32.ShellClass();			
			Shell32.Folder shell32Folder = shell32.NameSpace(Win32API.ShellFolder.Desktop);
						
			//Iterate through the Desktop namespace and populate the first level nodes
			SetListViewItems(shell32Folder);
		}

		/// <summary>
		/// Make the Control refresh its content based on the current folder.
		/// </summary>
		public void RefreshView()
		{			
			Initialize();
		}	
		#endregion
	
		#region Component Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			components = new System.ComponentModel.Container();
		}
		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect CGI
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions