Beiträge und Konfigurationen

Sie können Erweiterungen für Visual Studio verfügbar machen, indem Sie von bestimmten Basisklassen abgeleitet werden, und Sie können sie konfigurieren, indem Sie bestimmte Eigenschaften definieren und verschiedene Attribute verwenden.

Visual Studio-Beiträge

Der Zweck einer Visual Studio-Erweiterung besteht darin, neue Features zu Visual Studio beizutragen . Dies wird erreicht, indem eine von vielen Klassen wie Command, ToolWindowoder ExtensionPart das Attribut angewendet VisualStudioContribution wird.

In diesem Artikel wird auf die Beispielerweiterung "Command Parenting " verwiesen, um die Konzepte des Beitragens und Konfigurierens von Erweiterungskomponenten zu erläutern.

Jede VisualStudio.Extensibility-Erweiterung muss mindestens eine Extension Klasse beitragen:

namespace CommandParentingSample;

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

Die Extension Klasse ist die erste instanziierte Klasse der Erweiterung und ermöglicht ihnen das Hinzufügen eigener Dienste, die IServiceCollection zum Einfügen von Abhängigkeiten verwendet werden sollen.

Das Beispiel "Command Parenting" trägt zu Visual Studio eine andere Klasse, ein Command, zu Visual Studio bei:

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

Wenn Sie eine Basisklasse erweitern, die vom VisualStudio.Extensibility SDK bereitgestellt wird, können Sie wissen, ob Sie das VisualStudioContribution Attribut verwenden möchten, indem Sie überprüfen, ob die Basisklasse implementiert IVisualStudioContributionClass wird (beide Extension und Command do).

Visual Studio-Beitragsklassen werden laziell instanziierte Singletons instanziiert: Es wird nur eine Instanz erstellt, und die Erstellung wird verzögert, bis Visual Studio mit ihm interagieren muss (z. B. wenn ein Command Benutzer zum ersten Mal aufgerufen wird).

Die VisualStudio.Extensibility-Infrastruktur ermöglicht ihnen auch das Empfangen von Diensten über abhängigkeitseinfügung als Konstruktorparameter von Visual Studio-Beitragsklassen (siehe Dienste, die vom SDK zum Einfügen bereitgestellt werden), einschließlich aller Dienste, die Sie der IServiceCollection Methode der Extension Klasse InitializeServices hinzugefügt haben.

Visual Studio erfordert häufig einen eindeutigen Bezeichner, der Beiträge zugeordnet werden muss. In den meisten Fällen verwendet die VisualStudio.Extensibility-Infrastruktur den vollständigen Namen der Visual Studio-Beitragsklasse als Beitragsbezeichner. Der Bezeichner der Extension obigen Klasse wäre CommandParentingSample.CommandParentingSampleExtensionbeispielsweise . Möglicherweise sollten Sie sorgfältig den Typnamen und den Namespace Ihrer Visual Studio-Beitragsklassen auswählen, da sie in Visual Studio-Protokollen und Fehlermeldungen angezeigt werden können.

Konfigurieren von Visual Studio-Beiträgen

Für die meisten Visual Studio-Beitragsklassen ist eine Konfiguration erforderlich oder zulässig. Die abstrakte Klasse erfordert beispielsweise die Implementierung einer CommandConfiguration Eigenschaft, Command die mindestens den Anzeigenamen des Befehls und optional andere Eigenschaften wie die Platzierung angibt.

