Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Customized Solution & Project Explorer in .NET using C# and Windows Forms

0.00/5 (No votes)
9 May 2007 1  
This application will allow us to see any project's or solution's contents as in Solution Explorer view without loading process-heavy VS.NET

Introduction

.NET has been in action for many years, yet project and solution files are not familiar to most programmers. The reason behind this is that Visual Studio takes care of project and solution files for us. However, if the project or solution contents are large, it takes a long time to load and display them in Solution Explorer for VS.

In most situations we just need to know the files, references and contents of a project -- or list of projects -- present in a solution. The application I have created will allow us to see any project's or solution's contents as in Solution Explorer view, without having to load process-heavy VS.NET. I designed this application using C# and Windows Forms in .NET. Before explaining its design and functionality, I first will explain a little bit about its features.

Application features

This application...

  • Loads any C# project and allows exploration of its contents.
  • Loads any solution and shows a list of the projects and their contents.
  • Has built-in support for displaying XML data in both XML and Data (Grid) View.
  • Supports reference exploration (.dll) like an object browser in VS.
  • Loads quickly when compared to Solution Explorer.
  • Can maintain a list of files recently opened through this application.

Creating the application

First, create a new Windows Forms project in C# and name it SolutionExplorer. Then place the controls as shown in the figure below:

Start-up form controls

I will now explain the purpose of each control on the start-up form, Form1:

  • First, I placed a TreeView control and an ImageList to display the selected project or solution contents with images on each node.
  • Then I added a TabControl; in one tab I placed a RichTextBox and in the other, a datagrid control.
  • Next I added menuitems to MainMenu as shown in the figure above. A context menu was added with the following items:
    • Expand
    • Collapse
    • Full Expand
    • Grid View
  • The context menu property of TreeView was then set to this control.
  • Finally, OpenFileDialog and tooltip controls were added.

By using the FileDialog control, we can select any C# project or solution file to analyze and display its contents in TreeView. ContextMenu for TreeView is used to expand, collapse and display XML in Grid.

Code for the Click event

I will now explain what I have done in the Click event of Browse menuitem:

if(DialogResult.OK == dglopensoln.ShowDialog())
{
    string selectedprjfile = dglopensoln.FileName.ToString();
    txtsolnpath.Text = selectedprjfile;
    toolTip1.SetToolTip(txtsolnpath,selectedprjfile);
    MenuItem testitem = new MenuItem(selectedprjfile);
    testitem.Click += new EventHandler(testitem_Click);
    mnurecent.MenuItems.Add(testitem);
    obj1.Text = selectedprjfile;
    menuItem7_Click(sender,e);
}

By using the above code, we can browse the selected project (.csproj) or solution (.soln). Then we can create a new menuitem with text as the selected file path and a handler for the click event of that menuitem. We can then internally call a click to analyze menuitem.

Code for loading the solution

Next, I will explain the logic of loading the solution and its contents into the TreeView control. Similar logic can be used to load the project, as well.

string prevselfilecontents = selfilecontents.Text;
try
{
    selfilecontents.Text = "";
    treeView1.Nodes.Clear();
    menuItem7.Enabled = false;
    TreeNode mainnode = null;
    string httpprjs = null;
    if(txtsolnpath.Text.EndsWith(".sln"))
    {
        string tmpsolndata = @"c:\tempsoln.xml";
        string solnname = Path.GetFileNameWithoutExtension(txtsolnpath.Text);
        mainnode = new TreeNode(solnname);
        treeView1.Nodes.Add(mainnode);
        if(Directory.Exists(@"C:\"+solnname))
        {
            Directory.Delete(@"C:\"+solnname,true);
        }
        Directory.CreateDirectory(@"C:\"+solnname);
        prjsdetailsinsoln = new Hashtable();
        if(!File.Exists(tmpsolndata))
        {
            File.Create(tmpsolndata);
        }
        string solncontents = "";
        StreamReader solnreader = new StreamReader(txtsolnpath.Text.Trim());
        while(solncontents != null)
        {
            solncontents = solnreader.ReadLine();
            if(solncontents != null)
                try
            {
                if(solncontents.StartsWith("Project"))
                {
                    string[] prjprops = solncontents.Split(',');
                    string prjdispname = 
                        prjprops[0].Substring(prjprops[0].LastIndexOf(
                            "=")+1).Replace("\"",
                            "").Trim();
                    string prjpath1   = prjprops[1].ToString().Replace(
                            "\"","").Trim();
                    prjsdetailsinsoln.Add(prjdispname,prjpath1);
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
    IDictionaryEnumerator enprj = prjsdetailsinsoln.GetEnumerator();
    while (enprj.MoveNext())
    {
        string strprjname = enprj.Key.ToString();
        if(enprj.Value.ToString().IndexOf(
            "http://") == -1 && 
        enprj.Value.ToString().EndsWith(".csproj"))
        {
            string prjpath = txtsolnpath.Text.Substring(
                0,txtsolnpath.Text.LastIndexOf(
                    @"\")+1)+enprj.Value.ToString();
            if(File.Exists(prjpath))
            {
                StreamReader prjreader = new StreamReader(prjpath);
                string prjcontents = prjreader.ReadToEnd();
                prjreader.Close();
                //Format Project File into XML file...

                tmpxmlfileforsolndata = 
                    @"C:\"+solnname+"\\"+enprj.Key.ToString()+".xml";
                if(prjcontents.Length != 0)
                {
                    StreamWriter solntoxmlconverter = 
                        new StreamWriter(tmpxmlfileforsolndata,false);
                    solntoxmlconverter.Write("");
                    solntoxmlconverter.Write(prjcontents);
                    solntoxmlconverter.Close();
                }
                else
                {
                    MessageBox.Show(
                        "Selected Project File is empty...");
                    txtsolnpath.Text = "";
                }
                //General project's Details....
                TreeNode rootnode = new TreeNode();
                rootnode.Text = strprjname;
                mainnode.Nodes.Add(rootnode);
                //Project's references information...
                TreeNode referencenode = new TreeNode();
                referencenode.Text = "References";
                rootnode.Nodes.Add(referencenode);
                //aspx Files Included in the Project...
                TreeNode includedaspxfilesnode = new TreeNode();
                includedaspxfilesnode.Text = "ASPX Files";
                rootnode.Nodes.Add(includedaspxfilesnode);
                //aspx.cs Files Included in the Project...
                TreeNode includedaspxcsfilesnode = new TreeNode();
                includedaspxcsfilesnode.Text = "ASPX.CS Files";
                rootnode.Nodes.Add(includedaspxcsfilesnode);
                //Class  Files Included in the Project...
                TreeNode includedcsfilenode = new TreeNode();
                includedcsfilenode.Text = "Class Files";
                rootnode.Nodes.Add(includedcsfilenode);
                //Class  Files Included in the Project...
                TreeNode includedusercntrlfilenode = new TreeNode();
                includedusercntrlfilenode.Text = "User Controls";
                rootnode.Nodes.Add(includedusercntrlfilenode);
                //Web config Files Included in the Project...
                TreeNode includedwebconfignode = new TreeNode();
                includedwebconfignode.Text = "Web Config Files";
                rootnode.Nodes.Add(includedwebconfignode);
                //Javascript Files Included in the Project...
                TreeNode includedjsfilenode = new TreeNode();
                includedjsfilenode.Text = "JavaScript Files";
                rootnode.Nodes.Add(includedjsfilenode);
                //CSS  Files Included in the Project...
                TreeNode includedcssfilenode = new TreeNode();
                includedcssfilenode.Text = "CSS Files";
                rootnode.Nodes.Add(includedcssfilenode);
                //Image  Files Included in the Project...
                TreeNode includedimgfilenode = new TreeNode();
                includedimgfilenode.Text = "Image Files";
                rootnode.Nodes.Add(includedimgfilenode);
                //XML  Files Included in the Project...
                TreeNode includedxmlfilenode = new TreeNode();
                includedxmlfilenode.Text = "XML Files";
                rootnode.Nodes.Add(includedxmlfilenode);
                //XSL  Files Included in the Project...
                TreeNode includedxslfilenode = new TreeNode();
                includedxslfilenode.Text = "XSL Files";
                rootnode.Nodes.Add(includedxslfilenode);
                //Other Files present in unknown format Included in the 
                //Project...
                TreeNode includedunknownfilenode = new TreeNode();
                includedunknownfilenode.Text = "Unknown Files";
                rootnode.Nodes.Add(includedunknownfilenode);
                //To Load all items of the Project into the Treeview...
                XPathDocument prjfile = new XPathDocument(
                    tmpxmlfileforsolndata);
                XPathNavigator nav = prjfile.CreateNavigator();
                //TO Load all references of the selected Project...
                XPathNodeIterator referenceiterator = 
                    nav.Select(@"/VisualStudioProject/CSHARP/Build" +
                    "/References/Reference"); 
                while(referenceiterator.MoveNext())
                {
                    string reffile = 
                        referenceiterator.Current.GetAttribute(
                            "Name","").ToString();
                    TreeNode refnode = new TreeNode(reffile);
                    if(reffile.StartsWith("System"))
                    {
                        refnode.ForeColor  = Color.Green;
                    }
                    else
                    {
                        refnode.ForeColor = Color.Orange;
                    }
                    referencenode.Nodes.Add(refnode);
                }
                //TO Load all ASPX of the selected Project...
                XPathNodeIterator aspxfileiterator = 
                    nav.Select(@"/VisualStudioProject/" +
                    "CSHARP/Files/Include/File"); 
                LoadselectedDetails(
                    "aspx",includedaspxfilesnode,aspxfileiterator);
                RemoveUnwatedNodes(includedaspxfilesnode);
                //TO Load all ASPX.CS(Code-Behind) of the selected Project...
                XPathNodeIterator aspxcsfileiterator = 
                    nav.Select(@"/VisualStudioProject/CSHARP" +
                        "/Files/Include/File"); 
                LoadselectedDetails("aspx.cs",
                    includedaspxcsfilesnode,aspxcsfileiterator);
                RemoveUnwatedNodes(includedaspxcsfilesnode);
                //TO Load all Assembly Config of the selected Project...
                XPathNodeIterator webconfigfileiterator = 
                    nav.Select(@"/VisualStudioProject/CSHARP/" +
                        "Files/Include/File"); 
                LoadselectedDetails("config",
                    includedwebconfignode,webconfigfileiterator);
                RemoveUnwatedNodes(includedwebconfignode);
                //TO Load all Assembly Config of the selected Project...
                XPathNodeIterator jsfileiterator = 
                    nav.Select(@"/VisualStudioProject/CSHARP" +
                        "/Files/Include/File"); 
                LoadselectedDetails("js",
                    includedjsfilenode,jsfileiterator);
                RemoveUnwatedNodes(includedjsfilenode);
                //TO Load all CSS files of the selected Project...
                XPathNodeIterator cssfileiterator = 
                    nav.Select(@"/VisualStudioProject/CSHARP" +
                        "/Files/Include/File"); 
                LoadselectedDetails("css",
                    includedcssfilenode,cssfileiterator);
                RemoveUnwatedNodes(includedcssfilenode);
                //TO Load all Image files of the selected Project...
                XPathNodeIterator imgfileiterator = 
                    nav.Select(@"/VisualStudioProject/CSHARP" +
                    "/Files/Include/File"); 
                LoadselectedDetails("gif",
                    includedimgfilenode,imgfileiterator);
                RemoveUnwatedNodes(includedimgfilenode);
                //TO Load all XML files of the selected Project...
                XPathNodeIterator xmlfileiterator = 
                    nav.Select(@"/VisualStudioProject/" +
                    "CSHARP/Files/Include/File"); 
                LoadselectedDetails("xml",
                    includedxmlfilenode,xmlfileiterator);
                RemoveUnwatedNodes(includedxmlfilenode);
                //TO Load all XSL files of the selected Project...
                XPathNodeIterator xslfileiterator = 
                    nav.Select(@"/VisualStudioProject/CSHARP" +
                    "/Files/Include/File"); 
                LoadselectedDetails("xsl",
                    includedxslfilenode,xslfileiterator);
                RemoveUnwatedNodes(includedxslfilenode);
                //TO Load all Class files of the selected Project...
                XPathNodeIterator csfileiterator = 
                    nav.Select(@"/VisualStudioProject/" +
                    "CSHARP/Files/Include/File"); 
                LoadselectedDetails("cs",
                    includedcsfilenode,csfileiterator);
                RemoveUnwatedNodes(includedcsfilenode);
                //TO Load all User Controls files of the selected Project...
                XPathNodeIterator usercntrlsfileiterator = 
                    nav.Select(@"/VisualStudioProject/CSHARP" +
                    "/Files/Include/File"); 
                LoadselectedDetails("ascx.cs",
                    includedusercntrlfilenode,usercntrlsfileiterator);
                RemoveUnwatedNodes(includedusercntrlfilenode);
                //TO Load all Unknown files of the selected Project...
                XPathNodeIterator unknownsfileiterator = 
                    nav.Select(@"/VisualStudioProject/CSHARP" +
                    "/Files/Include/File"); 
                while(unknownsfileiterator.MoveNext())
                {
                string filename = unknownsfileiterator.Current.GetAttribute(
                        "RelPath","").ToString().ToLower();
                    if(!filename.EndsWith(".aspx") && !
                        filename.EndsWith(".aspx.cs") && 
                    !filename.EndsWith(".cs") && !
                        filename.EndsWith(".ascx.cs") && 
                    !filename.EndsWith(".js") &&  !
                        filename.EndsWith(".xml") && 
                    !filename.EndsWith(".xsl") && 
                        filename.EndsWith(".css") &&  
                    !filename.EndsWith(".gif") &&  !
                        filename.EndsWith(".config"))
                    {
                        includedunknownfilenode.Nodes.Add(
                            filename.Substring(
                                filename.LastIndexOf(@"\")+1));
                    }
                }
                RemoveUnwatedNodes(includedunknownfilenode);
            }
            else
            {
                TreeNode httpprjnode = new TreeNode(enprj.Value.ToString());
                httpprjnode.ForeColor = Color.Red;
                mainnode.Nodes.Add(httpprjnode);
            }
        }
        if(enprj.Value.ToString().IndexOf("http://") != -1)

        {
            httpprjs+=enprj.Value.ToString()+"#";
        }
    }
    foreach(string httpprj in httpprjs.Split(new char[]{'#'}))
    {
        if(httpprj.Trim() != "")
        {
            TreeNode node = new TreeNode(httpprj.Trim());
            mainnode.Nodes.Add(node);
        }
    }
}
}
catch(Exception ex)
{
    MessageBox.Show(ex.Message);
    selfilecontents.Text = prevselfilecontents;
}
finally
{
    menuItem7.Enabled = true;
}

In this click event, I am first finding whether the selected file is a project file or solution file. This is done by referring to its extension, since a solution file will not be in XML format. I am therefore using some text search patterns to get the project details of the solution file.

I am looping for each project present in the solution, creating a temporary XML file to store the project contents. Then I create a structure in TreeView with nodes named as ASPX user controls. In this way, we can add any number of nodes based on the types of files present in the project. I am using XPath to navigate through the project file that is present in XML format.

I am using the following Xpath statement to get all of the project's references:

@"/VisualStudioProject/CSHARP/Build/References/Reference"

...and the following to get all of the files included in the project:

@"/VisualStudioProject/CSHARP/Files/Include/File"

Based on its extension, I am adding each item to a specific node (i.e. adding .aspx files to the ASPX node). Then I am removing nodes which don't have any items in them. Finally, I am formatting TreeView for aesthetics.

To display the contents of the selected file in TreeView , I chose the AfterSelect event. This way, I am going to get the absolute physical path of the selected file by using HashTable. A HashTable is created at the time of node creation for each file type present in the project or solution. I am getting the absolute path of the selected file by using the selected item's text and searching its path attribute in its corresponding project file. After getting its path, I am reading its entire contents and displaying it in richtextbox.

Then I add another form to get the internal details of the selected reference and create UI as shown:

Here I placed a menu, FileDialog and tooltip followed by a TreeView to display selected reference details. In Load Click, I am getting the selected reference path and using reflection. This displays the namespaces, classes, events and methods in TreeView .

The final output will look like this:

Conclusion

We can still enhance this application with better UI, support of more file types and multiple-language project file exploration. Please see this article's download for further reference. I hope this code will be useful to all.

History

  • May 9, 2007 - Original version posted

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