it-swarm.dev

Jak uložit nastavení aplikace v aplikaci Windows Forms?

To, co chci dosáhnout, je velmi jednoduché: Mám aplikaci Windows Forms (.NET 3.5), která používá cestu ke čtení informací. Tuto cestu může uživatel upravit pomocí formuláře možností, který poskytuji.

Nyní chci uložit hodnotu cesty do souboru pro pozdější použití. To by bylo jedno z mnoha nastavení uložených v tomto souboru. Tento soubor by seděl přímo ve složce aplikace.

Chápu, že jsou k dispozici tři možnosti:

  • Soubor ConfigurationSettings (appname.exe.config)
  • Registr
  • Vlastní soubor XML

Četl jsem, že konfigurační soubor .NET se nepředpokládá pro ukládání hodnot zpět do něj. Pokud jde o registr, rád bych se od něj dostal co nejdál.

Znamená to, že bych měl použít vlastní soubor XML k uložení nastavení konfigurace? Pokud ano, rád bych viděl příklad kódu (C #).

Viděl jsem další diskuse na toto téma, ale stále mi to není jasné.

545
Fueled

Pokud pracujete s Visual Studio, je snadné získat trvalá nastavení. Klikněte pravým tlačítkem na projekt v aplikaci Solution Explorer a vyberte Vlastnosti. Vyberte kartu Nastavení, klikněte na hypertextový odkaz, pokud nastavení neexistuje. Na kartě Nastavení vytvořte nastavení aplikace. Visual Studio vytvoří soubory Settings.settings a Settings.Designer.settings, které obsahují třídu singleton Settings zděděnou z ApplicationSettingsBase . K této třídě můžete přistupovat z kódu a číst/zapisovat nastavení aplikace:

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

Tato technika je použitelná pro konzoly, Windows Forms a další typy projektů.

Je třeba nastavit vlastnost rozsah vašeho nastavení. Pokud vyberete Rozsah aplikace, pak Nastavení. Výchozí. <Vaše vlastnost> bude pouze pro čtení.

564
aku

Pokud plánujete uložit do souboru ve stejném adresáři jako spustitelný soubor, je zde pěkné řešení, které používá formát 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;
        }
    }
}
89
Trevor

Registr je neúčinný. Nejste si jisti, zda uživatel, který používá vaši aplikaci, má dostatečná práva k zápisu do registru.

Soubor app.config můžete použít k uložení nastavení na úrovni aplikace (která jsou stejná pro každého uživatele, který používá vaši aplikaci).

Uložil bych uživatelsky specifická nastavení do souboru XML, který by byl uložen v izolované úložiště nebo v adresáři SpecialFolder.ApplicationData .

Kromě toho je možné od .NET 2.0 ukládat hodnoty zpět do souboru app.config.

66

Třída ApplicationSettings nepodporuje ukládání nastavení do souboru app.config. To je do značné míry záměrné, aplikace spuštěné s řádně zabezpečeným uživatelským účtem (myslím Vista UAC) nemají přístup pro zápis do instalační složky programu.

Se systémem můžete bojovat pomocí třídy ConfigurationManager. Triviální řešení je však jít do Návrháře nastavení a změnit rozsah nastavení na Uživatel. Pokud to způsobí potíže (řekněme, že nastavení je relevantní pro každého uživatele), měli byste funkci Možnosti umístit do samostatného programu, abyste mohli požádat o výzvu pro zvýšení oprávnění. Nebo se vzdejte nastavení.

20
Hans Passant

Chtěl jsem sdílet knihovnu, kterou jsem pro toto postavil. Je to malá knihovna, ale velké vylepšení (IMHO) oproti souborům .settings.

Knihovna se jmenuje Jot (GitHub) , tady je starý článek Project Project Napsal jsem o tom.

Zde je návod, jak byste jej použili ke sledování velikosti a umístění okna:

public MainWindow()
{
    InitializeComponent();

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

Výhoda oproti souborům .settings: Je zde výrazně méně kódu a je to mnohem méně náchylné k chybám, protože stačí zmínit každou vlastnost jednou .

U souborů nastavení musíte uvést každou vlastnost pětkrát : jednou, když explicitně vytvoříte vlastnost, a další čtyřikrát v kódu, který kopíruje hodnoty sem a tam.

Úložiště, serializace atd. Jsou kompletně konfigurovatelné. Když jsou cílové objekty vytvořeny kontejnerem IOC, můžete [připojit jej] [], takže automaticky použije sledování na všechny objekty, které vyřeší, takže vše, co musíte udělat, aby vlastnost zůstala trvalá, je facku na něj [sledovatelný] atribut.

Je vysoce konfigurovatelný, můžete nakonfigurovat: - když data přetrvávají a jsou aplikována globálně nebo pro každý sledovaný objekt - jak jsou serializována - kde jsou uložena (např. Soubor, databáze, online, izolované úložiště, registr) - pravidla, která mohou zrušit použití/přetrvávání data pro vlastnost

Věř mi, knihovna je prvotřídní!

16
anakic

Argument registry/configurationSettings/XML se stále jeví jako velmi aktivní. Použil jsem je všechny, protože technologie pokročila, ale můj oblíbený je založen na Threedův systém v kombinaci s izolované úložiště .

Následující ukázka umožňuje ukládání objektů pojmenovaných vlastnosti do souboru v izolovaném úložišti. Jako:

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

Vlastnosti lze obnovit pomocí:

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

Je to pouze vzorek, který nenaznačuje osvědčené postupy.

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

Jednoduchým způsobem je použít konfigurační datový objekt, uložit jej jako soubor XML s názvem aplikace do místní složky a po spuštění jej načíst zpět.

Zde je příklad uložení pozice a velikosti formuláře.

Konfigurační datový objekt je pevně zadán a snadno použitelný:

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

Třída správce pro ukládání a načítání:

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

Nyní můžete vytvořit instanci a použít v událostech načtení a uzavření formuláře:

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

A vytvořený soubor XML je také čitelný:

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

Nelíbí se mi navrhované řešení použití web.config nebo app.config. Zkuste si přečíst vlastní XML. Podívejte se na Soubory nastavení XML - Žádné další web.config.

7
gatapia

Další možnosti namísto použití vlastního souboru XML můžeme použít uživatelsky přívětivější formát souboru: soubor JSON nebo YAML.

  • Pokud používáte dynamiku .NET 4.0, lze tuto knihovnu snadno používat (serializaci, deserializaci, podporu vnořených objektů a objednávání výstupu podle potřeby + sloučení více nastavení do jednoho) JsonConfig (použití je ekvivalentní aplikaci ApplicationSettingsBase )
  • Pro konfigurační knihovnu .NET YAML ... nenalezl jsem knihovnu, která je stejně snadno použitelná jako JsonConfig

Můžete uložit svůj soubor nastavení do několika speciálních složek (pro všechny uživatele a pro jednoho uživatele), jak je uvedeno zde Environment.SpecialFolder Enumeration a více souborů (výchozí pouze pro čtení, podle role, na uživatele atd.)

Pokud se rozhodnete použít více nastavení, můžete je sloučit: Například sloučení nastavení pro výchozí + BasicUser + AdminUser. Můžete použít vlastní pravidla: poslední přepíše hodnotu atd.

4
kite

"Znamená to, že bych měl použít vlastní soubor XML k uložení nastavení konfigurace?" Ne, ne nutně. Pro takové operace používáme SharpConfig.

Například pokud je konfigurační soubor takový

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

Můžeme načíst takové hodnoty

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

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

Je kompatibilní s .Net 2.0 a vyšší. Můžeme vytvářet konfigurační soubory za běhu a můžeme je uložit později. Zdroj: http://sharpconfig.net/ Github: https://github.com/cemdervis/SharpConfig

Doufám, že to pomůže.

4
Turker Tunali

Pokud mohu říci, .NET podporuje trvalá nastavení pomocí vestavěné funkce nastavení aplikace:

Funkce Nastavení aplikací v systému Windows Forms usnadňuje vytváření, ukládání a údržbu vlastních preferencí aplikací a uživatelů v klientském počítači. Pomocí nastavení aplikace Windows Forms můžete ukládat nejen aplikační data, jako jsou řetězce připojení k databázi, ale také data specifická pro uživatele, jako jsou předvolby uživatelské aplikace. Pomocí Visual Studio nebo vlastního spravovaného kódu můžete vytvářet nová nastavení, číst je a zapisovat na disk, svázat je s vlastnostmi ve formulářích a ověřovat data nastavení před načtením a uložením. - http://msdn.Microsoft.com/en-us/library/k4s6c3a0.aspx

3
Jacob

Někdy se chcete zbavit těchto nastavení uložených v tradičním souboru web.config nebo app.config. Chcete více jemnou kontrolu nad rozmístěním položek nastavení a návrhem oddělených dat. Nebo je požadavkem umožnit přidávání nových položek za běhu.

Dokážu si představit dvě dobré možnosti:

  • Silně napsaná verze a
  • Objektově orientovaná verze.

Výhodou silně zadané verze jsou silně zadané názvy a hodnoty nastavení. Neexistuje žádné riziko smíchání jmen nebo datových typů. Nevýhodou je, že více nastavení musí být kódována, nelze je přidat za běhu.

U objektově orientované verze je výhodou to, že nová nastavení lze přidat za běhu. Nemáte však pevně zadané názvy a hodnoty. U řetězcových identifikátorů musíte být opatrní. Při získávání hodnoty musíte vědět, jaký typ dat byl dříve uložen.

Najdete kód obou plně funkčních implementací ZDE .

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