Jak Mogę zapisać ustawienia aplikacji w aplikacji Windows Forms?

To, co chcę osiągnąć, jest bardzo proste: mam aplikację Windows Forms (. NET 3.5), która używa ścieżki do odczytu informacji. Ścieżka ta może być modyfikowana przez Użytkownika, za pomocą opcji podanych przeze mnie w formularzu.

Teraz chcę zapisać wartość ścieżki do pliku do późniejszego użycia. Byłoby to jedno z wielu ustawień zapisanych w tym pliku. Plik ten znajduje się bezpośrednio w folderze aplikacji.

Rozumiem, że trzy opcje to dostępne:

  • ConfigurationSettings file (appname.exe.config)
  • rejestr
  • własny plik XML

Czytałem, że plik konfiguracyjny. NET nie jest przewidziany do zapisywania wartości z powrotem do niego. Jeśli chodzi o rejestr, chciałbym jak najdalej od niego uciec.

Czy to oznacza, że powinienem używać niestandardowego pliku XML do zapisywania ustawień konfiguracyjnych?

Jeśli tak, to chciałbym zobaczyć przykład kodu (C#).

Widziałem inne dyskusje na ten temat, ale nadal nie jest to dla mnie jasne.

Author: Peter Mortensen, 2009-01-17

14 answers

Jeśli pracujesz z Visual Studio, łatwo jest uzyskać trwałe ustawienia. Kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań i wybierz Właściwości. Wybierz kartę Ustawienia i kliknij hiperłącze, jeśli ustawienia nie istnieją.

Użyj zakładki Ustawienia, aby utworzyć ustawienia aplikacji. Visual Studio tworzy pliki Settings.settings i Settings.Designer.settings, które zawierają klasę singleton Settings odziedziczoną po aplikacjach . Możesz uzyskać dostęp do tej klasy z kodu do odczytu/zapisu ustawienia aplikacji:

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

Ta technika ma zastosowanie zarówno do konsoli, formularzy Windows, jak i innych typów projektów.

Pamiętaj, że musisz ustawić właściwość scope w swoich ustawieniach. Jeśli wybierzesz zakres aplikacji, a następnie Ustawienia.Default. będzie tylko do odczytu.

Reference: Jak: zapisywać ustawienia użytkownika w czasie wykonywania za pomocą C# - Microsoft Docs

 611
Author: aku,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-21 23:06:09

Jeśli planujesz zapis do pliku w tym samym katalogu co plik wykonywalny, oto dobre rozwiązanie, które używa formatu 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;
        }
    }
}
 97
Author: Trevor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 22:33:07

Rejestr nie działa. Nie masz pewności, czy użytkownik, który korzysta z Twojej aplikacji, ma wystarczające prawa do zapisu do rejestru.

Możesz użyć pliku app.config, aby zapisać ustawienia na poziomie aplikacji (takie same dla każdego użytkownika, który korzysta z Twojej aplikacji).

Zapisywałbym ustawienia specyficzne dla użytkownika w pliku XML, który byłby zapisany w izolowanym magazynie lub w specjalnym folderze.Katalog ApplicationData .

Obok tego, od. NET 2.0, to można zapisać wartości z powrotem do pliku app.config.

 68
Author: Frederik Gheysels,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-01 11:51:51

Klasa ApplicationSettings nie obsługuje zapisywania ustawień w aplikacji .plik config. To bardzo z założenia; aplikacje, które działają z odpowiednio zabezpieczonym kontem użytkownika (pomyśl Vista UAC), nie mają prawa zapisu do folderu instalacyjnego programu.

Możesz walczyć z systemem za pomocą klasy ConfigurationManager. Ale banalnym obejściem jest przejście do projektanta ustawień i zmiana zakresu ustawienia na użytkownika. Jeśli powoduje to trudności (powiedzmy, ustawienie jest istotne dla każdego użytkownika), można należy umieścić funkcję opcji w osobnym programie, aby można było poprosić o monit o podwyższenie uprawnień. Lub zrezygnować z używania ustawień.

 20
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-17 14:58:02

Argument registry/configurationSettings/XML nadal wydaje się bardzo aktywny. Używałem ich wszystkich, w miarę rozwoju technologii, ale mój ulubiony opiera się na systemie Threed połączonym z izolowanym magazynem.

Poniższa próbka umożliwia przechowywanie obiektów o nazwie properties do pliku w izolowanym magazynie. Np.:

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

