Meilleure pratique pour sauvegarder les paramètres d'application dans une application Windows Forms [fermé]

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 de chemin dans un fichier pour une utilisation ultérieure. Ce serait un des nombreux paramètres enregistrés dans ce fichier. Ce fichier serait placé directement dans le dossier de la demande.

je comprends que trois options sont disponibles:

  • fichier de configuration (appname.EXE.config)
  • Registre
  • fichier XML personnalisé

j'ai lu que le fichier de configuration .NET n'est pas prévu pour sauvegarder les valeurs. Comme pour le registre, je voudrais aller aussi loin d'elle que possible.

est-ce que cela signifie que je devrais utiliser un fichier XML personnalisé pour enregistrer les paramètres de configuration? Si oui, je voudrais voir Exemple de code de cela (C#).

j'ai vu d'autres discussions sur ce sujet, mais il n'est pas encore clair pour moi.

519
demandé sur Răzvan Flavius Panda 2009-01-17 14:23:36

13 réponses

si vous travaillez avec Visual Studio alors il est assez facile d'obtenir des paramètres persistants. Cliquez avec le bouton droit de la souris sur le projet dans Solution Explorer, choisissez Propriétés. Sélectionnez L'onglet Paramètres, cliquez sur l'hyperlien 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ée de ApplicationSettingsBase . Vous pouvez accéder à cette classe de 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 s'applique aussi bien aux consoles Qu'aux fenêtres et à d'autres types de projets.

notez que vous devez définir la propriété scope de vos paramètres. Si vous sélectionnez application scope puis Paramètres.Défaut.< propriété > sera en lecture seule.

538
répondu aku 2013-11-06 06:15:32

si vous prévoyez de sauvegarder dans un fichier du même répertoire que votre exécutable, voici une bonne solution qui utilise le 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.json";

        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;
        }
    }
}
79
répondu Trevor 2016-08-02 22:33:07

, Le registre est un no-go. Vous ne savez pas si l'utilisateur qui utilise votre application a suffisamment de droits pour écrire au registre.

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

Je stockerais les paramètres spécifiques à l'utilisateur dans un fichier XML, qui serait sauvegardé dans stockage isolé ou dans le SpecialFolder.ApplicationData directory.

à côté de cela, à partir de .NET 2.0, Il est possible de stocker des valeurs dans le fichier app.config .

63
répondu Frederik Gheysels 2012-08-07 08:33:07

la classe ApplicationSettings ne supporte pas les paramètres de sauvegarde de l'application.fichier de configuration. De par leur conception, les applications qui fonctionnent avec un compte utilisateur correctement sécurisé (pensez à Vista UAC) 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 triviale est d'aller dans le concepteur de paramètres et de changer la portée du paramètre à L'utilisateur. Si cela provoque des difficultés (par exemple, le cadre est pertinent à chaque utilisateur), vous devriez mettre votre option dans un programme séparé pour que vous puissiez demander l'invite d'élévation de privilèges. Ou renoncez à utiliser un cadre.

18
répondu Hans Passant 2016-08-12 18:35:25

je voulais partager une bibliothèque que j'ai construite pour ça. C'est une bibliothèque minuscule, mais une grande amélioration (IMHO) plus .paramètres des fichiers.

la bibliothèque s'appelle Jot (GitHub) , voici un vieux l'article du projet de Code j'ai écrit à son sujet.

Voici comment vous l'utiliseriez pour suivre la taille et l'emplacement d'une fenêtre:

public MainWindow()
{
    InitializeComponent();

    _stateTracker.Configure(this)
        .IdentifyAs("MyMainWindow")
        .AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
        .RegisterPersistTrigger(nameof(Closed))
        .Apply();
}

L'avantage, par rapport à .paramètre fichiers: il y a beaucoup moins de code, et c'est beaucoup moins sujet aux erreurs puisque vous n'avez besoin de mentionner chaque propriété qu'une seule fois .

avec des fichiers de paramètres, vous devez mentionner chaque propriété cinq fois: une fois lorsque vous créez explicitement la propriété et quatre fois supplémentaires dans le code qui copie les valeurs avant et arrière.

