Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Пользовательские настройки в WPF

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

Конфигурируемое окно для WPF

Ответ 2

Вы можете сохранить информацию о настройках как 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);
}

Ответ 3

Я также предпочитаю сериализовать файл. Файлы XML подходят в основном для всех требований. Вы можете использовать сборку ApplicationSettings но у них есть некоторые ограничения и определенное, но (для меня) очень странное поведение, в котором они хранятся. Я использовал их много, и они работают. Но если вы хотите полностью контролировать, как и где они хранятся, я использую другой подход.

  1. Сделайте класс Где-нибудь со всеми вашими настройками. Я назвал его MySettings
  2. Внедрить сохранение и чтение для сохранения
  3. Используйте их в своем коде приложения

Преимущества:

  • Очень простой подход.
  • Один класс для настроек. Загрузка. Сохранить.
  • Все ваши настройки безопасны по типу.
  • Вы можете упростить или расширить логику в соответствии с вашими потребностями (Версии, много профилей на пользователя и т.д.).
  • Он работает очень хорошо в любом случае (база данных, WinForms, WPF, Service и т.д.)
  • Вы можете определить, где хранить файлы 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);
    }
}

возможно, кто-то вдохновляется этим подходом. Вот как я это делаю сейчас уже много лет, и я вполне доволен этим.

Ответ 4

Самый продолжительный наиболее типичный подход к этому вопросу: Изолированное хранилище.

Сериализуйте свое состояние управления в формате 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);
        }

Ответ 5

Помимо базы данных, вы также можете иметь следующие параметры для сохранения настроек, связанных с пользователем.

  • в разделе HKEY_CURRENT_USER

  • в папке AppData

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

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

Ответ 9

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