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.
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.
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;
}
}
}
, 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
.
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.
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:)
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) { }
}
}
}
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>
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 .
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
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.)
- exemple pour obtenir le chemin du dossier spécial: C# obtenir le chemin de % AppData %
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.
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 .
" 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.
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();
}
}