655 votes

Meilleure pratique pour sauvegarder les paramètres de l'application dans une application Windows Forms

Ce que je veux réaliser est très simple : J'ai une application Windows Forms (.NET 3.5) qui utilise un chemin pour lire des informations. Ce chemin peut être modifié par l'utilisateur, en utilisant le formulaire d'options que je fournis.

Maintenant, je veux enregistrer la valeur du chemin dans un fichier pour une utilisation ultérieure. Ce serait l'un des nombreux paramètres enregistrés dans ce fichier. Ce fichier se trouverait directement dans le dossier de l'application.

Je comprends que trois options sont disponibles :

  • Fichier ConfigurationSettings (appname.exe.config)
  • Registre
  • Fichier XML personnalisé

J'ai lu que le fichier de configuration .NET n'est pas prévu pour y sauvegarder des valeurs. Quant au registre, j'aimerais m'en éloigner le plus possible.

Cela signifie-t-il que je dois utiliser un fichier XML personnalisé pour enregistrer les paramètres de configuration ? Si c'est le cas, j'aimerais voir un exemple de code à cet effet (C#).

J'ai vu d'autres discussions sur ce sujet, mais ce n'est toujours pas clair pour moi.

1 votes

S'agit-il d'une application .NET WinForms ? Si oui, sur quelle version de .NET développez-vous ?

2 votes

Oui, il s'agit d'une application WinForms du cadre .NET version 3.5.

1 votes

Avez-vous besoin de sauver les valeurs des mots de passe ou des secrets ? Il faut peut-être cryptage

665voto

aku Points 54867

Si vous travaillez avec Visual Studio, il est assez facile d'obtenir des paramètres persistants. Cliquez avec le bouton droit de la souris sur le projet dans l'explorateur de solutions, puis choisissez Propriétés. Sélectionnez l'onglet Paramètres, cliquez sur le lien hypertexte si les paramètres n'existent pas. Utilisez l'onglet Paramètres pour créer les paramètres de l'application. Visual Studio crée les fichiers Settings.settings et Settings.Designer.settings qui contiennent la classe singleton Settings hérité de ApplicationSettingsBase . Vous pouvez accéder à cette classe depuis votre code pour lire/écrire les paramètres de l'application :

Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file

Cette technique est applicable à la fois pour les projets de type console, Windows Forms et autres.

Notez que vous devez définir le portée de vos paramètres. Si vous sélectionnez Application scope, alors Settings.Default.< votre propriété > sera en lecture seule.

2 votes

Si j'ai une solution, cela s'appliquera-t-il à l'ensemble de la solution ou à chaque projet ?

2 votes

Par défaut, le Settings.Default.Save() ne donne rien. Vous devez utiliser un autre fournisseur. Voir : geek-republic.com/2010/11/08/c-portable-settings-provider

9 votes

@Four : J'ai un projet WinApp .NET 4.0 ici, et ma SomeProperty n'est pas en lecture seule. Settings.Default.SomeProperty = 'value'; Settings.Default.Save(); fonctionne comme un charme. Ou est-ce parce que j'ai des paramètres d'utilisateur ?

104voto

threed Points 2131

Si vous prévoyez d'enregistrer dans un fichier situé dans le même répertoire que votre exécutable, voici une solution intéressante qui utilise la fonction JSON format :

using System;
using System.IO;
using System.Web.Script.Serialization;

namespace MiscConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            MySettings settings = MySettings.Load();
            Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
            Console.WriteLine("Incrementing 'myInteger'...");
            settings.myInteger++;
            Console.WriteLine("Saving settings...");
            settings.Save();
            Console.WriteLine("Done.");
            Console.ReadKey();
        }

        class MySettings : AppSettings<MySettings>
        {
            public string myString = "Hello World";
            public int myInteger = 1;
        }
    }

    public class AppSettings<T> where T : new()
    {
        private const string DEFAULT_FILENAME = "settings.jsn";

        public void Save(string fileName = DEFAULT_FILENAME)
        {
            File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
        }

        public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
        {
            File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
        }

        public static T Load(string fileName = DEFAULT_FILENAME)
        {
            T t = new T();
            if(File.Exists(fileName))
                t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
            return t;
        }
    }
}

0 votes

Oui, changez le DEFAULT_FILENAME en un chemin absolu si vous voulez enregistrer dans un autre répertoire. Je pense qu'il est plus courant d'enregistrer le fichier dans le même répertoire que l'application, ou dans un sous-répertoire, si vous ne les enregistrez pas dans le registre.

0 votes

Oh, peut-être que la meilleure option serait de stocker le fichier de paramètres dans le dossier appdata de l'utilisateur.

1 votes

