Domanda

Quello che voglio ottenere è molto semplice:Ho un'applicazione Windows Forms (.NET 3.5) che utilizza un percorso per leggere le informazioni.Questo percorso può essere modificato dall'utente, utilizzando il modulo di opzioni che fornisco.

Ora, voglio salvare il valore del percorso in un file per un uso successivo.Questa sarebbe una delle tante impostazioni salvate in questo file.Questo file si troverebbe direttamente nella cartella dell'applicazione.

Mi risulta che siano disponibili tre opzioni:

  • File ConfigurationSettings (nomeapp.exe.config)
  • Registro
  • File XML personalizzato

Ho letto che il file di configurazione .NET non è previsto per il salvataggio dei valori al suo interno.Per quanto riguarda il registro, vorrei allontanarmene il più possibile.

Ciò significa che dovrei utilizzare un file XML personalizzato per salvare le impostazioni di configurazione?Se è così, mi piacerebbe vederne un esempio di codice (C#).

Ho visto altre discussioni sull'argomento ma non mi è ancora chiaro.

È stato utile?

Soluzione

Se lavori con Visual Studio, è abbastanza facile ottenere impostazioni permanenti. Fare clic con il tasto destro sul progetto in Esplora soluzioni, selezionare Proprietà. Seleziona la scheda Impostazioni, fai clic sul collegamento ipertestuale se le impostazioni non esistono. Utilizzare la scheda Impostazioni per creare le impostazioni dell'applicazione. Visual Studio crea i file Settings.settings e Settings.Designer.settings che contengono la classe singleton Settings ereditata da ApplicationSettingsBase . Puoi accedere a questa classe dal tuo codice per leggere / scrivere le impostazioni dell'applicazione:

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

Questa tecnica è applicabile sia per console, Windows Form e altri tipi di progetti.

Nota che devi impostare la proprietà scope delle tue impostazioni. Se si seleziona Ambito applicazione, Impostazioni.Default. & Lt; la tua proprietà > sarà di sola lettura.

Altri suggerimenti

Se stai pensando di salvare su un file nella stessa directory del tuo eseguibile, ecco una bella soluzione che usa il Formato 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;
        }
    }
}

Il registro è un no-go. Non sei sicuro che l'utente che utilizza l'applicazione disponga di diritti sufficienti per scrivere nel registro.

È possibile utilizzare il file app.config per salvare le impostazioni a livello di applicazione (che sono le stesse per ogni utente che utilizza l'applicazione).

Vorrei memorizzare le impostazioni specifiche dell'utente in un file XML, che verrebbe salvato in Archiviazione isolata o nella Directory SpecialFolder.ApplicationData .

Accanto a questo, a partire da .NET 2.0, è possibile memorizzare i valori nel file <=>.

La classe ApplicationSettings non supporta il salvataggio delle impostazioni nel file app.config. Questo è molto legato alla progettazione, le app eseguite con un account utente adeguatamente protetto (pensa Vista UAC) non hanno accesso in scrittura alla cartella di installazione del programma.

Puoi combattere il sistema con la classe ConfigurationManager. Ma la banale soluzione alternativa è accedere alla finestra di progettazione Impostazioni e modificare l'ambito dell'impostazione su Utente. Se ciò causa difficoltà (ad esempio, l'impostazione è pertinente per ogni utente), è necessario inserire la funzionalità Opzioni in un programma separato in modo da poter richiedere il prompt di elevazione dei privilegi. O rinunciare usando un'impostazione.

L'argomento register / configurationSettings / XML sembra ancora molto attivo. Li ho usati tutti, poiché la tecnologia è progredita, ma il mio preferito è basato su Sistema di Threed combinato con Archiviazione isolata .

Il seguente esempio consente l'archiviazione di un oggetto denominato proprietà in un file in un archivio isolato. Come ad esempio:

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

Le proprietà possono essere recuperate usando:

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

È solo un esempio, non suggestivo delle migliori pratiche.

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) { }
        }
    }
}

Volevo condividere una libreria che ho creato per questo. È una piccola libreria, ma un grande miglioramento (IMHO) rispetto ai file .settings.

La libreria si chiama Jot (GitHub) , ecco un vecchio L'articolo del progetto Code che ho scritto al riguardo.

Ecco come lo useresti per tenere traccia delle dimensioni e della posizione di una finestra:

