簡體   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