c# - подход для сохранения пользовательских настроек в приложении WPF?


какой подход вы рекомендуете для сохранения пользовательских настроек в приложении WPF windows (desktop)? Обратите внимание, что идея заключается в том, что пользователь может изменить свои настройки во время выполнения, а затем может закрыть приложение, а затем при запуске приложения позже приложение будет использовать текущие настройки. Фактически тогда он будет выглядеть так, как будто настройки приложения не меняются.

Q1-база данных или другой подход? У меня есть база данных SQLite, что я буду использование в любом случае, следовательно, использование таблицы в базе данных было бы так же хорошо, как и любой подход?

Q2-если база данных: какой дизайн таблицы базы данных? Одна таблица со столбцами для разных типов данных, которые могут иметь (например,string,long,DateTime etc) или просто таблица со строкой для значения, на котором вы должны сериализовать и де-сериализовать значения? Я думаю, что первый будет проще, и если нет много настроек накладные расходы не так много?

Q3-Может Настройки приложения будут использоваться для этого? Если да, то существуют ли какие-либо специальные задачи, необходимые для обеспечения сохраняемости здесь? Также, что произойдет с использованием значения "по умолчанию" в конструкторе настроек приложения в этом случае? Будет ли значение по умолчанию переопределять любые настройки, которые были сохранены между запуском приложения? (или вам не нужно использовать значение по умолчанию)

9 59

9 ответов:

можно использовать Настройки Приложения для этого использование базы данных не является лучшим вариантом, учитывая время, затраченное на чтение и запись настроек (особенно если вы используете веб-службы).

вот несколько ссылок, которые объясняют, как достичь этого и использовать их в WPF -

Настройки пользователя в WPF

Быстрый совет WPF: как привязать к ресурсам и настройкам приложения WPF?

Настраиваемые Окно для WPF

вы можете хранить информацию о настройках как Strings XML в Settings.Default. Создать несколько классов для хранения данных конфигурации и убедитесь, что они [Serializable]. Затем с помощью следующих помощников можно сериализовать экземпляры этих объектов--или List<T> (или массивы T[] и т. д.) из них--к String. Хранить каждый из этих различных строк в своем собственном Settings.Default слот в вашем приложении WPF 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);
}

Я также предпочитаю идти с сериализацией в файл. 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 или какой-либо другой формат (особенно легко, если вы сохраняете свойства зависимостей с помощью 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

  2. в файле AppData папку

  3. используя Settings файл в WPF и установив его область как User

по моему опыту хранение всех настроек в таблице базы данных является лучшим решением. Даже не беспокойтесь о производительности. Современные базы данных быстры и могут легко хранить тысячи столбцов в таблице. Я узнал это на собственном горьком опыте-до того, как я сериализовал/десериализовал - кошмар. Хранение его в локальном файле или реестре имеет одну большую проблему - если вам нужно поддерживать свое приложение, а компьютер выключен - пользователь не находится перед ним - вы ничего не можете сделать.... если настройки находятся в БД-вы можете изменил их и Виола не говоря уже о том, что можно сравнить настройки....

Я обычно делаю такие вещи с помощью пользовательского [Serializable] настройки класса и просто сериализации его на диск. В вашем случае вы можете так же легко хранить его как строковый blob в своей базе данных SQLite.

  1. во всех местах, где я работал, база данных была обязательной, потому что поддержки приложения. Как сказал Адам, пользователь может не находиться за своим столом или машина может быть выключена, или вы можете быстро изменить чью-то конфигурацию или назначить новому столяру конфигурацию по умолчанию (или члена команды).

  2. Если параметры, вероятно, будут расти по мере выпуска новых версий приложения, вы можете сохранить данные в виде больших двоичных объектов, которые затем могут быть десериализован с помощью приложения. Это особенно полезно, если вы используете что-то вроде Prism, который обнаруживает модули, так как вы не можете знать, какие настройки вернет модуль. Большие двоичные объекты могут быть введены с помощью составного ключа username/machine. Таким образом, вы можете иметь различные настройки для каждой машины.

  3. Я не использовал встроенный класс настроек, поэтому я воздержусь от комментариев. :)

Я хотел использовать xml-файл управления на основе класса для моего VB.net настольное приложение WPF. Приведенный выше код, чтобы сделать это все в один прекрасный и поставил меня в правильном направлении. В случае, если кто-то ищет a 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