Pegar datos de una hoja de Excel a un DataGridView

Un intento de simplificar el uso de una aplicación por lo demás bastante simple (de cara al usuario) me ha llevado a jugar con el portapapeles para permitir que el usuario copie una serie de valores de una hoja de cálculo (Excel, para más señas) y las pegue en un DataGridView, algo que me ha costado un buen rato, no porque sea complicado, sino porque no he encontrado información al respecto por Internet (seguramente por la torpeza «buscativa» de uno).

El problema, como digo, no es complicado. Por una parte, acceder al portapapeles es muy sencillo, mediante My.Computer.Clipboard y hay varios métodos para extraer su contenido según lo que contenga. En este caso (la copia de texto) usaremos el método GetText, que nos devuelve un String. El dónde gestionar esto ya queda a gusto del consumidor pero, para mí, lo más fácil es añadir un menú contextual con el habitual atajo de teclado (Ctrl + V).

El siguiente paso es tratar ese texto. Cualquier colección de celdas de Excel es copiada al portapapeles como un conjunto de valores separados por tabulación. El otro día mostraba el uso de la clase TextFieldParser para procesar ficheros de texto que nos viene como anillo al dedo. Bueno, casi, porque al TextFieldParser no le podemos pasar un String, está pensado para procesar ficheros. Si vemos sus constructores, a uno se le pasa la ruta de un fichero, a otro un Stream, precisamente para tratar con un fichero, y a la tercera sobrecarga, un TextReader.

¿Qué es un TextReader (era la primera vez que lo veía)? Según la biblioteca de MSDN, TextReader es la clase abstracta de StreamReader (éste si lo conocía) y StringReader. Éste último tiene en su nombre la palabra mágica, String, así que merece la pena echar un ojo. Me da igual los tutoriales que nos puedan aparecer ni los mil usos que tenga StringReader. Para el caso que nos ocupa, todo se reduce a crear un StringReader a partir del texto contenido en el portapapeles:

Dim miTexto As StringReader

miTexto = New StringReader(My.Computer.Clipboard.GetText)

Y pasarle ese StringReader a un TextFieldParser, con lo que estamos casi, casi, en el mismo caso del ejemplo de TextFieldParser. Ya podemos trabajar de forma simple con el texto del portapapeles. Sólo hay que añadir los controles de errores necesarios y decidir qué vamos a hacer con cada fila válida devuelta por el TextFieldParser. Siguiendo la lógica del título de esta entrada, pasárselas al DataGridView, pero tengo que confesar que no lo hice así. La razón es muy simple: me interesaba más pasárselo directamente al origen de datos del DataGridView.

Para mi caso concreto (Origen de datos + BindingSource + DataGridView), antes de iniciar el proceso de lectura de TextFieldParser, llamé al CancelEdit del BindingSource para evitar la posibilidad de que se generase una fila en blanco o no válida (si se da el caso, se saltaría la validación de datos) y le quité también la referencia al DataSource:

Me.bsArticulos.CancelEdit()

Me.bsArticulos.DataSource = «»

Después de añadir los valores del portapapeles al origen de datos, se vuelve a enlazar el BindingSource con éste y listo. Bueno, vale, no he pegado realmente en el DataGridView. Espero que nadie se sienta estafado.

Nos vemos en el Forlon.

¿No con Outlook?

Mi viejo HTC Touch empieza a darme problemas. Le ha dado por reiniciarse en mitad de una llamada, de forma aleatoria. El problema es que, claro, al que llama se le corta la llamada igual que si se la hubiera cortado deliberadamente, pero a mí no me queda constancia de la misma. Aprovechando que estamos en Navidades y suele haber ofertas varias para estas fechas, he empezado a buscar un posible sustituto. En su día me llamó bastante la atención las noticias que salían sobre el futuro Windows Phone 7 (o Windows Mobile 7), así que mi primera opción ahora que ya ha salido ha sido buscar un terminal con este sistema operativo, encontrando uno muy majo.

El siguiente paso ha sido buscar información concreta sobre Windows Phone 7. Tras una somera búsqueda, unos comentarios preocupantes y una búsqueda más a fondo, se me ha quedado una cara de tonto que espanta. Menor, claro está, que si me hubiera dado cuenta de la tontería que han hecho en Spectra después de comprarme un terminal.

