2015-09-23 25 views
7

Supponiamo di dover archiviare qualsiasi array nell'estensione appena creata dal modello.Archiviare array in opzioni utilizzando DialogPage

Ho appena creato nuovo progetto VSIX, ha aggiunto VSPackage ad esso, quindi aggiungere pagina opzione griglia (DialogPage). Poi ho seguito le istruzioni da risposte a una domanda simile: DialogPage - string array not persisted.

E, a scopo dimostrativo, diamo anche aggiungere int[] array e pianura int con l'abitudine tipo di convertitore.

// [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, '*'); 
    } 
} 

Quando posso modificare queste opzioni, posso vedere che il convertitore funziona davvero: Type Converter really works

Ma dopo che ho riaprirla, due dei valori andato! Solo pianura int persistito: Array values are lost, but plain int persisted

C'è anche una cosa strana: come e quando TypeConverter metodi vengono chiamati. CanConvertTo() è mai chiamato durante l'intera sessione. CanConvertFrom() e ConvertTo() sono chiamati spesso e più o meno in modo atteso. E ConvertFrom() è chiamato solo quando la rappresentazione di stringa dell'opzione viene modificata direttamente, ovvero non corrisponde a partecipare alle opzioni di caricamento/salvataggio!

non sono sicuro, ma ci si sente un po 'come int opzione è memorizzato come int e trasformato da/in string solo nelle opzioni di interfaccia grafica, mentre matrice opzioni solo in silenzio non riescono cercando di fare lo stesso.

PS: Se vuoi giocare direttamente con l'esempio personale, ecco un repo GitHub con il progetto di esempio in questione: FooBarVSIXProject

risposta

7

Dopo aver trascorso diverse ore cercando di risolvere rotto “facile da usare” meccanismo di (o se stesso è rotto o la sua documentazione), mi sono reso conto che invece di perdere tempo, avrei dovuto scendere solo un livello di astrazione e fare esattamente quello che volevo fare automaticamente il meccanismo DialogPage.

Ci si aspetterebbe che DialogPage dovrebbe salvare/caricare la rappresentazione di stringa (ottenuta attraverso convertitore di tipi) nel/dal User Settings Store (o qualcosa di simile), quando il suo SaveSettingsToStorage() e LoadSettingsFromStorage() sono chiamati. Dal momento che si rifiuta di farlo e quei metodi sono virtual, siamo in grado di fare esattamente questo a noi stessi:

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 
    } 
} 

Ora, naturalmente, se lo si fa in questo modo, non c'è bisogno di scrivere e l'uso TypeConverter, in realtà. Puoi semplicemente incorporare la logica di serializzazione direttamente in questi metodi o ovunque.

Inoltre, è possibile serializzare i dati in formato binario e utilizzare SetMemoryStream() per salvarlo.

+2

Questo è un bug in VS 2015. MS ha sostanzialmente modificato la logica in DialogPage.LoadSettingsFromStorage e SaveSettingsToStorage tra VS 2013 e VS 2015 e ha interrotto LoadSettingsFromStorage per le proprietà che utilizzano TypeConverters. Ho segnalato questo tramite la finestra di dialogo "Segnala un problema" di VS 2015 e tramite Connect, quindi forse lo risolveranno alla fine. Nel frattempo, ho anche dovuto risolvere il problema con l'override come hai fatto tu. Nota: TypeConverters è ancora utile per modificare i valori in PropertyGrid. Inoltre, il bug di MS si trova in DialogPage.SetPropertyValue, che chiama ora Convert.ChangeType. –