使用 C# 和 Windows Forms 在 .NET 中定制化解决方案和项目浏览器






2.17/5 (3投票s)
2007年5月9日
4分钟阅读

43126

685
此应用程序将使我们无需加载进程繁重的 VS.NET 即可查看任何项目或解决方案的内容,就像在解决方案资源管理器视图中一样。
引言
.NET 已经运行多年,但大多数程序员对项目和解决方案文件并不熟悉。其背后的原因是 Visual Studio 为我们处理项目和解决方案文件。然而,如果项目或解决方案的内容很大,在 VS 的解决方案资源管理器中加载和显示它们需要很长时间。
在大多数情况下,我们只需要了解解决方案中存在的一个或多个项目的文件、引用和内容。我创建的应用程序将使我们无需加载进程繁重的 VS.NET 即可查看任何项目或解决方案的内容,就像在解决方案资源管理器视图中一样。我使用 .NET 中的 C# 和 Windows Forms 设计了此应用程序。在解释其设计和功能之前,我将首先解释一下它的功能。
应用程序功能
此应用程序...
- 加载任何 C# 项目并允许探索其内容。
- 加载任何解决方案并显示项目及其内容的列表。
- 内置支持以 XML 和数据(网格)视图显示 XML 数据。
- 支持像 VS 中的对象浏览器一样进行引用探索(*.dll)。
- 与解决方案资源管理器相比,加载速度快。
- 可以维护通过此应用程序最近打开的文件列表。
创建应用程序
首先,创建一个新的 C# Windows Forms 项目,并将其命名为 SolutionExplorer
。然后按照下图所示放置控件。
启动窗体控件
现在我将解释启动窗体 Form1
上每个控件的用途。
- 首先,我放置了一个
TreeView
控件和一个ImageList
,以在每个节点上显示图像来显示选定的项目或解决方案内容。 - 然后我添加了一个
TabControl
;在一个选项卡中我放置了一个RichTextBox
,在另一个选项卡中放置了一个datagrid
控件。 - 接下来,我按照上图所示将
menuitems
添加到MainMenu
。添加了一个包含以下项目的上下文菜单:- 展开
- Collapse
- 全部展开
- Grid View
- 然后将
TreeView
的上下文菜单属性设置为此控件。 - 最后,添加了
OpenFileDialog
和tooltip
控件。
使用 FileDialog
控件,我们可以选择任何 C# 项目或解决方案文件进行分析,并在 TreeView
中显示其内容。TreeView
的 ContextMenu
用于展开、折叠和在网格中显示 XML。
Click 事件的代码
现在我将解释 Browse menuitem
的 Click 事件中我所做的工作。
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);
}
通过使用上面的代码,我们可以浏览选定的项目(*.csproj)或解决方案(*.soln)。然后,我们可以创建一个带有所选文件路径文本的新 menuitem
,并为其 Click 事件设置一个处理程序。然后,我们可以内部调用 Click 来分析 menuitem
。
加载解决方案的代码
接下来,我将解释将解决方案及其内容加载到 TreeView
控件中的逻辑。加载项目可以使用类似的逻辑。
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;
}
在此 Click 事件中,我首先通过其扩展名来判断选定的文件是项目文件还是解决方案文件。因为解决方案文件不是 XML 格式。因此,我使用一些文本搜索模式来获取解决方案文件的项目详细信息。
我遍历解决方案中的每个项目,创建一个临时 XML 文件来存储项目内容。然后,我在 TreeView
中创建一个结构,其节点命名为 ASPX 用户控件。这样,我们可以根据项目中存在的文件类型添加任意数量的节点。我使用 XPath 来导航以 XML 格式存在的项目文件。
我使用以下 XPath 语句来获取项目的所有引用。
@"/VisualStudioProject/CSHARP/Build/References/Reference"
以下语句用于获取项目中包含的所有文件。
@"/VisualStudioProject/CSHARP/Files/Include/File"
根据扩展名,我将每个项目添加到特定的节点(即,将 *.aspx 文件添加到 ASPX 节点)。然后,我删除不包含任何项目的节点。最后,我格式化 TreeView
以提高美观性。
为了在 TreeView
中显示选定文件的内容,我选择了 AfterSelect
事件。这样,我将通过 HashTable
获取选定文件的绝对物理路径。在创建项目中存在的每种文件类型的节点时,都会创建一个 HashTable
。我通过使用选定项的文本并在其对应的项目文件中搜索其路径属性来获取选定文件的绝对路径。获取路径后,我读取其全部内容并将其显示在 richtextbox
中。
然后我添加另一个窗体来获取选定引用的内部详细信息,并创建如图所示的用户界面。
在此,我放置了一个 menu
、FileDialog
和 tooltip
,后面跟着一个 TreeView
来显示选定的引用详细信息。在 Load Click 中,我获取选定的引用路径并使用反射。这会在 TreeView
中显示 命名空间
、类
、事件
和 方法
。
最终的输出看起来是这样的。
结论
我们仍然可以通过更好的 UI、对更多文件类型的支持以及多语言项目文件探索来增强此应用程序。请参阅本文的下载以供进一步参考。希望这些代码对大家有所帮助。
历史
- 2007 年 5 月 9 日 - 发布原始版本