public MainWindow()
{
    InitializeComponent();

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

Il vantaggio rispetto ai file .settings: c'è molto meno codice ed è molto meno soggetto ad errori poiché devi solo menzionare ogni proprietà una volta .

Con i file delle impostazioni è necessario menzionare ogni cinque ogni proprietà: una volta quando si crea esplicitamente la proprietà e altre quattro volte nel codice che copia i valori avanti e indietro.

Archiviazione, serializzazione, ecc. sono completamente configurabili. Quando gli oggetti di destinazione vengono creati da un contenitore IOC, è possibile [agganciarlo] [] in modo che applichi automaticamente il tracciamento a tutti gli oggetti che risolve in modo che tutto ciò che è necessario fare per rendere persistente una proprietà sia schiaffeggiare un attributo [Tracciabile] su di esso.

È altamente configurabile, puoi configurare: - quando i dati sono persistenti e applicati a livello globale o per ciascun oggetto tracciato - come è serializzato - dove è archiviato (ad es. file, database, online, archiviazione isolata, registro) - regole che possono annullare l'applicazione / il persistere di dati per una proprietà

Fidati di me, la biblioteca è di prim'ordine!

Un modo semplice è usare un oggetto dati di configurazione, salvarlo come file XML con il nome dell'applicazione nella Cartella locale e all'avvio rileggerlo.

Ecco un esempio per memorizzare la posizione e le dimensioni di un modulo.

L'oggetto dei dati di configurazione è fortemente tipizzato e facile da usare:

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

Una classe manager per il salvataggio e il caricamento:

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

Ora puoi creare un'istanza e utilizzare nel caricamento del modulo e chiudere gli eventi:

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

E anche il file XML prodotto è leggibile:

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

Non mi piace la soluzione proposta di utilizzare web.config o app.config. Prova a leggere il tuo XML. Dai un'occhiata a File delle impostazioni XML & # 8211; Niente più web.config .

Altre opzioni, invece di utilizzare un file XML personalizzato, possiamo utilizzare un formato di file più intuitivo: file JSON o YAML.

  • Se si utilizza .NET 4.0 dinamico, questa libreria è davvero facile da usare (serializza, deserializza, supporta oggetti nidificati e ordina l'output come desideri + unire più impostazioni in una) JsonConfig (l'utilizzo è equivalente a ApplicationSettingsBase)
  • Per la libreria di configurazione .NET YAML ... Non ne ho trovata una che sia come facile da usare come JsonConfig

Puoi archiviare il tuo file di impostazioni in più cartelle speciali (per tutti gli utenti e per utente) come elencato qui Environment.SpecialFolder Enumeration e più file (sola lettura predefinita, per ruolo, per utente, ecc.)

Se si sceglie di utilizzare più impostazioni, è possibile unire tali impostazioni: Ad esempio, unendo le impostazioni predefinite + Utente di base + Utente di amministrazione. Puoi usare le tue regole: l'ultima ha la precedenza sul valore, ecc.

" Significa che dovrei usare un file XML personalizzato per salvare le impostazioni di configurazione? " No, non necessariamente. Usiamo SharpConfig per tali operazioni.

Ad esempio, se il file di configurazione è simile

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

Possiamo recuperare valori come questo

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

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

È compatibile con .Net 2.0 e versioni successive. Siamo in grado di creare file di configurazione al volo e possiamo salvarli in un secondo momento. Fonte: http://sharpconfig.net/ Github: https://github.com/cemdervis/SharpConfig

Spero che sia d'aiuto.

Per quanto ne so, .NET supporta le impostazioni persistenti utilizzando la funzione di impostazioni dell'applicazione integrata:

  

La funzione Impostazioni applicazione di Windows Form semplifica la creazione, l'archiviazione e la gestione delle preferenze personalizzate dell'utente e dell'applicazione sul computer client. Con le impostazioni dell'applicazione Windows Form, è possibile archiviare non solo i dati dell'applicazione come le stringhe di connessione al database, ma anche i dati specifici dell'utente, come le preferenze dell'applicazione dell'utente. Utilizzando Visual Studio o codice gestito personalizzato, è possibile creare nuove impostazioni, leggerle e scriverle sul disco, associarle alle proprietà dei moduli e convalidare i dati delle impostazioni prima di caricare e salvare.    - http://msdn.microsoft.com/en-us/library/k4s6c3a0 aspx

A volte vuoi eliminare quelle impostazioni conservate nel tradizionale file web.config o app.config.Desideri un controllo più preciso sulla distribuzione delle voci delle impostazioni e sulla progettazione dei dati separati.Oppure il requisito è abilitare l'aggiunta di nuove voci in fase di esecuzione.

Posso immaginare due buone opzioni:

  • La versione fortemente tipizzata e
  • La versione orientata agli oggetti.

Il vantaggio della versione fortemente tipizzata sono i nomi e i valori delle impostazioni fortemente tipizzati.Non vi è alcun rischio di mescolare nomi o tipi di dati.Lo svantaggio è che è necessario codificare più impostazioni e non è possibile aggiungerle in fase di esecuzione.

Con la versione orientata agli oggetti il ​​vantaggio è che nuove impostazioni possono essere aggiunte in fase di esecuzione.Ma non hai nomi e valori fortemente tipizzati.Bisogna fare attenzione agli identificatori di stringa.È necessario conoscere il tipo di dati salvato in precedenza quando si ottiene un valore.

Puoi trovare il codice di entrambe le implementazioni completamente funzionanti QUI.

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();
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top