stockage, sérialisation, etc. sont entièrement configurables. Lorsque vous utilisez inversion du contrôle , vous pouvez le raccorder de sorte qu'il applique le tracking automatiquement à tous les objets qu'il résout de sorte que tout ce que vous devez faire pour rendre une propriété persistante est de lui coller un attribut [Trackable].

j'écris tout cela, parce que je pense que la Bibliothèque est de premier ordre, et je voudrais la populariser:)

13
répondu anakic 2017-01-15 16:59:16

l'argument registry/configurationSettings/XML semble encore très actif. Je les ai tous utilisés, car la technologie a progressé, mais mon préféré est basé sur système de Threed combiné avec stockage isolé .

l'échantillon suivant permet le stockage d'un objet nommé propriétés à un fichier dans le stockage isolé. Tels que:

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, et non d'une suggestion de pratiques exemplaires.

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) { }
        }
    }
}
12
répondu Boczek 2017-05-23 12:10:47

un moyen simple est d'utiliser un objet de données de configuration, enregistrez-le comme un fichier XML avec le nom de l'application dans le dossier local et au démarrage relisez-le.

Voici un exemple pour stocker la position et la taille d'un formulaire.

la configuration dataobject est fortement typée et facile à utiliser:

[Serializable()]
public class CConfigDO
{
    private System.Drawing.Point m_oStartPos;
    private System.Drawing.Size m_oStartSize;

    public System.Drawing.Point StartPos
    {
        get { return m_oStartPos; }
        set { m_oStartPos = value; }
    }

    public System.Drawing.Size StartSize
    {
        get { return m_oStartSize; }
        set { m_oStartSize = value; }
    }
}

Un gestionnaire de classe pour la sauvegarde et le chargement:

public class CConfigMng
{
    private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
    private CConfigDO m_oConfig = new CConfigDO();

    public CConfigDO Config
    {
        get { return m_oConfig; }
        set { m_oConfig = value; }
    }

    // Load configuration file
    public void LoadConfig()
    {
        if (System.IO.File.Exists(m_sConfigFileName))
        {
            System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
            Type tType = m_oConfig.GetType();
            System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
            object oData = xsSerializer.Deserialize(srReader);
            m_oConfig = (CConfigDO)oData;
            srReader.Close();
        }
    }

    // Save configuration file
    public void SaveConfig()
    {
        System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
        Type tType = m_oConfig.GetType();
        if (tType.IsSerializable)
        {
            System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
            xsSerializer.Serialize(swWriter, m_oConfig);
            swWriter.Close();
        }
    }
}

Maintenant, vous pouvez créer un exemple et utilisation dans les événements load et close de votre formulaire:

    private CConfigMng oConfigMng = new CConfigMng();

    private void Form1_Load(object sender, EventArgs e)
    {
        // Load configuration
        oConfigMng.LoadConfig();
        if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
        {
            Location = oConfigMng.Config.StartPos;
            Size = oConfigMng.Config.StartSize;
        }
    }

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        // Save configuration
        oConfigMng.Config.StartPos = Location;
        oConfigMng.Config.StartSize = Size;
        oConfigMng.SaveConfig();
    }

et le fichier XML produit est aussi lisible:

<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <StartPos>
    <X>70</X>
    <Y>278</Y>
  </StartPos>
  <StartSize>
    <Width>253</Width>
    <Height>229</Height>
  </StartSize>
</CConfigDO>
9
répondu Dieter Meemken 2017-01-25 13:30:14

Je n'aime pas la solution proposée d'utiliser web.config ou app.config . Essayez de lire votre propre XML. Regardez fichiers de paramètres XML – plus de web.config .

6
répondu gatapia 2016-12-28 00:41:28

pour autant que je sache, .NET supporte les paramètres persistants en utilisant la fonction intégrée de paramètres d'application:

la fonctionnalité de configuration D'Application des formulaires Windows rend facile à créer, à stocker et à maintenir des préférences d'application et d'utilisateur personnalisées sur l'ordinateur client. Avec les paramètres D'application Windows Forms, vous pouvez stocker non seulement des données d'application telles que des chaînes de connexion de base de données, mais aussi des données spécifiques à l'utilisateur, telles que l'application utilisateur préférence. En utilisant Visual Studio ou du code géré personnalisé, vous pouvez créer de nouveaux paramètres, les lire et les écrire sur le disque, les lier aux propriétés sur vos formulaires, et valider les données de paramètres avant le chargement et la sauvegarde. - http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx

