Question Meilleure pratique pour enregistrer 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 les 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 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 y sauvegarder des valeurs. En ce qui concerne le registre, j'aimerais m'en éloigner le plus possible.

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

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


514
2018-01-17 11:23


origine


Réponses:


Si vous travaillez avec Visual Studio, il est assez facile d'obtenir des paramètres persistants. Faites un clic droit sur le projet dans l'Explorateur de solutions, 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 à 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 pour la console, Windows Forms et d'autres types de projets.

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


533
2018-01-17 12:18



Si vous prévoyez d'enregistrer un fichier dans le 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;
        }
    }
}

78
2018-06-30 22:16



Le registre est un non-go. Vous n'êtes pas sûr que l'utilisateur qui utilise votre application dispose des droits suffisants pour écrire dans le registre.

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

Je stocker des paramètres spécifiques à l'utilisateur dans un fichier XML, qui serait enregistré dans Stockage isolé ou dans le SpecialFolder.ApplicationData annuaire.

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


63
2018-01-17 11:33



le ApplicationSettings La classe ne prend pas en charge les paramètres d'enregistrement dans le fichier app.config. C'est très bien par conception, les applications qui fonctionnent avec un compte d'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 le ConfigurationManager classe. Mais la solution de contournement triviale est d'aller dans le concepteur de paramètres et de modifier la portée du paramètre à l'utilisateur. Si cela cause des difficultés (par exemple, le paramètre est pertinent pour chaque utilisateur), vous devez placer votre option Options dans un programme distinct afin que vous puissiez demander l'invite d'élévation de privilèges. Ou renoncer à l'aide d'un paramètre.


17
2018-01-17 14:45



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

L'exemple suivant permet de stocker des objets nommés propriétés dans un fichier dans un stockage 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");

C'est juste un échantillon, pas suggestif 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) { }
        }
    }
}

12
2017-10-11 15:24



Je voulais partager une bibliothèque que j'ai créée pour cela. C'est une petite bibliothèque, mais une grande amélioration (IMHO) sur les fichiers .settings.

La bibliothèque est appelée Jot (GitHub), voici un vieux L'article du projet de code J'ai écrit à ce sujet.

Voici comment l'utiliser 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 beaucoup moins de code, et c'est beaucoup moins sujet aux erreurs car il suffit de mentionner chaque propriété une fois que.

Avec un fichier de paramètres, vous devez mentionner chaque propriété cinq times: 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. En utilisant inversion de contrôle, vous pouvez l'accrocher 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 soit un attribut [Trackable].

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


12
2018-06-07 20:56



Une manière 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, au démarrage, à le lire.

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

L'objet de données de configuration est fortement typé 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 l'enregistrement 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();
        }
    }
}

Vous pouvez maintenant créer une instance et l'utiliser dans le chargement et la fermeture des événements 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>

9
2017-11-25 13:18



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


6
2017-09-09 21:49



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

La fonctionnalité Paramètres de l'application de Windows Forms facilite la création, le stockage et la gestion des préférences d'utilisateur et d'application personnalisées sur l'ordinateur client. Avec les paramètres de l'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 également des données spécifiques à l'utilisateur, telles que les préférences de l'application utilisateur. À l'aide de Visual Studio ou du code managé personnalisé, vous pouvez créer de nouveaux paramètres, les lire 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


2
2018-01-17 11:34