Todas las entradas de: Juanjo Montiel

Controles HTML no nativos. ¿Son accesibles?

Ayer os contaba por twitter que las tablas con scroll infinito eran un infierno para los lectores de pantalla. Para explicaros el porqué, pensaba hacer un hilo, pero me ha salido tan largo que al final os lo pongo en un post 😉

Los lectores de pantalla interceptan casi todas las teclas cuando estamos en un navegador, para proporcionarnos numerosos atajos de teclado que nos permiten la navegación de forma cómoda por un sitio web.

Por ejemplo: si pulsamos la e nos moveremos entre cuadros de edición, b entre botones, t entre tablas, h entre encabezados, y así con casi todos los tipos de controles que nos ofrece html.

Por tanto, si añadís eventos de teclado a vuestra web, a priori no van a funcionar, porque el lector no pasa las teclas al navegador y los eventos no se ejecutan.

Existen varios roles de “ARIA” que aplicados a un control, indican al lector de pantallas que dicho control es un control interactivo, y que dentro de él, las teclas deben pasar sin ser interceptadas. Alguno de estos roles son:

Imaginad entonces. Podéis poner el rol grid a una tabla con scroll infinito y así las flechas ya serán manejadas por el navegador. Sí, pero…

Para empezar, deberéis crear un completo mecanismo de manejo de esa tabla por teclado, utilizando flechas para que el usuario pueda moverse por todas las celdas de la tabla, programar teclas para ir al inicio y fin de la misma, ETC. Y siempre, marcando las celdas como focalizables y aplicando el foco a cada una cuando se produzca el movimiento.

Y ahora pensad en el usuario, que está acostumbrado a moverse por una tabla utilizando su lector de pantallas y las teclas rápidas que éste le proporciona, y de repente no puede hacerlo.
Con un lector de pantallas, dentro de una tabla, podemos usar las flechas para leer carácter a carácter una palabra, pulsar control + flechas para ir a la siguiente palabra… Con un grid que se maneja con flechas, no podríamos ni siquiera analizar el contenido de la celda.

Y por si esto fuera poco, comentaros que el soporte de “ARIA” y de manejo de foco durante una sesión dentro de un widget no es igual de buena en todos los navegadores ni con todos los lectores de pantalla, por lo que la experiencia puede variar de buena a pésima en función de qué combinación de lector y navegador se utilice. Por ejemplo, en las hojas de cálculo de google, con JAWS e IE va lentísima la navegación y con NVDA y Firefox funciona súper bien.

¿Alternativas sencillas? Podéis dejar el scroll infinito si poner el rol de application, pero colocar un botón (incluso ocultándolo visualmente para que solo sea legible por lectores de pantalla), que cargue más resultados… O un sistema de paginación oculto visualmente.

Ocurre lo mismo con controles no nativos como presentaciones en árbol y presentaciones en lista. Hay implementaciones de estos controles que funcionan perfectamente con Firefox y JAWS, y no funcionan en absoluto con Internet Explorer o Edge, y JAWS o NVDA…

En la actualidad, la única forma de asegurarnos que algo complejo hecho con “ARIA” funcionará con todas las combinaciones es no hacerlo, pues casi siempre habrá un lector, un navegador, o la combinación de ambos, que hará que vuestro invento no funcione. Es por eso Por lo que digo que el soporte de “ARIA” es muy inestable y da unos dolores de cabeza que no os imagináis.

Y ahora viene la parte en la que cruzo la línea y me sitúo en la perspectiva de un desarrollador, que para algo juego a dos bandas 😉

El problema de todo esto es que hoy en día creo que tampoco tiene sentido decirle a un desarrollador que no puede utilizar una presentación en árbol en un formulario para elegir una opción dentro de un árbol jerárquico, por ejemplo, máxime cuando en teoría esto debería estar soportado usando ARIA de forma correcta.

Así que en mi opinión, sí que hay momentos en los que usar “ARIA” es la única solución viable en el mundo real, pero hay que luchar porque el soporte de la especificación sea completo tanto para lectores de pantalla como para los navegadores actuales, y sobre todo, utilizarla de forma correcta.

A más compleja la web, más compleja la accesibilidad, sobre todo si se quiere hacer una experiencia cercana al mundo desktop, ya que normalmente, para conseguir esto hay que utilizar controles no nativos. No hay más que ver, por ejemplo, webs como la del portal de Azure, que a pesar de que intentan (me consta de primera mano) hacerla lo más accesible posible, hay sitios en los que han usado tanto “ARIA” y con mecanismos tan complejos que es una locura.

¿Conclusión? Siempre y cuando podáis usar controles nativos, hacedlo. Nos facilitaréis la vida una barbaridad, ya que estos controles ofrecen soporte nativo de accesibilidad. De hecho, la primera de las cinco reglas del uso de “ARIA” dice:

Si puede utilizar un elemento HTML nativo o un atributo con la semántica y el comportamiento que necesita ya incorporado, en lugar de redefinir el propósito de un elemento y añadir un rol, estado o propiedad ARIA para hacerlo accesible, hágalo.

Sin embargo, Si veis que vuestra funcionalidad requiere de controles no nativos y no queda más remedio, utilizad ARIA, con cuidado, mimo, y sobre todo, haciendo tests con la mayor cantidad de navegadores, sistemas operativos y lectores de pantalla posibles.

Y si tenéis dudas, ¡preguntad! Podéis encontrarme en Twitter como @kastwey.

Entrada visitada 306 veces

¡Desde el MVP Summit 2018!

Cuando Microsoft me premió con el MVP Award, no os podéis ni imaginar lo que significó. Ya no solo por el honor que supone para mí y todo lo que este premio conlleva, sino por sentir que había conseguido llegar donde nunca creí que llegaría.

Integrarse laboralmente en un mundo de personas que ven es difícil, en muchas ocasiones. La sociedad no está preparada para que una persona con discapacidad disfrute de las mismas oportunidades que los demás. Y el desarrollo de software no es la excepción.
Cuidado, ¡no quiero decir que llegar hasta aquí haya sido una carrera de obstáculos, una serie de peripecias y un constante trabajo de autosuperación! ¡Nada más lejos de la realidad! Lo que quiero decir es que siempre te encuentras obstáculos (en mi caso en forma de multitud de herramientas inaccesibles), pero nunca he sentido que me haya tenido que esforzar muchísimo más que el resto de mis compañeros para conseguir mis metas. Quizá ha sido suerte, en gran parte, y que he sabido buscarme los trucos para hacer accesible lo que no lo era, o al menos para ser capaz de buscar el atajo que me permitiera soslayar (que no romper ) una determinada barrera. La cuestión es que he sido capaz de tirar adelante y seguir trabajando de lo que me apasiona, aunque soy consciente de que las cosas serían más fáciles si todo fuera más accesible.

