What approach do you recommend for persisting user settings in a WPF windows (desktop) application? Note that the idea is that the user can change their settings at run time, and then can close down the application, then when starting up the application later the application will use the current settings. Effectively then it will appear as if the application settings do not change.
Q1 - Database or other approach? I do have a sqlite database that I will be using anyway hence using a table in the database would be as good as any approach?
Q2 - If Database: What database table design? One table with columns for different data types that one might have (e.g. string
, long
, DateTime
etc) OR just a table with a string for the value upon which you have to serialize and de-serialize the values? I'm thinking the first would be easier, and if there aren't many settings the overhead isn't much?
Q3 - Could Application Settings be used for this? If so are there any special tasks required to enable the persistence here? Also what would happen regarding usage of the "default" value in the Application Settings designer in this case? Would the default override any settings that were saved between running the application? (or would you need to NOT use the default value)
You can use Application Settings for this, using database is not the best option considering the time consumed to read and write the settings(specially if you use web services).
Here are few links which explains how to achieve this and use them in WPF -
User Settings in WPF
Quick WPF Tip: How to bind to WPF application resources and settings?
A Configurable Window for WPF
Update: Nowadays I would use JSON.
I also prefer to go with serialization to file. XML files fits mostly all requirements. You can use the ApplicationSettings
build in but those have some restrictions and a defined but (for me) very strange behavior where they stored. I used them a lot and they work. But if you want to have full control how and where they stored I use another approach.
MySettings
Advantages:
Disadvantages: - You have to think about where to store your settings files. (But you can just use your installation folder)
Here is a simple example (not tested)-
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;
}
}
}
And here is how to use it. It's possible to load default values or override them with the user's settings by just checking if user settings exist:
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);
}
}
maybe someone get's inspired by this approach. This is how I do it now for many years and I'm quite happy with that.
You can store your settings info as Strings
of XML in the Settings.Default
. Create some classes to store your configuration data and make sure they are [Serializable]
. Then, with the following helpers, you can serialize instances of these objects--or List<T>
(or arrays T[]
, etc.) of them--to String
. Store each of these various strings in its own respective Settings.Default
slot in your WPF application's Settings
.
To recover the objects the next time the app starts, read the Settings
string of interest and Deserialize
to the expected type T
(which this time must be explcitly specified as a type argument to Deserialize<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);
}
The long running most typical approach to this question is: Isolated Storage.
Serialize your control state to XML or some other format (especially easily if you're saving Dependency Properties with WPF), then save the file to the user's isolated storage.
If you do want to go the app setting route, I tried something similar at one point myself...though the below approach could easily be adapted to use Isolated Storage:
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();
}
}
.....and....
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);
}
Apart from a database, you can also have following options to save user related settings
registry under HKEY_CURRENT_USER
in a file in AppData
folder
using Settings
file in WPF and by setting its scope as User
In my experience storing all the settings in a database table is the best solution. Don't even worry about performance. Today's databases are fast and can easily store thousands columns in a table. I learned this the hard way - before I was serilizing/deserializing - nightmare. Storing it in local file or registry has one big problem - if you have to support your app and computer is off - user is not in front of it - there is nothing you can do.... if setings are in DB - you can changed them and viola not to mention that you can compare the settings....
You can use SQLite, a small, fast, self-contained, full-featured, SQL database engine. I personally recommend it after trying settings file and XML file approach.
Install NuGet package System.Data.SQLite which is an ADO.NET provider for SQLite. The package includes support for LINQ and Entity Framework Overall you can do many things with such supporting features to your settings window.
1.Install SQLite 2.Create your database file 3.Create tables to save your settings 4.Access database file in your application to read and edit settings.
I felt this approach very much helpful for application settings, since i can do adjustments to database and also take advantage of ADO.Net and LINQ features
I typically do this sort of thing by defining a custom [Serializable
] settings class and simply serializing it to disk. In your case you could just as easily store it as a string blob in your SQLite database.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With