[英]C# - approach for saving user settings in a WPF application?
对于在 WPF windows(桌面)应用程序中持久保存用户设置,您推荐什么方法? 请注意,这个想法是用户可以在运行时更改他们的设置,然后可以关闭应用程序,然后在稍后启动应用程序时应用程序将使用当前设置。 实际上,应用程序设置似乎没有更改。
Q1 - 数据库或其他方法? 我确实有一个 sqlite 数据库,无论如何我都会使用它,因此在数据库中使用一个表会和任何方法一样好吗?
Q2 - 如果数据库:什么数据库表设计? 一个包含不同数据类型的列的表(例如string
、 long
、 DateTime
等),或者只是一个包含字符串的表,您必须根据该字符串对值进行序列化和反序列化? 我认为第一个会更容易,如果设置不多,开销也不大?
Q3 - 应用程序设置可以用于此吗? 如果是这样,是否需要执行任何特殊任务才能在此处启用持久性? 此外,在这种情况下,在应用程序设置设计器中使用“默认”值会发生什么情况? 默认值是否会覆盖在运行应用程序之间保存的任何设置? (或者您是否需要不使用默认值)
您可以为此使用应用程序设置,考虑到读取和写入设置所花费的时间(特别是如果您使用 Web 服务),使用数据库并不是最佳选择。
这里有几个链接解释了如何实现这一点并在 WPF 中使用它们 -
更新:现在我会使用 JSON。
我也更喜欢序列化到文件。 XML 文件几乎可以满足所有要求。 您可以使用ApplicationSettings
内置,但它们有一些限制和定义但(对我而言)它们存储的非常奇怪的行为。 我经常使用它们并且它们有效。 但是如果你想完全控制它们存储的方式和位置,我会使用另一种方法。
MySettings
优点:
缺点: - 您必须考虑在哪里存储您的设置文件。 (但你可以只使用你的安装文件夹)
这是一个简单的例子(未测试)-
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;
}
}
}
这是如何使用它。 只需检查用户设置是否存在,就可以加载默认值或使用用户设置覆盖它们:
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);
}
}
也许有人会受到这种方法的启发。 这就是我多年来一直这样做的方式,我对此感到非常满意。
您可以将设置信息作为 XML Strings
存储在Settings.Default
。 创建一些类来存储您的配置数据并确保它们是[Serializable]
。 然后,使用以下帮助程序,您可以将这些对象的实例(或它们的List<T>
(或数组T[]
等)序列化为String
。 将这些不同的字符串中的每一个存储在 WPF 应用程序的Settings
各自的Settings.Default
插槽中。
要在应用程序下次启动时恢复对象,请读取感兴趣的Settings
字符串并将其Deserialize
化为预期类型T
(这次必须明确指定为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);
}
解决这个问题的长期最典型的方法是:隔离存储。
将您的控件状态序列化为 XML 或某种其他格式(如果您使用 WPF 保存依赖属性,则尤其容易),然后将文件保存到用户的独立存储中。
如果你确实想走应用程序设置路线,我自己曾经尝试过类似的东西......尽管下面的方法可以很容易地适应使用隔离存储:
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();
}
}
……还有……
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);
}
除了数据库,您还可以使用以下选项来保存用户相关设置
HKEY_CURRENT_USER
下的HKEY_CURRENT_USER
在AppData
文件夹中的文件中
在 WPF 中使用Settings
文件并将其范围设置为用户
根据我的经验,将所有设置存储在数据库表中是最好的解决方案。 甚至不用担心性能。 今天的数据库速度很快,可以轻松地在一个表中存储数千列。 在我进行序列化/反序列化之前,我通过艰难的方式学到了这一点——噩梦。 将它存储在本地文件或注册表中有一个大问题 - 如果您必须支持您的应用程序并且计算机已关闭 - 用户不在它面前 - 您无能为力.... 如果设置在 DB 中 - 您可以更改了它们和中提琴,更不用说您可以比较设置....
您可以使用 SQLite,一个小型、快速、独立、功能齐全的 SQL 数据库引擎。 在尝试设置文件和 XML 文件方法后,我个人推荐它。
安装NuGet package SYSTEM.DATA.SQLite它是88393605555588提供商SQLite的提供程序。
1.安装 SQLite 2.创建数据库文件 3.创建表以保存设置 4.访问应用程序中的数据库文件以读取和编辑设置。
我觉得这种方法对应用程序设置非常有帮助,因为我可以对数据库进行调整,还可以利用 ADO.Net 和 LINQ 功能
我通常通过定义自定义 [ Serializable
] 设置类并将其序列化到磁盘来完成此类操作。 在您的情况下,您可以像将字符串 blob 一样轻松地存储在 SQLite 数据库中。
在我工作过的所有地方,由于应用程序支持,数据库一直是强制性的。 正如 Adam 所说,用户可能不在他的办公桌前或机器可能关闭,或者您可能想要快速更改某人的配置或为新加入者分配默认(或团队成员)配置。
如果设置可能会随着应用程序新版本的发布而增加,您可能希望将数据存储为 blob,然后应用程序可以反序列化这些数据。 如果您使用诸如发现模块的 Prism 之类的东西,这将特别有用,因为您无法知道模块将返回哪些设置。 blob 可以通过用户名/机器组合键进行键控。 这样您就可以为每台机器设置不同的设置。
我很少使用内置的 Settings 类,所以我将避免发表评论。 :)
我想为我的 VB.net 桌面 WPF 应用程序使用基于类的 xml 控制文件。 上面的代码合二为一地完成了这一切,它让我朝着正确的方向前进。 如果有人正在寻找 VB.net 解决方案,这里是我构建的类:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.