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

Max*_*lov 8 visual-studio-sdk vsix visual-studio-2015

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

我刚刚创建了新的VSIX项目,为其添加了VSPackage,然后添加了选项页面grid(DialogPage).然后我按照类似问题的答案的说明:DialogPage- 字符串数组没有持久化.

而且,为了演示目的,我们还添加了int[]数组和plain int以及自定义类型转换器.

// [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, '*');
    }
}
Run Code Online (Sandbox Code Playgroud)

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

但是在我重新打开之后,其中两个价值消失了!只有普通人int坚持: 数组值丢失,但是普通的int仍然存在

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

我不确定,但感觉有点像int选项存储为intstring仅在选项GUI中转入/转换,而数组选项只是默默地尝试执行相同操作.

PS:如果你想亲自直接使用这个例子,这里有一个GitHub repo,其中包含有问题的示例项目:FooBarVSIXProject

Max*_*lov 8

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

人们预计,DialogPage应该保存/字符串表示(类型转换器获得)装入从/ 用户设置存储(或类似的东西),其时SaveSettingsToStorage()LoadSettingsFromStorage()被调用.既然它拒绝这样做并且那些方法是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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

此外,您可以将数据直接序列化为二进制格式,并使用 SetMemoryStream()来保存它.

  • 这是VS 2015中的一个错误.MS在VS 2013和VS 2015之间大大改变了DialogPage.LoadSettingsFromStorage和SaveSettingsToStorage中的逻辑,并且它们打破了使用TypeConverters的属性的LoadSettingsFromStorage.我通过VS 2015的"报告问题"对话框并通过Connect报告了这一点,所以也许他们最终会修复它.与此同时,我还必须像你一样使用覆盖来解决它.注意:TypeConverters仍然可用于编辑PropertyGrid中的值.此外,MS错误位于DialogPage.SetPropertyValue中,它现在只调用Convert.ChangeType. (3认同)