Compartilhar via


Contribuições e configurações

Você pode expor componentes de extensões para o Visual Studio derivando de determinadas classes base, e você pode configurá-los definindo determinadas propriedades e usando vários atributos.

Contribuições do Visual Studio

O objetivo de uma extensão do Visual Studio é contribuir com novos recursos para o Visual Studio. Isso é conseguido estendendo uma das muitas classes como Command, ToolWindowou ExtensionPart e aplicando o VisualStudioContribution atributo.

Este artigo faz referência à extensão de exemplo Command Parenting para explicar os conceitos de contribuição e configuração de componentes de extensão.

Cada extensão do VisualStudio.Extensibility deve contribuir com pelo menos uma Extension classe:

namespace CommandParentingSample;

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

A Extension classe é a primeira classe instanciada da extensão e permite que você adicione seus próprios serviços ao IServiceCollection a ser usado para injeção de dependência.

O exemplo de parentalidade de comando contribui com outra classe, a , para o CommandVisual Studio:

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

Ao estender uma classe base fornecida pelo SDK do VisualStudio.Extensibility, você pode saber se deve usar o VisualStudioContribution atributo verificando se a classe base implementa IVisualStudioContributionClass (ambos Extension e Command fazem).

As classes de contribuição do Visual Studio são singletons instanciosamente instanciados: apenas uma instância é criada e sua criação é adiada até que o Visual Studio precise interagir com ela (por exemplo, quando um Command é invocado pela primeira vez pelo usuário).

A infraestrutura VisualStudio.Extensibility também permite que você receba serviços por meio de injeção de dependência como parâmetros de construtor de classes de contribuição do Visual Studio (consulte Serviços fornecidos pelo SDK para injeção), incluindo qualquer serviço que você adicionou ao IServiceCollection método in the Extension class' InitializeServices .

O Visual Studio geralmente requer que um identificador exclusivo seja associado a contribuições. Na maioria dos casos, a infraestrutura VisualStudio.Extensibility usa o nome completo da classe de contribuição do Visual Studio como o identificador de contribuição. Por exemplo, o Extension identificador da classe acima seria CommandParentingSample.CommandParentingSampleExtension. Talvez você queira escolher cuidadosamente o nome do tipo e o namespace de suas classes de contribuição do Visual Studio, já que eles podem aparecer em logs e mensagens de erro do Visual Studio.

Configurando contribuições do Visual Studio

A maioria das classes de contribuição do Visual Studio requer ou permite configuração. Por exemplo, a classe abstrata requer a Command implementação de uma CommandConfiguration propriedade especificando pelo menos o nome de exibição do comando e, opcionalmente, outras propriedades, como seu posicionamento.

[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 é uma constante de tempo de compilação, o que significa que seu valor é avaliado quando a extensão é construída e é incluída no manifesto de extensão (extension.json). O Visual Studio pode ler o manifesto da extensão sem carregar a própria extensão, o que permite um melhor desempenho.

As constantes de tempo de compilação estão sujeitas a limitações adicionais em comparação com as propriedades normais, por exemplo, elas devem ser somente leitura e seu código de inicialização não pode incluir referências a membros não estáticos ou blocos de código imperativo de várias instruções. Essas restrições são impostas pelas ferramentas de compilação VisualStudio.Extensibility e resultam em mensagens de erro como as seguintes:

Foi encontrado um problema ao avaliar a constante de tempo de compilação SampleCommand.CommandConfiguration. Não há suporte para referências a membros não estáticos definidos pelo usuário ao avaliar valores constantes em tempo de compilação.

Em geral, a extensão não deve fazer referência a propriedades de configuração constante em tempo de compilação em tempo de execução.

Você pode identificar facilmente as propriedades de configuração constante em tempo de compilação, uma vez que sua definição tem o CompileTimeEvaluation atributo.

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; }
    ...

Em raras ocasiões, as propriedades de configuração podem ser opcionais. Em certos casos, talvez seja necessário implementar várias propriedades de configuração na mesma classe. Isso é comum ao estender ExtensionPart e implementar várias interfaces, cada uma exigindo sua própria propriedade de configuração.

Propriedades de configuração autônomas

Conforme descrito acima, as classes de contribuição do Visual Studio definem uma classe singleton que geralmente expõe uma ou mais propriedades de configuração constante em tempo de compilação. Os valores das propriedades de configuração são salvos como metadados de extensão.

Alguns recursos de extensibilidade exigem que você especifique metadados de extensão que não estejam vinculados a nenhuma classe e que sejam significativos por si só ou que sejam referenciados por outras configurações. Alguns exemplos são definições de menu, barra de ferramentas e tipo de documento. Isso é obtido aplicando o VisualStudioContribution atributo a uma propriedade de configuração somente leitura estática.

As propriedades de contribuição do Visual Studio podem ser colocadas em qualquer classe.

O exemplo de parentalidade de comando define uma barra de ferramentas declarando uma propriedade estática do tipo ToolbarConfiguration e marcando-a como VisualStudioContribution.

namespace CommandParentingSample;

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

As propriedades de contribuição do Visual Studio também são constantes de tempo de compilação e estão sujeitas às mesmas limitações discutidas anteriormente.

Uma propriedade de contribuição do Visual Studio também pode fazer referência a outra propriedade de configuração. Por exemplo:

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>(),
        },
    };
    ...

Os tipos que devem ser usados para definir propriedades de contribuição do Visual Studio implementam a interface e são marcados com o CompileTimeEvaluation atributo para documentar que seus valores são avaliados quando a IVisualStudioContributionProperty extensão é criada.

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

A orientação sobre não fazer referência a propriedades de configuração constante em tempo de compilação em tempo de execução também se aplica às propriedades de contribuição do Visual Studio.

Caso um identificador exclusivo seja necessário para uma propriedade de contribuição do Visual Studio, seu nome completo (contendo nome completo do tipo e nome da propriedade) é usado pela infraestrutura VisualStudio.Extensibility como um identificador. Por exemplo, o identificador exclusivo da configuração da barra de ferramentas discutida aqui seria CommandParentingSample.ExtensionCommandConfiguration.ToolbarConfiguration.