Jakie podejście jest zalecane do utrwalania ustawień użytkownika w aplikacji WPF Windows (komputerowej)? Zwróć uwagę, że chodzi o to, aby użytkownik mógł zmienić swoje ustawienia w czasie wykonywania, a następnie zamknąć aplikację, a następnie podczas późniejszego uruchamiania aplikacji aplikacja użyje bieżących ustawień. Skutecznie wtedy będzie wyglądać tak, jakby ustawienia aplikacji się nie zmieniły.
Q1 - Baza danych czy inne podejście? Mam bazę danych sqlite, z której i tak będę korzystać, więc użycie tabeli w bazie danych byłoby tak dobre, jak każde inne podejście?
P2 - Jeśli baza danych: Jaki projekt tabeli bazy danych? Jedna tabela z kolumnami dla różnych typów danych, które mogą mieć jeden (np string
, long
, DateTime
etc) lub po prostu tabela z ciągiem dla wartości, na których trzeba Wartości serialize i de-serialize? Myślę, że pierwsze byłoby łatwiejsze, a jeśli nie ma wielu ustawień, narzut nie jest duży?
P3 - Czy można w tym celu użyć ustawień aplikacji? Jeśli tak, czy są jakieś specjalne zadania wymagane, aby umożliwić wytrwałość w tym miejscu? Co by się stało z użyciem „domyślnej” wartości w projektancie ustawień aplikacji w tym przypadku? Czy ustawienia domyślne zastąpią ustawienia zapisane między uruchomieniem aplikacji? (czy nie musisz używać wartości domyślnej)
Odpowiedzi:
Możesz użyć do tego ustawień aplikacji , korzystanie z bazy danych nie jest najlepszą opcją, biorąc pod uwagę czas poświęcony na odczyt i zapis ustawień (szczególnie jeśli korzystasz z usług internetowych).
Oto kilka linków, które wyjaśniają, jak to osiągnąć i używać ich w WPF -
Ustawienia użytkownika w WPF
Szybka wskazówka WPF: jak powiązać zasoby i ustawienia aplikacji WPF?
Konfigurowalne okno dla WPF
źródło
Aktualizacja : Obecnie używałbym JSON.
Wolę też przejść z serializacją do pliku. Pliki XML spełniają większość wymagań. Możesz użyć
ApplicationSettings
wbudowanej wersji, ale mają one pewne ograniczenia i określone, ale (dla mnie) bardzo dziwne zachowanie, gdy są przechowywane. Używałem ich dużo i działają. Ale jeśli chcesz mieć pełną kontrolę nad tym, jak i gdzie są przechowywane, używam innego podejścia.MySettings
Zalety:
Wady: - Musisz pomyśleć o tym, gdzie przechowywać pliki ustawień. (Ale możesz po prostu użyć folderu instalacyjnego)
Oto prosty przykład (nie testowany) -
public class MySettings { public string Setting1 { get; set; } public List<string> Setting2 { get; set; } public void Save(string filename) { using (StreamWriter sw = new StreamWriter(filename)) { XmlSerializer xmls = new XmlSerializer(typeof(MySettings)); xmls.Serialize(sw, this); } } public MySettings Read(string filename) { using (StreamReader sw = new StreamReader(filename)) { XmlSerializer xmls = new XmlSerializer(typeof(MySettings)); return xmls.Deserialize(sw) as MySettings; } } }
A oto jak z niego korzystać. Możliwe jest załadowanie wartości domyślnych lub nadpisanie ich ustawieniami użytkownika, po prostu sprawdzając, czy istnieją ustawienia użytkownika:
public class MyApplicationLogic { public const string UserSettingsFilename = "settings.xml"; public string _DefaultSettingspath = Assembly.GetEntryAssembly().Location + "\\Settings\\" + UserSettingsFilename; public string _UserSettingsPath = Assembly.GetEntryAssembly().Location + "\\Settings\\UserSettings\\" + UserSettingsFilename; public MyApplicationLogic() { // if default settings exist if (File.Exists(_UserSettingsPath)) this.Settings = Settings.Read(_UserSettingsPath); else this.Settings = Settings.Read(_DefaultSettingspath); } public MySettings Settings { get; private set; } public void SaveUserSettings() { Settings.Save(_UserSettingsPath); } }
może ktoś zainspiruje się tym podejściem. Tak to robię teraz od wielu lat i jestem z tego całkiem zadowolony.
źródło
Możesz przechowywać informacje o ustawieniach
Strings
w formacie XML w plikuSettings.Default
. Utwórz klasy do przechowywania danych konfiguracyjnych i upewnij się, że tak jest[Serializable]
. Następnie, korzystając z następujących pomocników, możesz serializować wystąpienia tych obiektów - lubList<T>
(lub tablicT[]
itp.) Z nich - doString
. Przechowuj każdy z tych różnych ciągów we własnym odpowiednimSettings.Default
gnieździe w aplikacji WPFSettings
.Aby odzyskać obiekty przy następnym uruchomieniu aplikacji, przeczytaj
Settings
interesujący Cię ciąg znaków iDeserialize
oczekiwany typT
(który tym razem musi być jawnie określony jako argument typuDeserialize<T>
).public static String Serialize<T>(T t) { using (StringWriter sw = new StringWriter()) using (XmlWriter xw = XmlWriter.Create(sw)) { new XmlSerializer(typeof(T)).Serialize(xw, t); return sw.GetStringBuilder().ToString(); } } public static T Deserialize<T>(String s_xml) { using (XmlReader xw = XmlReader.Create(new StringReader(s_xml))) return (T)new XmlSerializer(typeof(T)).Deserialize(xw); }
źródło
Najbardziej typowym podejściem do tego pytania jest: izolowana pamięć masowa.
Serializuj stan kontroli do formatu XML lub innego formatu (szczególnie łatwo, jeśli zapisujesz właściwości zależności za pomocą WPF), a następnie zapisz plik w izolowanym magazynie użytkownika.
Jeśli chcesz przejść do ścieżki ustawiania aplikacji, w pewnym momencie próbowałem czegoś podobnego ... chociaż poniższe podejście można łatwo dostosować do korzystania z izolowanej pamięci masowej:
class SettingsManager { public static void LoadSettings(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements) { EnsureProperties(sender, savedElements); foreach (FrameworkElement element in savedElements.Keys) { try { element.SetValue(savedElements[element], Properties.Settings.Default[sender.Name + "." + element.Name]); } catch (Exception ex) { } } } public static void SaveSettings(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements) { EnsureProperties(sender, savedElements); foreach (FrameworkElement element in savedElements.Keys) { Properties.Settings.Default[sender.Name + "." + element.Name] = element.GetValue(savedElements[element]); } Properties.Settings.Default.Save(); } public static void EnsureProperties(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements) { foreach (FrameworkElement element in savedElements.Keys) { bool hasProperty = Properties.Settings.Default.Properties[sender.Name + "." + element.Name] != null; if (!hasProperty) { SettingsAttributeDictionary attributes = new SettingsAttributeDictionary(); UserScopedSettingAttribute attribute = new UserScopedSettingAttribute(); attributes.Add(attribute.GetType(), attribute); SettingsProperty property = new SettingsProperty(sender.Name + "." + element.Name, savedElements[element].DefaultMetadata.DefaultValue.GetType(), Properties.Settings.Default.Providers["LocalFileSettingsProvider"], false, null, SettingsSerializeAs.String, attributes, true, true); Properties.Settings.Default.Properties.Add(property); } } Properties.Settings.Default.Reload(); } }
.....i....
Dictionary<FrameworkElement, DependencyProperty> savedElements = new Dictionary<FrameworkElement, DependencyProperty>(); public Window_Load(object sender, EventArgs e) { savedElements.Add(firstNameText, TextBox.TextProperty); savedElements.Add(lastNameText, TextBox.TextProperty); SettingsManager.LoadSettings(this, savedElements); } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { SettingsManager.SaveSettings(this, savedElements); }
źródło
Oprócz bazy danych możesz również mieć następujące opcje zapisywania ustawień związanych z użytkownikiem
rejestr pod
HKEY_CURRENT_USER
w pliku w
AppData
folderzeużywając
Settings
pliku w WPF i ustawiając jego zakres jako Userźródło
Z mojego doświadczenia wynika, że najlepszym rozwiązaniem jest przechowywanie wszystkich ustawień w tabeli bazy danych. Nie martw się nawet o wydajność. Dzisiejsze bazy danych są szybkie i mogą z łatwością przechowywać tysiące kolumn w tabeli. Nauczyłem się tego na własnej skórze - zanim zacząłem serilizować / deserializować - koszmar. Przechowywanie go w lokalnym pliku lub rejestrze ma jeden duży problem - jeśli musisz obsługiwać aplikację, a komputer jest wyłączony - użytkownik nie jest przed nią - nic nie możesz zrobić ... jeśli ustawienia są w DB - możesz zmieniłem je i altówkę nie wspominając już o tym, że można porównać ustawienia ....
źródło
Zazwyczaj robię tego typu rzeczy, definiując
Serializable
klasę ustawień niestandardowych [ ] i po prostu serializując ją na dysk. W twoim przypadku możesz równie łatwo przechowywać go jako obiekt typu blob w bazie danych SQLite.źródło
We wszystkich miejscach, w których pracowałem, baza danych była obowiązkowa ze względu na obsługę aplikacji. Jak powiedział Adam, użytkownik może nie być przy swoim biurku lub maszyna może być wyłączona, albo możesz chcieć szybko zmienić czyjąś konfigurację lub przypisać nowemu stolarzowi domyślną konfigurację (lub członka zespołu).
Jeśli ustawienia prawdopodobnie wzrosną wraz z wydaniem nowych wersji aplikacji, możesz chcieć przechowywać dane jako obiekty blob, które mogą być następnie deserializowane przez aplikację. Jest to szczególnie przydatne, jeśli używasz czegoś takiego jak Prism, który wykrywa moduły, ponieważ nie możesz wiedzieć, jakie ustawienia moduł zwróci. Obiekty blob mogą być wpisywane za pomocą klucza złożonego nazwy użytkownika / komputera. W ten sposób możesz mieć różne ustawienia dla każdego komputera.
Nie korzystałem zbytnio z wbudowanej klasy ustawień, więc powstrzymam się od komentowania. :)
źródło
Chciałem użyć pliku kontrolnego XML opartego na klasie dla mojej aplikacji WPF na pulpicie VB.net. Powyższy kod, aby zrobić to wszystko w jednym, jest doskonały i skierował mnie we właściwym kierunku. Na wypadek, gdyby ktoś szukał rozwiązania VB.net, oto klasa, którą zbudowałem:
Imports System.IO Imports System.Xml.Serialization Public Class XControl Private _person_ID As Integer Private _person_UID As Guid 'load from file Public Function XCRead(filename As String) As XControl Using sr As StreamReader = New StreamReader(filename) Dim xmls As New XmlSerializer(GetType(XControl)) Return CType(xmls.Deserialize(sr), XControl) End Using End Function 'save to file Public Sub XCSave(filename As String) Using sw As StreamWriter = New StreamWriter(filename) Dim xmls As New XmlSerializer(GetType(XControl)) xmls.Serialize(sw, Me) End Using End Sub 'all the get/set is below here Public Property Person_ID() As Integer Get Return _person_ID End Get Set(value As Integer) _person_ID = value End Set End Property Public Property Person_UID As Guid Get Return _person_UID End Get Set(value As Guid) _person_UID = value End Set End Property End Class
źródło