Allá por el 2000, cuando aún picaba en el block de notas, conocí Visual Basic 6.0. Y curiosamente, resultó que aquel entorno de programación era muy accesible para mi lector de pantallas. Tanto era así, que incluso nos permitía diseñar interfaces gráficas conociendo en todo momento si algún control se solapaba con otro, y en qué zonas de los mismos.
Conforme han ido evolucionando las versiones y pasamos a Visual Studio, han sido distintos los problemas y mejoras de accesibilidad que ha sufrido este entorno; pero hoy por hoy, puedo decir que es, sin duda alguna, la mejor herramienta de desarrollo con la que he trabajado nunca en términos de accesibilidad.
Gracias a ella he podido programar junto con mis compañeros, y he podido utilizar las mismas herramientas que ellos, con casi todas sus ventajas.

En fin, que me voy por las ramas.

La cosa es que gracias al MVP, he tenido la oportunidad de asistir al “MVP Summit” que se celebró la semana pasada en Seattle, en la sede de Microsoft en Redmon. Microsoft nos paga la estancia en un hotel chulísimo, y en mi caso, Pasiona me pagó el viaje (y los días que he estado fuera, claro); así que, ¡mil gracias para ellos! 🙂

Hace más o menos un mes y medio me contactaron desde Microsoft, y me ofrecieron la oportunidad de presentar una charla en el evento previo al “Summit”, el Pre-day, sobre la creación de presentaciones accesibles para todos… Así que pese a que sentía que todo aquello me quedaba grande, creí que era una oportunidad que no debía dejar pasar, y acepté.

Han sido un par de meses de trabajo intenso, porque quería montarles algo interesante que enseñar.
He desarrollado un visor de diapositivas accesible (la idea primigenia de esto me la dio Ramón Corominas cuando hace más de cuatro años nos presentó unas charlas de accesibilidad con un visor estático en HTML y javascript), y le he añadido algunas funcionalidades:

  • Traducción en tiempo real a sesenta y dos idiomas (gracias al translator de Azure Cognitive services).
  • Compartir las diapositivas desde una web donde la diapositiva en proyección se mostrará a todos los dispositivos conectados (Signal R power!) 😉
  • Proyección de subtítulos en tiempo real con lo que el presentador está contando (también traducibles en tiempo real al idioma seleccionado en la diapositiva para cada usuario conectado) (Speak to text, de Azure Cognitives services, again)
  • Interactuar con los asistentes a la charla, pudiendo crear encuestas durante la presentación, que todos los participantes podrán contestar desde sus dispositivos, y cuyos resultados el presentador podrá ver durante la proyección.

Un visor que en definitiva, intenta resolver las distintas barreras que una persona con discapacidad puede encontrarse a la hora de acceder a la proyección de una presentación, o las barreras que un presentador con discapacidad puede encontrarse a la hora de exponer en una charla.

Parece que a los asistentes a la charla les gustó el invento… y he de decir que gran parte del atractivo de la aplicación es gracias a mi amigo Jorge, un diseñador genial que convirtió un adefesio visual (lo mío es el back xD) en un diseño chulísimo 🙂 ¡Gracias tío!

Ahora mismo es solo una prueba de concepto, pero quiero publicar todo el código en github, para que no solo podáis usar la herramienta en vuestras presentaciones, sino para que también podáis colaborar en el desarrollo del proyecto si os apetece hacerlo.

¡En un próximo post os contaré más sobre el proyecto y sobre cómo podéis colaborar!

Son muchas las cosas que he aprendido, y muchas las personas interesantes a las que he conocido.
He tenido el inmenso placer de desvirtualizar a muchos MVP’s a los que solo conocía por Twitter, y que en persona resultaron ser un encanto. ¡Gracias a todos por hacerme sentir tan acogido!
He podido pasar más tiempo con mi compi de curro Carmen Checa (@cmcheca) (¡seguidla por Twitter, que le encanta! 😉 ), y la verdad es que me lo he pasado genial. ¡Gracias por echarme una mano con todo lo que he necesitado!

También conocí por fin en persona al crack de Carlos Mendible (@cmendibl3) (él me conocía del summit de Madrid, pero yo nunca le había visto 😛 ¡Vale, es un chiste muy malo, no me matéis, es viernes!. Fue mi compañero de habitación, y me ha soportado durante cuatro días ;). ¡Gracias por todo, compi! Además, ya hemos estado pensando en alguna que otra cosa que perpetrar juntos, así que os mantendremos informados 😉

Carmen, Carlos y yo.
Carmen, Carlos y yo.

Ha sido genial conocer a MVP’s de todo el mundo con los que he podido conversar (a pesar de mi deplorable inglés), y que también han sido super cercanos y pacientes con mis whats, mis “can yu ripit?” y mis “eeeh… ai zink aim not anderstanding yu! 😉 ¡Y cuál fue mi sorpresa cuando me encontré con Alexandre Costa, ¡otro MVP ciego que además tiene el honor de haber sido el primer MVP ciego del mundo! ¡No sabéis lo que mola poder hablar con alguien que se encuentra todos los días con tus mismos problemas usando las mismas tecnologías! 🙂

