貢獻和設定

您可以藉由衍生自特定基類將擴充功能元件公開給 Visual Studio,而且您可以定義特定屬性並使用各種屬性來進行設定。

Visual Studio 貢獻

Visual Studio 擴充功能是用來貢獻新功能給 Visual Studio。 其貢獻方式是將許多類別,例如 CommandToolWindow,或 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()
    {
    }
    ...

擴充 VisualStudio.Extensibility SDK 所提供的基類時,您可以檢查基類是否實作 IVisualStudioContributionClass (ExtensionCommand 都是) ,知道您是否預期要使用 VisualStudioContribution 屬性。

Visual Studio 貢獻類別是延遲具現化的單一實例:只會建立一個執行個體,而且其建立會延遲直到 Visual Studio 需要與其互動 (例如,使用者第一次叫用 Command 時)。

VisualStudio.Extensibility 基礎架構還可讓您透過相依性插入接收服務作為 Visual Studio 貢獻類別的建構函式參數 (請參閱 SDK 提供的插入服務),包括您在 Extension 類別的 InitializeServices 方法中新增至 IServiceCollection 的任何服務。

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