wake-up-neo.com

Speichern von Anwendungseinstellungen in einer Windows Forms-Anwendung

Was ich erreichen möchte, ist sehr einfach: Ich habe eine Windows Forms (.NET 3.5) -Anwendung, die einen Pfad zum Lesen von Informationen verwendet. Dieser Pfad kann vom Benutzer mithilfe des von mir bereitgestellten Formulars geändert werden.

Jetzt möchte ich den Pfadwert zur späteren Verwendung in einer Datei speichern. Dies ist eine der vielen Einstellungen, die in dieser Datei gespeichert werden. Diese Datei würde sich direkt im Anwendungsordner befinden.

Ich verstehe, dass drei Optionen zur Verfügung stehen:

  • Konfigurationsdatei (appname.exe.config)
  • Registrierung
  • Benutzerdefinierte XML-Datei

Ich habe gelesen, dass die .NET-Konfigurationsdatei nicht zum Zurückspeichern von Werten vorgesehen ist. Was die Registrierung betrifft, möchte ich mich so weit wie möglich davon entfernen.

Bedeutet dies, dass ich eine benutzerdefinierte XML-Datei zum Speichern der Konfigurationseinstellungen verwenden sollte? Wenn ja, würde ich gerne ein Codebeispiel dafür sehen (C #).

Ich habe andere Diskussionen zu diesem Thema gesehen, aber es ist mir immer noch nicht klar.

555
Fueled

Wenn Sie mit Visual Studio arbeiten, ist es ziemlich einfach, dauerhafte Einstellungen zu erhalten. Klicken Sie mit der rechten Maustaste auf das Projekt im Projektmappen-Explorer und wählen Sie Eigenschaften. Wählen Sie die Registerkarte Einstellungen und klicken Sie auf den Hyperlink, wenn keine Einstellungen vorhanden sind. Verwenden Sie die Registerkarte Einstellungen, um Anwendungseinstellungen zu erstellen. Visual Studio erstellt die Dateien Settings.settings und Settings.Designer.settings, die die Singleton-Klasse Settings enthalten, die von ApplicationSettingsBase geerbt wurde. Sie können von Ihrem Code aus auf diese Klasse zugreifen, um Anwendungseinstellungen zu lesen/schreiben:

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

Diese Technik ist sowohl für Konsolen- als auch für Windows Forms-Projekte und andere Projekttypen anwendbar.

Beachten Sie, dass Sie die Bereichseigenschaft Ihrer Einstellungen festlegen müssen. Wenn Sie Anwendungsbereich auswählen, ist Settings.Default. <Ihre Eigenschaft> schreibgeschützt.

578
aku

Wenn Sie vorhaben, in einer Datei im selben Verzeichnis wie Ihre ausführbare Datei zu speichern, finden Sie hier eine nützliche Lösung, die das Format JSON verwendet:

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

Die Registrierung ist ein No-Go. Sie sind sich nicht sicher, ob der Benutzer, der Ihre Anwendung verwendet, über ausreichende Schreibrechte für die Registrierung verfügt.

Sie können die Datei app.config verwenden, um Einstellungen auf Anwendungsebene zu speichern (die für jeden Benutzer, der Ihre Anwendung verwendet, gleich sind).

Ich würde benutzerspezifische Einstellungen in einer XML-Datei speichern, die im Verzeichnis Isolated Storage oder SpecialFolder.ApplicationData gespeichert wird.

Darüber hinaus ist es ab .NET 2.0 möglich, Werte zurück in die Datei app.config zu speichern.

66

Die Klasse ApplicationSettings unterstützt das Speichern von Einstellungen in der Datei app.config nicht. Dies ist sehr beabsichtigt. Apps, die mit einem ordnungsgemäß gesicherten Benutzerkonto (z. B. Vista UAC) ausgeführt werden, haben keinen Schreibzugriff auf den Installationsordner des Programms.

Sie können das System mit der Klasse ConfigurationManager bekämpfen. Die einfache Problemumgehung besteht jedoch darin, den Einstellungsdesigner aufzurufen und den Bereich der Einstellung in Benutzer zu ändern. Wenn dies zu Schwierigkeiten führt (z. B. ist die Einstellung für jeden Benutzer relevant), sollten Sie Ihre Optionsfunktion in einem separaten Programm ablegen, damit Sie nach der Aufforderung zur Erhöhung der Berechtigungen fragen können. Oder verzichten Sie auf eine Einstellung.

20
Hans Passant

Das Argument 'registry/configurationSettings/XML' scheint immer noch sehr aktiv zu sein. Ich habe sie alle verwendet, da die Technologie Fortschritte gemacht hat, aber mein Favorit basiert auf Threeds System kombiniert mit isolierter Speicher .

Das folgende Beispiel ermöglicht das Speichern von Objekten mit dem Namen properties in einer Datei im isolierten Speicher. Sowie:

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

Eigenschaften können wiederhergestellt werden mit:

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

Es handelt sich lediglich um ein Beispiel, das nicht auf bewährte Methoden hinweist.

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

Ich wollte eine Bibliothek teilen, die ich dafür gebaut habe. Es ist eine winzige Bibliothek, aber eine große Verbesserung (IMHO) gegenüber .settings-Dateien.

Die Bibliothek heißt Jot (GitHub) , hier ist ein alter The Code Project article Ich habe darüber geschrieben.

So können Sie die Größe und Position eines Fensters verfolgen:

public MainWindow()
{
    InitializeComponent();

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

Der Vorteil gegenüber .settings-Dateien: Es gibt erheblich weniger Code und es ist viel weniger fehleranfällig, da Sie nur jede Eigenschaft erwähnen müssen einmal .

Bei Einstellungsdateien müssen Sie jede Eigenschaft fünf Mal erwähnen: einmal, wenn Sie die Eigenschaft explizit erstellen, und vier weitere Male im Code, der die Werte kopiert Hin und her.

Speicherung, Serialisierung usw. sind vollständig konfigurierbar. Wenn die Zielobjekte von einem IOC -Container erstellt werden, können Sie [sie einbinden] [], damit die Verfolgung automatisch auf alle Objekte angewendet wird, die aufgelöst werden, sodass Sie nur noch eine Eigenschaft persistent machen müssen Schlagen Sie ein [Trackable] -Attribut darauf.

Es ist hochgradig konfigurierbar. Sie können Folgendes konfigurieren: - Wenn Daten dauerhaft gespeichert und global oder für jedes verfolgte Objekt angewendet werden - Wie sie serialisiert werden - Wo sie gespeichert werden (z. B. Datei, Datenbank, Online, isolierter Speicher, Registrierung) - Regeln, mit denen das Anwenden/Fortbestehen abgebrochen werden kann Daten für eine Immobilie

Vertrauen Sie mir, die Bibliothek ist erstklassig!

16
anakic

Eine einfache Möglichkeit besteht darin, ein Konfigurationsdatenobjekt zu verwenden, es als XML-Datei mit dem Namen der Anwendung im lokalen Ordner zu speichern und beim Start zurückzulesen.

Hier ist ein Beispiel zum Speichern der Position und Größe eines Formulars.

Das Konfigurationsdatenobjekt ist stark typisiert und einfach zu verwenden:

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

Eine Manager-Klasse zum Speichern und Laden:

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

Jetzt können Sie eine Instanz erstellen und in den Lade- und Schließereignissen Ihres Formulars verwenden:

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

Und die erzeugte XML-Datei ist auch lesbar:

<?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

Die vorgeschlagene Lösung, web.config oder app.config zu verwenden, gefällt mir nicht. Versuchen Sie, Ihr eigenes XML zu lesen. Schauen Sie sich XML-Einstellungsdateien - Keine web.config mehr an.

7
gatapia

Andere Optionen, anstatt eine benutzerdefinierte XML-Datei zu verwenden, können wir ein benutzerfreundlicheres Dateiformat verwenden: JSON- oder YAML-Datei.

  • Wenn Sie .NET 4.0 dynamic verwenden, ist diese Bibliothek sehr einfach zu verwenden (Serialisieren, Deserialisieren, Unterstützung verschachtelter Objekte und Sortieren der Ausgabe nach Belieben + Zusammenführen mehrerer Einstellungen zu einer) JsonConfig (Verwendung entspricht ApplicationSettingsBase )
  • Für .NET YAML-Konfigurationsbibliothek ... Ich habe keine gefunden, die so einfach zu verwenden ist wie JsonConfig

Sie können Ihre Einstellungsdatei in mehreren speziellen Ordnern (für alle Benutzer und pro Benutzer) speichern, wie hier aufgeführt Environment.SpecialFolder Enumeration und in mehreren Dateien (standardmäßig schreibgeschützt, pro Rolle, pro Benutzer usw.).

Wenn Sie sich für die Verwendung mehrerer Einstellungen entscheiden, können Sie diese Einstellungen zusammenführen: Beispiel: Zusammenführen von Einstellungen für default + BasicUser + AdminUser. Sie können Ihre eigenen Regeln verwenden: Die letzte überschreibt den Wert usw.

5
kite

"Bedeutet das, dass ich eine benutzerdefinierte XML-Datei verwenden sollte, um Konfigurationseinstellungen zu speichern?" Nein, nicht unbedingt. Wir verwenden SharpConfig für solche Operationen.

Zum Beispiel, wenn die Konfigurationsdatei so ist

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

Wir können Werte wie diesen abrufen

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

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

Es ist kompatibel mit .Net 2.0 und höher. Wir können Konfigurationsdateien im laufenden Betrieb erstellen und später speichern. Quelle: http://sharpconfig.net/ Github: https://github.com/cemdervis/SharpConfig

Ich hoffe, es hilft.

4
Turker Tunali

Soweit ich das beurteilen kann, unterstützt .NET persistierende Einstellungen mithilfe der integrierten Funktion für Anwendungseinstellungen:

Das Feature Anwendungseinstellungen von Windows Forms erleichtert das Erstellen, Speichern und Verwalten von benutzerdefinierten Anwendungs- und Benutzereinstellungen auf dem Clientcomputer. Mit den Windows Forms-Anwendungseinstellungen können Sie nicht nur Anwendungsdaten wie Datenbankverbindungszeichenfolgen, sondern auch benutzerspezifische Daten wie Benutzeranwendungseinstellungen speichern. Mit Visual Studio oder benutzerdefiniertem verwaltetem Code können Sie neue Einstellungen erstellen, von der Festplatte lesen und auf die Festplatte schreiben, sie an die Eigenschaften in Ihren Formularen binden und die Einstellungsdaten vor dem Laden und Speichern überprüfen. - http://msdn.Microsoft.com/en-us/library/k4s6c3a0.aspx

3
Jacob

Manchmal möchten Sie diese Einstellungen, die in der traditionellen Datei web.config oder app.config gespeichert sind, entfernen. Sie möchten eine genauere Kontrolle über die Bereitstellung Ihrer Einstellungen und das getrennte Datendesign. Oder Sie müssen das Hinzufügen neuer Einträge zur Laufzeit aktivieren.

Ich kann mir zwei gute Möglichkeiten vorstellen:

  • Die stark typisierte Version und
  • Die objektorientierte Version.

Der Vorteil der stark typisierten Version sind die stark typisierten Namen und Werte der Einstellungen. Es besteht keine Gefahr, Namen oder Datentypen zu vermischen. Der Nachteil ist, dass mehr Einstellungen codiert werden müssen, die zur Laufzeit nicht hinzugefügt werden können.

Bei der objektorientierten Version besteht der Vorteil darin, dass zur Laufzeit neue Einstellungen hinzugefügt werden können. Sie haben jedoch keine stark typisierten Namen und Werte. Muss vorsichtig mit String-Bezeichnern sein. Muss den Datentyp kennen, der zuvor gespeichert wurde, wenn ein Wert abgerufen wird.

Sie finden den Code beider voll funktionsfähiger Implementierungen HIER .

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