C #-在 WPF 应用程序中保存用户设置的方法?

对于在 WPF 窗口(桌面)应用程序中持久化用户设置,您推荐使用什么方法?请注意,其思想是用户可以在运行时更改其设置,然后可以关闭应用程序,然后在稍后启动应用程序时,应用程序将使用当前设置。有效地,然后它将出现如果应用程序设置不更改。

数据库还是其他方法?我确实有一个 sqlite 数据库,我将使用无论如何,因此在数据库中使用一个表将是任何方法一样好?

如果数据库: 什么数据库表设计?一个包含不同数据类型的列的表(例如 stringlongDateTime等等) ,还是一个包含值的字符串的表,您必须对这些值进行序列化和反序列化?我认为第一个会更容易,如果没有很多设置,开销不是很多?

Q3-应用程序设置是否可用于此?如果是这样,是否需要特殊的任务来启用这里的持久性?另外,在这种情况下,关于应用程序设置设计器中“默认”值的使用会发生什么?默认设置是否会覆盖在运行应用程序之间保存的任何设置?(或者不需要使用默认值)

167395 次浏览

Apart from a database, you can also have following options to save user related settings

  1. registry under HKEY_CURRENT_USER

  2. in a file in AppData folder

  3. using Settings file in WPF and by setting its scope as User

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

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

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.

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 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);
}
  1. In all the places I've worked, database has been mandatory because of application support. As Adam said, the user might not be at his desk or the machine might be off, or you might want to quickly change someone's configuration or assign a new-joiner a default (or team member's) config.

  2. If the settings are likely to grow as new versions of the application are released, you might want to store the data as blobs which can then be deserialized by the application. This is especially useful if you use something like Prism which discovers modules, as you can't know what settings a module will return. The blobs could be keyed by username/machine composite key. That way you can have different settings for every machine.

  3. I've not used the in-built Settings class much so I'll abstain from commenting. :)

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.

  1. Make a class Somewhere with all your settings. I named it MySettings
  2. Implement Save and Read for persistence
  3. Use them in you application-code

Advantages:

  • Very Simple approach.
  • One Class for Settings. Load. Save.
  • All your Settings are type safe.
  • You can simplify or extend the logic to your needs (Versioning, many Profiles per User, etc.)
  • It works very well in any case (Database, WinForms, WPF, Service, etc...)
  • You can define where to store the XML files.
  • You can find them and manipulate them either by code or manual
  • It works for any deployment method I can imagine.

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.

I wanted to use an xml control file based on a class for my VB.net desktop WPF application. The above code to do this all in one is excellent and set me in the right direction. In case anyone is searching for a VB.net solution here is the class I built:

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

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