¿Qué enfoque recomienda para conservar la configuración del usuario en una aplicación de WPF para Windows (escritorio)? Tenga en cuenta que la idea es que el usuario puede cambiar su configuración en tiempo de ejecución, y luego puede cerrar la aplicación, luego, al iniciar la aplicación más tarde, la aplicación utilizará la configuración actual. Efectivamente, entonces parecerá que la configuración de la aplicación no cambia.
Q1 - ¿Base de datos u otro enfoque? Tengo una base de datos sqlite que usaré de todos modos, por lo tanto, ¿usar una tabla en la base de datos sería tan bueno como cualquier enfoque?
P2 - If Database: ¿Qué diseño de tabla de base de datos? Una tabla con columnas para diferentes tipos de datos que se pueda tener (por ejemplo string
, long
, DateTime
etc) o simplemente una mesa con una cadena para el valor sobre el cual usted tiene que serializar y deserializar los valores? Creo que la primera sería más fácil, y si no hay muchas configuraciones, ¿la sobrecarga no es mucha?
P3 - ¿Se puede utilizar la configuración de la aplicación para esto? Si es así, ¿se requieren tareas especiales para habilitar la persistencia aquí? Además, ¿qué pasaría con respecto al uso del valor "predeterminado" en el diseñador de configuración de la aplicación en este caso? ¿El valor predeterminado anularía cualquier configuración que se guardó entre la ejecución de la aplicación? (o necesitaría NO usar el valor predeterminado)
Respuestas:
Puede usar la Configuración de la aplicación para esto, usar la base de datos no es la mejor opción considerando el tiempo consumido para leer y escribir la configuración (especialmente si usa servicios web).
Aquí hay algunos enlaces que explican cómo lograr esto y usarlos en WPF:
Configuración de usuario en WPF
Consejo rápido de WPF: ¿Cómo enlazar a los recursos y la configuración de la aplicación WPF?
Una ventana configurable para WPF
fuente
Actualización : hoy en día usaría JSON.
También prefiero ir con la serialización al archivo. Los archivos XML se adaptan principalmente a todos los requisitos. Puede usar la
ApplicationSettings
compilación, pero tienen algunas restricciones y un comportamiento definido pero (para mí) muy extraño donde se almacenan. Los usé mucho y funcionan. Pero si quieres tener un control total sobre cómo y dónde se almacenan, utilizo otro enfoque.MySettings
Ventajas:
Desventajas: - Tienes que pensar en dónde almacenar tus archivos de configuración. (Pero puede usar su carpeta de instalación)
Aquí hay un ejemplo simple (no probado):
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; } } }
Y así es como se usa. Es posible cargar valores predeterminados o anularlos con la configuración del usuario simplemente verificando si existe la configuración del usuario:
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); } }
tal vez alguien se sienta inspirado por este enfoque. Así es como lo hago ahora durante muchos años y estoy bastante contento con eso.
fuente
Puede almacenar su información de configuración a partir
Strings
de XML en el archivoSettings.Default
. Cree algunas clases para almacenar sus datos de configuración y asegúrese de que lo estén[Serializable]
. Luego, con los siguientes ayudantes, puede serializar instancias de estos objetos, oList<T>
(o matricesT[]
, etc.) de ellos, enString
. Almacene cada una de estas diversas cadenas en su propiaSettings.Default
ranura respectiva en su aplicación WPFSettings
.Para recuperar los objetos la próxima vez que se inicie la aplicación, lea la
Settings
cadena de interés yDeserialize
el tipo esperadoT
(que esta vez debe especificarse explícitamente como un argumento de tipoDeserialize<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); }
fuente
El enfoque más típico a largo plazo para esta pregunta es: Almacenamiento aislado.
Serialice su estado de control en XML o algún otro formato (especialmente fácilmente si está guardando Propiedades de dependencia con WPF), luego guarde el archivo en el almacenamiento aislado del usuario.
Si desea seguir la ruta de configuración de la aplicación, probé algo similar en un punto yo mismo ... aunque el enfoque a continuación podría adaptarse fácilmente para usar Almacenamiento aislado:
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(); } }
.....y....
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); }
fuente
Además de una base de datos, también puede tener las siguientes opciones para guardar la configuración relacionada con el usuario
registro bajo
HKEY_CURRENT_USER
en un archivo en
AppData
carpetausando el
Settings
archivo en WPF y estableciendo su alcance como Usuariofuente
En mi experiencia, almacenar todas las configuraciones en una tabla de base de datos es la mejor solución. Ni siquiera se preocupe por el rendimiento. Las bases de datos actuales son rápidas y pueden almacenar fácilmente miles de columnas en una tabla. Aprendí esto de la manera difícil, antes de serilizar / deserializar, una pesadilla. Almacenarlo en un archivo o registro local tiene un gran problema: si tiene que admitir su aplicación y la computadora está apagada, el usuario no está frente a ella, no hay nada que pueda hacer ... si las configuraciones están en la base de datos, puede los cambió y viola sin mencionar que puede comparar la configuración ....
fuente
Normalmente hago este tipo de cosas definiendo una
Serializable
clase de configuración personalizada [ ] y simplemente serializándola en el disco. En su caso, podría almacenarlo fácilmente como un blob de cadena en su base de datos SQLite.fuente
En todos los lugares en los que he trabajado, la base de datos ha sido obligatoria debido al soporte de la aplicación. Como dijo Adam, es posible que el usuario no esté en su escritorio o que la máquina esté apagada, o es posible que desee cambiar rápidamente la configuración de alguien o asignar a un nuevo usuario una configuración predeterminada (o miembro del equipo).
Si es probable que la configuración aumente a medida que se lanzan nuevas versiones de la aplicación, es posible que desee almacenar los datos como blobs que luego la aplicación puede deserializar. Esto es especialmente útil si usa algo como Prism que descubre módulos, ya que no puede saber qué configuraciones devolverá un módulo. Los blobs pueden estar codificados por nombre de usuario / clave compuesta de máquina. De esa manera, puede tener diferentes configuraciones para cada máquina.
No he usado mucho la clase de Configuración incorporada, así que me abstendré de comentar. :)
fuente
Quería usar un archivo de control xml basado en una clase para mi aplicación WPF de escritorio VB.net. El código anterior para hacer todo esto en uno es excelente y me puso en la dirección correcta. En caso de que alguien esté buscando una solución de VB.net, aquí está la clase que construí:
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
fuente