Así, sin anestesia: no hay forma humana de sincronizar contactos, tareas y calendario de Outlook con el nuevo Phone 7. No voy a preguntarme quién es el lumbreras a quien se le ha ocurrido semejante estupidez. Tengo otra pregunta más importante.

Y ahora, ¿qué? ¿Qué opciones tengo?

1) Esperar a ver si consigo hacerme con un terminal con Windows Mobile 6.5 a buen precio, algún resto de stock o similar.

2) Volver a Symbian.

3) Pasarme a Android.

4) ¿?

En todo caso, mis necesidades son simples: sincronización de contactos, tareas y calendario con Outlook. Que sirva para llamar y mandar SMS. Que tenga wi-fi. Y que me permita editar documentos de Word y Excel. Se valorará que haya una versión de SCUMMVM para él.

Me encanta mi trabajo

Hay días que me reconcilio con mi profesión. Días que me recuerdan lo estimulante que es ser administrador de sistema o comedor de marrones en general. Días que me demuestran que los ingenieros crean hermosas máquinas, pero los fp somos el lubricante que las permite funcionar. Hoy ha sido uno de esos días. Un día horroroso. Un día genial. Un día de recordar viejas entradas leídas en blogs y foros, día de darle caña al Process Explorer y rastrear lo que hace un programa al arrancar. Y a partir de ahí intentar entender qué quiso hacer el programador, pasar de ver el qué hace el programa al porqué lo hace. Y luego, los ojos lagrimeando de tanto ver líneas que indican accesos al registro y a archivos, de revisar los archivos de la aplicación y buscar dónde se guarda lo que estamos buscando, encontrar con que no hay forma de averiguarlo. No, por lo menos, con mis conocimientos.

Día perdido.

Pero el olfato está ahí. Sacando posibilidades de supuestos totalmente inconexos. Olfato, olfato, idea, prueba y… ¡bingo!

Problema resuelto.

Hay a quien le gusta los sudokus o los puzles. A mí que me den un problema interesante. Que las cabezas sesudas se preocupen de conquistar países, que yo pongo los puentes.

Leer ficheros csv y de campos de ancho fijo en Visual Basic

En mi vuelta al servicio activo he tenido que procesar dos ficheros en texto plano: uno con campos separados por un carácter y otro con campos de ancho fijo. En su día ya lo hice (concretamente para un csv, valores separados por comas), pero no me acordaba de cómo lo hice (fue al poco de empezar con VB2005) y no tenía a mano ni el código que hice ni el libro que usé de referencia, así que busqué en Internet.

Y fíjese usted por donde, encontré una forma más simple de hacer las cosas que no conocía: usando la clase TextFieldParser.

En la forma más fácil, le pasamos en el constructor la ruta del archivo a tratar. Le indicamos luego qué es, si de ancho fijo (FixedWith) o separado por carácter (Delimited) con la propiedad TextFieldType. Si es el segundo caso, con el método SetDelimiters indicamos el delimitador (por ejemplo, MiTfp.SetDelimiters(vbTab) para indicar campos separados por una tabulación).

En el primero, indicaríamos el ancho de los campos mediante una lista de enteros que le pasamos al método SetFieldWiths: MiTfp.SetFieldWiths(2, 3, 12, 85, 5).

Para leer cada línea tenemos el método ReadFields, que nos devuelve un array de cadenas con cada campo de la línea del fichero en la posición correspondiente del array. Se tarda más en explicar que en hacer.

Hay un pequeño problema adicional: la codificación de caracteres. Por defecto, se usa UTF8. Ahora mismo no recuerdo si Vista y 7 usan UTF8 por defecto, pero XP y versiones anteriores de Windows, no, y podemos encontrarnos con problemas con algunos caracteres, como ñ, tildes, etc. En ese caso, seguramente estemos usando Windows occidental (Windows 1252) o, más raramente, ISO-8859-1. Podemos indicarle esto al TextFieldParser en el constructor, pasándole el código de la página de códigos a emplear:

Dim MiTfp as New TextFieldParser(MiRuta, System.Text.Encoding.GetEncoding(1252))

Lo más largo, como siempre, es el control de errores, o el propio tratamiento de los valores que hayamos leído, pero el hecho de leer en sí más simple no puede ser.

DataRepeater y el evento Enter de sus controles

A la hora de evitar que el usuario manazas edite el valor de algún control, una opción habitual es controlar el evento Enter de ese control o de su contenedor (un GroupBox, un Panel…), mandando el foco a otro control mediante el método OtroControl.Select(). Esto funciona para buena parte de los controles disponibles en Windows Forms, pero no para todos (dtpicker, optionbutton… hay varios que pasarán de nosotros).

Si nosotros queremos usar este sistema con controles que estén dentro de un DataRepeater… En fin, probadlo si queréis, pero ya os digo que la aplicación se quedará muerta si mandáis el foco a un control que esté fuera del DataRepeater. ¿Entonces?

Pues no salgamos. Pasemos el foco al ítem del DataRepeater al que pertenezca el control y listo:

MiDataRepeater.CurrentItem.Select()

El control DataRepeater es más versátil que el habitual DataGridView, pero es caprichoso como él solo.

Evitar error en consultas de agregado de LINQ

Nombre pomposo de la entrada pero que contesta a un problema que se me ha presentado esta mañana (volver a trabajar tiene estas cosas): al calcular el valor máximo de un campo en un conjunto de datos con una consulta LINQ sobre un dataset (por ejemplo, el importe más alto de un determinado cliente) se producía una excepción si no se devuelve ningún valor (en el ejemplo, si ese cliente no tiene pedidos). Una búsqueda por Internet me ha apuntado como solución usar extensiones de métodos, algo que no domino y se me antojaba excesivamente complicado para la tarea.

Tras pensarlo un poco, he probado a convertir el valor del campo pasado a la instrucción MAX a un tipo Nullable, que acepta valores nulos. En mi caso, como era valores enteros, esa parte de la consulta LINQ quedaría tal que así:

Into Max(Ctype(Fila.Campo, Integer?))

La consulta ya no da error, y sólo nos queda controlar si hay valor devuelto (propiedad HasValue), convertirlo al tipo que queramos (Integer, en el ejemplo) y seguir adelante. Más sencillo se me hace que otras ideas que he visto por ahí, y más rápido.

Como siempre, si a alguien le resulta de utilidad, pues mejor.

Sincronizando el portátil y el sobremesa con SyncToy

Cuando tenía el 286 terminaba con múltiples copias de mis documentos (en aquel lejano entonces de WordPrefect 5.1) en el disco duro y en un montón de disquetes, así que me costaba Dios y ayuda dar con la versión adecuada del archivo. Ahora que uso dos ordenadores, varios discos duros externos y un puñado de memorias USB el lío es tremendo y he llegado a apañármelas para borrar los únicos que no tenían copia de respaldo. Sincronizar de alguna manera este lío de documentos, imágenes y algunas otras cosas se había vuelto una necesidad imperiosa desde la llegada de la Ono-Sendai. Hasta entonces había recurrido al Maletín presente en Windows desde tiempo inmemorial, y lo sigo usando para las memorias USB.

Ahora, a la hora de sincronizar documentos, la moda es usar un sistema de almacenamiento en la nube y poder conectarnos desde cualquier parte. Para mí este procedimiento tiene tres problemas: debo tener acceso a Internet, mis datos viajan alegremente por el ciberespacio y tengo que confiar en que la empresa que sea me siga prestando ese servicio. Así que busqué otra opción que sólo necesitara de red local, fuera fácil y gratuito.

La herramienta que he usado es de Microsoft y se llama SyncToy. Es compatible con Windows 7 y está presente en versiones de 32 y 64bits. Yo lo he usado para mantener sincronizadas las carpetas de Mis imágenes, Mis documentos y otras dos de discos duros externos entre el sobremesa y el portátil. Ha sido sencillo, rápido y cómodo, tanto configurar la sincronización como ejecutarla días después. No es una herramienta muy potente, pero me da lo que le pido.

Tenía pensado hacer un tutorial al respecto, pero resulta que es bastante popular y hay varios en la red. Os dejo este para revisar. Es breve, pero completo.

Nota final: como todo lo que sea en red tendremos que enfrentarnos a los permisos. La forma más cómoda es tener el mismo usuario y contraseña en los dos equipos. Ahorra muchos quebraderos de cabeza.

Solo es un gato

Es tremenda la indefensión que sufrimos con Internet. La noticia me llena de espanto y quiero creer que en España, con nuestra Agencia de Protección de Datos, tal cosa no pasaría o, por lo menos, al tipo en cuestión lo crujirían vivo (y a cierta prensa, de paso). Pero en el Reino Unido las cosas funcionan de otro modo. Cualquier mención a introducir un carné de identidad es visto como un terrible atentado contra la intimidad de las personas, sacar fotografías a edificios y monumentos por parte de los turistas, como un posible acto de terrorismo y el servicio de Google Street View es ambas cosas. Pero un tipo puede poner cámaras en su casa grabando la calle, colgar parte de esas grabaciones en Youtube y destrozarle la vida a una persona, que ahora se ve amenazada de muerte, debe llevar escolta policial y se encuentra marcada de por vida. A ese vídeo (y gracias a él) le siguió su nombre, dirección, teléfono, correo electrónico, perfiles en redes sociales… Algo terrorífico, un atentado contra la intimidad impensable en otra época.

Y, mientras, la gente mirando para otro lado, embobados con la historia de un lindo gatito (¡es cierto, es cierto, es un lindo gatito!), sin darse cuenta de la burrada de la situación y de que las autoridades siguen mirando para otro lado. Esto lo ha hecho un tipo cabreado y con ganas de venganza y la típica turba que se suma al linchamiento sin pensar, esa turba que tan bien retrató Fritz Lang en Furia. Y lo hacen las empresas y lo hace el estado. Y nosotros seguimos poniendo la cama.

Da miedo.

Poco a poco, de vuelta

Bueno, se me acabaron las vacaciones. Vale, no es exacto, ya que llevo de vacaciones forzosas más tiempo del que me gusta recordar, pero por lo menos tengo algo que hacer. Un curso interesante y, en principio, de buen nivel de Java, y encontrar algo así por aquí es como encontrar una cosa negra, pegajosa y más o menos líquida. Dejando de lado que aprender siempre es divertido y estimulante, espero que me abra puertas para ganarme los garbanzos. Por otra parte, el cambio de no tener nada que hacer realmente (sí, un montón de cosas, pero es tan fácil entrar en una espiral de nadismo) a tener las mañanas ocupadas igual consigue que entre en modo hiperactivo, que me deja baldado pero es muy gratificante. A ver si con esto retomo el blog, que anda casi abandonado, y los tutoriales que tengo a medio hacer o por terminar, tanto aquí como en el foro. Y saco tiempo para Visual Basic 2010, que seguro que con tanto Java lo termino echando de menos.

Me imagino que alguno me diréis que Java es la leche, o que el lenguaje es como C, que es lo mejor de lo mejor, pero a mí me gusta imprimirme los programas y atacar los problemas leyéndolo en voz alta y corrigiendo con rotulador fosforito y boli bic y para eso Basic es más apropiado. C y derivados (Java, C#, PHP) me dan la impresión de estar leyendo klingon y siempre termino con dolor de garganta. Además, ¿cómo demonios se pronuncia «{«? Gracias a Apple, ya sé cómo se pronuncia ! (ay!fon), pero { se me resiste y tengo grandes problemas con ciertos fonemas, así que prefiero lenguajes más… literarios.

El caso de los niñatos

Nos pasa en el foro de vez en cuando que nos entran, como plaga de langosta, un grupo de niñatos que nos inunda de mensajes chorras. Como vienen todos a la vez y desde la misma IP y en horas lectivas (en su país de origen), los moderadores creemos que igual es alguna clase de informática donde el profesor les «enseña» lo que son los foros y les hace dar por culo a los foreros haciendo alguna consulta. Pensamos esto por la riqueza idiomática y léxica de los mensajes, la desidia de su redacción (apenas una línea), lo chorra de lo planteado (en resumen, nada) y que sean todos en tan poco espacio de tiempo. Y, también, porque el aquí firmante ha sufrido una de esas clases. Que está bien enseñar la existencia de foros, y más si hablamos de foros técnicos y un FP de informática, como era el caso, pero creo más importante el cómo debe comportarse uno en un foro que el cómo crear o responder a un mensaje. Si de eso se trata, que se monten un foro para cacharrear en clase y nos dejen a los demás vivir en paz.

Esta vez los he pillado pronto, con sólo tres o cuatro mensajes y les he aplicado el correctivo de rigor: eliminación de mensajes y baneo de la IP por una temporada. A ver cuánto tiempo pasa hasta la siguiente clase práctica.