También he conocido a grandes estrellas (Miguel de Icaza (a quien abordé cual gruppie para contarle que gracias a Xamarin pude empezar en el mundo del desarrollo móvil de manera accesible), Scott Hanselman (que se acercó para pedirme un mail al que enviarme las slides de su presentación), a Julie Lerma (que tuvo una pequeña confusión con mi colega Alexandre Costa, pero que gracias a la cuál, acabamos teniendo una conversación más que interesante sobre vídeos de formación accesibles :), y también conocí a responsables de producto, como Jenny Lay-Flurrie (- Chief Accessibility Officer en Microsoft), a Leon Welicki (Principal Group Program Manager de Microsoft Azure)… Todos me han impresionado por su cercanía y por su buena disposición a abordar y resolver los problemas de accesibilidad de los mismos. Durante estos días he comprobado de primera mano que Microsoft está realmente comprometida con la accesibilidad, (y está poniendo mucho de su parte para mejorar los productos que desarrolla (aunque aún les quede mucho camino por recorrer en muchas cosas). Tengo el camino libre para reportar, ayudar y meterles caña, ¡así que es lo que voy a hacer, ahora que puedo estar más cerca de ellos!

Han sido tres días de sesiones intensas donde nos han enseñado muchas cosas que ya están o que estarán por venir, y algunas de ellas realmente me han encantado… ¡pero por ahora no puedo hablar de eso!

En definitiva, más de cuatro días donde he disfrutado como un niño con todo lo que nos tenían preparado los chicos de Microsoft. ¡Y de verdad que Whost y yo estuvimos allí! Tenemos una foto (no trucada) que lo demuestra!

También me gustaría agradecer a Cristina González, (nuestra MVP Lead), quien me acompañó en todo momento, se preocupó por que todo estuviera perfecto, y aguantó mis agobios cuando se acercaba la hora de mi charla el domingo, y a Molly Warner, quien se puso en contacto conmigo para darme la oportunidad de dar una charla en el pre-day, me brindó toda la ayuda que necesité para prepararla, e hizo que todo estuviera tal y como le pedí para que si algo fallara, fuera solo cosa mía 😉 ¡Mil gracias a las dos!

Y por último, aunque perfectamente podría haberlo puesto lo primero, agradecer a mi mujer, Núria (@amaterasu_n), pues gracias a que estuvo con el peque durante mis fines de semana de reclusión preparando la charla, y a que se encargó de todo por casa y cuidó al vikingo en solitario durante todo este tiempo, pude disfrutar de esta pedazo de experiencia. ¡Lo sé, los family points están en mínimos históricos, a ver cómo me lo monto para remontar! xDDD. ¡Gracias, amor!

Entrada visitada 492 veces

¡Las manos sobre el teclado! Algunas teclas rápidas para desengancharos del ratón en VS Studio

¡Hola!

El sábado pasado, tuve el honor de participar en la Dotnet Málaga 2017. Fue un eventazo (no porque yo fuera uno de los ponentes, que conste 😉 ). Fue el evento más grande al sur de España sobre tecnologías Microsoft. Participaron veintiún ponentes, y se ofrecieron quince charlas y dos talleres la mar de interesantes. ¡Y qué narices, que era en mi Málaga! 🙂

En este evento, di una charla sobre teclas rápidas en Visual Studio. Una manera de aumentar nuestra agilidad al programar, sin tener que estar levantando las manos del teclado cada dos por tres.

Este sábado, (aprovechando que tenía la charla aún fresca en la memoria), me colé en la agenda de las 4Sessions de la Fundación Techdencias de la que formo parte, y repetí la charla con algunas mejoras para hacerla algo menos tediosa 🙂 (¡Gracias Carmen y Nacho por las sugerencias!).

El único problema fue que, para intentar aligerar el ambiente y evitar que la gente desconectara demasiado, me dio por intentar hacer un par de trucos de magia, para demostrar que las manos son más rápidas que la vista. Y mirad, sí. Lo que demostré es que mejor voy a seguir dedicándome a programar, porque lo que es hacer magia, no se me da demasiado bien 😉

A parte del estrepitoso fracaso de hacer de trilero y enseñar trucos de cartas, lo cierto es que me lo pasé bien, y espero haber podido demostrar que, con un poco de memoria y práctica, podemos sacar un montón de partido a las potentes características de teclado de Visual Studio.

En realidad, al ser ciego, para mí el ratón es un elemento decorativo, de modo que las teclas rápidas son mi única manera de programar :). No obstante, y para mi fortuna, en este caso, no usar el ratón me supone una mejora, no lo contrario. Os aseguro que si os aprendéis los atajos más comunes, veréis cómo manejáis la herramienta mucho más rápido que si tenéis que estar quitando una mano, buscando los iconos con el ratón y volviendo a vuestro teclado.

En fin, que me voy por las ramas. Para que no me pase como siempre, me líe con otras cosas y al final no publique nada, aprovecho esta noche de domingo cuando nuestro peque duerme para hacer esta entrada en el blog, y poneros las teclas rápidas que expliqué en los dos eventos y que más utilizo en mi día a día con esta fenomenal herramienta que es Visual Studio.

¡Importante! Estos atajos vienen en el esquema “c#2005”. Si utilizáis otro esquema de teclado, todos estos atajos cambiarán. Podéis ver qué esquema está activo desde Tools > Options, pestaña “Keyboard”.

Los atajos están divididos en categorías para que os sea más fácil navegar por ellos.

En la columna de “Acción en VS”, he puesto el comando que ejecuta la acción indicada. Esto os servirá para encontrar dicho comando en las opciones de teclado de Visual Studio, y reasignar o añadir más teclas rápidas a los mismos si queréis.

Los atajos que contienen un asterisco (*), son aquellos que yo me he creado de manera personalizada. Para hacerlo vosotros, haced lo siguiente:

  1. id a las opciones de teclado de VS Studio (Tools / Options.
  2. Marcad la pestaña Keyboard.
  3. buscad el comando para el que queráis añadir la tecla (tenéis el nombre exacto en la columna Acción en VS). Podéis usar el cuadro de búsqueda para ello.
  4. Elegid en qué ventana queréis que ese comando funcione (marcad global si queréis que el atajo tenga efecto en todas las ventanas).
  5. Pulsad la combinación en el cuadro de asignación de atajo de teclado (podéis crear hasta dos combinaciones de teclas que tendréis que pulsar consecutivamente).
  6. Haced click en “Assign” y luego en “OK”.

A partir de ese momento, ya podréis hacer uso de ese atajo para ejecutar el comando.

Y ahora sí, vamos a por las teclas 🙂

¡Este código es un desastre!

¡Yo no he sido, esto ya estaba así cuando llegué!

Acción Atajo Acción en VS Descripción
Ordenar y eliminar usings ctrl+r, ctrl+g ProjectandSolutionContextMenus.Project.PowerCommands.RemoveandSortUsings Ordena los usings alfabéticamente y elimina los no necesarios
Acciones rápidas ctrl+. (punto) View.QuickActions Muestra el menú de opciones rápidas para el elemento actual
Comentar selección Ctrl+k, ctrl+c Edit.CommentSelection Comenta las líneas de código seleccionadas
Descomentar selección ctrl+k, ctrl+u Edit.UncommentSelection Descomenta las líneas seleccionadas
Formatear documento ctrl+e, d Edit.FormatDocument Formatea el documento abierto
Renombrar elemento f2 EditorContextMenus.CodeWindow.Refactor.RefactorRename Renombra un elemento, buscando sus referencias y renombrándolas también
Mover selección línea arriba alt+flecha arriba Edit.MoveSelectedLinesUp Mueve las líneas seleccionadas una línea hacia arriba
Mover selección línea abajo alt+flecha abajo Edit.MoveSelectedLinesDown Mueve las líneas seleccionadas una línea hacia abajo
Borrar línea ctrl+l (*) Edit.LineDelete Elimina la línea actual

¿dónde estoy? ¿dónde estaba? ¡Estoy perdido!

Cuando mi lector de pantallas me lee código, lo hace línea a línea, carácter a carácter o palabra a palabra. Yo no tengo una visión global de una ventana de código. Es por ello que, al menos para mí, es súper importante ser capaz de hacerme una idea global de dónde estoy, y sobre todo, ser capaz de moverme por los distintos elementos del código de forma rápida y no perderme nunca.

Acción Atajo Acción en VS Descripción
Ir a inicio o fin de bloque ctrl+ + (más) (*) Edit.GotoBrace Va al principio o fin del bloque actual
Método anterior ctrl+e,flecha arriba Edit.PreviousMethod Va al método anterior
Método siguiente ctrl+e,flecha abajo Edit.NextMethod Va al siguiente método
Crear marca ctrl+b, t Edit.ToggleBookmark Crea o elimina una marca en el punto seleccionado
Siguiente marca ctrl+b,n Edit.NextBookmark Va a la siguiente marca
Marca anterior ctrl+b,p Edit.PreviousBookmark Va a la marca anterior
Borrar todas las marcas ctrl+b,ctrl+c Edit.ClearBookmarks Elimina todas las marcas
Colapsar / expandir bloques ctrl+m, m Edit.ToggleOutliningExpansion Colapsa o expande el bloque actual
Volver el cursor atrás ctrl+- (guión) View.NavigateBackward Mueve el cursor a la posición anterior

Depurando ando

La depuración en Visual Studio es una de las cosas que más me gustan de esta herramienta. Y cómo no, tiene sus atajos para hacerlo aún más rápido.

Acción Atajo Acción en VS Descripción
Añadir breakpoint f9 Debug.ToggleBreakpoint Coloca o elimina un breakpoint bajo el cursor
Quitar todos los breakpoints ctrl+shift+f9 Debug.DeleteAllBreakpoints Quita todos los breakpoints de la solución.
Lista de breakpoints ctrl+d,b Debug.Breakpoints Muestra la ventana con la lista de los breakpoints de la solución
Breakpoint condicional alt+f9,c EditorContextMenus.CodeWindow.Breakpoint.BreakpointConditions Muestra la ventana para añadir condiciones a un breakpoint
Siguiente paso f10 Debug.StepOver Depura la siguiente instrucción de código
Depurar método f11 Debug.StepInto Depura el método seleccionado, entrando en él.
Salir del método shift+f11 Debug.StepOut Sale del método actual y continúa en el método padre
Detener depuración shift+f5 Debug.StopDebugging Detiene la sesión de depuración
Ejecutar sin depurar ctrl+f5 Debug.StartWithoutDebugging Ejecuta el proyecto de inicio sin depurar
Ventana de locales ctrl+d,l Debug.Locals
Quick watch ctrl+d,q Debug.QuickWatch Añade un "quick watch" de la instrucción seleccionada”
Ejecutar hasta el cursor ctrl+f10 Debug.RunToCursor Ejecuta la aplicación hasta el punto en el que tengamos situado el cursor

Dónde está mi código, matarile rile rile…

En proyectos grandes, es muy difícil recordar dónde están todas las cosas

Acción Atajo Acción en VS Descripción
Encontrar de todo en toda la solución ctrl+t Edit.GoToAll Busca en toda la solución: miembros, tipos, ficheros…
Ir a la línea ctrl+g Edit.GoTo Va a la línea que deseemos dentro del archivo actual
Buscar ctrl+f Edit.Find Busca cualquier texto en el bloque actual, documento actual, documentos abiertos, proyecto o solución
Reemplazar ctrl+h Edit.Replace Reemplaza un texto por otro en el bloque actual, documento actual, documentos abiertos, proyecto o solución,.
Buscar en archivos ctrl+shift+f Edit.FindinFiles Busca en el bloque actual, documento actual, documentos abiertos, proyecto o solución. También permite buscar en un conjunto de carpetas que no tiene porqué estar dentro de nuestros proyectos.
Reemplazar en archivos ctrl+shift+h Edit.ReplaceinFiles Busca en el bloque actual, documento actual, documentos abiertos, proyecto o solución. También permite buscar en un conjunto de carpetas que no tiene porqué estar dentro de nuestros proyectos.
Ir a la definición f12 Edit.GoToDefinition Va a la definición de un miembro
Ir a la declaración ctrl+f12 Edit.GoToDeclaration Navega a la declaración del miembro seleccionado. Si se trata de una interfaz, mostrará una ventana con su/s implementación/es.
Buscar todas las referencias ctrl+k, r Edit.FindAllReferences Encuentra todas las referencias de un miembro

Movernos entre ventanas y pestañas

En nuestro día a día, podemos llegar a acumular gran cantidad de ventanas abiertas en VS Stdio casi sin darnos cuenta. ¿Cómo movernos entre ellas sin tener que levantar las manos del teclado?

Acción Atajo Acción en VS Descripción
Movernos al siguiente documento ctrl+tab Window.NextDocumentWindowNav Navegamos al siguiente documento abierto
Movernos al documento anterior ctrl+shift+tab Window.PreviousDocumentWindowNav Navegamos al anterior documento abierto
Movernos a la siguiente pestaña ctrl+avpag Window.NextTab Movernos entre las pestañas de una ventana de propiedades, por ejemplo, propiedades de un proyecto.
Ir a la ventana de output ctrl+w, o View.Output Nos movemos a la ventana de output.
Navegar a la lista de errores ctrl+w, e View.ErrorList Nos movemos a la lista de errores
Navegar al explorador de solución ctrl+w, s View.SolutionExplorer Nos movemos al explorador de solución.
Navegar a la lista de tareas ctrl+w, ctrl+w View.TaskList Nos movemos a la lista de tareas
Navegar al Team explorer ctrl+º (ord masc) View.TfsTeamExplorer Nos movemos al “team explorer”.
Propiedades del ítem seleccionado alt +enter (no encontrada) Nos movemos a la ventana de propiedades del ítem seleccionado

Los tests, los últimos de la cola

Si tenemos tiempo, si sobran horas, si los astros se alinean… ¡haremos algo de testing! 😛

Acción Atajo Acción en VS Descripción
Ejecutar todos los tests ctrl+r, a TestExplorer.RunAllTests Ejecuta todos los tests descubiertos por el motor de testing
Depurar todos los tests ctrl+r,ctrl+a TestExplorer.DebugAllTests Depura todos los tests descubiertos por el motor de testing
Ejecutar los tests seleccionados ctrl+r, t TestExplorer.RunAllTestsInContext Ejecuta los tests seleccionados
Depurar los tests seleccionados ctrl+r, ctrl + t TestExplorer.DebugAllTestsInContext Depura todos los tests seleccionados.

Otros comandos útiles

Acción Atajo Acción en VS Descripción
Compilar la solución f6 Build.BuildSolution Compila la solución completa.
Compilar proyecto seleccionado shift+f6 Build.BuildSelection Compila el proyecto seleccionado
Guardar documento actual ctrl+s File.SaveSelectedItems Guarda el documento abierto
Guardar todos los documentos abiertos ctrl+shift+s File.SaveAll Guarda todos los documentos abiertos.
Cerrar el documento actual ctrl+f4 Window.CloseDocumentWindow Cierra el documento actualmente abierto

Y vosotros, ¿qué otros atajos utilizáis en vuestro día a día? ¡Dejadlos en los comentarios y los añado aquí, que seguro que se me han pasado unos pocos!

¡Espero que estos atajos os sean útiles… Y recordad, VS Studio 2017 tiene actualmente 3889 comandos asignables a teclado. ¡Aprovechadlo! 🙂

¡Hasta la próxima!

Entrada visitada 1227 veces

Diseñar una interfaz contando píxeles con los dedos

Cuando no puedes ver lo que estás diseñando, y además utilizas una tecnología antigua como Windows Forms que no es como WPF, en la que puedes implementar todo con medidas relativas y que no se solapen los controles, tienes que andar contando los píxeles a mano para que esto no ocurra.

Estaba hoy actualizando una aplicación que tiene algunos años, y he acabado hasta las narices de contar con los dedos para ver si había controles que solapaban a otros controles… Así que he acabado haciéndome una extensión para System.Windows.Forms.Control, que me devuelve una cadena indicándome qué solapamientos existen entre los controles hijos de ese control.

Ya sé que para quien me lea, posiblemente tendrá utilidad cero, pero me apetecía compartir las chapuzas que tengo que montar a veces para no acabar con dolor de cabeza 🙂

La extensión es la siguiente:

public static string GetOverlapping(this Control control)
		{
			StringBuilder strbOverlap = new StringBuilder();

			foreach (Control ctl in control.Controls.Cast<Control>().OrderBy(ct => ct.TabIndex))
			{
				int xFrom = ctl.Location.X, xTo = xFrom + ctl.Size.Width;
				int yFrom = ctl.Location.Y, yTo = yFrom + ctl.Size.Height;
				List<Control> controlsOverlapping = control.Controls.Cast<Control>().Where(ct =>
				ct!= ctl &&
				xFrom  < ct.Location.X + ct.Size.Width && ct.Location.X< xTo
				&& yFrom < ct.Location.Y + ct.Size.Height&& ct.Location.Y < yTo)
				.ToList();
				if (controlsOverlapping.Any())
				{
					strbOverlap.AppendLine($"{ctl.Name}  Es solapado por: " +
						$"{String.Join(", ", controlsOverlapping.Select(ct => ct.Name).ToArray())}.");
				}
				if (ctl.Controls.Count > 0)
				{
					strbOverlap.Append(ctl.GetOverlapping());
				}
			}
			return strbOverlap.ToString();
		}
	}

Para los que véis esto os parecerá una chorrada, pero oye, a mí me ha sacado los colores la muy hija de ….
Estaría bien aumentar la funcionalidad para que detecte desbordamientos, y sea capaz de decir en qué esquina se solapan los controles entre sí… Pero por lo pronto, así me vale 😉

¡Espero que os haya hecho gracia la curiosidad!

¡Un saludo!

Entrada visitada 158 veces

¿Puedes vivir sin tu ratón?

Inténtalo. Desconecta el ratón, o apártalo de tu mano.
Ahora, continúa con lo que estabas haciendo: abre el correo, responde un mail, entra a tu web favorita y examina tus finanzas en el banco. ¡Eh! ¡Que te he visto mirándolo de reojo! ¡No! ¡Concéntrate! ¡no caigas en la tentación!

¿Qué tal? ¿Cuánto has durado antes de volver a conectar el ratón?

En muchas interfaces el ratón es prescindible. Existen muchísimos atajos de teclado que el usuario medio no conoce, aunque de conocerlos y utilizarlos, le agilizarían el día a día de una manera notable.

Sin embargo, otras muchas interfaces son dependientes del ratón: iconos que no se alcanzan con las flechas o el tabulador, menúes que se despliegan al pasar el ratón por encima… Cosas muy monas, pero que excluyen a las personas que como yo, no podemos usar el ratón.

Esta tarde, intentando seleccionar una fila completa en el editor de tablas de SQL server, me di cuenta de que no había (o yo no encontré), ningún atajo de teclado para realizar esa operación. Si hacéis click con el ratón en el encabezado de la fila, se selecciona… y yo tuve que meterme en el navegador de la capa de accesibilidad del sistema operativo, buscar la fila 201, entrar dentro del control y buscar el encabezado. Por suerte, el objeto de accesibilidad permitía ser pinchado , así que pude simular el click de ratón.
Una operación que vosotros hacéis en medio segundo, tardé en hacerla más de 30 segundos (y porque lo mío con el navegador de objetos de UIA es puro vicio)
El siguiente paso podría ser automatizarlo con un script para que mi lector de pantallas, al pulsar una tecla, hiciera ese trabajo por mí y me seleccionara la fila… ¡Fijaros la de tiempo que tendría que perder, cuando lo único que debería haber hecho el desarrollador era poner un dichoso ítem más en el menú contextual!

Y para no alargarme innecesariamente, solo pedirte, amigo desarrollador, que cuando desarrolles alguna interfaz, te pares un momento, la manejes con teclado, y si no eres capaz de llegar a todos los rinconcitos, sabrás que yo tampoco podré hacerlo.

¡Gracias por tenerlo en cuenta a partir de ahora! ¡Si no lo haces, te remorderá la conciencia! 😉

¡A descansar!

Entrada visitada 308 veces

AppSettings de ficheros .config con tipado fuerte en c#

¡Hola!

No sé a vosotros, pero a mí me ha pasado más de una y de dos veces, eso de escribir mal una clave de configuración bien en el .config o bien en la llamada a ConfigurationManager.AppSettings[“…”], y volverme loco porque el código no funcionaba como yo quería.

Hace unos meses, un compañero me comentó que utilizaba una plantilla t4 (Text Template Transformation Toolkit)), para crear una clase estática a partir del contenido del a sección appSettings de un fichero web.config o App.config… Así que me puse a investigar un poco, y basándome en esta entrada del blog de “meie igapäevast IT’d anna meile igapäev”, me hice mi propio template para ese menester.

