65.9K
CodeProject 正在变化。 阅读更多。
Home

GoToFile Add In - 快速导航大型 Visual Studio 解决方案

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.67/5 (2投票s)

2009年3月20日

CPOL

3分钟阅读

viewsIcon

24233

downloadIcon

163

一个 Visual Studio 插件,只需几次键盘操作即可快速转到您所需的文件。Alt + G 列出解决方案中的文件。

介绍 

Visual Studio 用户花费大量时间来导航,使用解决方案资源管理器从一个文件移动到另一个文件。GoToFile 是一个 Visual Studio 插件,只需几次键盘操作即可快速转到您所需的文件。

背景  

现在,一个普通的 Visual Studio 解决方案有数百甚至数千个文件。我最近做了一些包含 1000 多个文件的项目。使用解决方案资源管理器从一个文件导航到另一个文件需要花费大量精力。要打开一个文件,您必须从项目到文件夹到许多子文件夹,然后再找到该文件。有时您不记得文件所在的文件夹。

此外,几周前,我使用 IntelliJ Idea IDE 进行 Java 开发,它具有类似于 GotToFile 的功能。因此,我从那里获得了为 Visual Studio 添加此插件的想法,只需几次键盘操作即可将您带到所需的文件。

使用插件

这个插件非常简单。当您按下 Alt + G 时,会弹出一个带有一个文本框的对话框。当您在文本框中键入文件名时,将显示解决方案中匹配的文件列表。您可以按 Enter 键打开文件,或按向上和向下箭头键在列表中移动。以下是键盘帮助:

  1. Alt + G = 打开 GoToFile
  2. Esc = 关闭 GoToFile
  3. Enter = 转到选定的文件
  4. 向上、向下箭头 & Tab = 在文件列表和文件过滤器文本框之间移动
  5. * = 通配符(例如 *.gif, *.cs
  6. Ctrl + F = 切换显示所有匹配的文件。默认值为 99 个文件

Using the Code

该插件主要由 Connect.cs 类和 MainForm 组成。Connect.cs 是在您创建一个新的插件项目时创建的。MainFormGoToFile 的主对话框。当 Visual Studio 调用 Connect.Exec() 方法以加载插件时,会创建 MainForm

插件在主窗体计时器 Tick 事件中加载所有解决方案文件列表。计时器 Tick 事件发生在 MainForm OnLoad 事件之后的几毫秒。将文件加载保存在 Timer Tick 事件中有助于快速加载 MainForm 并使 UI 更具响应性。

private void timer2_Tick(object sender, EventArgs e)
{
    timer2.Enabled = false;
    CreateSolutionFileList();
    fileText = File.ReadAllText(FilePathRsFilesTxt);
}		

插件快捷方式 Alt + G 是在 Connect.OnConnection() 事件中创建的。当插件加载时,Visual Studio 会调用 OnConnection()

     public void OnConnection(object application, 
	ext_ConnectMode connectMode, object addInInst, ref Array custom)
        {
		.
		.
		.
                    AddShortcut(command, "Global::Alt+G", "Edit");
                }
                catch (System.ArgumentException)
                {
                }
            }
        }

        private void AddShortcut(Command cmd, String szKey, String szMenuToAddTo)
        {
            if ("" != szKey)
            {
                // a default keybinding specified
                object[] bindings;
                bindings = (object[])cmd.Bindings;
                if (0 >= bindings.Length)
                {
                    // there is no preexisting key binding, so add the default
                    bindings = new object[1];
                    bindings[0] = (object)szKey;
                    cmd.Bindings = (object)bindings;
                }
            }

            if ("" != szMenuToAddTo)
            {
                CommandBars commandBars = (CommandBars)_applicationObject.CommandBars;
                Microsoft.VisualStudio.CommandBars.CommandBar commandBar =
 	(Microsoft.VisualStudio.CommandBars.CommandBar)commandBars[szMenuToAddTo];
                cmd.AddControl(commandBar, commandBar.Controls.Count);
            }
        }

关注点

为了快速创建文件列表而不显示 cmd.exe 窗口,我将 System.Diagnostics.Process.StartInfo.WindowStyle 属性设置为 false。以下是 CreateSolutionFileList() 的代码

private void CreateSolutionFileList()
{
    try
    {
        string folders = "";

        foreach (Project p in ApplicationObject.Solution.Projects)
        {
            folders += " " + DQuote(Connect.GetFolder(p.FullName));
        }

        System.Diagnostics.Process proc = new System.Diagnostics.Process();
        proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
        proc.EnableRaisingEvents = false;
        proc.StartInfo.FileName = "cmd";
        proc.StartInfo.Arguments = @"/c dir /s/b/a-d " + folders + ">" + 
			DQuote(FilePathRsFilesTxt);
        proc.Start();

        bool delay = !File.Exists(FilePathRsFilesTxt);

        if (delay)
        {
            System.Threading.Thread.Sleep(800); // let DOS create the file
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error occurred: " + ex.Message + "\n\n" + 
        ex.StackTrace, "GoToFile 2.0", MessageBoxButtons.OK, 
        MessageBoxIcon.Error);
    }
}

为了过滤出匹配的文件,我首先使用 RegEx 从 dir /s/b/a-d 命令生成的文件中过滤出匹配的文件。然后我创建了 DataTable 以在 GridView 中显示,并应用 DataView 过滤器以确保只有所需的文件出现在列表中。以下是 RefreshFileList() 的代码

private bool RefreshFileList(string filter)
{
    filter = filter.ToLower();

    bool hasMoreFiles = false;

    try
    {
        if (filter == "")
        {
            HideList();

            return hasMoreFiles;
        }

        Regex match = new Regex("^.*(" + 
        (filter.Contains("*") ? filter.Replace("*", "") 
        : filter) + ").*$", RegexOptions.Multiline | RegexOptions.IgnoreCase);

        MatchCollection c = match.Matches(fileText);

        if (c.Count > 0)
        {
            #region ShowList
            DataTable table = new DataTable();

            table.Columns.Add("FileName");
            table.Columns.Add("FilePath");

            int i = 0;

            foreach (Match var in c)
            {
                if (i++ == 99 && !showAll)
                {
                    hasMoreFiles = true;

                    break;
                }

                DataRow row = table.NewRow();

                row["FileName"] = GetFileName(var.Value);
                row["FilePath"] = var.Value.Trim();

                table.Rows.Add(row);
            }

            DataView view = table.DefaultView;

            view.RowFilter = "FileName LIKE '%" + 
            (filter.Contains("*") ? filter.Replace("*", "") : filter) + "%'";
            view.Sort = "FileName";

            if (view.Count > 0)
            {
                int hx = view.Count <= 11 ? view.Count * 
                (dataGridView1.RowTemplate.Height + 1) : 200;
                Height = h + hx;

                dataGridView1.DataSource = view;
                dataGridView1.Visible = true;

                if (hasMoreFiles)
                {
                    label1.Text = "Showing top 99 matches 
                    (Press Ctrl+F to toggle show all)";
                }
                else
                {
                    label1.Text = view.Count + (view.Count == 1 ? 
                    " file " : " files ") + "found";
                }

                return hasMoreFiles;
            }
     
            #endregion
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error occurred: " + ex.Message + 
        "\n\n" + ex.StackTrace, "GoToFile 2.0", 
        MessageBoxButtons.OK, MessageBoxIcon.Error);
    }

    HideList();

    return hasMoreFiles;
} 

历史

  • 2009 年 3 月 20 日:初始发布
© . All rights reserved.