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

Visual studio 2015 使用DialogPage将数组存储在选项中,visual-studio-2015,vsix,visual-studio-sdk,Visual Studio 2015,Vsix,Visual Studio Sdk,假设我需要在刚从模板创建的扩展中存储任何数组 我刚刚创建了新的VSIX项目,向其中添加了VSPackage,然后添加了选项页面网格(对话框页面)。然后,我按照对一个类似问题的回答中的说明进行操作: 出于演示目的,我们还将使用自定义类型转换器添加int[]数组和普通int /[标准属性] [提供选项页(类型)(选项页网格), “我的类别”,“我的网格页”,0,0,true)] 公共密封类FooBarVSPackage:Package { //标准代码 } 公共类选项PageGrid:DialogP

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

我刚刚创建了新的VSIX项目,向其中添加了VSPackage,然后添加了选项页面网格(
对话框页面
)。然后,我按照对一个类似问题的回答中的说明进行操作:

出于演示目的,我们还将使用自定义类型转换器添加
int[]
数组和普通
int

/[标准属性]
[提供选项页(类型)(选项页网格),
“我的类别”,“我的网格页”,0,0,true)]
公共密封类FooBarVSPackage:Package
{
//标准代码
}
公共类选项PageGrid:DialogPage
{
//[典型属性]
[TypeConverter(typeof(StringArrayConverter))]
公共字符串[]Foos
{get;set;}
//[典型属性]
[TypeConverter(typeof(CustomIntConverter))]
公共积分栏
{get;set;}
//[典型属性]
[TypeConverter(typeof(IntArrayConverter))]
公共综合商业区
{get;set;}
}
StringArrayConverter类:TypeConverter
{
//上述类似问题/答案代码的准确副本
}
公共类IntArrayConverter:TypeConverter
{
私有常量字符串分隔符=“#@#”;
//CanConvertFrom、ConvertTo等以类似方式覆盖
}
公共类CustomIntConverter:TypeConverter
{
//CanConvertFrom()被重写
//CanConvertTo()被重写
公共重写对象ConvertFrom(ITypeDescriptorContext上下文、CultureInfo区域性、对象值)
{
var v=字符串形式的值;
返回int.Parse(v.TrimStart('*');
}
公共重写对象转换为(ITypeDescriptorContext上下文、CultureInfo区域性、对象值、类型destinationType)
{
var v=(int)值;
返回v.ToString().PadLeft(25,*);
}
}
当我编辑这些选项时,我可以看到转换器确实可以工作:

但在我重新打开它之后,其中两个值消失了!只有纯
int
保留:

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

我不确定,但感觉有点像
int
选项被存储为
int
并仅在选项GUI中从
string
转换为
string
,而array选项只是默默地尝试同样的操作失败


附言:如果你想亲自直接玩这个例子,这里有一个GitHub回购,其中有一个例子项目有问题:

在花了几个小时试图修复坏了的“易于使用”机制(或者它本身坏了,或者它的文档坏了)之后,我意识到,与其浪费时间,不如,我应该降下一个抽象层,完全按照我想要的
DialogPage
机制自动执行

当调用其and时,
DialogPage
应该将字符串表示(通过类型转换器获得)保存/加载到/from(或类似的东西)中。由于它拒绝这样做,而且这些方法是虚拟的,我们自己可以做到:

公共类选项PageGrid:DialogPage
{
const string collectionName=“FooBarVSIX”;
[类别(“一般”)]
[显示名称(“Foos”)]
[说明(“Bla Foo Bla”)]
//请注意,TypeConverter属性已删除,
//因为它不再相关了
公共字符串[]Foos
{get;set;}
//缺少了Bar和Bazes属性以缩短此示例
public override void savesetingstostorage()
{
base.SaveSettingsToStorage();
var settingsManager=新的ShellSettingsManager(ServiceProvider.GlobalProvider);
var userSettingsStore=settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);
如果(!userSettingsStore.CollectionExists(collectionName))
userSettingsStore.CreateCollection(collectionName);
var转换器=新的StringArrayConverter();
userSettingsStore.SetString(
收藏名称,
姓名(Foos),
converter.ConvertTo(this.Foos,typeof(string))作为字符串);
//以类似的方式拯救巴兹
}
public override void loadsetings fromstorage()
{
base.LoadSettingsFromStorage();
var settingsManager=新的ShellSettingsManager(ServiceProvider.GlobalProvider);
var userSettingsStore=settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);
如果(!userSettingsStore.PropertyExists(collectionName,nameof(Foos)))
返回;
var转换器=新的StringArrayConverter();
this.Foos=converter.ConvertFrom(
GetString(collectionName,nameof(Foos)),作为字符串[];
//以类似的方式加载Bazes
}
}

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


此外,您还可以将数据序列化为二进制格式,并使用来保存数据。

这是VS 2015中的一个错误。MS在VS 2013和VS 2015之间对DialogPage.LoadSettingsFromStorage和SaveSettingsToStorage中的逻辑进行了实质性更改,并对使用类型转换器的属性中断了LoadSettingsFromStorage。我已经通过VS 2015的“报告问题”对话框和Connect报告了这一点,所以也许他们最终会解决它。同时,我还必须像您一样使用覆盖来解决它。注:TypeAR