Visual Studio 扩展中的自定义设置和选项

存储和检索设置是许多扩展的必备项。 让我们探讨如何使用以下目标使用设置:

  • 提供自定义选项的简单方法。
  • 公开“工具>选项”对话框中的选项
  • 访问和修改设置的线程安全方法。
  • 同步和异步支持。
  • 无需加载包,以便设置进行初始化。

以下视频演示了如何向扩展添加选项。

下面是“工具>选项”对话框中的外观

“添加选项”页

右键单击项目并选择“ 添加新 > 项...” 以显示可用的模板。 然后选择左侧的 “扩展性 ”类别,然后选择 “选项页”(社区) 模板。 在 下面的名称 字段中,编写 “常规”。

Adding an options page from the Add New Item dialog.

这将在项目的根目录中创建 /Options/General.cs

The Options Page C# file added to the project.

以下是 General.cs 文件的内容:

internal partial class OptionsProvider
{
    // Register the options with these attributes on your package class:
    // [ProvideOptionPage(typeof(OptionsProvider.GeneralOptions), "MyExtension", "General", 0, 0, true)]
    // [ProvideProfile(typeof(OptionsProvider.GeneralOptions), "MyExtension", "General", 0, 0, true)]
    public class GeneralOptions : BaseOptionPage<General> { }
}

public class General : BaseOptionModel<General>
{
    [Category("My category")]
    [DisplayName("My Option")]
    [Description("An informative description.")]
    [DefaultValue(true)]
    public bool MyOption { get; set; } = true;
}

这是简短和简单的,我们将介绍细节。 但首先,我们必须注册“选项”页。

注册“选项”页

在 General.cs 文件中的代码注释中,说明如何注册“选项”页。

我们只需将这两个属性复制到 Package 类中。 这看起来可能如下所示:

[ProvideOptionPage(typeof(OptionsProvider.GeneralOptions), "MyExtension", "General", 0, 0, true)]
[ProvideProfile(typeof(OptionsProvider.GeneralOptions), "MyExtension", "General", 0, 0, true)]
public sealed class OptionsPackage : ToolkitPackage
{
    ...
}

运行扩展后,现在应会看到“工具>选项”对话框中显示的“MyExtension/常规选项”页。

Custom options page registered.

这两个属性非常相似,但处理不同的方案。

ProvideOptionsPage 属性使“选项”页显示在 “工具 > 选项 ”对话框中。 如果不希望用户看到选项页,可以省略此属性。

ProvideProfile 在漫游配置文件上注册选项,这意味着各个设置将在实例和 Visual Studio 安装之间与用户帐户一起漫游。 它还启用 Visual Studio 的导入/导出设置功能。 此属性是可选的。

各个选项

在 General.cs 文件中,可以看到各个选项的修饰方式不仅仅是用属性修饰的简单 C# 属性。

    [Category("My category")]
    [DisplayName("My Option")]
    [Description("An informative description.")]
    [DefaultValue(true)]
    public bool MyOption { get; set; } = true;

简单数据类型(例如 stringboolint都现成支持,涵盖大多数用例。 对于其他数据类型,必须使用类型转换器。 有些内置于 Visual Studio 中,例如 EnumConverter.

请考虑以下枚举:

public enum Numbers
{
    First,
    Second,
    Third,
}

可以通过声明 TypeConverter 如下所示,将这些值公开为下拉列表中的选项:

[Category("My category")]
[DisplayName("My Enum")]
[Description("Select the value you want from the list.")]
[DefaultValue(Numbers.First)]
[TypeConverter(typeof(EnumConverter))]
public Numbers MyEnum { get; set; } = Numbers.First;

Dropdown with enum values on the options page.

读取和写入选项

现在,你已经注册了允许用户更改其值的选项,接下来可以读取这些值以在我们的扩展中使用。

可以使用同步上下文和异步上下文中的设置。 让我们从同步开始:

// read settings
var number = General.Instance.MyEnum;

// write settings
General.Instance.MyEnum = Numbers.Second;
General.Instance.Save();

用于读取和写入设置的 API 非常简单和直接。

在异步上下文中工作时,API 看起来非常相似。

// read settings
var general = await General.GetLiveInstanceAsync();
var number = general.MyEnum;

// write settings
general.MyEnum = Numbers.Second;
await general.SaveAsync();

事件

保存设置后,将触发静态事件 General.Saved 。 可以像 .NET 中的任何其他事件一样订阅该事件,如下所示:

General.Saved += OnSettingsSaved;

...

private void OnSettingsSaved(object sender, General e)
{
   
}

获取源代码

可以在示例存储库中找到此扩展的源代码。

阅读有关这些方案的所有详细信息的文档,但请注意,虽然它们确实提供了更详细的文档,但它们不会遵循此示例中概述的最佳做法。 它们也不使用社区工具包,使使用设置变得容易得多。