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

Filtrar y apilar

Todo el mundo sabe, a tenor de lo que se cuenta en Internet, que Vista es menos usable (curioso palabro) que XP y el rendimiento es, igualmente, menor. Por ejemplo, si yo necesito encontrar un archivo que fue modificado el miércoles o el jueves pasado en una carpeta con unos doscientos archivos, en XP es tan fácil como abrir el menú contextual con el botón derecho del ratón y elegir Organizar iconos, Modificado y así tendré todo el contenido ordenado por la fecha en orden ascendente. Si quiero orden descendente, debo primero poner la Vista detalles. Puedo marcar la opción Mostrar en grupos y así tendré algo más manejable y en orden descendente (primero lo de hoy, luego lo de ayer, y así).

En Vista es mucho más largo, complicado y lento. Tengo que desplegar Fecha modificación, seleccionar (pinchar y arrastrar) los días y se me filtra el contenido, de forma que sólo se mostrarán aquellos archivos modificados en esas fechas. En fin, desde mi punto de vista de vago altamente especializado, sé qué me gustaría tener en el curro. 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…