Pas besoin de changer DEFAULT_FILENAME Il suffit d'appeler settings.Save(theFileToSaveTo) En étant tout en majuscules, DEFAULT_FILENAME est censé être un constant . Si vous voulez une propriété en lecture-écriture, créez-en une et faites en sorte que le constructeur lui donne la valeur suivante DEFAULT_FILENAME . Ensuite, la valeur par défaut de l'argument est null Si vous n'êtes pas en mesure de le faire, testez-le et utilisez votre propriété comme valeur par défaut. Cela demande un peu plus de frappe, mais vous donne une interface plus standard.

71voto

Frederik Gheysels Points 36354

Le registre n'existe pas. Vous n'êtes pas sûr que l'utilisateur qui utilise votre application ait les droits suffisants pour écrire dans le registre.

Vous pouvez utiliser le app.config pour enregistrer les paramètres de l'application (qui sont les mêmes pour chaque utilisateur qui utilise votre application).

Je stockerai les paramètres spécifiques à l'utilisateur dans un fichier XML, qui sera sauvegardé dans le fichier Stockage isolé ou dans le SpecialFolder.ApplicationData répertoire.

En outre, à partir de la version 2.0 de .NET, il est possible de stocker des valeurs dans la base de données de l'utilisateur. app.config fichier.

9 votes

Utilisez le registre, cependant, si vous voulez des paramètres par connexion/utilisateur.

11 votes

@thenonhacker : Ou utiliser Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)

1 votes

@Kb. Oui, tout comme une structure anonyme dans une union. Ce n'est pas une bonne raison pour ne pas l'utiliser, si vous visez la plate-forme Windows (en C#, rien de moins).

22voto

Hans Passant Points 475940

La classe ApplicationSettings ne prend pas en charge l'enregistrement des paramètres dans le fichier app.config. C'est tout à fait normal, les applications qui s'exécutent avec un compte utilisateur correctement sécurisé (pensez à l'UAC de Vista) n'ont pas accès en écriture au dossier d'installation du programme.

Vous pouvez combattre le système avec la classe ConfigurationManager. Mais la solution de contournement la plus simple est d'aller dans le concepteur de paramètres et de changer la portée du paramètre en Utilisateur. Si cela pose des problèmes (par exemple, le paramètre est pertinent pour chaque utilisateur), vous devriez placer votre fonction Options dans un programme distinct afin de pouvoir demander l'invite d'élévation de privilège. Ou alors, renoncez à utiliser un paramètre.

0 votes

Pourriez-vous développer votre dernière phrase ? Demander une élévation pour écrire app.config ou pour écrire une application séparée qui passerait par tous les dossiers d'accueil des utilisateurs, chercherait user.config et les éditerait ?

2 votes

Le programme séparé nécessite un manifeste pour demander l'élévation. Recherchez 'asinvoker requireadministrator' sur Google pour trouver la syntaxe appropriée. Modifier le fichier user.config n'est ni pratique, ni nécessaire.

18voto

Boczek Points 61

L'argument du registre/configurationSettings/XML semble toujours très actif. Je les ai toutes utilisées, au fur et à mesure que la technologie a progressé, mais ma préférée est basée sur Le système de Threed combiné avec Stockage isolé .

L'exemple suivant permet le stockage d'un objet nommé properties dans un fichier en stockage isolé. Par exemple :

AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");

Les propriétés peuvent être récupérées en utilisant :

AppSettings.Load(myobject, "myFile.jsn");

Il ne s'agit que d'un échantillon, qui n'est pas représentatif des meilleures pratiques.

internal static class AppSettings
{
    internal static void Save(object src, string targ, string fileName)
    {
        Dictionary<string, object> items = new Dictionary<string, object>();
        Type type = src.GetType();

        string[] paramList = targ.Split(new char[] { ',' });
        foreach (string paramName in paramList)
            items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));

        try
        {
            // GetUserStoreForApplication doesn't work - can't identify.
            // application unless published by ClickOnce or Silverlight
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write((new JavaScriptSerializer()).Serialize(items));
            }

        }
        catch (Exception) { }   // If fails - just don't use preferences
    }

    internal static void Load(object tar, string fileName)
    {
        Dictionary<string, object> items = new Dictionary<string, object>();
        Type type = tar.GetType();

        try
        {
            // GetUserStoreForApplication doesn't work - can't identify
            // application unless published by ClickOnce or Silverlight
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
            using (StreamReader reader = new StreamReader(stream))
            {
                items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
            }
        }
        catch (Exception) { return; }   // If fails - just don't use preferences.

        foreach (KeyValuePair<string, object> obj in items)
        {
            try
            {
                tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
            }
            catch (Exception) { }
        }
    }
}

1 votes

Ou mieux encore ; utiliser DataContractJsonSerializer

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X