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

时间:2010-09-24 05:38:41

标签: c# .net wpf settings

您建议在WPF窗口(桌面)应用程序中保留用户设置的方法是什么?请注意,该想法是用户可以在运行时更改其设置,然后可以关闭应用程序,然后在稍后启动应用程序时,应用程序将使用当前设置。有效地,它看起来好像应用程序设置不会改变。

Q1 - 数据库还是其他方法?我确实有一个我将使用的sqlite数据库,因此使用数据库中的表将与任何方法一样好吗?

Q2 - 如果数据库:什么数据库表设计?一个表包含可能具有的不同数据类型的列(例如stringlongDateTime等)或者只是一个表格,其中包含您必须序列化的值的字符串和反序列化值?我想第一个会更容易,如果设置不多,开销就不多了?

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

9 个答案:

答案 0 :(得分:65)

您可以使用Application Settings,考虑到读取和写入设置所花费的时间(特别是如果您使用Web服务),使用数据库不是最佳选择。

以下是一些解释如何实现此目的并在WPF中使用它们的链接 -

User Settings in WPF

Quick WPF Tip: How to bind to WPF application resources and settings?

A Configurable Window for WPF

答案 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内置版本,但这些内容有一些限制和定义但(对我来说)存储的非常奇怪的行为。我经常使用它们并且它们起作用。但是如果你想完全控制他们存储的方式和位置,我会采用另一种方法。

  1. 使用您的所有设置在某处创建课程。我将其命名为MySettings
  2. 实施保存和读取持久性
  3. 在您的应用程序代码中使用它们
  4. 优点:

    • 非常简单的方法。
    • 一类设置。加载。保存。
    • 您的所有设置都是类型安全的。
    • 您可以根据需要简化或扩展逻辑(版本控制,每个用户的许多配置文件等)。
    • 它在任何情况下都很好用(数据库,WinForms,WPF,服务等......)
    • 您可以定义XML文件的存储位置。
    • 您可以通过代码或手动
    • 找到并操纵它们
    • 适用于我能想象的任何部署方法。

    缺点:   - 您必须考虑存储设置文件的位置。 (但你可以使用你的安装文件夹)

    这是一个简单的例子(未经测试) -

    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)

除数据库外,您还可以使用以下选项保存用户相关设置

  1. HKEY_CURRENT_USER下的注册表

  2. AppData文件夹

  3. 中的文件中
  4. 在WPF中使用Settings文件并将其范围设置为用户

答案 5 :(得分:3)

根据我的经验,将所有设置存储在数据库表中是最佳解决方案。甚至不担心性能。今天的数据库速度很快,可以轻松地在表格中存储数千列。在我进行serilizing / deserializing之前,我学到了很多困难 - 噩梦。将它存储在本地文件或注册表中有一个大问题 - 如果你必须支持你的应用程序和计算机关闭 - 用户不在它前面 - 你无能为力......如果setings在DB中 - 你可以改变了他们和中提琴,更不用说你可以比较设置....

答案 6 :(得分:1)

我通常通过定义自定义[Serializable]设置类并将其序列化到磁盘来完成此类操作。在您的情况下,您可以轻松地将其存储为SQLite数据库中的字符串blob。

答案 7 :(得分:0)

  1. 在我工作过的所有地方,由于应用程序支持,数据库已成为必需项。正如Adam所说,用户可能不在他的办公桌旁,或者机器可能已关闭,或者您可能想要快速更改某人的配置或为新连接人分配默认(或团队成员)配置。

  2. 如果在发布新版本的应用程序时设置可能会增长,您可能希望将数据存储为blob,然后可以由应用程序对其进行反序列化。如果您使用像Prism那样发现模块的东西,这一点尤其有用,因为您无法知道模块将返回什么设置。 blob可以通过用户名/机器复合键来键入。这样,您可以为每台机器设置不同的设置。

  3. 我没有使用内置的“设置”类,所以我会弃用评论。 :)

答案 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