Właściwości można odzyskać używając:

AppSettings.Load(myobject, "myFile.jsn");
To tylko próbka, a nie sugestia najlepszych praktyk.
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) { }
        }
    }
}
 18
Author: Boczek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:47

Chciałem podzielić się biblioteką, którą do tego zbudowałem. Mała biblioteka, ale duża poprawa (IMHO).Pliki Ustawień.

Biblioteka nazywa się Jot (GitHub) . Oto Stary artykuł projektu kodu , o którym pisałem.

Oto jak można go używać do śledzenia wielkości i lokalizacji okna:

public MainWindow()
{
    InitializeComponent();

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

Korzyści w porównaniu do .Pliki Ustawień: jest znacznie mniej kodu i jest o wiele mniej podatny na błędy, ponieważ wystarczy tylko wymień każdą nieruchomość raz .

Z plikami ustawień musisz wymienić każdą właściwość pięć razy: raz, gdy jawnie tworzysz właściwość i dodatkowe cztery razy w kodzie, który kopiuje wartości tam iz powrotem.

Przechowywanie, serializacja itp. są w pełni konfigurowalne. Gdy obiekty docelowe są tworzone przez kontener IoC, możesz [podłączyć go] [], aby automatycznie zastosował śledzenie do wszystkich obiektów, które rozwiązuje, tak aby wszystkie musisz zrobić, aby właściwość stała się trwała, jest na niej atrybut [Trackable].

Jest wysoce konfigurowalny i można skonfigurować: - gdy dane są przechowywane i stosowane globalnie lub dla każdego śledzonego obiektu - jak to jest serializowane - gdzie jest przechowywany (np. plik, baza danych, online, odizolowany magazyn, rejestr) - zasady, które mogą anulować stosowanie / utrzymywanie danych dla właściwości

Zaufaj mi, Biblioteka jest na najwyższym poziomie!
 17
Author: anakic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-17 14:35:18

Prostym sposobem jest użycie obiektu danych konfiguracyjnych, zapisanie go jako pliku XML z nazwą aplikacji w folderze lokalnym i po uruchomieniu odczytanie go z powrotem.

Oto przykład do przechowywania pozycji i rozmiaru formularza.

Konfiguracja dataobject jest silnie wpisywana i łatwa w użyciu:

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

Klasa menedżera do zapisywania i ładowania:

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

Teraz możesz utworzyć instancję i używać jej w zdarzeniach load I close formularza:

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

I produkowane Plik XML jest również czytelny:

<?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>
 15
Author: Dieter Meemken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-25 13:30:14

Nie podoba mi się proponowane rozwiązanie użycia web.config LUB app.config. Spróbuj odczytać swój własny XML. Zobacz też Pliki Ustawień XML-koniec z web.config.

 7
Author: gatapia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-28 00:41:28

Inne opcje, zamiast używać niestandardowego pliku XML, możemy użyć bardziej przyjaznego dla użytkownika formatu pliku: JSON lub YAML.

  • Jeśli używasz. NET 4.0 dynamic, ta Biblioteka jest naprawdę łatwa w użyciu (serialize, deserialize, nested objects support and ordering output jak chcesz + Scalanie wielu ustawień do jednego) JsonConfig (użycie jest równoważne aplikacjom)
  • dla biblioteki konfiguracji. NET YAML... Nie znalazłem takiego, który jest tak łatwy w użyciu jako JsonConfig

Możesz przechowywać plik ustawień w wielu specjalnych folderach (dla wszystkich użytkowników i dla każdego Użytkownika), jak wymieniono tutaj środowisko .SpecialFolder Enumeration i wiele plików (domyślnie tylko do odczytu, dla roli, dla użytkownika, itd.)

Jeśli zdecydujesz się użyć wielu ustawień, możesz scalić te ustawienia: na przykład scalanie ustawień dla domyślnego + BasicUser + AdminUser. Możesz użyć własnych reguł: ostatnia nadpisuje wartość, itd.

 5
Author: kite,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:36

" czy to oznacza, że powinienem używać niestandardowego pliku XML do zapisywania ustawień konfiguracyjnych?"Nie, niekoniecznie. Do takich operacji używamy SharpConfig.

Na przykład, jeśli plik konfiguracyjny jest taki

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

Możemy pobrać takie wartości

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

string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;
Jest kompatybilny z. NET 2.0 i nowszymi. Możemy tworzyć pliki konfiguracyjne w locie i zapisać je później.

Źródło: http://sharpconfig.net/
GitHub: https://github.com/cemdervis/SharpConfig

 4
Author: Turker Tunali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-17 07:30:35

Z tego, co wiem,. NET obsługuje stałe ustawienia za pomocą wbudowanej funkcji ustawień aplikacji:

Funkcja ustawień aplikacji w Windows Forms ułatwia tworzenie, przechowywanie i utrzymywanie niestandardowych aplikacji i preferencji użytkownika na komputerze klienckim. W ustawieniach aplikacji Windows Forms można przechowywać nie tylko Dane aplikacji, takie jak ciągi połączeń do bazy danych, ale także dane specyficzne dla użytkownika, takie jak preferencje aplikacji użytkownika. Korzystanie Z Visual Studio lub niestandardowy kod zarządzany, możesz tworzyć nowe ustawienia, odczytywać je i zapisywać na dysku, wiązać je z właściwościami formularzy i sprawdzać dane ustawień przed załadowaniem i zapisaniem. - http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx

 3
Author: Jacob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-24 23:26:17

Tak, możliwe jest zapisanie konfiguracji-ale to w dużej mierze zależy od sposobu, w jaki zdecydujesz się to zrobić. Pozwól, że opiszę różnice techniczne, abyś mógł zrozumieć opcje, które masz:

Najpierw musisz rozróżnić, czy chcesz używać appsettings czy AppSettings w pliku *.exe.config(aka App.config w Visual Studio) - istnieją podstawowe różnice, być tu opisane .

Obie podaj różne sposoby zapisywania zmian:

  • The AppSettings umożliwia odczyt i zapis bezpośrednio do pliku konfiguracyjnego (poprzez config.Save(ConfigurationSaveMode.Modified);, gdzie config jest zdefiniowany jako config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);).

  • The zastosowania Zezwalaj na odczyt, ale jeśli zapiszesz zmiany (za pomocą Properties.Settings.Default.Save();), będą one zapisywane na podstawie każdego Użytkownika, przechowywane w specjalnym miejscu (np. C:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0). Jak wspominał Hans Passant w swojej odpowiedzi, dzieje się tak dlatego, że użytkownik zwykle ma ograniczone prawa do plików programu i nie można do nich pisać bez wywołania monitu UAC. Wadą jest to, że jeśli dodajesz klucze konfiguracyjne w przyszłości, musisz zsynchronizować je z każdym profilem użytkownika.

