Archivo de la categoría: Visual Basic 2008

40 minutos perdidos por una tontería

Ayer hice el enésimo formulario de búsqueda (son aburridos de narices). Uno que me hacía falta para un usercontrol que forma parte de un asistente (vulgo, siguiente-siguiente-siguiente) que no sé en qué feliz día se me ocurrió que sería una buena idea. Hoy he embutido el usercontrol en un formulario de pruebas, para comprobar que hace lo que debe, y de paso ir ajustando tanto el usercontrol como el formulario de búsqueda: orden de tabulación, ámbito de los controles, propiedades varias.

En una de esas, el formulario de búsqueda ha decidido pasarse el ShowDialog por donde le da la gana y cerrarse sin hacer lo que debiera. Vale, partiendo de que no puede hacer eso, o sea, el ShowDialog es sagrado y que antes funcionaba, queda claro que alguien ha metido la pata. Como yo no he sido, la culpa debe ser, por narices, del manazas que comparte silla, ordenador y cuerpo con un servidor. Seguro que jugando con las propiedades de algo ha cambiado lo que no debía por error, y ahora no recuerda.

40 minutos después, 40 jodidos minutos de romperme la cabeza y revisar todos los controles (porque en ejecución paso a paso nothing de nothing) encuentro la causa: botón que tiene la propiedad DialogResult a algo que no es None. Creo que tocando algunas cosas del formulario asigné como AcceptButton o CancelButton al botón, luego lo quité, pero la propiedad DialogResult del puñetero botón siguió asignada.

En fin, el diseñador de Visual Studio ahorra trabajo, pero a veces dan ganas de pasar de él y escribir el código uno mismo.

MenuStrip heredado y vista diseño

Esto es un problema viejo y es fácil encontrar soluciones en Google, pero, bueno, supongo que repetirlo una vez más no viene mal.

La situación es la siguiente: tengo un formulario base, a modo de plantilla, que lo uso cuando tengo acceso a datos. Tiene una serie de controles y métodos entre los que se encuentra un MenuStrip con varios ToolStripMenuItem. Es un control (él y sus ítems) que da problemas con el diseñador de formularios de Visual Studio cuando es un control heredado. Aparece como de sólo lectura y no nos deja trabajar con él y lo digo en serio: no podemos añadir elementos al menú en vista diseño, ni cambiar ninguna propiedad (ni siquiera el texto mostrado) de los ítems que ya tenga. Tenemos que hacerlo directamente en código. Lo que es más incómodo: no podemos controlar un evento de un elemento ya existente.

Sigue leyendo

Un formulario para varias tablas

Digamos que tengo una docena de tablas con la misma estructura: 3 campos (Id para la clave primaria, Nombre y Descripción) con las mismas características. Estas tablas, además, van a tener pocos registros, no llegarán a 20. Concretamente, forman parte de una base de datos de series y películas y almacenan los datos de, por ejemplo, códecs, formatos de archivo, resoluciones, el soporte (DVD, CD, disco duro) donde están almacenados, etc. La pregunta es ¿cómo gestiono el contenido de estas tablas (altas, bajas y modificaciones)? A cada cual se le ocurrirá una opción, la mía, con pocas ganas de complicarme la vida, es la siguiente:

Tengo un formulario sencillo con los siguientes elementos: un ListBox que mostrará el nombre de todos los elementos de la tabla y servirá para navegar por los registros, dos TextBox, uno para el Nombre y otro para la Descripción, con sus respectivas etiquetas, y los controles necesarios para la gestión (podrían ser botones, pero yo uso un MenuStrip): Nuevo, Modificar, Eliminar, Aceptar y Cancelar. Añadimos un BindingSource a la ecuación y, si nos olvidamos por el momento de la generación de la clave primaria, esto ya está hecho, independientemente de lo que pongamos debajo del BindingSource.

Sigue leyendo

Corrigiendo un… problema de diseño con un evento