2
répondu Jacob 2010-12-24 23:26:17

autres options, au lieu d'utiliser un fichier XML personnalisé, nous pouvons utiliser un format de fichier plus convivial: JSON ou fichier YAML.

  • si vous utilisez .NET 4.0 dynamic, cette bibliothèque est vraiment facile à utiliser (serialize, deserialize, les objets imbriqués supportent et ordonnent la sortie comme vous le souhaitez + la fusion de plusieurs paramètres à un) JsonConfig (l'usage est l'équivalent de ApplicationSettingsBase)
  • pour la configuration .NET YAML bibliothèque... Je n'ai pas trouvé un qui est comme facile à utiliser comme JsonConfig

vous pouvez stocker votre fichier de paramètres dans plusieurs dossiers spéciaux (pour tous les utilisateurs et par utilisateur) comme indiqué ici environnement.Énumération spéciale et plusieurs fichiers (lecture par défaut seulement, par rôle, par utilisateur, etc.)

si vous choisissez d'utiliser plusieurs paramètres, vous pouvez les fusionner: par exemple, fusionner les paramètres par défaut + BasicUser + AdminUser. Vous pouvez utiliser vos propres règles: le dernier remplace la valeur, etc.

2
répondu kite 2017-05-23 12:26:36

Parfois, vous voulez vous débarrasser de ces paramètres conservés dans le web traditionnel.config ou app.fichier de configuration. Vous souhaitez un contrôle à grains plus fins sur le déploiement de vos entrées de paramètres et de la conception de données séparées. Ou l'exigence est d'activer l'ajout de nouvelles entrées à l'exécution.

je peux imaginer deux bonnes options:

  • la version fortement typée et
  • la version orientée objet.

l'avantage de la version fortement dactylographiée sont les noms et les valeurs de paramètres fortement dactylographiés. Il n'y a aucun risque de confusion de noms ou de types de données. L'inconvénient est que plus de paramètres doivent être codés, ne peuvent pas être ajoutés à l'exécution.

avec la version orientée objet, l'avantage est que de nouveaux paramètres peuvent être ajoutés à l'exécution. Mais vous n'avez pas fortement typé noms et les valeurs. Doit être prudent avec les identificateurs de chaîne. Doit savoir Type de données enregistré plus tôt l'obtention d'une valeur.

vous pouvez trouver le code des deux implémentations entièrement fonctionnelles ici .

1
répondu user3130351 2013-12-27 18:35:03

" est-ce que cela signifie que je devrais utiliser un fichier XML personnalisé pour enregistrer les paramètres de configuration?"Non, pas nécessairement. Nous utilisons SharpConfig pour de telles opérations.

par exemple, si le fichier de configuration est comme ça

[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment

nous pouvons récupérer des valeurs comme ceci

var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];

string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;

il est compatible avec .Net 2.0 et supérieur. Nous pouvons créer des fichiers de configuration à la volée et nous pouvons l'enregistrer plus tard. Source: http://sharpconfig.net / Github: https://github.com/cemdervis/SharpConfig

j'espère que ça aidera.

1
répondu Turker Tunali 2017-12-14 20:07:28
public static class SettingsExtensions
{
    public static bool TryGetValue<T>(this Settings settings, string key, out T value)
    {
        if (settings.Properties[key] != null)
        {
            value = (T) settings[key];
            return true;
        }

        value = default(T);
        return false;
    }

    public static bool ContainsKey(this Settings settings, string key)
    {
        return settings.Properties[key] != null;
    }

    public static void SetValue<T>(this Settings settings, string key, T value)
    {
        if (settings.Properties[key] == null)
        {
            var p = new SettingsProperty(key)
            {
                PropertyType = typeof(T),
                Provider = settings.Providers["LocalFileSettingsProvider"],
                SerializeAs = SettingsSerializeAs.Xml
            };
            p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
            var v = new SettingsPropertyValue(p);
            settings.Properties.Add(p);
            settings.Reload();
        }
        settings[key] = value;
        settings.Save();
    }
}
0
répondu Paul - Soura Tech LLC 2016-07-27 16:44:11