您建议在WPF窗口(桌面)应用程序中保留用户设置的方法是什么?请注意,该想法是用户可以在运行时更改其设置,然后可以关闭应用程序,然后在稍后启动应用程序时,应用程序将使用当前设置。有效地,它看起来好像应用程序设置不会改变。
Q1 - 数据库还是其他方法?我确实有一个我将使用的sqlite数据库,因此使用数据库中的表将与任何方法一样好吗?
Q2 - 如果数据库:什么数据库表设计?一个表包含可能具有的不同数据类型的列(例如string
,long
,DateTime
等)或者只是一个表格,其中包含您必须序列化的值的字符串和反序列化值?我想第一个会更容易,如果设置不多,开销就不多了?
Q3 - 可以使用应用程序设置吗?如果是这样,是否需要在此处启用持久性的特殊任务?在这种情况下,在应用程序设置设计器中使用“默认”值会发生什么?默认会覆盖运行应用程序之间保存的所有设置吗? (或者你需要不使用默认值)
答案 0 :(得分:65)
您可以使用Application Settings,考虑到读取和写入设置所花费的时间(特别是如果您使用Web服务),使用数据库不是最佳选择。
以下是一些解释如何实现此目的并在WPF中使用它们的链接 -
Quick WPF Tip: How to bind to WPF application resources and settings?
答案 1 :(得分:12)
您可以将设置信息存储为Strings
中的Settings.Default
XML。创建一些类来存储配置数据,并确保它们是[Serializable]
。然后,使用以下帮助程序,您可以将这些对象的实例 - 或List<T>
(或数组T[]
等)序列化为String
。将这些不同的字符串中的每一个存储在WPF应用程序Settings.Default
中各自的Settings
位置。
要在下次应用启动时恢复对象,请将感兴趣的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);
}
答案 2 :(得分:10)
更新:现在我会使用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);
}
}
也许有人会受到这种方法的启发。这就是我多年来一直这样做的原因,我很满意。
答案 3 :(得分:6)
长期运行此问题的最典型方法是:隔离存储。
将控件状态序列化为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);
}
答案 4 :(得分:4)
除数据库外,您还可以使用以下选项保存用户相关设置
HKEY_CURRENT_USER
下的注册表
在AppData
文件夹
在WPF中使用Settings
文件并将其范围设置为用户
答案 5 :(得分:3)
根据我的经验,将所有设置存储在数据库表中是最佳解决方案。甚至不担心性能。今天的数据库速度很快,可以轻松地在表格中存储数千列。在我进行serilizing / deserializing之前,我学到了很多困难 - 噩梦。将它存储在本地文件或注册表中有一个大问题 - 如果你必须支持你的应用程序和计算机关闭 - 用户不在它前面 - 你无能为力......如果setings在DB中 - 你可以改变了他们和中提琴,更不用说你可以比较设置....
答案 6 :(得分:1)
我通常通过定义自定义[Serializable
]设置类并将其序列化到磁盘来完成此类操作。在您的情况下,您可以轻松地将其存储为SQLite数据库中的字符串blob。
答案 7 :(得分:0)
在我工作过的所有地方,由于应用程序支持,数据库已成为必需项。正如Adam所说,用户可能不在他的办公桌旁,或者机器可能已关闭,或者您可能想要快速更改某人的配置或为新连接人分配默认(或团队成员)配置。
如果在发布新版本的应用程序时设置可能会增长,您可能希望将数据存储为blob,然后可以由应用程序对其进行反序列化。如果您使用像Prism那样发现模块的东西,这一点尤其有用,因为您无法知道模块将返回什么设置。 blob可以通过用户名/机器复合键来键入。这样,您可以为每台机器设置不同的设置。
我没有使用内置的“设置”类,所以我会弃用评论。 :)
答案 8 :(得分:0)
我想在我的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