Je crée une application Windows Forms simple à l'aide de C # express 2008. Je suis un développeur C++ expérimenté, mais je suis à peu près tout nouveau en C # et .NET.
Je stocke actuellement certains de mes paramètres d'application simples à l'aide du concepteur de paramètres et du code comme ceci:
// Store setting
Properties.Settings.Default.TargetLocation = txtLocation.Text;
...
// Restore setting
txtLocation.Text = Properties.Settings.Default.TargetLocation;
Maintenant, je voudrais stocker soit un tableau d'ints (int[]
), ou éventuellement une liste d'entiers (List< int >
), comme paramètre. Cependant, je ne peux pas comprendre comment procéder. J'ai cherché dans la documentation, stackoverflow et google, et je ne trouve pas d'explication décente sur la façon de procéder.
Mon intuition basée sur les exemples clairsemés que j'ai trouvés est que je dois créer une classe sérialisable qui enveloppe mon tableau ou ma liste, puis je pourrai utiliser ce type dans le concepteur de paramètres. Cependant, je ne sais pas exactement comment procéder.
Il existe également une autre solution - nécessite un peu d'édition manuelle du fichier de paramètres, mais fonctionne ensuite correctement dans l'environnement VS et dans le code. Et ne nécessite ni fonctions ni wrappers supplémentaires.
Le fait est que VS permet de sérialiser int[]
tapez par défaut dans le fichier de paramètres - il ne vous permet tout simplement pas de le sélectionner par défaut. Donc, créez un paramètre avec le nom souhaité (par exemple SomeTestSetting) et faites-le de n'importe quel type (par exemple string
par défaut). Enregistrez les modifications.
Maintenant, allez dans votre dossier de projet et ouvrez le fichier "Properties\Settings.settings" avec l'éditeur de texte (Bloc-notes, par exemple) Ou vous pouvez l'ouvrir dans VS en cliquant avec le bouton droit dans l'Explorateur de solutions sur "-> Propriétés -> Settings.settings ", sélectionnez" Ouvrir avec ... "puis choisissez" Editeur XML "ou" Editeur de code source (texte) ". Dans les paramètres xml ouverts, trouvez votre paramètre (il ressemblera à ceci):
<Setting Name="SomeTestSetting" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
Modifiez le paramètre "Type" de System.String
à System.Int32[]
. Maintenant, cette section ressemblera à ceci:
<Setting Name="SomeTestSetting" Type="System.Int32[]" Scope="User">
<Value Profile="(Default)" />
</Setting>
Maintenant, enregistrez les modifications et rouvrez les paramètres du projet - voilà! - Nous avons le paramètre SomeTestSetting avec le type System.Int32[]
accessibles et modifiables via VS Settings Designer (valeurs également), ainsi que dans le code.
ranger:
string value = String.Join(",", intArray.Select(i => i.ToString()).ToArray());
recréer:
int[] arr = value.Split(',').Select(s => Int32.Parse(s)).ToArray();
Edit: suggestion Abel!
Il existe un autre moyen d'atteindre ce résultat qui est beaucoup plus propre à utiliser, mais nécessite plus de code. Mon implémentation d'un type personnalisé et d'un convertisseur de type, le code suivant est possible:
List<int> array = Settings.Default.Testing;
array.Add(new Random().Next(10000));
Settings.Default.Testing = array;
Settings.Default.Save();
Pour ce faire, vous avez besoin d'un type avec un convertisseur de type qui permet la conversion vers et depuis des chaînes. Pour ce faire, vous décorez le type avec TypeConverterAttribute:
[TypeConverter(typeof(MyNumberArrayConverter))]
public class MyNumberArray ...
Ensuite, implémentez ce convertisseur de type comme une dérivation de TypeConverter:
class MyNumberArrayConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext ctx, Type type)
{ return (type == typeof(string)); }
public override bool CanConvertFrom(ITypeDescriptorContext ctx, Type type)
{ return (type == typeof(string)); }
public override object ConvertTo(ITypeDescriptorContext ctx, CultureInfo ci, object value, Type type)
{
MyNumberArray arr = value as MyNumberArray;
StringBuilder sb = new StringBuilder();
foreach (int i in arr)
sb.Append(i).Append(',');
return sb.ToString(0, Math.Max(0, sb.Length - 1));
}
public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
{
List<int> arr = new List<int>();
if (data != null)
{
foreach (string txt in data.ToString().Split(','))
arr.Add(int.Parse(txt));
}
return new MyNumberArray(arr);
}
}
En fournissant des méthodes pratiques sur la classe MyNumberArray que nous pouvons ensuite affecter en toute sécurité à et depuis List, la classe complète ressemblerait à quelque chose comme:
[TypeConverter(typeof(MyNumberArrayConverter))]
public class MyNumberArray : IEnumerable<int>
{
List<int> _values;
public MyNumberArray() { _values = new List<int>(); }
public MyNumberArray(IEnumerable<int> values) { _values = new List<int>(values); }
public static implicit operator List<int>(MyNumberArray arr)
{ return new List<int>(arr._values); }
public static implicit operator MyNumberArray(List<int> values)
{ return new MyNumberArray(values); }
public IEnumerator<int> GetEnumerator()
{ return _values.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator()
{ return ((IEnumerable)_values).GetEnumerator(); }
}
Enfin, pour l'utiliser dans les paramètres, vous ajoutez les classes ci-dessus à un assembly et compilez. Dans votre éditeur Settings.settings, vous cliquez simplement sur l'option "Parcourir" et sélectionnez la classe MyNumberArray et c'est parti.
Encore une fois, c'est beaucoup plus de code; cependant, il peut être appliqué à des types de données beaucoup plus compliqués qu'un simple tableau.
Spécifiez le paramètre en tant que System.Collections.ArrayList, puis:
Settings.Default.IntArray = new ArrayList(new int[] { 1, 2 });
int[] array = (int[])Settings.Default.IntArray.ToArray(typeof(int));
Une solution simple consiste à définir la valeur par défaut d'un paramètre sur null dans la propriété, mais dans le constructeur, vérifiez si la propriété est null et, le cas échéant, définissez-la sur sa valeur par défaut réelle. Donc, si vous vouliez un tableau d'ints:
public class ApplicationSettings : ApplicationSettingsBase
{
public ApplicationSettings()
{
if( this.SomeIntArray == null )
this.SomeIntArray = new int[] {1,2,3,4,5,6};
}
[UserScopedSetting()]
[DefaultSettingValue("")]
public int[] SomeIntArray
{
get
{
return (int[])this["SomeIntArray"];
}
set
{
this["SomeIntArray"] = (int[])value;
}
}
}
Cela semble un peu hacky, mais son propre et fonctionne comme vous le souhaitez car les propriétés sont initialisées à leurs derniers paramètres (ou par défaut) avant l'appel du constructeur.
Utilisé System.Object
.
Exemple:
byte[] arBytes = new byte[] { 10, 20, 30 };
Properties.Settings.Default.KeyObject = arBytes;
Extrait:
arBytes = (byte[])Properties.Settings.Default.KeyObject;
Je pense que vous avez raison de sérialiser vos paramètres. Voir ma réponse à cette question pour un échantillon:
Techniques pour partager une configuration entre deux applications?
Vous auriez une propriété qui est un tableau, comme ceci:
/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
[XmlAttribute]
public int [] Numbers { get; set; }
Faites quelques fonctions qui convertissent un tableau int dans une chaîne, mais entre chacune mettez un caractère comme "" (espace).
Donc, si le tableau est {1,34,546,56}, la chaîne serait "1 34 645 56"