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.
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
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;
}
}
}
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
.
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ń.
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) { }
}
}
}
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!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>
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.
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.)
- próbka do pobrania ścieżki folderu specjalnego: C # getting The path of %AppData %
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.
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
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
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 jakoconfig = 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.
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 .
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();
}
}
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