Welchen Ansatz empfehlen Sie, um Benutzereinstellungen in einer WPF-Windows-Anwendung (Desktop-Anwendung) beizubehalten? Die Idee ist, dass der Benutzer seine Einstellungen zur Laufzeit ändern und dann die Anwendung schließen kann. Wenn die Anwendung später gestartet wird, verwendet die Anwendung die aktuellen Einstellungen. Es erscheint dann so, als würden sich die Anwendungseinstellungen nicht ändern.
Q1 - Datenbank oder anderer Ansatz? Ich habe eine sqlite-Datenbank, die ich trotzdem verwenden werde. Daher wäre die Verwendung einer Tabelle in der Datenbank so gut wie jeder Ansatz.
F2 - Wenn Datenbank: Welches Datenbanktabellen-Design? Eine Tabelle mit Spalten für verschiedene Datentypen (z. B. string
, long
, DateTime
etc) OR nur eine Tabelle mit einem String für den Wert, auf den Sie die Werte serialisieren und deserialisieren müssen? Ich denke, der erste wäre einfacher, und wenn es nicht viele Einstellungen gibt, ist der Aufwand nicht viel?
Q3 - Können Anwendungseinstellungen dafür verwendet werden? Wenn ja, gibt es spezielle Aufgaben, um hier die Persistenz zu ermöglichen? Was würde in diesem Fall auch mit dem "Standardwert" im Anwendungseinstellungsdesigner passieren? Würde die Standardeinstellung Einstellungen überschreiben, die zwischen der Ausführung der Anwendung gespeichert wurden? (oder müssten Sie NICHT den Standardwert verwenden)
Sie können Application Settings verwenden, um die Datenbank zu verwenden. Dies ist jedoch nicht die beste Option, wenn Sie die Zeit für das Lesen und Schreiben der Einstellungen in Anspruch nehmen (insbesondere, wenn Sie Web-Services verwenden).
Hier sind einige Links, die erläutern, wie dies erreicht und in WPF verwendet werden kann.
Schneller WPF-Tipp: Wie binden Sie WPF-Anwendungsressourcen und -einstellungen?
Sie können Ihre Einstellungsinformationen als Strings
von XML im Settings.Default
speichern. Erstellen Sie einige Klassen, um Ihre Konfigurationsdaten zu speichern, und stellen Sie sicher, dass sie [Serializable]
sind. Anschließend können Sie mit den folgenden Helfern Instanzen dieser Objekte - oder List<T>
(oder Arrays T[]
usw.) - zu String
serialisieren. Speichern Sie jede dieser verschiedenen Zeichenfolgen in ihrem eigenen Settings.Default
-Slot in der Settings
Ihrer WPF-Anwendung.
Um die Objekte beim nächsten Start der App wiederherzustellen, lesen Sie die Settings
-Zeichenfolge und Deserialize
auf den erwarteten Typ T
(der diesmal explizit als Typargument in Deserialize<T>
angegeben werden muss).
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);
}
Ich gehe auch lieber mit der Serialisierung zur Datei. XML-Dateien erfüllen meistens alle Anforderungen. Sie können das ApplicationSettings
-Build verwenden, aber diese haben einige Einschränkungen und ein definiertes, aber für mich sehr merkwürdiges Verhalten, wo sie gespeichert wurden. Ich habe sie viel benutzt und sie arbeiten. Wenn Sie jedoch die vollständige Kontrolle darüber haben möchten, wie und wo sie gespeichert werden, verwende ich einen anderen Ansatz.
MySettings
genannt.Vorteile:
Nachteile: - Sie müssen darüber nachdenken, wo Ihre Einstellungsdateien gespeichert werden sollen. (Sie können jedoch nur Ihren Installationsordner verwenden.)
Hier ist ein einfaches Beispiel (nicht getestet) -
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;
}
}
}
Und hier ist, wie man es benutzt. Sie können Standardwerte laden oder mit den Benutzereinstellungen überschreiben, indem Sie lediglich prüfen, ob Benutzereinstellungen vorhanden sind:
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);
}
}
vielleicht lässt sich jemand von diesem Ansatz inspirieren. So mache ich das jetzt seit vielen Jahren und bin damit ziemlich zufrieden.
Der am weitesten verbreitete Ansatz für diese Frage ist: Isolated Storage.
Serialisieren Sie Ihren Steuerungsstatus in XML oder ein anderes Format (besonders einfach, wenn Sie Abhängigkeitseigenschaften mit WPF speichern), und speichern Sie die Datei anschließend im isolierten Speicher des Benutzers.
Wenn Sie die App-Einstellungsroute wählen möchten, habe ich selbst an einer Stelle etwas Ähnliches ausprobiert ... obwohl der folgende Ansatz leicht für die Verwendung von Isolated Storage angepasst werden könnte:
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();
}
}
.....und....
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);
}
Neben einer Datenbank können Sie folgende Optionen zum Speichern benutzerbezogener Einstellungen haben
registrierung unter HKEY_CURRENT_USER
in einer Datei im Ordner AppData
verwenden der Settings
-Datei in WPF und durch Festlegen des Bereichs als Benutzer
Nach meiner Erfahrung ist das Speichern aller Einstellungen in einer Datenbanktabelle die beste Lösung. Sorgen Sie sich nicht einmal um die Leistung. Die heutigen Datenbanken sind schnell und können problemlos Tausende von Spalten in einer Tabelle speichern. Ich habe das auf die harte Tour gelernt - bevor ich Serialisierung/Deserialisierung durchgeführt habe - ein Alptraum. Das Speichern in einer lokalen Datei oder in einer lokalen Registrierung hat ein großes Problem - wenn Sie Ihre App unterstützen müssen und der Computer ausgeschaltet ist - der Benutzer steht nicht davor - Sie können nichts tun geändert und Viola nicht zu vergessen, dass Sie die Einstellungen vergleichen können ....
Normalerweise mache ich dies, indem ich eine benutzerdefinierte Einstellungsklasse [Serializable
] definiere und sie einfach auf die Festplatte serialisiere. In Ihrem Fall können Sie es genauso einfach als String-Blob in Ihrer SQLite-Datenbank speichern.
Ich wollte eine XML-Steuerdatei basierend auf einer Klasse für meine VB.net-Desktop-WPF-Anwendung verwenden. Der obige Code, um dies alles in einem zu tun, ist ausgezeichnet und bringt mich in die richtige Richtung. Falls jemand nach einer VB.net-Lösung sucht, ist hier die Klasse, die ich aufgebaut habe:
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
An allen Orten, an denen ich gearbeitet habe, war die Datenbank aufgrund der Anwendungsunterstützung obligatorisch. Wie Adam sagte, ist der Benutzer möglicherweise nicht an seinem Schreibtisch oder der Computer ist ausgeschaltet, oder Sie möchten die Konfiguration einer Person schnell ändern oder einem neuen Teilnehmer eine Standardkonfiguration (oder ein Teammitglied) zuweisen.
Wenn die Einstellungen mit der Veröffentlichung neuer Versionen der Anwendung wahrscheinlich zunehmen, sollten Sie die Daten als Blobs speichern, die dann von der Anwendung deserialisiert werden können. Dies ist besonders nützlich, wenn Sie so etwas wie Prism verwenden, das Module entdeckt, da Sie nicht wissen können, welche Einstellungen ein Modul zurückgibt. Die Blobs könnten mit dem aus Username/Computer zusammengesetzten Schlüssel eingegeben werden. Auf diese Weise können Sie für jede Maschine unterschiedliche Einstellungen vornehmen.
Ich habe die eingebaute Settings-Klasse nicht viel benutzt, daher verzichte ich auf Kommentare. :)