He de confesar que ahora no puedo vivir sin él 😉

Son unas pocas líneas de código. Solo tenéis que guardar el fichero en vuestro proyecto, añadir la referencia a System.Configuration si aún no la teníais, hacer click con el botón derecho sobre el fichero, pulsar en la opción “run custom tool”, y desde ese momento, podréis usar vuestra clase estática “AppSettings” con las claves de configuración que hayáis escrito en la sección “appSettings” de vuestro fichero config. El nombre de espacios generado será el mismo que el del ensamblado de vuestro proyecto, así que no tendréis que usar usings adicionales.

Varias consideraciones sobre la generación:

  • Las claves que contengan valores decimales se transformarán a propiedades de tipo decimal, siempre que la cultura del proyecto reconozca el formato de cadena como tal.
  • Las claves con contenido numérico entero se convertirán a propiedades de tipo entero.
  • Las claves cuyo contenido sea “true” o “false” se convertirán a propiedades booleanas.
  • En claves con caracteres no alfanuméricos, estos se reemplazarán por guiones bajos en su propiedad correspondiente.

Podéis descargar el fichero desde este enlace.

El código es el siguiente:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Configuration" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Configuration" #>
<#@ import namespace="System.Text.RegularExpressions"#>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.IO"#>
<#@ import namespace="System.Globalization" #>
using System.Configuration;
<# string ns = (string)System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("NamespaceHint"); #>