[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 ist eine Kompilierungszeitkonstante, was bedeutet, dass der Wert ausgewertet wird, wenn die Erweiterung erstellt wird und sie im Erweiterungsmanifest (extension.json) enthalten ist. Visual Studio kann das Erweiterungsmanifest lesen, ohne die Erweiterung selbst zu laden, was eine bessere Leistung ermöglicht.

Kompilierungszeitkonstanten unterliegen zusätzlichen Einschränkungen im Vergleich zu normalen Eigenschaften, z. B. müssen sie schreibgeschützt sein, und ihr Initialisierungscode kann keine Verweise auf nicht statische Member oder imperative Codeblöcke mit mehreren Anweisungen enthalten. Diese Einschränkungen werden von den VisualStudio.Extensibility-Buildtools erzwungen und führen zu Fehlermeldungen wie den folgenden:

Beim Auswerten der Kompilierung der Kompilierungskonstante SampleCommand.CommandConfiguration ist ein Problem aufgetreten. Verweise auf benutzerdefinierte, nicht statische Member werden beim Auswerten von Konstantenwerten für die Kompilierungszeit nicht unterstützt.

Im Allgemeinen sollte die Erweiterung nicht zur Laufzeit auf Konstantenkonfigurationseigenschaften der Kompilierungszeit verweisen.

Sie können konstanten Konfigurationseigenschaften für die Kompilierungszeit ganz einfach identifizieren, da ihre Definition das CompileTimeEvaluation Attribut aufweist.

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

In seltenen Fällen können Konfigurationseigenschaften optional sein. In bestimmten Fällen müssen Sie möglicherweise mehrere Konfigurationseigenschaften für dieselbe Klasse implementieren. Dies ist üblich, wenn sie mehrere Schnittstellen erweitern ExtensionPart und implementieren, wobei jeder eine eigene Konfigurationseigenschaft erfordert.

Eigenständige Konfigurationseigenschaften

Wie oben beschrieben, definieren Visual Studio-Beitragsklassen eine Singleton-Klasse, die in der Regel eine oder mehrere Kompilierungszeitkonstantenkonfigurationseigenschaften verfügbar macht. Die Konfigurationseigenschaftenwerte werden als Erweiterungsmetadaten gespeichert.

Einige Erweiterungsfeatures erfordern, dass Sie Erweiterungsmetadaten angeben, die nicht an eine Klasse gebunden sind, und sie ist entweder eigenständig sinnvoll oder soll von anderen Konfigurationen referenziert werden. Einige Beispiele sind Menü-, Symbolleisten- und Dokumenttypdefinitionen. Dies wird durch Anwenden des VisualStudioContribution Attributs auf eine statische Readonly-Konfigurationseigenschaft erreicht.

Visual Studio-Beitragseigenschaften können in einer beliebigen Klasse platziert werden.

Das Beispiel "Übergeordnete Befehlserstellung" definiert eine Symbolleiste, indem eine statische Eigenschaft vom Typ ToolbarConfiguration deklariert und als VisualStudioContributiongekennzeichnet wird.

namespace CommandParentingSample;

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

Visual Studio-Beitragseigenschaften sind auch Kompilierungszeitkonstanten und unterliegen den gleichen Einschränkungen, die zuvor erläutert wurden.

Eine Visual Studio-Beitragseigenschaft kann auch auf eine andere Konfigurationseigenschaft verweisen. Beispiel:

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

Typen, die zum Definieren von Visual Studio-Beitragseigenschaften verwendet werden sollen, implementieren die IVisualStudioContributionProperty Schnittstelle und werden mit dem CompileTimeEvaluation Attribut zum Dokumentieren gekennzeichnet, dass ihre Werte beim Erstellen der Erweiterung ausgewertet werden.

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

Die Anleitung zum Verweisen auf Kompilierungszeitkonstantenkonfigurationseigenschaften zur Laufzeit gilt auch für Visual Studio-Beitragseigenschaften.The guidance about not referencing compile-time constant configuration properties at run time applies to visual Studio contribution properties.

Falls für eine Visual Studio-Beitragseigenschaft ein eindeutiger Bezeichner erforderlich ist, wird der vollständige Name (der den Vollständigen Namen und den Eigenschaftennamen enthält) von der VisualStudio.Extensibility-Infrastruktur als Bezeichner verwendet. Der eindeutige Bezeichner der hier erläuterten Symbolleistenkonfiguration wäre CommandParentingSample.ExtensionCommandConfiguration.ToolbarConfigurationbeispielsweise .