2010-09-24 36 views
54

¿Qué enfoque recomienda para la persistencia de la configuración del usuario en una aplicación de Windows (escritorio) de WPF? 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, cuando inicie la aplicación más tarde, la aplicación usará la configuración actual. Efectivamente, entonces parecerá que la configuración de la aplicación no cambia.C# - enfoque para guardar la configuración del usuario en una aplicación WPF?

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.

Q2 - Si la base de datos: ¿Qué diseño de la tabla de la base de datos? Una tabla con columnas para diferentes tipos de datos que uno podría tener (por ejemplo, string, long, DateTime, etc.) ¿O simplemente una tabla con una cadena para el valor sobre el que debe serializar y deserializar los valores? Estoy pensando que el primero sería más fácil, y si no hay muchos ajustes, la sobrecarga no es mucho.

Q3 - ¿Se podrían usar las configuraciones de la aplicación para esto? Si es así, ¿hay alguna tarea especial requerida para habilitar la persistencia aquí? ¿Qué sucedería con respecto al uso del valor "predeterminado" en el diseñador de configuraciones de la aplicación en este caso? ¿El valor predeterminado anularía las configuraciones que se guardaron entre ejecutar la aplicación? (O si es necesario que usted no utiliza el valor por defecto)

Respuesta

56

Puede usar Application Settings para esto, usar la base de datos no es la mejor opción teniendo en cuenta el tiempo consumido para leer y escribir la configuración (especialmente si usa servicios web).

Éstos son algunos enlaces que explica cómo lograr esto y usarlos en WPF -

User Settings in WPF

Quick WPF Tip: How to bind to WPF application resources and settings?

A Configurable Window for WPF

+2

Aquí hay otro buen enlace. http: // stackoverflow.com/a/396243/878612 – lko

4

Aparte de una base de datos, también puede tener las siguientes opciones para guardar los ajustes relacionados con el usuario

  1. registro bajo HKEY_CURRENT_USER

  2. en un archivo en AppData carpeta

  3. usando Settings archivo en WPF y estableciendo su alcance como usuario

+2

Sugerencia 1 es la razón por la cual las aplicaciones de Windows más lento, mejor que no llenan las claves de registro con algo mejor hecho en un archivo de la OMI. – Console

+1

@Console, escribir archivo en un disco desacelera (desgaste) SSD, escribe datos en la base de datos de ralentizaciones de la base de datos. ¿Cuál es tu opción entonces? El registro de Windows * debe * ser utilizado como uno de los lugares para guardar * configuraciones *. – Sinatr

+1

Tiene razón, creo que es importante mencionar que el registro tiene algunos inconvenientes si cada aplicación guarda allí las preferencias de los usuarios. – Console

6

La carrera de larga enfoque más típica a esta pregunta es: Almacenamiento aislado.

Serialice su estado de control a XML u otro formato (especialmente si está guardando Propiedades de dependencia con WPF), luego guarde el archivo en el almacenamiento aislado del usuario.

Si quieres ir a la ruta de configuración de aplicaciones, he intentado algo similar en un momento dado a mí mismo ... aunque el enfoque de abajo podría adaptarse fácilmente al uso aislado de almacenamiento:

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); 
     } 
1

Me suelen hacer este tipo de cosas mediante la definición de un [Serializable] clase configuración personalizada y simplemente la serialización en el disco. En su caso, podría fácilmente almacenarlo como un bloque de cadena en su base de datos SQLite.

3

En mi experiencia, almacenar la configuración en una tabla de base de datos es la mejor solución. Ni siquiera te preocupes 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 más difícil, antes de ser serilizante/deserializador, 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á delante de ella, no hay nada que pueda hacer ... si los ajustes están en DB, puede los cambió y viola sin mencionar que puede comparar la configuración ....

+0