namespace <#= ns#>
{
	public static class AppSettings {
<# 
	var configurationFileMap = new ExeConfigurationFileMap();
	string currentDir = Path.GetDirectoryName(this.Host.TemplateFile);
	string configFile = Path.Combine(currentDir, "Web.Config");
	if (!System.IO.File.Exists(configFile))
	{
		configFile = Path.Combine(currentDir, "App.Config");
	}
	if (!System.IO.File.Exists(configFile))
	{
		throw new System.IO.FileNotFoundException("No se encontró el fichero de configuración del que extraer los valores.");
	}

	configurationFileMap.ExeConfigFilename = configFile;
	var configuration = ConfigurationManager.OpenMappedExeConfiguration(configurationFileMap, ConfigurationUserLevel.None);
	foreach(KeyValueConfigurationElement setting in configuration.AppSettings.Settings)
	{ 
		if (setting.Key.Contains(":")) // estas suelen ser de ASP.NET MVC keys
		{
			continue;
		}
		// Reemplazamos todos los caracteres no alfanuméricos por guiones bajos
		string key = Regex.Replace(setting.Key, "[^a-zA-Z0-9]", "_");
		// Si la clave empieza por un número, le anteponemos el carácter 'N'
		if (Regex.IsMatch(key, "^[0-9]")) key = "N" + key;
		// Convertimos la clave a PascalCase. Normalmente me gusta poner las claves en
		// CamelCase, así que para que quede bien en .Net...
		key = key.Substring(0, 1).ToUpper() + key.Substring(1);
		string settingType;
		int i; bool b; decimal d;
		
		if (int.TryParse(setting.Value, out i))
		{
			settingType = "int";
		}
		else if (bool.TryParse(setting.Value, out b))
		{
			settingType = "bool";
		}
		else if (decimal.TryParse(setting.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out d))
		{
			settingType = "decimal";
		}
		else
		{
			#>
		public static string <#= key#> { get { return ConfigurationManager.AppSettings["<#= setting.Key #>"]; } }
<# continue;
} #>
		public static <#= settingType #> <#= key#> { get { return <#= settingType #>.Parse(ConfigurationManager.AppSettings["<#= setting.Key #>"]); }}
<#
} #>
	}
}

¡Espero que os sirva!

¡Un saludo!

Entrada visitada 831 veces

Rotar imágenes según sus metadatos de orientación

¡Hola!

Hay herramientas que se te ocurren pensando en qué cosas podrían ser útiles; y otras que surgen cuando te topas con un problema y dices: ¡joder, seguro que hay alguna solución para esto!

El otro día, mi mujer, @amaterasu_n estaba escribiendo en su blog de mami the vikings mama un post, y quería poner algunas fotos. Al ser ciegos, el tema de las imágenes en los posts es algo complejo. Nunca sabemos si la foto ha quedado bien, o se corta, o se descentra… así que después de ponerlas en el post, preguntamos a una compañera de trabajo, y me dijo que había fotos que estaban giradas… Ya os podéis imaginar, la típica foto tomada en horizontal, y que necesitas girar para que no tengas que darle la vuelta a la pantalla.

Así que me dije: Los smartphones tienen acelerómetros y giroscopios para detectar el cambio de orientación y adaptar las interfaces a esos cambios. ¿No guardarán esta información en los metadatos exif de las fotos? Y sorprendentemente, ¡la respuesta es sí! Imagino que también habrá cámaras que lo hacen, pero no he podido comprobarlo.

Buscando un poco por internet, me encontré con ExifExtractor, una pequeña librería en c# que me permitía extraer los datos exif de las imágenes. Por otro lado, en este artículo sobre las etiquetas exif encontré los valores y significados de esta etiqueta…

¡Problema resuelto!

He desarrollado una pequeñísima aplicación en c# que dada una imagen, extrae la orientación, la rota o voltea (rotate / flip) en consecuencia e informa al usuario de la operación que ha realizado sobre ella.

Podéis descargar la herramienta FixPictureOrientation desde este enlace.

Solo tenéis que descomprimirlo en alguna carpeta, ejecutar el exe y pulsar el botón de abrir y corregir foto, buscar la foto, abrirla… ¡y ya está!

