Вклады и конфигурации

Вы можете предоставлять компоненты расширений в Visual Studio, производные от определенных базовых классов, и их можно настроить, определив определенные свойства и используя различные атрибуты.

Вклады Visual Studio

Целью расширения Visual Studio является участие новых функций в Visual Studio. Это достигается путем расширения одного из многих классов, таких как Command, ToolWindowили ExtensionPart применения атрибута VisualStudioContribution .

В этой статье приводится пример расширения "Родительская команда" для объяснения концепций участия и настройки компонентов расширения.

Каждое расширение VisualStudio.Extensibility должно внести по крайней мере один Extension класс:

namespace CommandParentingSample;

[VisualStudioContribution]
public class CommandParentingSampleExtension : Extension
{
    /// <inheritdoc/>
    protected override void InitializeServices(IServiceCollection serviceCollection)
    {
        base.InitializeServices(serviceCollection);
    }
}

Класс Extension является первым экземпляром класса расширения и позволяет добавлять собственные службы для IServiceCollection внедрения зависимостей.

Пример "Родительский элемент команд" вносит другой класс, а Commandв Visual Studio:

[VisualStudioContribution]
internal class SampleCommand : Command
{
    public SampleCommand()
    {
    }
    ...

При расширении базового класса, предоставленного пакетом SDK для VisualStudio.Extensibility, можно знать, следует ли использовать VisualStudioContribution атрибут, проверка, реализуя IVisualStudioContributionClass ли базовый класс (оба Extension и Command делать).

Классы вкладов Visual Studio являются неясными одноэлементными одноэлементными: создается только один экземпляр и его создание задерживается до тех пор, пока Visual Studio не потребуется взаимодействовать с ним (например, при Command первом вызове пользователем).

Инфраструктура VisualStudio.Extensibility также позволяет получать службы через внедрение зависимостей в качестве параметров конструктора классов вкладов Visual Studio (см . службы, предоставляемые пакетом SDK для внедрения), включая любую службу, добавленную IServiceCollection в метод класса ExtensionInitializeServices .

Visual Studio часто требует, чтобы уникальный идентификатор был связан с вкладами. В большинстве случаев инфраструктура VisualStudio.Extensibility использует полное имя класса вклада Visual Studio в качестве идентификатора вклада. Например, идентификатор приведенного Extension выше класса будет CommandParentingSample.CommandParentingSampleExtension. Вам может потребоваться тщательно выбрать имя типа и пространство имен классов вкладов Visual Studio, так как они могут отображаться в журналах и сообщениях об ошибках Visual Studio.

Настройка вкладов Visual Studio

Большинство классов вкладов Visual Studio требуют или разрешают настройку. Например, Command абстрактный класс требует реализации CommandConfiguration свойства, указывающего по крайней мере отображаемое имя команды и, при необходимости, другие свойства, такие как его размещение.

[VisualStudioContribution]
internal class SampleCommand : Command
{
    /// <inheritdoc />
    public override CommandConfiguration CommandConfiguration => new("%CommandParentingSample.SampleCommand.DisplayName%")
    {
        Placements = new[]
        {
            // File in project context menu
            CommandPlacement.VsctParent(new Guid("{d309f791-903f-11d0-9efc-00a0c911004f}"), id: 1072, priority: 0),

            // Project context menu
            CommandPlacement.VsctParent(new Guid("{d309f791-903f-11d0-9efc-00a0c911004f}"), id:  1026, priority: 0),

            // Solution context menu
            CommandPlacement.VsctParent(new Guid("{d309f791-903f-11d0-9efc-00a0c911004f}"), id:  1043, priority: 0),
        },
    };
    ...

CommandConfigurationявляется константой во время компиляции, что означает, что его значение вычисляется при построении расширения и включается в манифест расширения (extension.json). Visual Studio может считывать манифест расширения без загрузки самого расширения, что позволяет повысить производительность.

Константы времени компиляции подвергаются дополнительным ограничениям по сравнению с обычными свойствами, например, они должны быть прочитаны, а код инициализации не может содержать ссылки на нестатические элементы или блоки императивного кода с несколькими операторами. Эти ограничения применяются средствами сборки VisualStudio.Extensibility и приводят к сообщениям об ошибках, как показано ниже:

При оценке константы sampleCommand.CommandConfiguration возникла проблема. Ссылки на определяемые пользователем нестатические элементы не поддерживаются при оценке значений константы во время компиляции.

Как правило, расширение не должно ссылаться на свойства конфигурации констант времени компиляции во время выполнения.

Вы можете легко определить свойства конфигурации констант во время компиляции, так как их определение имеет CompileTimeEvaluation атрибут.

public abstract class Command : ExecutableCommandHandler, IVisualStudioContributionClass
{
    ...
    /// <summary>
    /// Gets the configuration for this command. The value of this property is evaluated at compile time
    /// when building the Visual Studio extension.
    /// </summary>
    [CompileTimeEvaluation]
    public abstract CommandConfiguration CommandConfiguration { get; }
    ...

В редких случаях свойства конфигурации могут быть необязательными. В некоторых случаях может потребоваться реализовать несколько свойств конфигурации в одном классе. Это часто происходит при расширении ExtensionPart и реализации нескольких интерфейсов, каждый из которых требует собственного свойства конфигурации.

Свойства автономной конфигурации

Как описано выше, классы вкладов Visual Studio определяют одинтонный класс, который обычно предоставляет один или несколько свойств конфигурации констант времени компиляции. Значения свойств конфигурации сохраняются в виде метаданных расширения.

Для некоторых функций расширяемости требуется указать метаданные расширения, которые не привязаны к любому классу, и он либо имеет смысл самостоятельно, либо он должен ссылаться на другие конфигурации. В некоторых примерах приведены определения типов меню, панели инструментов и документов. Это достигается путем применения атрибута к свойству VisualStudioContribution статической конфигурации чтения.

Свойства вклада Visual Studio можно поместить в любой класс.

Пример "Родительская команда" определяет панель инструментов, объявляя статическое свойство типа ToolbarConfiguration и помечая его как VisualStudioContribution.

namespace CommandParentingSample;

internal static class ExtensionCommandConfiguration
{
    [VisualStudioContribution]
    public static ToolbarConfiguration ToolBar => new("%CommandParentingSample.ToolBar.DisplayName%")
    {
        Children = new[]
        {
            ToolbarChild.Command<SampleCommand>(),
        },
    };
}

Свойства вклада Visual Studio также являются константами во время компиляции и подвержены тем же ограничениям, которые обсуждались ранее.

Свойство вклада Visual Studio также может ссылаться на другое свойство конфигурации. Например:

public static class MenuConfigurations
{
    [VisualStudioContribution]
    public static CommandGroupConfiguration MyCommandGroup => new(GroupPlacement.KnownPlacements.ExtensionsMenu)
    {
        Children = new GroupChild[]
        {
            GroupChild.Menu(MyMenu),
        },
    };

    [VisualStudioContribution]
    public static MenuConfiguration MyMenu => new("%MyMenu.DisplayName%")
    {
        Children = new[]
        {
            MenuChild.Command<MyCommand>(),
        },
    };
    ...

Типы, которые предназначены для определения свойств вклада Visual Studio, реализующих IVisualStudioContributionProperty интерфейс, и помечаются CompileTimeEvaluation атрибутом для документа о том, что их значения оцениваются при построении расширения.

[CompileTimeEvaluation]
public sealed class DocumentTypeConfiguration : IVisualStudioContributionProperty ...

Рекомендации о том, как не ссылаться на свойства конфигурации констант времени компиляции во время выполнения, также применяются к свойствам вклада Visual Studio.

Если для свойства вклада Visual Studio требуется уникальный идентификатор, его полное имя (содержащее полное имя типа и имя свойства) используется инфраструктурой VisualStudio.Extensibility в качестве идентификатора. Например, будет уникальным идентификатором конфигурации панели инструментов, описанной здесь CommandParentingSample.ExtensionCommandConfiguration.ToolbarConfiguration.