Si ya me lo decían: “no vayas a Z’ha’dum“. Pero yo, ni caso. Me puse a hacer una interfaz MDI tan ricamente para la aplicación de fábrica sin pensarlo con detenimiento (eso también me lo decían, en este caso Coco y Barrio Sésamo, lo de “tienes que planificar”, pero, igualmente, ni caso) y ahora me encuentro con lo normal: mucho impedirle cambiar de registro cuando está modificando una pieza, por ejemplo, pero nada le impide irse a otro formulario a trastear allí. Y, como es un luser, lo hará. O sea, que me pueden coger en un renuncio (error de concurrencia en el mejor de los casos) sin necesidad de tener dos lusers, con uno me basta y sobra.

Vale, que no cunda el pánico. Pensemos. O cubro bien todas las posibilidades o me curo en salud y no le dejo tocar al usuario donde no deba. Como soy alumno de mi profe, he optado por lo segundo. Así que quiero que cuando el luser quiera modificar o dar de alta “algo” en uno de los formularios, todos los demás se hagan los suecos (disabled). Pregunta: ¿cómo lo hago?

Sigue leyendo

Error al acceder a una DataRow borrada mediante una consulta LINQ to DataSet

Estaba haciendo unas pruebas a una parte de la aplicación de fábrica que debería funcionar cuando me casca todo, de manera catastrófica, dando un bonito y magnífico error de DeletedRowInaccessibleException, así, en mi cara. Estaba añadiendo, borrando y modificando varias filas de un datatable y, en un momento dado, ha intentado acceder a una de las filas borradas. Guay.

Rastreando el error lo he encontrado en una sentencia LINQ que se ejecuta sobre la datatable. La muy puñetera arrampla con todo y, claro, lo que está borrado está borrado aunque siga estando ahí. Tsktsktsk.

La solución ha sido rápida: añadir una cláusula WHERE a la sentencia LINQ para que no incluya las filas borradas. O sea, algo como:

Where Fila.RowState <> DataRowState.Deleted

Mover los elementos de un ListBox

Hay veces que lo que parece más simple da unos dolores de cabeza terribles. Estaba yo, feliz y despistado, queriendo montar un listbox y dos botoncitos, uno con una flecha para arriba y otro con una flecha para abajo, de forma que, al pulsar el botoncito con la flecha hacia arriba, el elemento seleccionado en el listbox intercambie su posición con el que tiene encima (vulgo, suba) y cuando pulse sobre el botoncito con la flecha para abajo… en fin, creo que os lo imagináis.

Pues tiene su aquél. Bueno, vale, no tiene mucho “aquél” pero me ha costado un buen rato dar con la tecla. O sea, sacar el elemento, borrarlo, insertarlo en su nueva posición. Ahora mismo no estoy seguro, pero creo haber hecho algo parecido en VB6 sin necesidad de dar tantos pasos. Por ejemplo, el código del click del botón de subir quedaría más o menos así:

Dim MiMecanizado As MecanizadoPieza
Dim i As Integer = Me.lstOrdenMecanizado.SelectedIndex
If i > 0 Then
    MiMecanizado = TryCast(Me.lstOrdenMecanizado.SelectedItem, _
                          MecanizadoPieza)
    If MiMecanizado Is Nothing Then Exit Sub
    Me.lstOrdenMecanizado.Items.RemoveAt(i)
    Me.lstOrdenMecanizado.Items.Insert(i - 1, MiMecanizado)
    Me.lstOrdenMecanizado.SelectedIndex = i - 1
End If

Donde MecanizadoPieza es una clase que incluye un campo Descripción (DisplayMember) y un campo Id (ValueMember) y lstOrdenMecanizado es el listbox de marras.

Si alguien lo encuentra útil, pues mejor.

Trasteando en un dataset: seguimos jugando con valores timestamp

Hace unas semanas hablé de usar valores timestamp para controlar la versión del registro de cara a controlar a su vez los problemas de concurrencia, para actualizar datos, etc. Hoy voy a dar un posible uso a todo eso, usando dataset tipados. Vamos a trabajar con una tabla de ejemplo. Supongamos que:

  1. La tabla en cuestión tiene definida una columna, Control, del tipo timestamp.

  2. En el TableAdapter correspondiente hemos añadido dos consultas: una que nos recupera el MAX(Control) de la tabla (el valor más alto de control) y otra que nos devuelve las filas actualizadas desde que obtuvimos ese MAX(Control), o sea, aquellas cuyo valor timestamp sea mayor que el que tenemos guardado.