Nota: Para ejecutar el programa deberéis tener instalado el .NET Framework 4 (si usáis Windows 7 o superior ya viene por defecto, y si no, casi seguro que lo tenéis de todos modos 😉 Si no fuera así, podéis descargar el instalador del .NET Framework 4 desde este enlace

El código c# es muy sencillo (obviando toda la parte de la extracción de datos Exif, cuyo código podéis encontrar en el sitio de codeproject que os puse arriba:

using Goheer.EXIF;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FixPictureOrientation
{
	public partial class FrmPrincipal : Form
	{
		public FrmPrincipal()
		{
			InitializeComponent();
		}

		private void BtnCorregir_Click(object sender, EventArgs e)
		{
			OpenFileDialog dlg = new OpenFileDialog()
			{
				Filter = "Archivos de imagen JPG (*.jpg)|*.jpg",
				Title = "Abrir foto",
				ShowReadOnly = false,
				ShowHelp = false,
				InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyComputer),
				CheckFileExists = true
			};
			DialogResult res = dlg.ShowDialog();
			if (res == DialogResult.Cancel) return;
			var rutaImagen = dlg.FileName;
			// Rotamos la imagen de acuerdo a los datos de exif
			Bitmap bmp;
			try
			{
				bmp = new Bitmap(rutaImagen);
			}
			catch (Exception)
			{
				MessageBox.Show("¡Pero qué me has dado! Esto no parece una imagen válida!", "¡Esto no se come!", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}
			try
			{
				var exif = new EXIFextractor(ref bmp, Environment.NewLine);
				if (exif["Orientation"] != null)
				{
					int iOrientacion;
					if (!Int32.TryParse(exif["Orientation"].ToString(), out iOrientacion))
					{
						MessageBox.Show("Los datos de orientación parecen no ser correctos. ¡Disculpa!", "Uups!", MessageBoxButtons.OK, MessageBoxIcon.Error);
						return;
					}
					string rotado;
					RotateFlipType tipoRotacion = GetDesiredRotation(iOrientacion, out rotado);
					if (tipoRotacion == RotateFlipType.RotateNoneFlipNone)
					{
						MessageBox.Show("¡Esta foto no necesita ninguna rotación! ¡Puedes usarla sin problemas!", "¡Esta ya está!", MessageBoxButtons.OK, MessageBoxIcon.Information);
						return;
					}

					bmp.RotateFlip(tipoRotacion);
					var equivalenciasExif = new Goheer.EXIF.translation();
					int idOrientacion = equivalenciasExif.Keys.OfType<int>().FirstOrDefault(k => equivalenciasExif[k].ToString() == "Orientation");
					// Reajustamos la propiedad de orientación para que coincida con la orientación actual.
					bmp.RemovePropertyItem(idOrientacion);
					exif.setTag(idOrientacion, "1");
					bmp.Save(rutaImagen, ImageFormat.Jpeg);
					MessageBox.Show($"¡Perfecto! La imagen se ha rotado {rotado}.", "¡Listo!", MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
				else
				{
					MessageBox.Show("Lo siento, no hay datos de orientación en los metadatos de la foto... ¡No puedo detectar la posición de la fotografía!", "Me cachis!", MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show($"Se produjo un error inesperado: {ex.Message}.", "Uuups.", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			finally
			{
				if (bmp != null) bmp.Dispose();
			}
		}
		
		private void BtnSalir_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		/// <summary>
		///  Devuelve la rotación que habría que realizar para que la foto rote a la posición adecuada en función del dato de orientación EXIF
		/// </summary>
		/// <param name="orientation"> Valor numérico de orientación que indica la orientación actual de la foto</param>
		/// <param name="rotationExplanation">Explicación de qué rotación se va a realizar</param>
		/// <returns>Uno de los valores de la enumeración RotateFlipType indicando la rotación que se debe aplicar</returns>
		private static RotateFlipType GetDesiredRotation(int orientation, out string rotationExplanation)
		{
			RotateFlipType rotationType;
			switch (orientation)
			{
				case 1: // fila 0 = arriba, columna 0 = lado izquierdo
					rotationExplanation = "0 grados";
					rotationType = RotateFlipType.RotateNoneFlipNone;
					break;
				case 2: // fila 0 = arriba, columna 0 = lado derecho
					rotationExplanation = "0 grados y volteo horizontal";
					rotationType = RotateFlipType.RotateNoneFlipX;
					break;
				case 3: // fila 0 = abajo, columna 0 = lado derecho
					rotationExplanation = "180 grados en sentido horario";
					rotationType = RotateFlipType.Rotate180FlipNone;
					break;
				case 4: // fila 0 = abajo, columna 0 = lado izquierdo
					rotationExplanation = "180 grados en sentido horario y volteo horizontal";
					rotationType = RotateFlipType.Rotate180FlipX;
					break;
				case 5: // fila 0 = lado izquierdo, columna 0 = arriba
					rotationExplanation = "90 grados en sentido horario y volteo horizontal";
					rotationType = RotateFlipType.Rotate90FlipX;
					break;
				case 6: // fila 0 = lado derecho, columna 0 = arriba
					rotationExplanation = "90 grados en sentido horario";
					rotationType = RotateFlipType.Rotate90FlipNone;
					break;
				case 7: // fila 0 = lado derecho, columna 0 = abajo
					rotationExplanation = "270 grados en sentido horario y volteo horizontal";
					rotationType = RotateFlipType.Rotate270FlipX;
					break;
				case 8: // fila 0 = lado izquierdo, columna 0 = abajo
					rotationExplanation = "270 grados en sentido horario";
					rotationType = RotateFlipType.Rotate270FlipNone;
					break;
				default:
					rotationExplanation = "0 grados";
					rotationType = RotateFlipType.RotateNoneFlipNone;
					break;
			}
			return rotationType;
		}

	}
}

¡Espero que os sea útil!

¡Un saludo!

Entrada visitada 5024 veces

SonarLint. Analiza tu código mientras programas

Hace unos meses, en mi empresa montaron un departamento de QA (Quality Assurance o garantía de calidad), ¡y uno de los primeros proyectos que iban a auditar era uno de los míos! ¡Una hecatombe, desde que me enteré no podía ni dormir! ¡Iban a auditar mi código, a desmenuzarlo, a sacarme los fallos y a hacer un informe. ¡Horrible! Ya no podría generar código espagueti, ni crear funciones de 800 líneas, ni hacer copy paste sin parar, ni crear métodos con una complejidad ciclomática de siete cifras, ni crear siete variables llamadas a, b, c, d, e, f y g. ¡Estaba desolado! Ya veía el informe: 300 evidencias bloqueantes, 840 críticas, 1567 mayores, 8399 menores y 4300 informativas. ¡Pum! ¡Cataclán! SonarQube has crashed due a out of memmory while counting the critical bugs!

Lamentablemente, el concepto de calidad en el software, pese a estar muy documentado y cuya teoría todos conocemos en mayor o menor medida, es un aspecto del ciclo de desarrollo que, al menos en el entorno en el que me he movido, se ha tenido poco en cuenta. Puedo contar con los dedos de una mano los proyectos empresariales en los que me han permitido meterme a hacer testing para comprobar la calidad e integridad del software que había que entregar. Todo es para ayer, hay poco tiempo, los presupuestos hay que ajustarlos. Además, ¡los tests son de cobardes!

Gracias a dios, la cosa está cambiando, y parece que cada vez más, una parte del tiempo de desarrollo empieza a reservarse para pasar tests, reglas de calidad y en definitiva, aprender a mejorar la forma en la que desarrollamos nuestros proyectos.

Pensando en tener alguna herramienta que me ayudase a descubrir qué miserias aparecerían cuando auditaran mi proyecto, estuve buscando por internet, y encontré una herramienta muy interesante para VsStudio 2015 llamada SonarLint.

Su descripción en inglés dice:

SonarLint for Visual Studio is based on and benefits from the .NET Compiler Platform (“Roslyn”) and its code analysis API to provide a fully-integrated user experience in Visual Studio 2015.

SonarLint para Visual Studio se basa (y se beneficia) de la plataforma de compilación de .NET (“roslyn”) y su API de análisis de código, para proporcionar una experiencia totalmente integrada en Visual Studio.

Está desarrollado por la empresa Sonar Source, aunque tienen repositorio en Github, desde el que podréis contribuir en el proyecto si os apetece.

Esta extensión añade bastantes reglas de las que analiza el servidor SonarQube, aunque por el momento no tiene la capacidad de integrarse con él.
SonarLint es totalmente autónomo, y solo necesitamos la extensión para empezar a trabajar.

Lo bueno de esta extensión es que, al integrarse perfectamente con VisualStudio 2015, se beneficia de las características de accesibilidad del entorno, por lo que con JAWS 16 he conseguido trabajar con él perfectamente.
Lo que hace es enviarnos warnings a la lista de errores del entorno, y podremos hacer click (o enter) sobre cada uno para ir al fichero y línea en el que se está produciendo ese error.

Os pongo un ejemplo de código chungo y veréis todo lo que saca 😀

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Kastwey.PruebasSonarLint
{
	class Program
	{
		static void Main(string[] args)
		{
			try
			{
				string nombre, apellidos, docIdentidad;
				nombre = "Juanjo";
				apellidos = "Montiel";
				if (nombre.ToLower() == "juanjo")
				{
					if (apellidos.ToLower() == "montiel")
					{
						// WriteLine("Línea comentada");
						WriteLine($"Nombre completo: {nombre} {apellidos}");
					}
				}
				ReadLine();

			}
			catch
			{
			}
		}
	}
}

Y aquí, el resultado, en tiempo de desarrollo (¡ni siquiera tenemos que compilar el proyecto!):

Severity Code Description Project File Line Suppression State
Warning S1118 Add a “protected” constructor or the “static” keyword to the class declaration. Kastwey.PruebasSonarLint d:\proyectos\Kastwey.PruebasSonarLint\Kastwey.PruebasSonarLint\Program.cs 10 Active
Warning S1172 Remove this unused method parameter “args”. Kastwey.PruebasSonarLint d:\proyectos\Kastwey.PruebasSonarLint\Kastwey.PruebasSonarLint\Program.cs 12 Active
Warning S1481 Remove this unused “docIdentidad” local variable. Kastwey.PruebasSonarLint d:\proyectos\Kastwey.PruebasSonarLint\Kastwey.PruebasSonarLint\Program.cs 16 Active
Warning CS0168 The variable ‘docIdentidad’ is declared but never used Kastwey.PruebasSonarLint d:\proyectos\Kastwey.PruebasSonarLint\Kastwey.PruebasSonarLint\Program.cs 16 Active
Warning S1449 Define the locale to be used in this String operation. Kastwey.PruebasSonarLint d:\proyectos\Kastwey.PruebasSonarLint\Kastwey.PruebasSonarLint\Program.cs 19 Active
Warning S1066 Merge this if statement with the enclosing one. Kastwey.PruebasSonarLint d:\proyectos\Kastwey.PruebasSonarLint\Kastwey.PruebasSonarLint\Program.cs 21 Active
Warning S1449 Define the locale to be used in this String operation. Kastwey.PruebasSonarLint d:\proyectos\Kastwey.PruebasSonarLint\Kastwey.PruebasSonarLint\Program.cs 21 Active
Warning S125 Remove this commented out code. Kastwey.PruebasSonarLint d:\proyectos\Kastwey.PruebasSonarLint\Kastwey.PruebasSonarLint\Program.cs 23 Active
Warning S108 Either remove or fill this block of code. Kastwey.PruebasSonarLint d:\proyectos\Kastwey.PruebasSonarLint\Kastwey.PruebasSonarLint\Program.cs 31 Active

¡Espectacular!, ¿a que sí? 😉
Ahora, imaginad que por políticas de vuestro desarrollo, os piden que en algunas funciones pongáis un pequeño ejemplo de uso con parámetros fictícios, por lo que la regla de borrar el código comentado no se aplica aquí. ¿Qué podemos hacer?
Si pulsáis con el botón derecho (o tecla aplicaciones) en el aviso, veréis un submenú que dice: “Suppress”, y dentro, tenemos dos opciones: “Suppress in source” (suprimir en el código) o “suppress in suppression file” (suprimir en un archivo de supresiones).
Si pulsamos cualquiera de los dos, el aviso desaparecerá… Y fijaros qué hace si le decimos que nos elimine el error en el código:

#pragma warning disable S125 // Sections of code should not be "commented out"
						// WriteLine("Línea comentada");
#pragma warning restore S125 // Sections of code should not be "commented out"

Está utilizando preprocesadores para decirle a VsStudio: Este error no me lo muestres aunque la extensión te esté diciendo que sí.
Lo bueno de estos preprocesadores es que podemos aplicarlos, por ejemplo, a nivel de clases.
A mí me ha resultado útil para eliminar la regla de: “utilice sobrecarga de funciones en lugar de parámetros opcionales”, ya que en los controladores de MVC, usar parámetros opcionales es la única opción viable.
Y después de mirar cada error y arreglarlo, nuestro código sin errores podría quedar tal que así:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Kastwey.PruebasSonarLint
{
	static class Program
	{
		static void Main()
		{
			try
			{
				string nombre, apellidos;
				nombre = "Juanjo";
				apellidos = "Montiel";
				if (nombre.Equals("juanjo", StringComparison.InvariantCultureIgnoreCase) && apellidos.Equals("montiel", StringComparison.InvariantCultureIgnoreCase))
				{
					WriteLine($"Nombre completo: {nombre} {apellidos}");
				}
			}
			catch (Exception ex)
			{
				WriteLine($"Error inesperado: {ex.Message}.");
			}
			ReadLine();
		}
		
	}
}

Y ya no me enrollo más. Probadla, que merece la pena, ¡y es gratis!

¡Que lo disfrutéis!

Entrada visitada 5012 veces

Reproductor accesible html5

¡Hola!

Hace algunos meses, Salvi Melguizo me pidió que le hiciera un reproductor accesible para su blog, así que como me gusta cacharrear y ganarme un sobresueldo cuando se puede :P, a ello me puse.
Se trata de un script jQuery que, por cada elemento audio de HTML5 de una página, genera un conjunto de controles encima del elemento, que permiten manejar de forma totalmente accesible dicho reproductor.

El reproductor está probado con Internet Explorer 9, 10 y 11, Firefox 42 y 43, Chrome 47 y Safari con iOS 8 y 9. Funciona correctamente con JAWS, NVDA y VoiceOver para MAC e iOS… He de confesar que con window Eyes no lo he probado 😉

Podéis ver
una demo del reproductor accesible aquí.
El reproductor está en español, aunque por defecto el ejemplo está con la traducción al inglés macarrónico (lo he traducido yo), así que si alguien se anima a corregir la traducción, yo encantado.
Podéis colaborar con el proyecto en su repositorio de github, o si solo queréis probarlo, podéis descargar la última versión del proyecto en formato zip.

Sugerencias, críticas constructivas, mejoras… ¡son bienvenidas!

¡Espero que os parezca interesante!

¡Un saludo!

Entrada visitada 707 veces

Atributos HTML condicionales con Razor en MVC 4+

¡Hola!

Haciendo una vista en razor, tenía que pintar unas clases a los elementos li de una lista desordenada en función de algunas condicionales, así que se me ocurrió buscar la forma de poner atributos condicionales sin tener que usar sintaxis rebuscadas o duplicar código con un if dentro del HTML.
Lo que encontré me encantó por su simplicidad: Si usamos una variable nula dentro de un atributo HTML, razor obviará el atributo y no lo escribirá.
Ejemplo:

			<ul>
			@foreach (var modulo in Model.Modulos)
			{
				var claseCSS = (modulo.Completado ? "completed" : modulo.Actual ? "actual" : null);
				<li class="@claseCSS">
					<a href="@modulo.Link">
						@modulo.Titulo
					</a>
				</li>
			}
</ul>

		

Si la cadena tiene algún valor, se pintará la clase correspondiente en el elemento li. Si la cadena está a nulo, el atributo ni se pintará.
¿A que mola? 🙂

¡Nos vemos!

Entrada visitada 916 veces