繁体   English   中英

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

[英]C# - approach for saving user settings in a WPF application?

对于在 WPF windows(桌面)应用程序中持久保存用户设置,您推荐什么方法? 请注意,这个想法是用户可以在运行时更改他们的设置,然后可以关闭应用程序,然后在稍后启动应用程序时应用程序将使用当前设置。 实际上,应用程序设置似乎没有更改。

Q1 - 数据库或其他方法? 我确实有一个 sqlite 数据库,无论如何我都会使用它,因此在数据库中使用一个表会和任何方法一样好吗?

Q2 - 如果数据库:什么数据库表设计? 一个包含不同数据类型的列的表(例如stringlongDateTime等),或者只是一个包含字符串的表,您必须根据该字符串对值进行序列化和反序列化? 我认为第一个会更容易,如果设置不多,开销也不大?

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

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

这里有几个链接解释了如何实现这一点并在 WPF 中使用它们 -

WPF 中的用户设置

WPF 快速提示:如何绑定到 WPF 应用程序资源和设置?

WPF 的可配置窗口

更新:现在我会使用 JSON。

我也更喜欢序列化到文件。 XML 文件几乎可以满足所有要求。 您可以使用ApplicationSettings内置,但它们有一些限制和定义但(对我而言)它们存储的非常奇怪的行为。 我经常使用它们并且它们有效。 但是如果你想完全控制它们存储的方式和位置,我会使用另一种方法。

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

优点:

  • 非常简单的方法。
  • 一类设置。 负载。 保存。
  • 您的所有设置都是类型安全的。
  • 您可以根据需要简化或扩展逻辑(版本控制、每个用户的多个配置文件等)
  • 它在任何情况下都能很好地工作(数据库、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);
    }
}

也许有人会受到这种方法的启发。 这就是我多年来一直这样做的方式,我对此感到非常满意。

您可以将设置信息作为 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);
        }

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

  1. HKEY_CURRENT_USER下的HKEY_CURRENT_USER

  2. AppData文件夹中的文件中

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

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

您可以使用 SQLite,一个小型、快速、独立、功能齐全的 SQL 数据库引擎。 在尝试设置文件和 XML 文件方法后,我个人推荐它。

安装NuGet package SYSTEM.DATA.SQLite它是88393605555588提供商SQLite的提供程序。

1.安装 SQLite 2.创建数据库文件 3.创建表以保存设置 4.访问应用程序中的数据库文件以读取和编辑设置。

我觉得这种方法对应用程序设置非常有帮助,因为我可以对数据库进行调整,还可以利用 ADO.Net 和 LINQ 功能

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

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

  2. 如果设置可能会随着应用程序新版本的发布而增加,您可能希望将数据存储为 blob,然后应用程序可以反序列化这些数据。 如果您使用诸如发现模块的 Prism 之类的东西,这将特别有用,因为您无法知道模块将返回哪些设置。 blob 可以通过用户名/机器组合键进行键控。 这样您就可以为每台机器设置不同的设置。

  3. 我很少使用内置的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM