创建 Visual Studio 工具窗口

工具窗口是向 Visual Studio 添加复杂 UI 和交互的一种方法。 它们通常提供用户友好的方法来与各种 API 和功能进行交互。 例如,“解决方案资源管理器”工具窗口提供当前项目/解决方案/文件夹的基于树的视图,并提供用于打开、重命名和创建文件的简单手势。

工具窗口是单实例,这意味着一次只能打开工具窗口的一个实例。 当工具窗口在 IDE 中关闭时,它显而易见地被隐藏,并且不像文档那样被完全关闭和处置。

开始吧

若要开始,请按照 创建您的第一个扩展 教程。

使用工具窗口

本指南旨在覆盖使用工具窗口时的主要用户场景。

创建工具窗口

使用新的扩展性模型创建工具窗口就像扩展基类ToolWindow并用VisualStudioContribution属性装饰你的类一样简单。

[VisualStudioContribution]
public class MyToolWindow : ToolWindow

ToolWindow 属性

ToolWindow抽象类需要实现ToolWindowConfiguration配置,该配置具有一些你应该熟悉的属性:

参数 类型 必选 DESCRIPTION 默认值
放置 ToolWindowPlacement Visual Studio 中应首次打开工具窗口的位置。 ToolWindowPlacement.DockedTo 允许将工具窗口停靠到与旧 VSIX 样式工具窗口 ID 匹配的 GUID。 查看有关 ToolWindowPlacement 的更多信息。 ToolWindowPlacement.Floating
DockDirection 码头 相对于工具窗口第一次打开时应停靠的位置的方向。 请参阅 Dock Dock.None
AllowAutoCreation 布尔值 指定是否可以自动创建工具窗口。 将此参数设置为 false 意味着当 Visual Studio 关闭时打开的工具窗口不会在 Visual Studio 再次打开时自动还原。 true

示例:

[VisualStudioContribution]
public class MyToolWindow : ToolWindow
{
    public MyToolWindow(VisualStudioExtensibility extensibility)
        : base(extensibility)
    {
        this.Title = "My Tool Window";
    }

    public override ToolWindowConfiguration ToolWindowConfiguration => new()
    {
        Placement = ToolWindowPlacement.Floating,
        DockDirection = Dock.Right,
        AllowAutoCreation = true,
    };

    public override Task<IRemoteUserControl> GetContentAsync(CancellationToken cancellationToken)
    {
        // Create and return a RemoteUserControl
    }
}

将内容添加到工具窗口

由于 VisualStudio.Extensibility 中的扩展可能来自 IDE 进程外,因此无法直接使用 WPF(Windows Presentation Foundation)作为工具 Windows 中内容的呈现层。 相反,将内容添加到工具窗口需要为该控件创建 RemoteUserControl 和相应的数据模板。 虽然下面有一些简单的示例,但建议在添加工具窗口内容时阅读 远程 UI 文档

[VisualStudioContribution]
public class MyToolWindow : ToolWindow
{
    public MyToolWindow(VisualStudioExtensibility extensibility)
        : base(extensibility)
    {
        this.Title = "My Tool Window";
    }

    public override ToolWindowConfiguration ToolWindowConfiguration => new()
    {
        Placement = ToolWindowPlacement.DocumentWell,
    };

    public override async Task InitializeAsync(CancellationToken cancellationToken)
    {
        // Do any work here that is needed before creating the control.
    }

    public override Task<IRemoteUserControl> GetContentAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult<IRemoteUserControl>(new MyToolWindowControl());
    }
}

MyToolWindowControl.cs:(这是一个示例文件名,应与数据模板文件同名)

internal class MyToolWindowControl : RemoteUserControl
{
    public MyToolWindowControl()
        : base(dataContext: null)
    {
    }
}

MyToolWindowControl.xaml:(这是一个示例文件名,应与派生自 RemoteUserControl 的类同名)

<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:vs="http://schemas.microsoft.com/visualstudio/extensibility/2022/xaml">
    <Label></Label>
</DataTemplate>

有关创建RemoteUserControl的详细信息,请参阅远程 UI

创建命令以显示工具窗口

显示工具窗口的一种常见机制是添加一个 命令 ,该命令在调用时通过调用 ShellExtensibility.ShowToolWindowAsync()显示工具窗口。

ShowToolWindowAsync() 具有布尔参数, activate

  • true 时,工具窗口在 IDE 中均可见。
  • false 时,工具窗口在 IDE 中是可见的,但如果其他工具窗口处于活动状态,它可能仅作为选项卡组中的一个选项卡可见。

示例:

[VisualStudioContribution]
public class MyToolWindowCommand : Command
{
    public MyToolWindowCommand(VisualStudioExtensibility extensibility)
        : base(extensibility)
    {
    }
    
    public override CommandConfiguration CommandConfiguration => new("My Tool Window")
    {
        Placements = new[] { CommandPlacement.KnownPlacements.ToolsMenu },
        Icon = new(ImageMoniker.KnownValues.ToolWindow, IconSettings.IconAndText),
    };

    public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
    {
        await this.Extensibility.Shell().ShowToolWindowAsync<MyToolWindow>(activate: true, cancellationToken);
    }
}

请参阅 命令 文档,了解有关创建和使用命令的详细信息。

控制工具窗口的可见性

除了使用命令,还可以控制工具窗口的可见性的另一种方法是使用基于规则的激活约束。 这些约束允许在满足某些条件时自动打开工具窗口,并在这些条件不再适用时再次隐藏。

ToolWindowVisibleWhenAttribute

VisibleWhen 属性具有一些应该熟悉的参数:

参数 类型 必选 DESCRIPTION
表达式 字符串 是的 一个布尔表达式字符串,如果为 true,则表示上下文处于活动状态,工具窗口将显示。
TermNames 字符串数组[] 是的 表达式中使用的术语的名称。
TermValues 字符串数组[] 是的 每个术语的值。 术语值的顺序必须与术语名数组相同。

示例:

// The tool window will be shown if the active document is a .cs file, and
// will be hidden if the active document is any any other type of file.
public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
    VisibleWhen = ActivationConstraint.ClientContext(ClientContextKey.Shell.ActiveSelectionFileName, @"\.cs$"),
};

有关有效术语值的详细信息,请参阅 基于规则的激活约束

向工具窗口添加工具栏

工具栏可以添加到工具窗口。 首先,按照 菜单和工具栏文档中的说明定义工具栏:

[VisualStudioContribution]
public static ToolbarConfiguration MyToolbar => new("%MyToolbar.DisplayName%")
{
    Children = [
        ToolbarChild.Command<MyCommand1>(), // Assuming there is a `Command` defined in the extension called `MyCommand1`
        ToolbarChild.Separator,
        ToolbarChild.Command<MyCommand2>(), // Assuming there is a `Command` defined in the extension called `MyCommand2`
    ],
};

然后,从工具窗口配置中引用工具栏:

public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
    ...
    Toolbar = new(MyToolbar),
};

后续步骤

请务必了解 远程 UI 在 VisualStudio.Extensibility 框架中的工作原理。

工具窗口内容是使用 WPF 创建的,因此请参阅 WPF 文档 以获取指导。

有关使用工具窗口创建扩展的完整示例,请参阅 ToolWindow 示例。