Uwaga: Jak wspomniano w pytaniu, istnieje trzecia opcja: jeśli traktujesz plik konfiguracyjny jako dokument XML, możesz go załadować, zmodyfikować i zapisać za pomocąSystem.Xml.Linq.XDocument klasy. Nie jest wymagane używanie niestandardowego pliku XML, możesz odczytać istniejący plik konfiguracyjny; do zapytań elementów możesz nawet użyć zapytań Linq. Podałem przykład proszę., sprawdź funkcję GetApplicationSetting tam w odpowiedzi.

Jeśli potrzebujesz szyfrowania, aby chronić swoje wartości, sprawdź to odpowiedz.

 3
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-28 11:52:48

Czasami chcesz pozbyć się tych ustawień przechowywanych w tradycyjnej sieci.config lub app.plik konfiguracyjny. Chcesz uzyskać bardziej precyzyjną kontrolę nad wdrażaniem wpisów ustawień i oddzielnym projektem danych. Lub wymaganiem jest włączenie dodawania nowych wpisów w czasie wykonywania.

Wyobrażam sobie dwie dobre opcje:

  • mocno wpisana wersja i
  • Wersja zorientowana obiektowo.

Zaletą mocno wpisanej wersji są mocno wpisane ustawienia nazwy i wartości. Nie ma ryzyka mieszania nazw lub typów danych. Wadą jest to, że więcej ustawień trzeba zakodować, nie można ich dodać w czasie wykonywania.

W wersji obiektowej zaletą jest możliwość dodawania nowych ustawień w czasie wykonywania. Ale nie masz mocno wpisanych nazw i wartości. Należy uważać na identyfikatory łańcuchów. Musi znać typ danych zapisany wcześniej podczas uzyskiwania wartości.

Można znaleźć kod obu w pełni funkcjonalnych implementacji tutaj .

 2
Author: user3130351,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-27 18:35:03
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
Author: Paul - Soura Tech LLC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-27 16:44:11