Y almacenarlos remotamente también tiene un gran problema cuando la conexión no está disponible ... Muchas aplicaciones escritas en trabajos en línea tienen una experiencia menos que ideal cuando se trabaja fuera de línea o en algún momento incluso tienen errores que crean alguna funcionalidad para no trabajar fuera de línea, incluso si no debería tener otro impacto que no sea "espiar" cómo se usa el dispositivo. – Phil1970

10

Puede almacenar la información de configuración como Strings de XML en el Settings.Default. Cree algunas clases para almacenar sus datos de configuración y asegúrese de que sean [Serializable]. Luego, con los siguientes ayudantes, puede serializar instancias de estos objetos - o List<T> (o matrices T[], etc.) de ellos - al String. Almacene cada una de estas varias cadenas en su ranura respectiva Settings.Default en su aplicación WPF Settings.

para recuperar los objetos la próxima vez que se inicia la aplicación, leer la cadena Settings de interés y Deserialize al tipo esperado T (que en esta ocasión se debe especificar explcitly como un argumento de tipo de 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); 
} 
0
  1. En todos los lugares en los que he trabajado, la base de datos ha sido obligatorio debido al apoyo 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 quizás desee cambiar rápidamente la configuración de alguien o asignarle a un nuevo ensamblador una configuración predeterminada (o miembro del equipo).

  2. Si la configuración es probable que crezca a medida que se lanzan nuevas versiones de la aplicación, es posible que desee almacenar los datos como blobs que luego pueden ser deserializados por la aplicación. Esto es especialmente útil si utiliza algo como Prism que descubre módulos, ya que no puede saber qué configuraciones devolverá un módulo. Los blobs podrían estar codificados por clave compuesta de usuario/máquina. De esta manera puede tener diferentes configuraciones para cada máquina.

  3. No he usado mucho la clase de configuración integrada, así que me abstendré de comentar. :)

8

También prefiero ir con la serialización al archivo. Los archivos XML se ajustan principalmente a todos los requisitos. Puede usar la compilación ApplicationSettings, pero esas tienen algunas restricciones y un comportamiento definido pero (para mí) muy extraño en el que se almacenan. Los usé mucho y funcionan. Pero si quiere tener un control total sobre cómo y dónde almacenan, utilizo otro enfoque.

  1. Haz una clase En algún lugar con todas tus configuraciones.Lo nombré MySettings
  2. Implementar guarden y lean para la persistencia
  3. usarlos en que la aplicación de código

Ventajas:

  • enfoque muy simple.
  • One Class for Settings. Carga. Salvar.
  • Todas sus configuraciones son tipo seguro.
  • Se puede simplificar o ampliar la lógica a sus necesidades (de versiones, muchos perfiles por usuario, etc.)
  • funciona muy bien en cualquier caso (base de datos, Windows Forms, WPF, servicio, etc ...)
  • Puede definir dónde almacenar los archivos XML.
  • Puede encontrarlos y manipularlos ya sea por código o manual
  • Funciona para cualquier método de implementación que pueda imaginar.

Desventajas: - Tiene que pensar en dónde almacenar sus archivos de configuración. (Sin embargo, sólo se puede utilizar la carpeta de instalación)

Aquí está un ejemplo sencillo (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 aquí es cómo usarlo. Es posible cargar los valores por defecto o anular con la configuración del usuario con sólo comprobar si existen ajustes de 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 de inspirado por este método GET. Así es como lo hago ahora durante muchos años y estoy bastante contento con eso.

+0

Por la desventaja, sería que ya no tienes el diseñador de configuraciones, por lo que es un poco menos amigable cuando ambas funcionen. – Phil1970

+0

Totalmente de acuerdo con el "comportamiento muy extraño en el que están almacenados", estoy utilizando su enfoque precisamente por eso. +1. – Hannish

0

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 esto todo en uno es excelente y me puso en la dirección correcta. En caso de que alguien está buscando una solución VB.net aquí está la clase 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 
Cuestiones relacionadas