Pregunta Práctica recomendada para guardar la configuración de la aplicación en una aplicación Windows Forms [cerrado]


Lo que quiero lograr es muy simple: tengo una aplicación Windows Forms (.NET 3.5) que utiliza una ruta para leer información. Esta ruta puede ser modificada por el usuario, utilizando las opciones de formulario que proporciono.

Ahora, quiero guardar el valor de la ruta en un archivo para su uso posterior. Esta sería una de las muchas configuraciones guardadas en este archivo. Este archivo se ubicaría directamente en la carpeta de la aplicación.

Entiendo que hay tres opciones disponibles:

  • Archivo ConfigurationSettings (appname.exe.config)
  • Registro
  • Archivo XML personalizado

Leí que el archivo de configuración .NET no está previsto para volver a guardar los valores. En cuanto al registro, me gustaría alejarme lo más posible de él.

¿Esto significa que debería usar un archivo XML personalizado para guardar la configuración? Si es así, me gustaría ver un ejemplo de código de eso (C #).

He visto otras discusiones sobre este tema, pero todavía no está claro para mí.


514
2018-01-17 11:23


origen


Respuestas:


Si trabaja con Visual Studio, entonces es bastante fácil obtener configuraciones persistentes. Haga clic con el botón derecho en el proyecto en el Explorador de soluciones, elija Propiedades. Seleccione la pestaña Configuración, haga clic en el hipervínculo si la configuración no existe. Use la pestaña Configuración para crear configuraciones de aplicaciones. Visual Studio crea los archivos Settings.settings y Settings.Designer.settings que contienen la clase singleton Settings heredado de ApplicationSettingsBase. Puede acceder a esta clase desde su código para leer / escribir la configuración de la aplicación:

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

Esta técnica es aplicable tanto para consola, Windows Forms y otros tipos de proyectos.

Tenga en cuenta que debe configurar el alcance propiedad de su configuración. Si selecciona el alcance de la aplicación, entonces Settings.Default. <Su propiedad> será de solo lectura.


533
2018-01-17 12:18



Si planea guardar en un archivo dentro del mismo directorio que su ejecutable, aquí hay una buena solución que usa el JSON formato:

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



El registro es un no-go. No está seguro de si el usuario que usa su aplicación tiene suficientes derechos para escribir en el registro.

Puedes usar el app.config archivo para guardar configuraciones de nivel de aplicación (que son las mismas para cada usuario que usa su aplicación).

Almacenaba las configuraciones específicas del usuario en un archivo XML, que se guardaría en Almacenamiento aislado o en el SpecialFolder.ApplicationData directorio.

Junto a eso, a partir de .NET 2.0, es posible almacenar valores en el app.config archivo.


63
2018-01-17 11:33



los ApplicationSettings clase no admite guardar configuraciones en el archivo app.config. Eso es mucho por diseño, las aplicaciones que se ejecutan con una cuenta de usuario debidamente segura (creo que Vista UAC) no tienen acceso de escritura a la carpeta de instalación del programa.

Puedes luchar contra el sistema con el ConfigurationManager clase. Pero la solución trivial es ingresar al diseñador de Configuraciones y cambiar el alcance de la configuración a Usuario. Si eso causa dificultades (por ejemplo, la configuración es relevante para cada usuario), debe poner su función de Opciones en un programa separado para que pueda solicitar la solicitud de elevación de privilegios. O renunciar a usar una configuración.


17
2018-01-17 14:45



El argumento registry / configurationSettings / XML todavía parece muy activo. Los he usado todos, ya que la tecnología ha progresado, pero mi favorito se basa en El sistema de Threed combinado con Almacenamiento aislado.

El siguiente ejemplo permite el almacenamiento de un objeto llamado propiedades en un archivo en almacenamiento aislado. Como:

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

Las propiedades se pueden recuperar usando:

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

Es solo una muestra, que no sugiere las mejores prácticas.

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



Quería compartir una biblioteca que he creado para esto. Es una pequeña biblioteca, pero una gran mejora (en mi humilde opinión) sobre archivos .settings.

La biblioteca se llama Jot (GitHub), aquí hay un viejo El artículo del Proyecto de Código Yo escribí sobre eso.

A continuación, le mostramos cómo lo usaría para realizar un seguimiento del tamaño y la ubicación de una ventana:

public MainWindow()
{
    InitializeComponent();

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

El beneficio comparado con los archivos .settings: Hay considerablemente menos código, y es mucho menos propenso a errores ya que solo necesita mencionar cada propiedad una vez.

Con los archivos de configuración, debe mencionar cada propiedad cinco veces: una vez cuando crea explícitamente la propiedad y cuatro veces adicionales en el código que copia los valores hacia adelante y hacia atrás.

El almacenamiento, la serialización, etc. son completamente configurables. Cuando usas Inversión de control, puede conectarlo para que aplique el seguimiento automáticamente a todos los objetos que resuelve, de modo que todo lo que necesita hacer para que una propiedad sea persistente es darle un atributo [Trackable].

Estoy escribiendo todo esto, porque creo que la biblioteca es de primera clase, y me gustaría popularizarlo :)


12
2018-06-07 20:56



Una forma simple es usar un objeto de datos de configuración, guardarlo como un archivo XML con el nombre de la aplicación en la Carpeta local y al inicio leerlo nuevamente.

Aquí hay un ejemplo para almacenar la posición y el tamaño de un formulario.

El objeto de datos de configuración está fuertemente tipado y es fácil de usar:

[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 clase de administrador para guardar y cargar:

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

Ahora puede crear una instancia y usar en la carga de su formulario y cerrar eventos:

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

Y el archivo XML producido también es legible:

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



No me gusta la solución propuesta para usar web.config o app.config. Intenta leer tu propio XML. Mira esto Archivos de configuración XML - No más de web.config.


6
2017-09-09 21:49



Por lo que puedo decir, .NET admite configuraciones persistentes utilizando la función de configuración de aplicaciones integrada:

La característica Configuración de la aplicación de Windows Forms facilita la creación, almacenamiento y mantenimiento de aplicaciones y preferencias de usuario personalizadas en la computadora cliente. Con la configuración de la aplicación Windows Forms, puede almacenar no solo los datos de la aplicación, como las cadenas de conexión de la base de datos, sino también los datos específicos del usuario, como las preferencias de la aplicación del usuario. Con Visual Studio o un código administrado personalizado, puede crear configuraciones nuevas, leerlas y escribirlas en el disco, vincularlas a las propiedades en sus formularios y validar los datos de configuración antes de cargar y guardar.    - http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx


2
2018-01-17 11:34



Otras opciones, en lugar de usar un archivo XML personalizado, podemos usar un formato de archivo más amigable para el usuario: archivo JSON o YAML.

  • Si usa .NET 4.0 dinámico, esta biblioteca es realmente fácil de usar (serializar, deserializar, compatibilidad con objetos anidados y salida ordenada como desee + fusionar múltiples configuraciones a una) JsonConfig (el uso es equivalente a ApplicationSettingsBase)
  • Para la biblioteca de configuración .NET YAML ... No he encontrado uno que sea como fácil de usar como JsonConfig

Puede almacenar su archivo de configuración en múltiples carpetas especiales (para todos los usuarios y por usuario) como se lista aquí Environment.SpecialFolder Enumeration y múltiples archivos (solo lectura por defecto, por rol, por usuario, etc.)

Si elige usar varias configuraciones, puede fusionar esas configuraciones: por ejemplo, combinar las configuraciones para el valor predeterminado + Usuario básico + Usuario administrador. Puede usar sus propias reglas: la última anula el valor, etc.


2
2017-09-19 03:04