La batallita:
A partir de .NET Framework 2.0, cuando usamos los datos de configuración
por medio de "la clase" Settings (en VB usando
My.Settings y
en C# usando Properties.Settings.Default), los datos que se almacenan dependen
de la versión del ensamblado, es decir, si cambiamos la versión de nuestro
ejecutable se usarán otros datos diferentes. Lo que aquí te cuento es para
recuperar desde una versión posterior los datos que se hubieran guardado con
la versión anterior, de esa forma, el usuario mantendrá los mismos datos a
pesar de que se cambia la versión.
¿No sabes de qué te hablo?
Te explico: Cuando usas los datos de configuración a nivel de usuario
(que son los que se pueden modificar), esos datos se guardan en una carpeta
del directorio del usuario actual. Esa carpeta tiene una estructura
predefinida, que para simplificar te diré que está formada (la estructura)
por una carpeta con el nombre de la aplicación y dentro de ésta hay otra con
la versión actual del ejecutable. Por tanto, si tu aplicación es la versión
1.0.0.0, los datos de configuración estarán en el directorio 1.0.0.0, si
cambias la versión del ejecutable a la 1.1.0.0, se creará otra carpeta con
ese número y los datos correspondientes a esa nueva versión se guardarán
dentro de esa otra carpeta, por tanto, los datos de la versión anterior no
estarán disponibles... salvo que sigas leyendo y te enteres cómo conseguir
de forma "automatizada" esos datos de la versión anterior.
Vamos a lo que vamos
Pues bien, si sabemos que nuestra aplicación está usando una versión
diferente de nuestra aplicación, podemos leer los datos de la versión
anterior y usarlos en esa nueva versión.
Esto se puede hacer de dos formas distintas, una de ellas la podemos usar
para leer solo algunos de los datos de la configuración (en lugar de leer
todos los que hubiera en la versión anterior), y la otra forma es para leer
todos los datos de la versión anterior y asignarlos como si ya estuvieran
asignados. Esta segunda forma es la recomendada, entre otras cosas porque no
dará error si intentáramos leer los datos de una versión anterior cuando en
realidad no hay ninguna versión anterior.
Y es que esto último puede que nos pase... porque... ¿cómo sabemos si
estamos usando datos que ya se han guardado con anterioridad (de la misma
versión) o es la primera vez que vamos a leer los datos (ya sean porque es
la primera vez o porque es la primera vez de una nueva versión)?
Te explico lo que yo suelo hacer:
Habitualmente guardo la posición en que está el formulario principal, y para
saber si es la primera vez que leo esos datos, suelo asignarle a algunos de
esos datos (normalmente al valor de la posición izquierda) un valor inicial
de -999, de esa forma (si el valor devuelto por ese valor de la
configuración es el valor predeterminado) sé con seguridad que no se han leído los datos. Ya que
al cerrar el formulario siempre guardo la posición en los datos de
configuración, y salvo que "accidentalmente" tenga un valor de -999, pues...
ya sé que si tiene otro valor es que se ha guardado aunque sea una vez los
datos de configuración.
De todas formas, no quiero alargar más esto... supongo que si has usado
los valores de la configuración, ya habrás tenido oportunidad de ingeniarte
la forma de saber si es la primera vez que lees los datos o no.
Empecemos por el final, es decir, veamos
cómo guardar los datos de configuración cuando el formulario
principal de la aplicación se va a cerrar y así sabremos qué
datos son los que manejamos.
En el evento FormClosing escribe lo siguiente (se incluye
primero el código de Visual Basic y después el de C#):
Private Sub Form1_FormClosing(ByVal sender As Object, _
ByVal e As FormClosingEventArgs) _
Handles Me.FormClosing
' guardar los datos en la configuración
' Si el formulario no está en modo normal
' guardar los datos de la posición que tenía
' antes de minimizar o maximizar
If WindowState <> FormWindowState.Normal Then
My.Settings.Left = Me.RestoreBounds.Left
My.Settings.Top = Me.RestoreBounds.Top
Else
My.Settings.Left = Me.Left
My.Settings.Top = Me.Top
End If
My.Settings.Nombre = txtNombre.Text
' En VB no es necesario, pero por si alguien cambia
' la forma predeterminada de que se auto guarden los datos
My.Settings.Save()
End Sub
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// guardar los datos en la configuración
// Si el formulario no está en modo normal
// guardar los datos de la posición que tenía
// antes de minimizar o maximizar
if (WindowState != FormWindowState.Normal)
{
Properties.Settings.Default.Left = this.RestoreBounds.Left;
Properties.Settings.Default.Top = this.RestoreBounds.Top;
}
else
{
Properties.Settings.Default.Left = this.Left;
Properties.Settings.Default.Top = this.Top;
}
Properties.Settings.Default.Nombre = txtNombre.Text;
// En VB no es necesario, pero por si alguien cambia
// la forma predeterminada de que se auto guarden los datos
Properties.Settings.Default.Save();
}
Como puedes ver, se guardan los valores de la posición izquierda y superior
del formulario en dos valores de la configuración llamados Left
y Top. También se guarda lo que haya en una caja de textos
llamada txtNombre en el valor de configuración llamado
Nombre.
En Visual Basic los valores de configuración se manejan desde la
propiedad Settings definida en el objeto My,
en C# no existe un objeto similar a My, por tanto, para
acceder a los valores de la configuración debemos acceder a la propiedad
estática (compartida) Default definida en la clase
Settings.
En ambos lenguajes los valores de la configuración se guardan como
propiedades de la clase Settings (en
VB aunque se accede como a una propiedad, en realidad es también una clase
llamada Settings, cosas de facilitar las cosas... se supone... lo malo es
cuando hay que explicarlo o cuando uno se pone a indagar de dónde salen esas
propiedades "mágicas", en fin... ese trabajo extra que tenemos los que
usamos Visual Basic). Y en esa misma clase existe el método Save para
guardar los valores en el fichero de configuración. En Visual Basic, al
menos de forma predeterminada, se hace una llamada a ese método cuando se
cierra la aplicación, pero a mi me gusta indicarlo expresamente, así si se
cambia esa forma "automatizada" de guardar los valores de configuración, no
pasará nada y los datos se guardarán.
Otra cosa que puedes comprobar en ese código es que a la hora de guardar
los valores de la posición del formulario se tiene en cuenta si está
mostrado en forma normal o está minimizado o maximizado, y es que si no se
muestra de forma normal, los valores de la posición puede que no sean los
correctos, en esos casos, lo que hago es usar los valores de
RestoreBounds para saber cuáles eran antes de que se maximizara o
minimizara.
Ya que sabemos qué valores usamos y cómo se guardan, veamos qué habría
que hacer para leerlos y en caso de que queramos recuperar los valores de
una versión anterior, cómo lo haríamos.
Empecemos a complicarnos la vida (y ver lo que quería
mostrarte desde que empecé, es que cuando me
enrollo no hay quién me pare, jejeje).
Para poder probar esto que te muestro (y sepas cómo funciona) he creado
un proyecto (que puedes bajarte) en el cual he añadido un
CheckBox para saber si se deben leer los valores de la
versión anterior o no. Por supuesto ese CheckBox solo es para usarlo en
estas pruebas, ya que no tendría mucha utilidad en una aplicación normal...
pero bueno, es para que puedas hacer tus pruebas con los dos modos que te
muestro de recuperar la configuración de una versión anterior.
Nota:
En los comentarios del código fuente del formulario principal te
explico lo que debes hacer para hacer las pruebas
correspondientes y ver cómo funciona todo esto.
Para recuperar los valores de la configuración de una versión
anterior, lo más fácil es usar el método Upgrade
de la clase Settings, de esa forma, si hay
valores de alguna versión anterior, se usarán esos valores y se
asignarán todos los valores de configuración
con lo que hubiera en esa versión anterior.
Por supuesto la llamada a ese método no debes hacerla siempre,
solo la primera vez que leas los datos (recuerda eso que te
comenté arriba sobre el valor -999 de una de las propiedades),
ya que si siempre recuperas los valores anteriores... pues...
como que no tendrás oportunidad de guardar los nuevos valores,
ya que el método Upgrade lo que hace es
desechar los valores actuales (de la versión actual) y utilizar
los que hubiera de una versión anterior.
La otra forma de recuperar valores de configuración de una
versión anterior es hacerlo de forma "manual", es decir,
recuperar los datos de configuración uno a uno. Esto es práctico
cuando no necesitamos recuperar todos los valores. La forma de
hacerlo es por medio del método GetPreviousVersion
al cual debemos indicarle una cadena con el nombre de la
propiedad de la que queremos recuperar el valor de la versión
anterior. El problema de este método es que fallará si no existe
una versión anterior, por tanto habrá que usarlo con más cuidado
y teniendo en cuenta que se puede producir una excepción al
intentar acceder a un valor que no existe. Para usar este método
no es necesario hacer una llamada a Upgrade, ya
que si usamos Upgrade, no es necesario usar
GetPreviousVersion, ya que se recuperan todos los valores
de la versión anterior, por tanto, sería redundante usar el método
GetPreviousVersion después de haber recuperado los datos con
Upgrade.
Otro inconveniente que
tiene GetPreviousVersion es que el valor
devuelto es de tipo Object y habrá que hacer la
conversión correspondiente al tipo de datos adecuado (aclarar
que esto que acabo de decir solamente es cierto si usamos C# o si
usamos VB de la forma recomendada, es decir activando Option
Strict, ya que con Option Strict Off las conversiones entre tipos se
"intentan" hacer en tiempo de ejecución y aunque en las conversiones de este
ejemplo siempre funcionarán las conversiones "automáticas", es recomendable
hacerlas de forma explícita, por si falla la conversión saber que ahí es
donde se puede producir un error).
Veamos el código que he usado en el evento Load
del formulario de la aplicación de ejemplo, en el que se hace la
comprobación de si queremos usar los datos de la versión
anterior o no. En ese código se muestra tanto el método
Upgrade como el método GetPreviousVersion,
pero como ya te he comentado antes no se deben usar los dos al
mismo tiempo, y de hacerlo, es casi como perder el tiempo, al
menos si primero se hace la llamada al método Upgrade...
en fin... que salvo que lo necesites de forma expresa, te
recomiendo que uses Upgrade y no el otro
método... queda dicho.
Este es el código del evento Load, primero
para VB, después para C# (aclaración
por si alguien aún no distingue el código de uno y otro
lenguaje,
jejeje):
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As EventArgs) _
Handles MyBase.Load
If chkVersiones.Checked Then
' recuperar los datos de la versión anterior
' (esto actualizará todos los valores)
My.Settings.Upgrade()
' También se puede hacer
' con los valores individuales que nos interesen
' por si no queremos recuperarlos todos
txtNombre.Text = My.Settings.GetPreviousVersion("Nombre").ToString
Me.Left = CInt(My.Settings.GetPreviousVersion("Left"))
Me.Top = CInt(My.Settings.GetPreviousVersion("Top"))
' La recuperación de los valores anteriores fallará
' si se usa GetPreviousVersion desde la primera versión,
' sin embargo con Upgrade siempre funcionará.
Else
' La posición solo si se ha guardado anteriormente
If My.Settings.Left <> -999 Then
Me.Left = My.Settings.Left
Me.Top = My.Settings.Top
End If
txtNombre.Text = My.Settings.Nombre
End If
End Sub
private void Form1_Load(object sender, EventArgs e)
{
if (chkVersiones.Checked)
{
// recuperar los datos de la versión anterior
// (esto actualizará todos los valores)
Properties.Settings.Default.Upgrade();
// También se puede hacer
// con los valores individuales que nos interesen
// por si no queremos recuperarlos todos
txtNombre.Text =
Properties.Settings.Default.GetPreviousVersion("Nombre").ToString();
this.Left = (int)Properties.Settings.Default.GetPreviousVersion("Left");
this.Top = (int)Properties.Settings.Default.GetPreviousVersion("Top");
// La recuperación de los valores anteriores fallará
// si se usa GetPreviousVersion desde la primera versión,
// sin embargo con Upgrade siempre funcionará.
}
else
{
// La posición solo si se ha guardado anteriormente
if (Properties.Settings.Default.Left != -999)
{
this.Left = Properties.Settings.Default.Left;
this.Top = Properties.Settings.Default.Top;
}
txtNombre.Text = Properties.Settings.Default.Nombre;
}
}
Y esto es todo... espero que te haya sido de utilidad y que te sirva para
saber cómo recuperar los valores de configuración de una versión anterior...
ya que esa era la intención.
Nos vemos.
Guillermo