c# - подход для сохранения пользовательских настроек в приложении WPF?
какой подход вы рекомендуете для сохранения пользовательских настроек в приложении WPF windows (desktop)? Обратите внимание, что идея заключается в том, что пользователь может изменить свои настройки во время выполнения, а затем может закрыть приложение, а затем при запуске приложения позже приложение будет использовать текущие настройки. Фактически тогда он будет выглядеть так, как будто настройки приложения не меняются.
Q1-база данных или другой подход? У меня есть база данных SQLite, что я буду использование в любом случае, следовательно, использование таблицы в базе данных было бы так же хорошо, как и любой подход?
Q2-если база данных: какой дизайн таблицы базы данных? Одна таблица со столбцами для разных типов данных, которые могут иметь (например,string
,long
,DateTime
etc) или просто таблица со строкой для значения, на котором вы должны сериализовать и де-сериализовать значения? Я думаю, что первый будет проще, и если нет много настроек накладные расходы не так много?
Q3-Может Настройки приложения будут использоваться для этого? Если да, то существуют ли какие-либо специальные задачи, необходимые для обеспечения сохраняемости здесь? Также, что произойдет с использованием значения "по умолчанию" в конструкторе настроек приложения в этом случае? Будет ли значение по умолчанию переопределять любые настройки, которые были сохранены между запуском приложения? (или вам не нужно использовать значение по умолчанию)
9 ответов:
можно использовать Настройки Приложения для этого использование базы данных не является лучшим вариантом, учитывая время, затраченное на чтение и запись настроек (особенно если вы используете веб-службы).
вот несколько ссылок, которые объясняют, как достичь этого и использовать их в WPF -
Быстрый совет WPF: как привязать к ресурсам и настройкам приложения WPF?
вы можете хранить информацию о настройках как
Strings
XML вSettings.Default
. Создать несколько классов для хранения данных конфигурации и убедитесь, что они[Serializable]
. Затем с помощью следующих помощников можно сериализовать экземпляры этих объектов--илиList<T>
(или массивыT[]
и т. д.) из них--кString
. Хранить каждый из этих различных строк в своем собственномSettings.Default
слот в вашем приложении WPFSettings
.чтобы восстановить объекты при следующем запуске приложения, прочитайте
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
сборка, но у них есть некоторые ограничения и определенное, но (для меня) очень странное поведение, где они хранятся. Я использовал их много и они работают. Но если вы хотите иметь полный контроль, как и где они хранятся я использую другой подход.
- сделайте класс где-нибудь со всеми вашими настройками. Я назвал его
MySettings
- реализовать сохранение и Чтение для настойчивость
- используйте их в вашем приложении-код
плюсы:
- очень простой подход.
- один класс для настроек. Нагрузка. Спасать.
- все настройки типа безопасности.
- вы можете упростить или расширить логику для ваших нужд (управление версиями, множество профилей для каждого пользователя и т. д.)
- он работает очень хорошо в любом случае (база данных, 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); }
помимо базы данных, вы также можете иметь следующие параметры для сохранения пользовательских настроек
реестре под
HKEY_CURRENT_USER
в файле
AppData
папкуиспользуя
Settings
файл в WPF и установив его область как User
по моему опыту хранение всех настроек в таблице базы данных является лучшим решением. Даже не беспокойтесь о производительности. Современные базы данных быстры и могут легко хранить тысячи столбцов в таблице. Я узнал это на собственном горьком опыте-до того, как я сериализовал/десериализовал - кошмар. Хранение его в локальном файле или реестре имеет одну большую проблему - если вам нужно поддерживать свое приложение, а компьютер выключен - пользователь не находится перед ним - вы ничего не можете сделать.... если настройки находятся в БД-вы можете изменил их и Виола не говоря уже о том, что можно сравнить настройки....
Я обычно делаю такие вещи с помощью пользовательского [
Serializable
] настройки класса и просто сериализации его на диск. В вашем случае вы можете так же легко хранить его как строковый blob в своей базе данных SQLite.
во всех местах, где я работал, база данных была обязательной, потому что поддержки приложения. Как сказал Адам, пользователь может не находиться за своим столом или машина может быть выключена, или вы можете быстро изменить чью-то конфигурацию или назначить новому столяру конфигурацию по умолчанию (или члена команды).
Если параметры, вероятно, будут расти по мере выпуска новых версий приложения, вы можете сохранить данные в виде больших двоичных объектов, которые затем могут быть десериализован с помощью приложения. Это особенно полезно, если вы используете что-то вроде Prism, который обнаруживает модули, так как вы не можете знать, какие настройки вернет модуль. Большие двоичные объекты могут быть введены с помощью составного ключа username/machine. Таким образом, вы можете иметь различные настройки для каждой машины.
Я не использовал встроенный класс настроек, поэтому я воздержусь от комментариев. :)
Я хотел использовать 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