使用DialogPage将数组存储在选项中

时间:2015-09-23 23:23:03

标签: visual-studio-2015 vsix visual-studio-sdk

假设我需要在刚刚从模板创建的扩展中存储任何数组。

我刚刚创建了新的 VSIX 项目,为其添加了 VSPackage ,然后添加了选项页面网格'title' => 'required|unique:topics,title,'.Request::input('id'), )。然后我按照类似问题的答案的说明:DialogPage - string array not persisted.

为了演示目的,我们还要添加DialogPage数组和普通int[]以及自定义类型转换器

int

当我编辑这些选项时,我可以看到转换器确实有效: Type Converter really works

但是在我重新打开之后,其中两个价值消失了!只有普通// [standard attributes] [ProvideOptionPage(typeof(OptionPageGrid), "My Category", "My Grid Page", 0, 0, true)] public sealed class FooBarVSPackage : Package { // standard code } public class OptionPageGrid : DialogPage { // [typical attributes] [TypeConverter(typeof(StringArrayConverter))] public string[] Foos { get; set; } // [typical attributes] [TypeConverter(typeof(CustomIntConverter))] public int Bar { get; set; } // [typical attributes] [TypeConverter(typeof(IntArrayConverter))] public int[] Bazes { get; set; } } class StringArrayConverter : TypeConverter { // exact copy of code from similar question/answer mentioned above } public class IntArrayConverter : TypeConverter { private const string delimiter = "#@#"; // CanConvertFrom, ConvertTo, etc. overridden in similar fashion } public class CustomIntConverter : TypeConverter { // CanConvertFrom() overridden // CanConvertTo() overridden public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { var v = value as string; return int.Parse(v.TrimStart('*')); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { var v = (int)value; return v.ToString().PadLeft(25, '*'); } } 持续存在: Array values are lost, but plain int persisted

还有一个奇怪的事情:如何以及何时调用int方法。在整个会话期间,TypeConverter 从不被调用。 CanConvertTo()CanConvertFrom()经常被调用,或多或少地以预期方式调用。当直接编辑选项的字符串表示时,ConvertTo()被称为,即根本不参与加载/保存选项!

我不确定,但感觉有点像ConvertFrom()选项存储为int并且仅在选项GUI中从/转为int,而数组选项只是默默地尝试执行相同的操作。

P.S。:如果你想亲自直接玩这个例子,这里有一个GitHub仓库,里面有一个问题:FooBarVSIXProject

1 个答案:

答案 0 :(得分:8)

在花了几个小时试图修复破坏的“易于使用”机制(要么本身已损坏或其文档)之后,我意识到我不应该浪费时间,而应该只下降一个抽象层并完全按照我的意愿行事DialogPage机制会自动执行。

可以预期DialogPage应该在User Settings Store和{{3}时将字符串表示(通过类型转换器获取)保存/加载到SaveSettingsToStorage()(或类似的东西)中。 }} 叫做。由于它拒绝这样做并且这些方法是virtual,我们可以自己做到这一点:

public class OptionPageGrid : DialogPage
{
    const string collectionName = "FooBarVSIX";

    [Category("General")]
    [DisplayName("Foos")]
    [Description("Bla Foo Bla")]
    // note that TypeConverter attribute is removed,
    // because it's not relevant anymore
    public string[] Foos
    { get; set; }

    // Bar and Bazes properties missed out to make this example shorter

    public override void SaveSettingsToStorage()
    {
        base.SaveSettingsToStorage();

        var settingsManager = new ShellSettingsManager(ServiceProvider.GlobalProvider);
        var userSettingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);

        if (!userSettingsStore.CollectionExists(collectionName))
            userSettingsStore.CreateCollection(collectionName);

        var converter = new StringArrayConverter();
        userSettingsStore.SetString(
            collectionName,
            nameof(Foos),
            converter.ConvertTo(this.Foos, typeof(string)) as string);
        // save Bazes in similar way
    }

    public override void LoadSettingsFromStorage()
    {
        base.LoadSettingsFromStorage();

        var settingsManager = new ShellSettingsManager(ServiceProvider.GlobalProvider);
        var userSettingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);

        if (!userSettingsStore.PropertyExists(collectionName, nameof(Foos)))
            return;

        var converter = new StringArrayConverter();
        this.Foos = converter.ConvertFrom(
            userSettingsStore.GetString(collectionName, nameof(Foos))) as string[];
        // load Bazes in similar way
    }
}

现在,当然,如果你这样做,你实际上不必编写和使用TypeConverter。您可以将序列化逻辑直接嵌入到这些方法中,也可以在任何地方嵌入。

此外,您可以将数据直接序列化为二进制格式,并使用LoadSettingsFromStorage()进行保存。