c# - подход для сохранения пользовательских настроек в приложении WPF?
какой подход вы рекомендуете для сохранения пользовательских настроек в приложении WPF windows (desktop)? Обратите внимание, что идея заключается в том, что пользователь может изменить свои настройки во время выполнения, а затем может закрыть приложение, а затем при запуске приложения позже приложение будет использовать текущие настройки. Фактически тогда он будет выглядеть так, как будто настройки приложения не меняются.
Q1-база данных или другой подход? У меня есть база данных SQLite, что я буду использование в любом случае, следовательно, использование таблицы в базе данных было бы так же хорошо, как и любой подход?
Q2-если база данных: какой дизайн таблицы базы данных? Одна таблица со столбцами для разных типов данных, которые могут иметь (например,string,long,DateTime etc) или просто таблица со строкой для значения, на котором вы должны сериализовать и де-сериализовать значения? Я думаю, что первый будет проще, и если нет много настроек накладные расходы не так много?
Q3-Может Настройки приложения будут использоваться для этого? Если да, то существуют ли какие-либо специальные задачи, необходимые для обеспечения сохраняемости здесь? Также, что произойдет с использованием значения "по умолчанию" в конструкторе настроек приложения в этом случае? Будет ли значение по умолчанию переопределять любые настройки, которые были сохранены между запуском приложения? (или вам не нужно использовать значение по умолчанию)
9 ответов:
можно использовать Настройки Приложения для этого использование базы данных не является лучшим вариантом, учитывая время, затраченное на чтение и запись настроек (особенно если вы используете веб-службы).
вот несколько ссылок, которые объясняют, как достичь этого и использовать их в WPF -
Быстрый совет WPF: как привязать к ресурсам и настройкам приложения WPF?
вы можете хранить информацию о настройках как
StringsXML в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