web-dev-qa-db-fra.com

Comment enregistrer les paramètres d'application dans une application Windows Forms?

Ce que je veux réaliser est très simple: je dispose d’une application Windows Forms (.NET 3.5) qui utilise un chemin pour la lecture des informations. Ce chemin peut être modifié par l'utilisateur à l'aide du 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 serait assis directement dans le dossier de l'application.

Je comprends que trois options sont disponibles:

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

J'ai lu que le fichier de configuration .NET n'est pas prévu pour la sauvegarde des valeurs. En ce qui concerne le registre, je voudrais aller aussi loin que possible.

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

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

555
Fueled

Si vous travaillez avec Visual Studio, il est assez facile d’obtenir des paramètres persistants. Cliquez avec le bouton droit sur le projet dans l'Explorateur de solutions, 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 contenant la classe de singleton Settings héritée de ApplicationSettingsBase . Vous pouvez accéder à cette classe à partir 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 est applicable à la fois à la console, à Windows Forms et à d’autres types de projets.

Notez que vous devez définir la propriété scope de vos paramètres. Si vous sélectionnez Domaine d'application, Paramètres.Default. <Votre propriété> sera en lecture seule.

578
aku

Si vous envisagez de sauvegarder dans un fichier du même répertoire que votre exécutable, voici une solution agréable utilisant le format JSON :

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;
        }
    }
}
91
Trevor

Le registre est un non-aller. Vous ne savez pas si l'utilisateur qui utilise votre application dispose des droits suffisants pour écrire dans le registre.

Vous pouvez utiliser le fichier app.config pour enregistrer les paramètres d'application (identiques pour chaque utilisateur utilisant votre application).

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

A partir de cela, à partir de .NET 2.0, il est possible de stocker les valeurs dans le fichier app.config.

66
Frederik Gheysels

La classe ApplicationSettings ne prend pas en charge l'enregistrement des paramètres dans le fichier app.config. En effet, les applications fonctionnant avec un compte d'utilisateur correctement sécurisé (pensez à Vista UAC) n'ont pas d'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 cause des difficultés (par exemple, le paramètre est pertinent pour chaque utilisateur), vous devez placer votre fonction Options dans un programme séparé afin de pouvoir demander l'invite d'élévation de privilèges. Ou renoncer à l'aide d'un paramètre.

20
Hans Passant

L'argument registry/configurationSettings/XML semble toujours très actif. Je les ai tous utilisés, au fur et à mesure de l'évolution de la technologie, mais mon préféré est basé sur système de Threed combiné avec stockage isolé .

L'exemple suivant permet de stocker des objets nommés propriétés dans un fichier isolé. Tel 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, qui ne suggère pas les 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) { }
        }
    }
}
16
Boczek

Je voulais partager une bibliothèque que j'ai construite pour cela. C'est une petite bibliothèque, mais une grosse amélioration (IMHO) par rapport aux fichiers .settings.

La bibliothèque s'appelle Jot (GitHub) , voici un ancien article de Code Project J'ai écrit à ce 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 aux fichiers .settings: Il y a considérablement moins de code, et c'est beaucoup moins sujet aux erreurs puisqu'il suffit de mentionner chaque propriété une fois .

Avec un fichier 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. d'avant en arrière.

Le stockage, la sérialisation, etc. sont entièrement configurables. Lorsque les objets cibles sont créés par un conteneur IOC, vous pouvez [le lier] [] pour qu'il applique automatiquement le suivi à tous les objets qu'il résout, de sorte que tout ce que vous devez faire pour rendre une propriété persistante est giflez un attribut [Trackable] dessus.

Il est hautement configurable. Vous pouvez configurer: - quand les données sont persistées et appliquées globalement ou pour chaque objet suivi - comment elles sont sérialisées - où elles sont stockées (fichier, base de données, en ligne, stockage isolé, registre, etc.) - des règles pouvant annuler l’application/la persistance données pour une propriété

Faites-moi confiance, la bibliothèque est top!

16
anakic

Un moyen simple consiste à utiliser un objet de données de configuration, à l’enregistrer en tant que fichier XML avec le nom de l’application dans le dossier local et à le relire au démarrage.

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

Une classe de gestionnaire 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 une instance et utiliser 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 également 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>
11
Dieter Meemken

Je n'aime pas la solution proposée consistant à utiliser web.config ou app.config. Essayez de lire votre propre XML. Jetez un oeil à Fichiers de paramètres XML - Plus de web.config.

7
gatapia

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

  • Si vous utilisez .NET 4.0 dynamic, cette bibliothèque est vraiment facile à utiliser (sérialiser, désérialiser, prendre en charge et ordonner la sortie à votre guise + fusionner plusieurs paramètres en un). JsonConfig (l'utilisation est équivalente à ApplicationSettingsBase )
  • Pour la bibliothèque de configuration .NET YAML ... Je n’en ai pas trouvé de aussi facile à utiliser que JsonConfig

Vous pouvez stocker votre fichier de paramètres dans plusieurs dossiers spéciaux (pour tous les utilisateurs et par utilisateur), comme indiqué ici Enumération Environment.SpecialFolder et dans plusieurs fichiers (lecture par défaut uniquement, par rôle, par utilisateur, etc.).

Si vous choisissez d'utiliser plusieurs paramètres, vous pouvez les fusionner: Par exemple, fusion des paramètres pour les paramètres par défaut + BasicUser + AdminUser. Vous pouvez utiliser vos propres règles: la dernière remplace la valeur, etc.

5
kite

"Cela signifie-t-il que je devrais utiliser un fichier XML personnalisé pour enregistrer les paramètres de configuration?" Non pas forcément. 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 celle-ci

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 les sauvegarder ultérieurement. Source: http://sharpconfig.net/ Github: https://github.com/cemdervis/SharpConfig

J'espère que ça aide.

4
Turker Tunali

Autant que je sache, .NET prend en charge les paramètres persistants à l'aide de la fonctionnalité de paramètres d'application intégrée:

La fonctionnalité Paramètres d'application de Windows Forms facilite la création, le stockage et la maintenance des préférences personnalisées pour les applications et les utilisateurs sur l'ordinateur client. Avec les paramètres d'application Windows Forms, vous pouvez stocker non seulement des données d'application telles que les chaînes de connexion à la base de données, mais également des données spécifiques à l'utilisateur, telles que les préférences d'application utilisateur. À l'aide de Visual Studio ou d'un code géré personnalisé, vous pouvez créer de nouveaux paramètres, les lire depuis et les écrire sur le disque, les lier aux propriétés de vos formulaires et valider les données de paramètres avant le chargement et l'enregistrement. - http://msdn.Microsoft.com/en-us/library/k4s6c3a0.aspx

3
Jacob

Parfois, vous souhaitez vous débarrasser de ces paramètres conservés dans le fichier web.config ou app.config traditionnel. Vous souhaitez un contrôle plus fin sur le déploiement de vos entrées de paramètres et la conception de données séparées. Ou l'exigence consiste à activer l'ajout de nouvelles entrées au moment de 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 typée réside dans les noms et les valeurs des paramètres fortement typés. Il n'y a aucun risque de mélanger des noms ou des types de données. L'inconvénient est que plus de paramètres doivent être codés, ils ne peuvent pas être ajoutés au moment de l'exécution.

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

Vous pouvez trouver le code des deux implémentations entièrement fonctionnelles ICI .

2
user3130351
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();
    }
}
1