Skip to main content
Email Password   helpLost your password?

Sample Image - ExplorerTree.jpg

Introduction

Idea: Functionality of windows explorer wrapped up as a control. User can browse through all the folders in the computer including network folders and select the path.

The Long story, while working on a photo editing software i frequently needed to test different images from different folders. i have to call an open dialog then browse for the folder and then select the file. 4 clicks well not too much but if you have to test 10 images in the same folder same process have to be repeated for all of them, more if you have 10 images in different folders well 10 X 4 clicks, i call it Multiple Mouse Clicks For Single Operation (MMCFSO). Explains why the whole software world relates reducing MMCFSO with the ease of use.

MMCFSO is not just needed for a imaging application. Where ever you have to select multiple files from multiple destinations you need this. So i think an effort to create a windows explorer user control is worth it. Here is the result.

To hold your interest, here is how the ExplorerTree control looks like.

A UserControl is an object which can display and accept information from a user. It usually fulfills a specific functions of input or output. What is our ExplorerTree control going to do ?

1. Display a treeview of all the folders like Windows Explorer
2. It will take user input as mouse click and expand the folder
3. Output will be the path of the current selection

The target was to create a user friendly control which simulates windows explorer with the following

Without any furthur ado, lets jump into how each of these targets are met.

THE UPDATE

Customizable Toolbar and addressbar

updated

Functionality

Features

Properties

Events

The Code behind : explore my computer