Sigue leyendo

No es conmutativo, no

Supongamos lo siguiente: tengo un formulario con, entre otros, los siguientes controles:

  1. Un ListBox que se usa como control de navegación. En este caso, muestra los nombres de todos los clientes. Está enlazado mediante un BindingSource a la DataTable de clientes.

  2. Un TextBox que muestra la fecha de adquisición de “algo” por el cliente.

  3. Un DateTimePicker que permite seleccionar la fecha de adquisición de “algo” por el cliente.

El DateTimePicker no se muestra cuando estamos en modo “Ver datos”, sólo al crear o modificar un “algo” comprado por el cliente. Para ello tenemos un método que se encarga de que en modo “Ver datos” se vea el ListBox y el TextBox y en modo “Altas y modificaciones de algos” se vea el DateTimePicker y no el ListBox ni el TextBox.

Hasta aquí sencillo, ¿no?

Bien, pues si al pasar a modo “Ver datos” el orden es el siguiente:

MiListBox.Visible = True

MiDateTimePicker.Visible = False

MiTextBox.Visible = True

Si el DateTimePicker tiene el foco se selecciona el último cliente que hay en el ListBox. Sin embargo, si el orden es:

MiListBox.Visible = True

MiTextBox.Visible = True

MiDateTimePicker.Visible = False

Se queda seleccionado el cliente en el que estaba.

Supongo que sus razones habrá, pero a mí me lleva dando la tarde. Y no ha sido mucho tiempo porque la gestión de las Visitas también tiene su DateTimePicker y su TextBox, pero por casualidad en el orden correcto y sólo he tenido que comparar línea a línea qué se hacía en Visitas y no en “algos”, que si no…

Jugando con DataTables

Hace unos días veíamos una forma de trabajar con una relación m:n usando LINQ. En esta ocasión vamos a ver otra posibilidad y no voy a poner código, que ando mal de tiempo, así que a ver si consigo explicarme bien.

Supongamos que tengo dos tablas, Series y Personajes. Entre ellas hay una relación n:m (una serie tiene varios personajes, un personaje puede salir en varias series). La tabla que nos permite esta relación digamos que se llama PersonajesDeSerie y que sólo tiene dos campos: IdSerie e IdPersonaje. Por otra parte, en el formulario de personajes, que es donde podemos añadir las series donde aparece el mismo, queremos mostrar el título de la serie y el año de producción (podían ser más cosas, pero tampoco es plan de complicar el ejemplo). Para facilitar las cosas, nos creamos una vista en la base de datos que metemos como DataTable en el DataSet de Personajes. Es decir, tengo tres DataTable: Personajes, PersonajesDeSerie y vMisSeries, ésta última con los campos IdPersonaje, IdSerie, Titulo y Año. En mi caso, metidos en el mismo DataSet por comodidad.

Sigue leyendo

Un ListBox y una relación n:m

Supongamos que tenemos una relación n:m facilita. Por ejemplo, series y los géneros de estas series. Digamos que tengo mi tabla de series con su clave primaria IdSeries, mi tabla de géneros con su clave IdGenero y la otra que tiene únicamente los campos IdSerie e IdGenero para hacer la relación. Digamos también que quiero mostrar los géneros de cada serie en un ListBox, que llamaremos lstGeneros. Y digamos, de paso, que quiero usar ese ListBox no sólo para mostrar los géneros de la serie, sino también para seleccionarlos en altas y modificaciones. Uhm, ya la cosa se complica.

Vayamos por partes: visualización. Esto es lo más fácil y hay opciones para todos los gustos. Por ejemplo, podría generar una vista en la base de datos que me englobase las tablas de género y “géneros de series” y montar un dataset tipado con la tabla de series, la vista y la relación entre ambas. De ahí a montar un maestro-detalle de tutorial, sólo que con un listbox en lugar de un datagridview, sólo hay un paso.

Sigue leyendo