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