string [] drives = Environment.GetLogicalDrives();
foreach(string drive in drives)
{

    nodeDrive = new TreeNode();
    nodeDrive.Tag = drive;

    nodeDrive.Text = drive ;

    //Determine icon to display by drive
    switch(Win32.GetDriveType(drive))
    {
        case 2:
            nodeDrive.ImageIndex = 17;
            nodeDrive.SelectedImageIndex  = 17;
            break;
        case 3:
            nodeDrive.ImageIndex = 0;
            nodeDrive.SelectedImageIndex  = 0;
            break;
        case 4:
            nodeDrive.ImageIndex = 8;
            nodeDrive.SelectedImageIndex = 8;
            break;
        case 5:
            nodeDrive.ImageIndex = 7;
            nodeDrive.SelectedImageIndex = 7;
            break;
        default:
            nodeDrive.ImageIndex = 0;
            nodeDrive.SelectedImageIndex = 0;
            break;
    }

    nodemyC.Nodes.Add(nodeDrive);
    nodeDrive.EnsureVisible();
    tvwMain.Refresh(); 
    try
    {
        //add dirs under drive
        if (Directory.Exists (drive))
        {
            foreach(string dir in Directory.GetDirectories(drive))
            {
                dir2 = dir;
                node = new TreeNode();
                node.Tag = dir;
                node.Text = dir.Substring(dir.LastIndexOf(@"\") + 1);
                node.ImageIndex = 1;
                nodeDrive.Nodes.Add(node);
            }
        }

    }
    catch(Exception)    //error just add blank dir
    {
    }
    nodemyC.Expand(); 
}

The Code behind : explore my folders

    if (ShowMyDocuments) 
    {
        nodemd = new TreeNode();
        nodemd.Tag = Environment.GetFolderPath(
                     Environment.SpecialFolder.Personal);
        nodemd.Text = "My Documents";
        nodemd.ImageIndex = 9;
        nodemd.SelectedImageIndex = 9;
        nodeD.Nodes.Add(nodemd);
        FillFilesandDirs(nodemd);
    }
    
    if (ShowMyNetwork) 
    {
        nodemyN = new TreeNode();
        nodemyN.Tag = "My Network Places";
        nodemyN.Text = "My Network Places";
        nodemyN.ImageIndex = 13;
        nodemyN.SelectedImageIndex = 13;
        nodeD.Nodes.Add(nodemyN);
        nodemyN.EnsureVisible();

        nodeEN = new TreeNode();
        nodeEN.Tag = "Entire Network";
        nodeEN.Text = "Entire Network";
        nodeEN.ImageIndex = 14;
        nodeEN.SelectedImageIndex = 14;
        nodemyN.Nodes.Add(nodeEN);

        nodeNN = new TreeNode();
        nodeNN.Tag = "Network Node";
        nodeNN.Text = "Network Node";
        nodeNN.ImageIndex = 15;
        nodeNN.SelectedImageIndex = 15;
        nodeEN.Nodes.Add(nodeNN);
        nodeEN.EnsureVisible();
    }

    if (ShowMyFavorites) 
    {
        nodemf = new TreeNode();
        nodemf.Tag = Environment.GetFolderPath(
                     Environment.SpecialFolder.Favorites);
        nodemf.Text = "My Favorites";
        nodemf.ImageIndex = 26;
        nodemf.SelectedImageIndex = 26;
        nodeD.Nodes.Add(nodemf);
        FillFilesandDirs(nodemf);
    }   

The Go Back and Go Forward buttons are handled using a listview as shown below, the selected is the current path and go back will just move the cursor to one up and go next to one down.

The Code behind : Go Back and Go Forward

    
private void UpdateListGoBack() 
{    
 if ((listView1.Items.Count >0)&&
     (String.Compare(listView1.Items[0].SubItems[1].Text,"Selected")==0))
        return;
     int i=0;
    for (i = 0;i< listView1.Items.Count;i++)
    {
        if (String.Compare(listView1.Items[i].SubItems[1].Text,"Selected")==0)
        {
            if (i != 0)
            {
                listView1.Items[i - 1].SubItems[1].Text = "Selected";
                txtPath.Text =listView1.Items[i - 1].Text;
            }
        }
        if (i != 0)
        {
            listView1.Items[i].SubItems[1].Text = " -/- ";
        }
    }
    }
private void UpdateListGoFwd()
{
    if ((listView1.Items.Count >0) && 
        (String.Compare(
         listView1.Items[listView1.Items.Count -1 ].SubItems[1].Text, 
         "Selected")==0))
        return;
    int i=0;
    for (i = listView1.Items.Count-1;i >= 0;i--)
    {
        if (String.Compare(listView1.Items[i].SubItems[1].Text,"Selected")==0)
        {
            if (i != listView1.Items.Count) 
            {
                listView1.Items[i + 1].SubItems[1].Text = "Selected";
                txtPath.Text =listView1.Items[i + 1].Text;   
            }
        }

        if (i != listView1.Items.Count-1)
            listView1.Items[i].SubItems[1].Text = " -/- ";
    }
}

Update list function : Go Back and Go Forward

    
private void updateList(string f)
{
    int i=0;
    ListViewItem listviewitem;        // Used for creating listview items.

    int icount =0;
    UpdateListAddCurrent();
    icount = listView1.Items.Count + 1;
    try
    {
        if (listView1.Items.Count> 0)
        {    
            if (String.Compare(listView1.Items[listView1.Items.Count-1].Text, f)==0)
            {
                return;
            }
        }
    
        for (i = 0;i < listView1.Items.Count;i++)
        {
            listView1.Items[i].SubItems[1].Text = " -/- ";
        }
        listviewitem = new ListViewItem(f);
        listviewitem.SubItems.Add("Selected");
        listviewitem.Tag = f;
        this.listView1.Items.Add(listviewitem);
    }
    catch(Exception e)
    {
    MessageBox.Show(e.Message);   
    }
}

Explore Network Places

When i started porting one of my old existing Visual Basic Server enumeration function for the network places i came across a brilliant article by Rob Manderson here , He had ported successfully NETRESOURCE class in c sharp. I have used his class to furthur get all the different kinds of network resources and shared folders in the systematic way, how Windows explorer does it. His article actually helped me to do what i wanted to do without worrying about the enumeration process.

    
ServerEnum servers = new ServerEnum(ResourceScope.RESOURCE_GLOBALNET,
    ResourceType.RESOURCETYPE_DISK, 
    ResourceUsage.RESOURCEUSAGE_ALL, 
    ResourceDisplayType.RESOURCEDISPLAYTYPE_SERVER,pS);


foreach    (string    s1 in servers)
{
    string s2="";


    if((s1.Length <6)||(String.Compare(s1.Substring(s1.Length-6,6),"-share")!=0))
    {
        s2 = s1;//.Substring(s1.IndexOf("\\",2));
        nodeNN = new TreeNode();
        nodeNN.Tag =  s2;
        nodeNN.Text = s2.Substring(2) ;
        nodeNN.ImageIndex = 12;
        nodeNN.SelectedImageIndex = 12;
        n.Nodes.Add(nodeNN);
        foreach    (string    s1node in servers)
        {
            if (s1node.Length >6)
            {
                if(String.Compare(s1node.Substring(s1node.Length-6,6),"-share")==0)
                {
                    if (s2.Length <=s1node.Length )
                    {

        try
            {
            if (String.Compare(s1node.Substring(0, 
                       s2.Length+1),s2 + @"\")==0)  
                {
                nodeNNode = new TreeNode();
                nodeNNode.Tag =  s1node.Substring(0,s1node.Length -6);
                nodeNNode.Text = 
                 s1node.Substring(s2.Length+1,s1node.Length -s2.Length-7) ;
                nodeNNode.ImageIndex = 28;
                nodeNNode.SelectedImageIndex = 28;
                nodeNN.Nodes.Add(nodeNNode);
                }
            }
            catch(Exception)
            {}
        }
        }
        }
    }
    }

}

Enumerate network servers

This function basically creates the tree nodes of the network places, and decides which all network resources are the domains and which all the shared folders under that domain.

private void EnumerateServers(NETRESOURCE pRsrc, 
     ResourceScope scope, ResourceType type, 
     ResourceUsage usage, ResourceDisplayType displayType, 
     string kPath)
{
uint        bufferSize = 16384;
IntPtr        buffer    = Marshal.AllocHGlobal((int) bufferSize);
IntPtr        handle = IntPtr.Zero;
ErrorCodes    result;
uint        cEntries = 1;
bool serverenum = false;

result = WNetOpenEnum(scope, type, usage, pRsrc, out handle);

if (result == ErrorCodes.NO_ERROR)
{
    do
    {
        result = WNetEnumResource(handle, ref cEntries, buffer, 
                                  ref bufferSize);

        if ((result == ErrorCodes.NO_ERROR))
        {
            Marshal.PtrToStructure(buffer, pRsrc);

 if(String.Compare(kPath,"")==0)
  {
  if ((pRsrc.dwDisplayType==displayType) || 
      (pRsrc.dwDisplayType == ResourceDisplayType.RESOURCEDISPLAYTYPE_DOMAIN))
  aData.Add(pRsrc.lpRemoteName + "-" + pRsrc.dwDisplayType );

 if ((pRsrc.dwUsage&ResourceUsage.RESOURCEUSAGE_CONTAINER ) == 
                    ResourceUsage.RESOURCEUSAGE_CONTAINER )
      {    
       if ((pRsrc.dwDisplayType== displayType))
         {
           EnumerateServers(pRsrc, scope, type, usage, displayType,kPath);
           
          }
               
        }
    }
    else
    {
        if (pRsrc.dwDisplayType    == displayType)
        {
            aData.Add(pRsrc.lpRemoteName);
            EnumerateServers(pRsrc, scope,type, usage, displayType,kPath);
            //return;
            serverenum = true;
        }
        if (!serverenum)
        {
            if (pRsrc.dwDisplayType == 
                  ResourceDisplayType.RESOURCEDISPLAYTYPE_SHARE)
            {
                aData.Add(pRsrc.lpRemoteName + "-share");
            }
        }
        else
        {
            serverenum =false;
        }
 if((kPath.IndexOf(pRsrc.lpRemoteName)>=0)||
    (String.Compare(pRsrc.lpRemoteName, 
     "Microsoft Windows Network")==0))
        {
            EnumerateServers(pRsrc, scope, type, usage, displayType,kPath);
            //return;
            
        }

    }
    }            
        
        }
        else if    (result    != ErrorCodes.ERROR_NO_MORE_ITEMS)
            break;
    } while    (result    != ErrorCodes.ERROR_NO_MORE_ITEMS);

    WNetCloseEnum(handle);
}

Marshal.FreeHGlobal((IntPtr) buffer);
}

User Interface

About the user interface how to give it a professional touch. First thing is to create an icon for the control which will be displayed in the toolbox as shown below


Add a 16 x 16 gif image tree.gif here in the project and change its property BUILD ACTION = Embedded Resource and add the following

[ToolboxBitmapAttribute(typeof(WindowsExplorer.ExplorerTree), 
          "tree.gif"),DefaultEvent("PathChanged")    ] 

public class ExplorerTree : System.Windows.Forms.UserControl
{
        

Reusability

Any user control created in .Net is reusable in the sense that , once you compile it as a dll file , you can add it in the toolbox as shown in the figure below , and that control can be used with VisualBasic.Net or C# or any other .net interoperable language

You can create as many instances of the user control as shown below
4 ExplorerTree control with different properties, can you SPOT the difference

Extensibility

Now the most important part, How to extend our user control , one way which i thought would be useful is to add shortcut to frequently used folders, so you don't have to go through the whole tree structure. the most common example is the way "My Documents" is handled by Windows Explorer, though "My documents" actually resides in "C:\Documents and Settings\Username\My Documents" but the windows explorer gives us a shortcut to go there directly. So keeping this in mind , i have extended the ExplorerTree so that user can add/remove shortcuts to frequently used folders as shown below

The Code behind : Add shortcuts for frequently used folders

            
private void AddFolderNode(string name, string path)
{

    try
    {
        TreeNode nodemyC = new TreeNode();
    
        nodemyC.Tag = path;
        nodemyC.Text = name;

        nodemyC.ImageIndex = 18;
        nodemyC.SelectedImageIndex = 18;

        TreeNodeRootNode.Nodes.Add(nodemyC); 

        try
        {
            //add dirs under drive
            if (Directory.Exists (path))
            {
                foreach(string dir in Directory.GetDirectories(path))
                {
                    TreeNode node = new TreeNode();
                    node.Tag = dir;
                    node.Text = dir.Substring(dir.LastIndexOf(@"\") + 1);
                    node.ImageIndex = 1;
                    nodemyC.Nodes.Add(node);
                }
            }
            
            
        }
        catch(Exception ex)    //error just add blank dir
        {
            MessageBox.Show ("Error while Filling the Explorer:" + 
                             ex.Message );
        }
    }
    catch(Exception e)
    {
        MessageBox.Show (e.Message);  
    }
}

In Action: ExplorerTree control in a Test application

With Visual Basic FileListBox

Acknowledgement

Thanks to Rob Manderson for his article on porting the NetResource class in C sharp here http://www.codeproject.com/csharp/csenumnetworkresources.asp and also all those authors who have contributed for code project whose ideas knowingly or unknowingly, directly or indirectly have influenced me to write this article.

Article History

And thanks

For coming so far! I hope you find this useful, and give me a vote/comment if you do and take care.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralFTP Pin
jammmie999
1:00 31 May '09  
GeneralManually typed directory gives error Pin
jm33
13:23 28 May '08  
GeneralMy Network Places not working in Vista and partially in XP, fully only under Win2000[modified] Pin
ionutzu
1:51 4 May '08  
GeneralWindows Explorer is now a part of FREE software ToeTag Pin
Quartz.
16:43 2 Mar '08  
QuestionFolders don't update correctly if the files are changed outside of the explorer tree.. Pin
flacoman91
18:22 17 Nov '07  
GeneralRe: Folders don't update correctly if the files are changed outside of the explorer tree.. Pin
poirelotto
4:26 13 Feb '08  
GeneralRe: Folders don't update correctly if the files are changed outside of the explorer tree.. Pin
flacoman91
4:54 13 Feb '08  
Generalany thoughts on adding a file system watcher? Pin
flacoman91
8:23 10 Nov '07  
Generalfiring an event on a vb.net form hosting the control. [modified] Pin
Greg Hazzard
7:57 29 Mar '07  
GeneralPersisting Shortcuts Pin
yesildal
9:42 15 Mar '07  
GeneralFolders SHown Twice on Desktop Pin
scorpion_pgm82
23:56 7 Mar '07  
AnswerRe: Folders SHown Twice on Desktop Pin
Quartz...
8:11 8 Mar '07  
GeneralRe: Folders SHown Twice on Desktop Pin
scorpion_pgm82
20:26 14 Mar '07  
AnswerRe: Folders SHown Twice on Desktop Pin
Quartz...
8:43 15 Mar '07  
GeneralRe: Folders SHown Twice on Desktop Pin
scorpion_pgm82
0:54 16 Mar '07  
GeneralRe: Folders SHown Twice on Desktop Pin
scorpion_pgm82
23:52 29 Mar '07  
Generallaunch into ExplorerTree from a most recent directories list? Pin
Greg Hazzard
9:08 14 Feb '07  
AnswerRe: launch into ExplorerTree from a most recent directories list? Pin
Quartz...
9:38 14 Feb '07  
GeneralRe: launch into ExplorerTree from a most recent directories list? [modified] Pin
Greg Hazzard
14:27 14 Feb '07  
QuestionShellCommands Pin
hootsman
3:42 29 Jan '07  
AnswerRe: ShellCommands Pin
Quartz...
9:28 29 Jan '07  
QuestionUpdated version? Pin
psxp
6:50 13 Dec '06  
AnswerRe: Updated version? - FIXED V 2.0 Pin
Quartz...
13:47 14 Dec '06  
GeneralUpgrade for the GetDirectories() function Pin
Evan Stein
0:58 17 Sep '06  
GeneralRe: Upgrade for the GetDirectories() function Pin
Quartz...
17:50 17 Sep '06  


Last Updated 15 Mar 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2009