Pergunta

O que eu quero alcançar é muito simples: eu tenho um Windows Forms (.NET 3.5) do aplicativo que usa um caminho para a leitura de informações. Esse caminho pode ser modificado pelo usuário, usando as opções de formar I proporcionar.

Agora, eu quero salvar o valor do caminho para um arquivo para uso posterior. Esta seria uma das muitas configurações salvas nesse arquivo. Este arquivo se sentar diretamente na pasta do aplicativo.

Eu entendo três opções estão disponíveis:

  • arquivo ConfigurationSettings (AppName.exe.config)
  • Registro
  • arquivo XML personalizado

Eu li que o arquivo de configuração do .NET não está prevista para salvar os valores de volta para ele. Quanto ao registro, eu gostaria de chegar o mais longe possível dela.

Isso significa que eu deveria usar um arquivo XML personalizado para salvar as definições de configuração? Se assim for, eu gostaria de ver exemplo de código de que (C #).

Já vi outras discussões sobre este assunto, mas ainda não está claro para mim.

Foi útil?

Solução

Se você trabalha com o Visual Studio, então é muito fácil de obter as configurações persistente. Botão direito do mouse no projeto em Solution Explorer, escolha Propriedades. Selecione a guia Configurações, clique no hiperlink se as configurações não existe. Use a guia Configurações para criar configurações do aplicativo. Visual Studio cria a Settings.settings arquivos e Settings.Designer.settings que contêm o Settings única classe herdada de ApplicationSettingsBase . Você pode acessar essa classe do seu código de leitura / gravação configurações do aplicativo:

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

Esta técnica é aplicável tanto para console, Windows Forms e outros tipos de projeto.

Note que você precisa para definir o escopo propriedade de suas configurações. Se você selecionar Espaço de aplicação, em seguida, Settings.Default. será somente leitura.

Outras dicas

Se você está pensando em salvar a um arquivo dentro do mesmo diretório do executável, aqui está uma boa solução que utiliza o 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;
        }
    }
}

O registro é um no-go. Você não tem certeza se o usuário que usa a sua aplicação, tem direitos suficientes para gravar o registro.

Você pode usar o arquivo app.config para salvar as configurações de nível de aplicação (que são as mesmas para cada usuário que usa o aplicativo).

Gostaria de armazenar configurações específicas do usuário em um arquivo XML, que seriam salvas em Isolado Armazenamento ou no SpecialFolder.ApplicationData diretório.

Junto a isso, a partir de .NET 2.0, é possível armazenar valores volta para o arquivo app.config.

A classe ApplicationSettings não suporta salvar as configurações para o arquivo app.config. Isso é muito pelo design, aplicativos que são executados com uma conta de usuário devidamente protegidas (pense Vista UAC) não tem acesso de gravação para a pasta de instalação do programa.

Você pode lutar contra o sistema com a classe ConfigurationManager. Mas a solução trivial é ir para o designer Configurações e alterar o escopo da definição de usuário. Se que as dificuldades causas (por exemplo, a definição é relevante para cada usuário), você deve colocar o seu recurso de Opções em um programa separado para que possa pedir a elevação de privilégios pronta. Ou renunciar usando uma configuração.

O argumento Registro / ConfigurationSettings / XML ainda parece muito ativa. Eu usei todos eles, como a tecnologia tem avançado, mas o meu favorito é baseado em sistema de Threed combinado com isolado armazenamento.

O exemplo a seguir permite o armazenamento de uma objetos nomeados propriedades para um arquivo no armazenamento isolado. Tais como:

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

Propriedades podem ser recuperados usando:

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

É apenas uma amostra, não sugestivas de melhores práticas.

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

Eu queria compartilhar uma biblioteca que eu construí para isso. É uma pequena biblioteca, mas uma melhoria grande (IMHO) sobre os arquivos .settings.

A biblioteca é chamado Jot (GitHub) , aqui é um velho O artigo Code Project eu escrevi sobre isso

.

Aqui está como você usá-lo para manter o controle de tamanho e localização de uma janela:

public MainWindow()
{
    InitializeComponent();

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

O benefício em comparação com arquivos .settings: Há consideravelmente menos código, e é muito menos desde que você só precisa mencionar cada propriedade propenso a erros uma vez

Com uma configuração de arquivos que você precisa mencionar cada propriedade de cinco vezes:. Uma vez ao criar explicitamente a propriedade e um adicional de quatro vezes no código que copia os valores e para trás

Armazenamento, serialização, etc, são totalmente configuráveis. Quando os objetos alvo são criados por um recipiente IOC, você pode [ligá-lo] [] para que se aplica automaticamente o rastreio para todos os objetos que ele resolve de modo que tudo o que você precisa fazer para fazer uma propriedade é persistente tapa um atributo [Trackable] sobre ele.

É altamente configurável, você pode configurar: - quando os dados são persistiu e aplicado globalmente ou para cada objecto seguido - como ele é serializado - onde ele é armazenado (por exemplo, arquivo, banco de dados on-line, isolado de armazenamento, de registro) - regras que pode cancelar a aplicação / persistência de dados para uma propriedade

Trust me, a biblioteca é de primeira qualidade!

Uma maneira simples é usar um objeto de dados de configuração, salve-o como um arquivo XML com o nome do aplicativo na pasta local e na inicialização lê-lo de volta.

Aqui está um exemplo para armazenar a posição eo tamanho de um formulário.

O dataobject configuração é fortemente tipado e 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; }
    }
}

A classe de gestão para salvar e carregar:

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

Agora você pode criar uma instância e uso em eventos próximos carga e do formulário:

    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 o arquivo XML produzido também é legível:

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

Não Eu gosto da solução proposta de usar web.config ou app.config. Tente ler o seu próprio XML. Dê uma olhada no XML Configurações de Arquivos -. Não há mais web.config

Outras opções, em vez de usar um arquivo XML personalizado, podemos usar um usuário formato mais amigável arquivo:. Arquivo JSON ou YAML

  • Se você usar o .NET dinâmica 4.0, esta biblioteca é realmente fácil de usar (Serialize, desserializar objetos aninhados apoiar e saída de ordenação como você deseja + fusão de várias configurações para um) JsonConfig (uso é equivalente a ApplicationSettingsBase)
  • Para biblioteca de configuração .NET YAML ... Eu não encontrei um que é tão fácil de usar como JsonConfig

Você pode armazenar seu arquivo de configurações em várias pastas especiais (para todos os usuários e por usuário) como aqui Environment.SpecialFolder enumeração e arquivos de múltiplas (padrão somente leitura, por papel, por usuário, etc.)

Se você optar por usar múltiplas configurações, você pode mesclar essas configurações: Por exemplo, mesclando configurações para padrão + BasicUser + AdminUser. Você pode usar suas próprias regras:. O último substitui o valor, etc

"Isso significa que eu deveria usar um arquivo XML personalizado para salvar as definições de configuração?" Não, não necessariamente. Usamos SharpConfig para tais operações.

Por exemplo, se o arquivo de configuração é assim

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

Podemos recuperar valores como este

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

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

É compatível com .Net 2.0 e superior. Podemos criar arquivos de configuração em tempo real e podemos salvá-lo mais tarde. Fonte: http://sharpconfig.net/ Github: https://github.com/cemdervis/SharpConfig

Espero que ajude.

Tanto quanto eu posso dizer, .NET suporta configurações persistentes usando o built-in facilidade de aplicação configurações:

O recurso Configurações do aplicativo do Windows Forms torna mais fácil para criar, armazenar e manter o aplicativo personalizado e preferências do usuário no computador cliente. Com o Windows Forms configurações do aplicativo, você pode armazenar não apenas dados de aplicativos, como seqüências de conexão de banco de dados, mas também dados específicos do usuário, como preferências do aplicativo do usuário. Usando o Visual Studio ou código gerenciado e personalizado, você pode criar novas configurações, lê-los e escrever-los no disco, ligá-los a propriedades em suas formas e configurações validar os dados antes de carregar e salvar. - http://msdn.microsoft.com/en-us/library/k4s6c3a0 aspx

Às vezes você quer se livrar dessas configurações bem guardados no arquivo web.config ou app.config tradicional. Você quer mais grão fino controle sobre a implantação das suas configurações de entradas e design de dados separados. Ou a exigência é para permitir a adição de novas entradas em tempo de execução.

Eu posso imaginar duas boas opções:

  • A versão fortemente tipado e
  • A versão orientada a objeto.

A vantagem da versão fortemente tipado são fortemente digitado configurações nomes e valores. Não há risco de misturando nomes ou tipos de dados. A desvantagem é que mais definições tem de ser codificada, não podem ser adicionadas em tempo de execução.

Com o objeto orientado versão a vantagem é que novas configurações podem ser adicionadas em tempo de execução. Mas você não tem nomes e valores rigidez. Deve ter cuidado com identificadores de cordas. Deve saber o tipo de dados salvos antes, quando a obtenção de um valor.

Você pode encontrar o código de ambas as implementações totalmente funcionais AQUI .

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();
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top