Vous êtes sur la page 1sur 782

Negro Pantone 301 C

Construya aplicaciones .NET 3.5 con


la herramienta para negocios RAD de Microsoft

Programacin con Visual Basic 2008


Programacin con

Visual Basic 2008


Programacin con
Es fcil programar con Visual Basic 2008, todo lo
que necesita es comprender .NET y Visual Basic Nunca haba revisado un
libro que me hiciera disfrutar

Visual Basic
claramente y darse la oportunidad de probarlos. Este
libro le da estos elementos. No slo conseguir una tanto como ste. Excelente
firme comprensin sobre conceptos de desarrollo de software en cobertura, perfecto para la
Visual Basic, tambin tendr prctica real al disear, construir y
audiencia a la que est
desplegar una aplicacin completa orientada a base de datos.
dirigido. Descripciones

2008
Cada captulo de Programacin con Visual Basic 2008 ofrece
explicaciones claras, repletas de cdigo de ejemplo para concisas, claras, exactas.
ayudarle a construir su aprendizaje durante el proceso de Es un ganador.
desarrollo. Con esta obra completa, usted: -Ken Getz
Consultor senior
Adquirir experiencia prctica en el desarrollo de aplicaciones MCW Technologies
.NET, desde el diseo hasta la implementacin.
Disear bases de datos con SQL Server y ADO.NET.
Construir aplicaciones de escritorio complejas con Tim Patrick es arquitecto de software
formularios de Windows y aplicaciones Web con ASP.NET. y desarrollador; tiene 25 aos de
experiencia en diseo y construccin
Dominar las nuevas caractersticas de VB 2008 como de soluciones personalizadas de
expresiones lambda y tipos null. software. MVP de Microsoft y
Acelerar los procesos con consultas LINQ y generacin desarrollador de soluciones
de XML dinmico. certificado de Microsoft, Tim ha
publicado cinco tutoriales y
Descubrir cmo dar licencias, documentar, implementar
referencias sobre desarrollo de
y dar soporte a sus aplicaciones.
Visual Basic, junto con varios
Extender an ms su aprendizaje, usando el cdigo fuente artculos. Entre sus libros se incluyen
de aplicaciones incluido. Visual Basic 2005 in a Nutshell y
Visual Basic 2005 Cookbook.
Obtendr la mentalidad de un desarrollador al adquirir
habilidades de programacin cotidianas.

Patrick
978-607-15-0248-3

Tim Patrick
Programacin con Visual Basic 2008

00_PATRICK-FROT MATTER.indd 1 17/2/10 15:17:36


00_PATRICK-FROT MATTER.indd 2 17/2/10 15:17:36
Programacin
con Visual Basic 2008

Tim Patrick

Traduccin
Eloy Pineda Rojas
Traductor profesional

Educacin

MXICO BOGOT BUENOS AIRES CARACAS GUATEMALA MADRID NUEVA YORK


SAN JUAN SANTIAGO SO PAULO AUCKLAND LONDRES MILN MONTREAL
NUEVA DELHI SAN FRANCISCO SINGAPUR ST. LOUIS SIDNEY TORONTO

00_PATRICK-FROT MATTER.indd 3 17/2/10 15:17:36


Director editorial: Fernando Castellanos Rodrguez
Editor: Miguel ngel Luna Ponce
Supervisor de produccin: Zeferino Garca Garca

PROGRAMACIN CON VISUAL BASIC 2008

Prohibida la reproduccin total o parcial de esta obra,


por cualquier medio, sin la autorizacin escrita del editor.

Educacin

DERECHOS RESERVADOS 2010 respecto a la primera edicin en espaol por


McGRAW-HILL INTERAMERICANA EDITORES, S.A. DE C.V.
A Subsidiary of The McGraw-Hill Companies, Inc.
Corporativo Punta Santa Fe
Prolongacin Paseo de la Reforma 1015, Torre A
Piso 17, Colonia Desarrollo Santa Fe,
Delegacin lvaro Obregn
C.P. 01376, Mxico, D. F.
Miembro de la Cmara Nacional de la Industria Editorial Mexicana, Reg. Nm. 736

ISBN: 978-607-15-0248-3
Authorized translation of the English edition of Programming Visual Basic 2008.
ISBN 9780596518431. Tim Patrick. This translation is published and sold
by permission of OReilly Media, Inc., the owner of all rights to publish and sell the same.

1234567890 109876543210
Impreso en Mxico Printed in Mexico

00_PATRICK-FROT MATTER.indd 4 17/2/10 15:17:37


Para Maki, mi amorosa esposa

00_PATRICK-FROT MATTER.indd 5 17/2/10 15:17:37


00_PATRICK-FROT MATTER.indd 6 17/2/10 15:17:38
Contenido

Prlogo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv

1. Introduccin a .NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
Antes de .NET 1
De nuevo, la presentacin de .NET 2
El objeto en .NET 3
Las partes de .NET Framework 7
Del cdigo fuente a EXE 16
Temas relacionados con Visual Studio y Visual Basic 17
Visual Studio 2008 18
Resumen 22
Proyecto 23

2. Introduccin a Visual Basic . . . . . . . . . . . . . . . . . . . . . . . . . . 30


La historia de la revolucin de Visual Basic 30
Visual Basic de adentro hacia fuera 32
Los fundamentos de la lgica y los datos 32
Tipos de datos y variables 35
Intermedio 44
Comentarios 44
Instrucciones Option 45
Operadores bsicos 47
Uso de funciones y subrutinas 49
Condiciones 50
Bucles 54
Creacin de procedimientos propios 57
Otras caractersticas de control de flujo 61
Eventos y manejador de eventos 64
Espacios de nombres 66

vii

00_PATRICK-FROT MATTER.indd 7 17/2/10 15:17:38


El espacio de nombres My 69
Resumen 70
Proyecto 70

3. Presentacin del proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . 75


El Proyecto Biblioteca 76
Las necesidades de los usuarios 79
La vida de un proyecto 83
Resumen 90
Proyecto 90

4. Diseo de la base de datos . . . . . . . . . . . . . . . . . . . . . . . . . . 95


Bases de datos relacionales 95
SQL Server 2005 98
SQL 100
Uso de bases de datos en Visual Basic 107
Documentacin de la base de datos 108
Resumen 109
Proyecto 109

5. Ensamblados de .NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126


Qu es un ensamblado? 126
Qu hay dentro de un ensamblado? 128
Ensamblados y aplicaciones 131
El espacio de nombres My y los ensamblados 132
Directivas y ensamblados 134
Resumen 136
Proyecto 137

6. Datos y tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . .151


La naturaleza de los datos en computacin 151
Datos en .NET 153
Tipos de datos de Visual Basic 158
Literales 159
Constantes 160
Enumeraciones 161

viii | Contenido

00_PATRICK-FROT MATTER.indd 8 17/2/10 15:17:38


Variables 162
Convenciones de asignacin de nombres a variables y constantes 165
Inferencia de tipo local 166
Operadores 167
Variables estticas 172
Matrices 172
Tipos que pueden ser nulos 175
Funciones comunes de Visual Basic 176
Resumen 182
Proyecto 182

7. Windows Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187


Dentro de una aplicacin de Windows 187
Ventanas en .NET 191
Cmo hacer formularios tiles 210
Resumen 212
Proyecto 212

8. Clases y herencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219


Conceptos de programacin orientada a objetos 219
Programacin orientada a objetos en Visual Basic y .NET 224
Problemas relacionados 241
Resumen 244
Proyecto 244

9. Programacin funcional . . . . . . . . . . . . . . . . . . . . . . . . . . . 253


Expresiones lambda 253
Inicializadores de objetos 259
Manejo de errores en Visual Basic 260
La naturaleza de los errores en Visual Basic 260
Manejo de errores no estructurado 263
Manejo de errores estructurado 265
Errores no manejados 267
Administracin de errores 269
Resumen 273
Proyecto 274

Contenido | ix

00_PATRICK-FROT MATTER.indd 9 17/2/10 15:17:38


10. ADO.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .277
Qu es ADO.NET? 278
Revisin general de ADO.NET 279
Comparacin entre usar y no usar conjuntos de datos 282
Conexin a SQL Server con Visual Studio 284
Interaccin con SQL Server en cdigo 289
Transacciones de base de datos 292
Marco de trabajo de la entidad ADO.NET 293
Resumen 294
Proyecto 294

11. Seguridad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303


Caractersticas de seguridad en .NET 304
Criptografa y cifrado 304
Cifrado en .NET 306
Otras caractersticas de seguridad 311
Resumen 312
Proyecto 312

12. Sobrecargas y extensiones . . . . . . . . . . . . . . . . . . . . . . . . . .330


Qu es la sobrecarga de un operador? 330
Qu puede sobrecargar? 332
Otros problemas con la sobrecarga de operadores 338
Mtodos de extensin 340
Resumen 342
Proyecto 342

13. XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361


Qu es XML? 361
La Regla de XML 364
Contenido XML 365
Uso de XML en .NET: el viejo estilo 371
Uso de XML en .NET: el nuevo estilo 375
Resumen 378
Proyecto 379

x | Contenido

00_PATRICK-FROT MATTER.indd 10 17/2/10 15:17:38


14. Configuraciones de la aplicacin . . . . . . . . . . . . . . . . . . . . . . . 392
Una breve historia sobre las configuraciones 392
Configuracin en Visual Basic 2008 394
Resumen 400
Proyecto 401

15. Archivos y directorios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416


La administracin tradicional de archivos de Visual Basic 417
Manipulacin de archivos mediante flujo 418
Administracin de archivo con el espacio de nombres My 424
Resumen 427
Proyecto 428

16. Genricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433


Qu son los genricos? 433
Variaciones en las declaraciones de los genricos 436
Resumen 442
Proyecto 442

17. LINQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448


Qu es LINQ? 448
Tipos annimos 450
LINQ to Objects 451
Expresiones bsicas de consulta 453
Conversin de resultados a otras formas 459
Consultas agregadas 459
Expresiones de consulta avanzada 460
LINQ to XML 461
LINQ para datos relacionados con ADO.NET 463
Ejecucin diferida 468
Resumen 469
Proyecto 470

18. Interfaz de usuario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486


Revisin general de GDI+ 487
Seleccin de un lienzo 488

Contenido | xi

00_PATRICK-FROT MATTER.indd 11 17/2/10 15:17:38


Eleccin de plumas y pinceles 490
Flujo de texto a partir de la fuente 493
Creacin de imgenes 497
Exposicin de su verdadero artista 499
Rutas: dibujos en macrovisin 501
Regiones e imgenes 502
Modificaciones elaboradas con transformaciones 503
Mejoramiento de controles mediante el dibujo de propietario 505
Windows Presentation Foundation 507
Mejoramiento de clases con atributos 510
Resumen 511
Proyecto 511

19. Localizacin y globalizacin . . . . . . . . . . . . . . . . . . . . . . . . . 526


Definicin de globalizacin y localizacin 526
Archivos de recursos 527
El objeto My.Resources 529
Localizacin de formularios dentro de Visual Studio 531
Adicin de recursos fuera de Visual Studio 534
Compilacin manual de recursos 535
Otras caractersticas de localizacin 537
Resumen 538
Proyecto 539

20. Impresin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552


Impresin en Windows 553
Impresin en .NET 554
Impresin de un documento 557
Vista previa de impresin 559
Conteo y numeracin de pginas 561
Impresin en modo simple 563
Resumen 564
Proyecto 564

21. Creacin de informes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581


Opciones de informe en .NET 581
Uso de controles de informe en .NET 584
Resumen 597
Proyecto 597

xii | Contenido

00_PATRICK-FROT MATTER.indd 12 17/2/10 15:17:39


22. Otorgue licencia a su aplicacin . . . . . . . . . . . . . . . . . . . . . . . . 611
Opciones de licenciamiento de software 611
Acuerdos de licencia 615
Ofuscacin 616
El sistema de licenciamiento de biblioteca 618
Resumen 621
Proyecto 622

23. Desarrollo Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .642


Cmo funciona Internet 642
Programacin de Internet 644
Caractersticas de ASP.NET 645
Prueba de ASP.NET 646
Ms acerca de eventos 653
Estado y vista de estado 654
Validacin de datos 655
Integracin de base de datos 657
Base de comunicacin de Windows 658
Resumen 663
Proyecto 663

24. Adicin de ayuda en lnea . . . . . . . . . . . . . . . . . . . . . . . . . . 672


Opciones de Windows Online Help 672
Diseo de HTML Help 674
Acceso a HTML Help 680
Resumen 683
Proyecto 683

25. Implementacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689


Qu elementos participan en la implementacin? 689
Mtodos de implementacin dentro de Visual Studio 690
Resumen 700
Proyecto 700

26. Proyecto completo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711


El proyecto Biblioteca 711
Flexibilidad de Visual Basic 714
El marco conceptual de la programacin 716
Resumen 717

Contenido | xiii

00_PATRICK-FROT MATTER.indd 13 17/2/10 15:17:39


A. Instalacin del software . . . . . . . . . . . . . . . . . . . . . . . . . . . 719

B. Acuerdo de licencia de software . . . . . . . . . . . . . . . . . . . . . . . . 722

ndice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725

xiv | Contenido

00_PATRICK-FROT MATTER.indd 14 17/2/10 15:17:39


Prlogo

Bienvenido a Programacin con Visual Basic 2008! S que va a disfrutarlo. Ya lo he ledo cinco
veces. Es probable que se encuentre ansioso de llegar al captulo 1, pero le recomiendo que lea
este prlogo para asegurarse de que pag por el libro correcto.

Quin debe leer este libro?


Escribir un libro es como escribir una aplicacin de Visual Basic. Bueno, excepto por la parte
acerca de encontrar un editor y trabajar con un gua editorial. Y luego estn esas quisquillosas
reglas acerca de una redaccin correcta. Si nos ponemos a pensar, en realidad son muy diferentes.
Pero en una manera, los libros y los programas son similares: ambos se escriben para cumplir las
necesidades del usuario. Cuando se escriben aplicaciones de software, las necesidades del usuario
orientan la organizacin y las caractersticas del programa final. Cuando se escribe un libro,
como el que est revisando ahora, las necesidades del usuario (se es usted, el lector) orientan la
organizacin y las caractersticas del texto final.
As que es con usted en mente que me puse a escribir este libro. Oh, estn la fama y el presti-
gio, pero en realidad se trata de usted. Usted, la persona que busca comprender Visual Basic y
.NET Framework, que es sobre el que est construido. Cuando pensaba en sus necesidades, me
surgieron estas ideas:
Tal vez conozca el programa, tal vez no.
En el mundo de la programacin, hay cuatro tipos de personas: 1) quienes ya programan
felizmente; 2) quienes no programan, pero aprendern y les encantar; 3) quienes no pro-
graman, pero aprendern y lucharn con ello; y 4) quienes deben regresar este libro de
inmediato al estante. Si se encuentra en uno de los primeros tres grupos, este libro es defini-
tivamente para usted. Creo que cualquiera que pueda dividir una tarea en sus instrucciones
bsicas paso a paso puede programar con xito en Visual Basic. Si est inseguro acerca de
su capacidad de cuantificar tareas de esta manera, tal vez quiera empezar con un libro sobre
conceptos bsicos de programacin.

xv

00_PATRICK-FROT MATTER.indd 15 17/2/10 15:17:39


Tal vez sepa cmo programar en Visual Basic o .NET, tal vez no.
Y est bien, porque este libro le ensear. En la mayor parte de los captulos se presentan
temas importantes para el desarrollo en Visual Basic y .NET, como los conceptos de progra-
macin orientada a objetos. O el uso de diferentes tipos de variables disponibles para usted,
o la interaccin con una base de datos. Si ya sabe cmo usar Visual Basic 6 o anterior, es
estupendo, pero no es un prerrequisito.
Quiere escribir programas.
Casi todos los libros de programacin le ensean a codificar en incrementos de 10 lneas.
Por lo menos, eso es lo que aparece disperso por todas sus pginas. He puesto algunos de es-
tos fragmentos de cdigo en este libro. Pero paso mis das escribiendo programas reales, no
programas de ejemplo de 10 lneas. Si quiere escribir programas completos, debe aprender
usando programas completos. Por eso es por lo que tambin puse un programa en mi libro
(un programa completo). En los siguientes cientos de pginas, desarrollar un programa
real: una base de datos para una pequea biblioteca) y usted lo escribir conmigo.
Puse todas estas ideas en 26 captulos fciles de leer, e hice que McGraw-Hill los pusiera a su
alcance para conveniencia de usted. Cuando llegue al ndice, habr aprendido cmo escribir
programas completos en Visual Basic y .NET. Ser una aventura de programacin, as que
empecemos!

Qu hay en este libro?


Como vamos a pasar mucho tiempo juntos, tal vez quiera saber algo acerca de m. Bueno, mi
nombre es Tim Patrick, y durante muchos aos viv en la misma calle en que se encontraba el
enorme campus de Microsoft. He escrito programas durante 25 aos, y en estos das escribo
aplicaciones de Visual Basic orientadas a bases de datos personalizadas. Y no estoy solo. Casi
todos los desarrolladores de Visual Basic escriben software de negocios. Si eso es lo que hace, o
planea hacer, tiene mucha compaa.
Mientras recorre las pginas de este libro, leer acerca de las principales actividades de .NET y
Visual Basic que orientan el desarrollo de aplicaciones del consumidor general y en el nivel de
negocios. Si planea hacer otro tipo de programacin, como desarrollo de juegos, este libro ser
til, pero no hablar acerca de caractersticas avanzadas o especializadas como modelos 3D inter
activos o transformaciones geomtricas.
En cada captulo se analiza un tema importante de la programacin, y luego se sigue con una
implementacin prctica de ese tema: la creacin del programa de base de datos Biblioteca. No
mostrar cada lnea de cdigo en el libro; si lo hiciera, el libro pesara 25 kilos y costara cinco mil
pesos, ms impuestos. Para obtener cada lnea de cdigo, tendr que descargar el cdigo fuente
del sitio Web del libro. El cdigo y el libro de texto estn unidos en un propsito: entrenarlo en
el hbil uso de Visual Basic en la plataforma .NET, de modo que pueda desarrollar las aplicacio-
nes de la ms elevada calidad posible. El texto y el cdigo fuente incluyen valiosos recursos que
puede usar todos los das en su vida de programacin.

xvi | Prlogo

00_PATRICK-FROT MATTER.indd 16 17/2/10 15:17:39


Qu hay en el software descargado?
Le va a gustar lo que descargue. Contiene todo el cdigo fuente del proyecto de base de datos
Biblioteca. Lo que es estupendo es que cuando instala los ejemplos de cdigo fuente, se vuelven
parte de Visual Studio. Una vez que estn instalados, puede crear un proyecto especfico de un
nuevo captulo desde el men Archivo Nuevo proyecto en Visual Studio. El apndice A tiene
todos los detalles de la descarga y la instalacin.
Escrib el cdigo del proyecto usando Visual Basic 2008 Professional Edition. Algunas partes tal
vez no sean compatibles con versiones anteriores del lenguaje .NET. Ninguno es compatible con
Visual Basic 6.0 o anterior, de modo que ni se preocupe en probarlo. El cdigo fuente funcionar
con cualquier edicin de Visual Basic 2008, incluida Express Edition.
El cdigo fuente tambin utiliza SQL Server 2005 para el almacenamiento de su base de datos.
Puede usar cualquier edicin de SQL Server 2005, incluida Express Edition. En el captulo 4 se
introducen las bases de datos y SQL Server 2005. Si estar usando la base de datos en un entorno
de red controlado por el departamento de tecnologa de la informacin, tal vez necesite hablar
con el representante de ese departamento acerca de la instalacin de la base de datos de ejemplo.
El cdigo SQL que uso es muy simple, de modo que debe trabajar sobre versiones anteriores de
SQL Server, y podra ajustar fcilmente para que trabaje con Oracle, DB2, Microsoft Access u
otros motores comunes de base de datos. Tambin puede usar la prxima versin SQL Server
2008, si la tiene disponible.
Puede usar el cdigo fuente descargable para sus propios proyectos, pero por favor dle crdito a
quien crdito se merece. Hay un acuerdo de licencia relacionado con el cdigo (consulte el apn-
dice B), de modo que por favor no venda el software como si fuera suyo. Slo para estar seguro,
he agregado unos cuantos errores difciles de encontrar. Slo bromeaba! (No, no lo hice!)

Convenciones usadas en este libro


Las siguientes convenciones tipogrficas se usan en este libro:
Cursivas
Indica nuevos trminos, URL, nombres de archivo y extensiones de archivo.
Ancho constante
Indica cdigo de computadora en un sentido amplio. Esto incluye todo el cdigo fuente
de Visual Basic, contenido HTML y XML, comandos, opciones, cdigo fuente de otros
lenguajes y contenido generado por herramientas de Visual Studio.
Ancho constante en negritas
Indica comandos u otro texto que el usuario debe escribir literalmente. Tambin se usa para
resaltar una seccin particular del cdigo.
Ancho constante en cursivas
Indica texto que debe reemplazarse con valores proporcionados por el usuario o valores
determinados por el contexto.

Prlogo | xvii

00_PATRICK-FROT MATTER.indd 17 17/2/10 15:17:39


Este cono significa un consejo, una sugerencia o una nota general.

Este cono indica un aviso o precaucin.

Uso de los ejemplos de cdigo


Este libro est aqu para ayudarle a hacer su trabajo. En general, puede usar el cdigo en este
libro en sus programas y documentacin. No es necesario que se ponga en contacto con el edi-
tor o conmigo para pedir permiso, a menos que est reproduciendo una parte importante del
cdigo. Por ejemplo, escribir un programa que use varios fragmentos de cdigo de este libro
no requiere permiso. Vender o distribuir un CD-ROM de ejemplos de libros de McGraw-Hill
requiere permiso. Responder una pregunta al citar este libro y poner el cdigo como ejemplo, no
requiere permiso. Incorporar una cantidad importante de cdigo de ejemplo de este libro en la
documentacin de su producto requiere que se apegue a los trminos del acuerdo de licencia del
software que se encuentra en el apndice B.
Apreciamos, pero no exigimos atribucin. Por lo general, una atribucin incluye ttulo, autor,
editor e ISBN. Por ejemplo, Programacin con Visual Basic 2008, por Tim Patrick. Copyright
2010 Tim Patrick, 978-607-15-0248-3.
Si siente que la manera en que usa los ejemplos del cdigo caen fuera del uso limpio del permiso otor-
gado aqu, sintase en la libertad de ponerse en contacto con nosotros en permissions@oreilly.com.

Cmo ponerse en contacto con nosotros?


Por favor, dirija los comentarios y las preguntas relacionadas con este libro al editor:
McGraw-Hill Interamericana Editores S.A. de C.V.
Prolongacin Paseo de la reforma 1015 Torre a pisos 16 y 17.
Colonia Desarrollo Santa Fe. 01376 Mxico D.F.
1500 5000
5005 5000
Tenemos una pgina Web para este libro, donde presentamos una lista de erratas, ejemplos y
cualquier informacin adicional. Puede acceder a esta pgina en:
www.mcgraw-hill-educacion.com (haga una bsqueda por ISBN, autor o ttulo)
Para comentar o plantear preguntas tcnicas acerca de este libro, enve un correo electrnico a:
profesional@mcgraw-hill.com

xviii | Prlogo

00_PATRICK-FROT MATTER.indd 18 17/2/10 15:17:39


Agradecimientos
El desarrollo de Programacin con Visual Basic 2008 fue una labor que exigi amor de mi parte,
y he sido bendecido por contar con quienes compartieron esa labor conmigo. Joan Murray de
Addison-Wesley fue mi editora en la primera edicin del libro. John Osborn, de OReilly Media
se tom la tarea de guiar la segunda edicin. He sido afortunado al trabajar con John en tres
diferentes proyectos de libros, y su xito fue posible gracias a sus atentos esfuerzos.
Otros autores y programadores tomaron tiempo de sus trabajos para revisar cada captulo del
libro y sealar sus deficiencias, que fueron numerosos antes de su llegada. En especial, deseo dar
las gracias a Glenn Berry, Alex Bierhaus, Harry Chen, Ken Getz, Lowell Mauer y Dan Sullivan
por sus estupendos comentarios. Cuando lleg el momento de concentrarse en la versin 2008
de Visual Basic, tambin recib informacin fantstica de Chris Williams, Daniel Seara, Ron
Petrusha y Sander Gerz.
Muchas gracias a Joe Binder, Jay Roxe, Prasadi de Silva y Eric Knox, todos ellos miembros del
equipo de Visual Basic en Microsoft. Cada uno de ellos tom en cuenta una interminable can-
tidad de preguntas acerca de caractersticas esotricas de Visual Basic y .NET, y proporcion
respuestas llenas de conocimiento, paciencia y gracia.
Mi agente, Claudette Moore, siempre merece su propio prrafo en cualquier libro de compu
tacin que escriba. En realidad, sera un tema estupendo para una de esas biografas concentra-
das en agentes literarios que el pblico siempre est reclamando. No slo hace un estupendo
trabajo en todas las cosas normales de los agentes, sino que tambin comparte personalmente las
alegras y tristezas de los autores bajo su cargo. Gracias por otro ao divertido en los libros.
Para Maki, mi esposa, y para Spencer, mi hijo, les doy una ola especial de gracias. Si alguna vez
usted pasa tiempo con autores, sabr lo excntricos que pueden ser. Pero Maki y Spencer com-
baten la excentricidad con cuidado y amor, y funciona. La palabra gracias parece tan inadecuada
cuando les debo tanto. Gracias a Dios por haberme proporcionado una familia tan tremenda.

Prlogo | xix

00_PATRICK-FROT MATTER.indd 19 17/2/10 15:17:39


00_PATRICK-FROT MATTER.indd 20 17/2/10 15:17:39
Captulo 1
Introduccin a .NET

Bienvenido a .NET! Tambin podra decir Bienvenido al universo, porque .NET es grande
como el universo. Y es complejo. Y est lleno de hoyos negros y otras cosas que no siempre
tienen sentido. Pero resulta que es un sistema fantstico (.NET, no el universo) para desarrollar
aplicaciones de software.
El .NET Framework fue desarrollado en un vaco (a diferencia del universo); Microsoft lo desa
rroll, junto con sus lenguajes de desarrollo (sobre todo C# y Visual Basic) para atender varios
de los problemas que padecan los desarrolladores y usuarios del software de Windows. Para
comprender por completo por qu .NET era necesario, necesitamos hacer un corto viaje por los
caminos de la historia de la computadora.

Antes de .NET
Las computadoras de propsito general han existido desde mediados del siglo xx. Sin embargo,
eran inaccesibles para la mayora porque: (a) costaban millones de dlares; (b) consuman enor
mes cantidades de energa elctrica; (c) el mantenimiento y la programacin slo podan reali
zarlos especialistas capacitados, y (d) tendan a entrar en conflicto con los muebles de la sala.
Treinta aos despus, IBM desarroll la idea de la computadora personal. Estas computadoras
de escritorio representaron un gran avance en tecnologa, pero slo una minora las us alguna
vez. Seguan siendo costosas (miles de dlares) y el mantenimiento y la programacin an re
queran una importante inversin en entrenamiento. Las PC de IBM an se vean abominables
junto a los muebles de la sala.
Luego surgi la Macintosh de Apple. Con su brillante diseo y su funcionalidad amigable, llev
la alegra de la computacin a las masas. Y aunque la programacin no siempre era sencilla,
brind agradables resultados. No maravilla que Microsoft decidiera copiar (perdn, quise decir
mejorar) su funcionalidad.

01_PATRICK-CHAPTER_01.indd 1 17/2/10 15:18:25


Microsoft Windows 1.0 trajo un mayor nivel de capacidad de uso a la plataforma de compu
tacin de IBM/Intel. Pero no era un viaje gratis para los programadores. El desarrollo de MS-
DOS ya era lo suficientemente difcil sin la adicin de los mensajes emergentes y las cientos
de llamadas a la interfaz de programacin de aplicaciones (API, Application Programming In
terface) que necesitaban los programas de Windows. Visual Basic 1.0, presentado en 1991,
simplific enormemente el proceso de desarrollo, pero con el advenimiento de los sistemas de
32 bits, los componentes ActiveX y COM, adems de Web, aun los programadores de VB se
sentan abrumados.
En todos los aos de la dcada de 1990 la situacin slo pareci empeorar. Microsoft vio aumen
tada la competencia en la forma del lenguaje JavaTM y el sistema operativo Linux. Los hackers
estaban explotando los desbordamientos de bfer y otros problemas de seguridad presentes en
la plataforma de Windows. Los usuarios experimentaban mltiples problemas que surgan de
estndares en conflicto, tecnologas que competan por la integracin de datos, un registro que
no haca ms que crecer y el infierno de las DLL. Frustrados, un grupo de usuarios de Excel
prendi fuego a todo el campus de Microsoft en Redmond.
No todo iba tan mal. Pero Microsoft vio que necesitaba atender los problemas de desarrollo
general del software y del uso de su amada plataforma Windows. Su solucin lleg en la forma
de .NET Framework.

De nuevo, la presentacin de .NET


Cuando Microsoft anunci sus planes de crear .NET, sorprendi a muchos desarrolladores,
sobre todo a los de Visual Basic, que lo vieron como un gigantesco paso en retroceso al rpido
desarrollo de aplicaciones. Pero el lanzamiento de .NET Framework versin 1.0 brind en
2002 muchos beneficios necesarios:
.NET introdujo un entorno de programacin unificado
Todos los lenguajes compatibles con .NET se compilan en un lenguaje intermedio de Mi
crosoft antes de ensamblarse en cdigo mquina especfico de la plataforma. Visual Basic,
C# y otros lenguajes de .NET son envolturas alrededor de este lenguaje .NET comn.
Como todos los compiladores compatibles con .NET hablan el mismo lenguaje bsico, ya
no experimentan los innumerables conflictos entre datos y lenguaje inherentes de otros siste
mas basados en componentes de lenguaje cruzado como COM. La versin .NET de Visual
Studio tambin unific la interfaz estndar de usuario que deja que los programadores creen
cdigo fuente.
.NET comprometi a los desarrolladores con las tecnologas orientadas a objetos
.NET no slo abarca por completo el paradigma de la programacin orientada a objetos,
sino que todo en .NET est contenido en un objeto: todos los valores de datos, todos los
bloques de cdigo fuente y los detalles internos de todos los eventos iniciados por el usuario.
Todo aparece en el contexto de un objeto.

2 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 2 17/2/10 15:18:25


.NET simplific la programacin en Windows
La programacin en Visual Basic antes de .NET era muy fcil, hasta que llegaba el momen
to de interactuar con una de las bibliotecas API, algo que suceda con mucha frecuencia en
la programacin profesional. Con .NET casi todas las API de uso regular se reemplazan con
una jerarqua de objetos que proporciona acceso a muchas caractersticas comunes necesa
rias en Windows. Debido a que la jerarqua es extensible, otros vendedores pueden agregar
nueva funcionalidad sin alterar el marco conceptual existente.
.NET mejor la seguridad
Los usuarios y administradores pueden establecer ahora reglas de seguridad para diferentes
caractersticas de .NET, para limitar el dao que pueden provocar los programas maliciosos.
El entorno administrado de .NET tambin resuelve los problemas de desbordamiento de
bfer y fugas de memoria mediante caractersticas como asignacin slida de tipos y reco
leccin de basura.
.NET mejor la productividad del desarrollador mediante estndares
.NET Framework est construido sobre muchos estndares nuevos y existentes (y adems
los usa), como XML y SOAP. Esto mejora el intercambio de datos no slo en la plataforma
de Windows, sino tambin en interacciones con otras plataformas y sistemas.
.NET mejor el desarrollo de aplicaciones Web
Hasta antes del arribo de .NET, gran cantidad del desarrollo de aplicaciones Web se reali
zaba mediante lenguajes de creacin de secuencias de comandos. .NET trajo el poder del
desarrollo compilado, de escritorio, a Internet.
.NET simplific la implementacin de aplicaciones
Si .NET est instalado en un sistema, para lanzar un programa basta con copiar su archivo
EXE al sistema de destino (aunque un programa de instalacin es mucho ms amigable con
el usuario). Caractersticas como implementacin lado a lado y de ClickOnce, adems de la
eliminacin de los conflictos de versin de archivos y el infierno de las DLL (la presencia
de varias versiones de la misma DLL en un sistema, o la incapacidad de eliminar una ver
sin de una DLL), simplificaron en gran medida la implementacin de aplicaciones Web
y de escritorio.
Si no comprendi algunos de los trminos empleados en esta seccin, no hay problema. Los
encontrar de nuevo, con explicaciones, en captulos posteriores.

El objeto en .NET
Para comprender totalmente el desarrollo del software en .NET, debe entender qu es un objeto.
(Si est familiarizado con la programacin orientada a objetos, puede omitir lo siguiente y pasar
a la prxima seccin, aunque se perder un contenido estupendo.) A pesar de que parte de la
informacin de esta seccin tambin aparece en el captulo 8, es tan importante analizar .NET
que una parte de ella tambin aparecer aqu.

El objeto en .NET | 3

01_PATRICK-CHAPTER_01.indd 3 17/2/10 15:18:25


Objetos y datos
Desde el punto de vista de la programacin, una computadora realiza cuatro tareas bsicas:
Almacena datos en su rea de memoria.
Da soporte al procesamiento de datos mediante operaciones bsicas, incluidas adicin y
sustraccin, lgebra booleana y manipulacin de cadenas de texto.
Permite que el usuario interacte con los datos almacenados en su memoria.
Proporciona una manera de introducir y extraer datos de la memoria mediante dispositivos
de entrada y salida tales como teclados e impresoras, y con medios de almacenamiento de
datos como discos duros.
La esencia de estas cuatro actividades son los datos. El objetivo de la existencia de las computado
ras es la manipulacin de datos. Los sistemas operativos proporcionan la base para estas activida
des, pero son las aplicaciones de software las que hacen que estas caractersticas (la capacidad de
manipular datos) sean reales y tengan algn significado para el usuario. Los lenguajes de progra
macin de alto nivel son las principales herramientas usadas para desarrollar estas aplicaciones,
cada una de las cuales usa algunos mtodos generales para que las caractersticas de manipulacin
de datos queden disponibles para el programador. De regreso a los felices das del desarrollo del
lenguaje ensamblador, si conoca la direccin en memoria de una pieza de datos, poda acceder
a ella y manipularla de manera directa. En las primeras versiones de BASIC y en casi todos los
dems lenguajes procedimentales, se acceda a los datos mediante variables.
A medida que aument la complejidad de los lenguajes, junto con sus objetivos, tambin lo hizo
la concepcin de los datos. En el lenguaje LISP (List Processing, procesamiento de listas, o Lots
of Irritating Silly Parentheses, gran cantidad de parntesis irritantes y tontos), cualquier valor de
datos exista dentro de una lista o un conjunto de datos ms largo. Pero en los lenguajes de .NET,
los datos se ven a travs del objeto.
Los objetos son colecciones de valores de datos y cdigo fuente relacionado. Mientras que en los
antiguos dialectos de BASIC, cada elemento de datos era ms o menos independiente a travs
de su variable con nombre, los valores de datos relacionados en los lenguajes de programacin
orientada a objetos pueden agruparse en objetos. La implementacin de objetos a menudo in
cluye cdigo fuente diseado para manipular los valores de los datos en ese objeto.
Por lo general, los objetos representan algo que en ocasiones tiene una contraparte en la vida real,
sea fsica o conceptual. Por ejemplo, su cdigo puede incluir un objeto Casa que tiene campos
de datos o propiedades para la direccin, el color de la pintura exterior y el nmero de personas
que viven en la casa. El cdigo fuente asociado podra manejar esos datos; un mtodo Pintura
podra modificar el valor de color empleado para la pintura exterior.
A los datos y elementos de cdigo dentro de un objeto se les denomina miembros. Algunos
miembros estn ocultos dentro del objeto y slo puede accederse a ellos mediante el cdigo
fuente del objeto. Otros miembros son ms pblicos; cualquier cdigo de su aplicacin puede
usarlos, no slo el subconjunto de cdigo de su aplicacin que se encuentra dentro del objeto.
Considere que una televisin es un objeto (vase la figura 1-1).

4 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 4 17/2/10 15:18:25


Vista exterior Vista interior

Figura 1-1. Una TV es un objeto, no slo objetable.

Por lo general, es fcil usar los miembros pblicos de una TV: la perilla de encendido, el selector
de canales, el control de volumen, etc. Son los conductos mediante los cuales el usuario controla
los valores de datos de la TV (su salida de video y audio). Tambin hay miembros ocultos den
tro de la TV; podra usar estos miembros para mejorar la calidad de imagen y sonido, aunque
esto sera una mala idea para la mayora de los usuarios. No querr meterse con los elementos
internos de su televisor, crame. De la misma manera, un objeto no querr que cdigo externo
al objeto se mezcle con sus miembros internos, excepto si lo hace a travs de los miembros pblicos.
No me preocupa la manera en que la TV funciona internamente, siempre y cuando obtenga las
imgenes y el sonido usando los controles (encendido, canales, volumen).

Objetos e interfaces
Los miembros pblicos de un objeto representan su interfaz. Si el cdigo externo del objeto
quiere manipular los datos que pertenecen a ese objeto, utiliza los miembros de la interfaz. No
tiene que imaginar los miembros ocultos o la manera en que funcionan, y eso es correcto. Sobre
todo, es correcto si esos miembros internos cambian alguna vez por una razn, lo que sucede con
ms frecuencia de lo que se imagina. Considere la manera en que los elementos internos de la TV
han cambiado en los ltimos 30 aos. He aqu un dibujo de la TV que mi familia tena cuando
era nio. Comprela con las TV de panel plano modernas de hoy en da (vase la figura 1-2).
La TV de mi familia era estupenda. Tena un radio estereofnico de alta fidelidad, una tornamesa
que reproduca discos de 33 1/3, 45 y 78 rpm, y una pantalla grande de 19 pulgadas en blanco y
negro, con un despliegue claro como un cristal. Dos nios podan ocultarse tras ella y jugar a las
escondidas. Y mi amigo que tena el mismo modelo afirmaba que poda dibujar lneas permanen
tes realmente asombrosas en la pantalla con un imn. A quin le importaba que los paneles de las
bocinas parecieran una alfombra gastada? A quin le importaba que la unidad ocupara hasta 30%
del espacio de la sala? A quin le importaba que pudieran cocinarse salchichas sobre ella por el
calor que generaban los bulbos? Era ms que una TV; se trataba de un centro de entretenimiento.

El objeto en .NET | 5

01_PATRICK-CHAPTER_01.indd 5 17/2/10 15:18:26


La TV de mi niez Una cosa novedosa

Figura 1-2. Son en realidad televisores?

Ahora comprela con la sosa pantalla plana de la derecha. Si la ve de cerca, notar que la interfaz
de la TV no ha cambiado mucho en tres dcadas. An tiene controles para encendido y selec
cin de canales (aunque ya han desaparecido los controles para lneas horizontales y verticales).
Lo que ha cambiado es la configuracin interna. Ya se fueron los bulbos que zumbaban, todos
ellos reemplazados con transistores eficientes y componentes de estado slido. Pero no tiene
mucha diferencia para el espectador, porque la interfaz pblica sigue siendo la misma.
En la programacin orientada a objetos, stos desarrollan su trabajo de la misma manera. Siem
pre y cuando la interfaz pblica siga siendo la misma, pueden cambiar el cdigo actual del objeto
y el sistema de almacenamiento de datos interno (a lo que se le conoce tambin como implemen-
tacin del objeto), pero no tiene impacto en la aplicacin general.

Objetos e instancias
La interfaz y la implementacin de un objeto en realidad slo representa su diseo; hay partes
que el programador crea mediante el cdigo fuente. Existen incluso antes de que se compile el
programa y se instalen en la computadora del usuario. En realidad, en este nivel, los objetos ni
siquiera son conocidos como objetos. En la mayora de los lenguajes (incluido Visual Basic), la
palabra clase indica la implementacin de la interfaz de un objeto.
Una vez que su aplicacin est instalada en una computadora y se inicia, el cdigo crea instancias
de la clase para almacenar datos reales en memoria. Estas instancias son los objetos reales del
desarrollo de la programacin orientada a objetos. Dependiendo de la manera en que se escribe
su cdigo, podra usarse la implementacin de una sola clase para crear uno o cientos de objetos
en memoria al mismo tiempo.

6 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 6 17/2/10 15:18:27


En .NET, todo su cdigo y sus valores de datos aparecen dentro de objetos. Casi todo lo que ve
en un programa en ejecucin es un objeto: un formulario de Windows es un objeto; un control
de cuadro de lista en ese formulario es un objeto, y un solo elemento en ese cuadro de lista es
un objeto.

Las partes de .NET Framework


Por tanto, ahora sabe todo acerca de los objetos, y tal vez est pensando que es momento de
poner este libro en la pila y empezar a programar. Pero an falta analizar algunas partes de .NET
Framework. Esas partes se muestran hasta el hartazgo en la documentacin de .NET, y todos
tienen un acrnimo de tres letras.

El motor comn de tiempo de ejecucin del lenguaje


En el centro de .NET Framework est el motor comn de tiempo de ejecucin del lenguaje (CLR,
Common Language Runtime), llamado as no porque sea comn u ordinario, sino porque todos
los lenguajes habilitados por .NET lo comparten en comn. Todo lo que hace en un programa
de .NET est administrado por un CLR. Cuando cree una variable, d las gracias a CLR y su
sistema de administracin de datos. Cuando diga adis a una pieza de datos, d las gracias a
CLR y la manera en que administra la liberacin de datos mediante su sistema de recoleccin de
basura. Observ la manera en que la palabra administra sigue apareciendo en estas frases? De
seguro mi editor s lo observ. Pero administra es la palabra exacta, porque es lo que hace CLR.
En realidad, al software escrito por .NET Framework se le llama cdigo administrado. Cualquier
cdigo que cae fuera del control de CLR, incluidos los componentes COM (ActiveX) usados
por su aplicacin .NET, es conocido como cdigo no administrado.
CLR se parece al Aeropuerto Internacional de Los ngeles. Si alguna vez ha estado en LAX,
sabe que hay gran cantidad de actividades. Los aviones llegan y salen cada minuto. Los autom
viles llegan y salen por miles de la carretera de dos niveles y las estructuras del estacionamiento
central. Las personas y los carteristas se desplazan constantemente entre las ocho terminales
principales y la enorme terminal internacional. Pasan muchas cosas, pero gran parte de ello es
administrado. Los aviones no pueden despegar sin aprobacin de la torre de control. Los puntos
de acceso y las compuertas administran las carreteras de acceso y los lugares de estacionamiento.
Agentes amigables y corteses administran el flujo de pasajeros y carteristas en las reas seguras
de la terminal.
Las estructuras de control y administracin ubicadas en LAX aseguran un flujo ordenado y seguro
de personas entre sus aviones y la ciudad de Los ngeles. Las estructuras de control y administra
cin del CLR aseguran un flujo ordenado y seguro de datos entre el cdigo .NET y el resto de
la computadora o la red conectada.
Tal vez le gustara saber el secreto de la manera en que el CLR puede procesar programas escritos
en cualquier lenguaje .NET, incluidos Visual Basic, C# y FORTRAN. Igual pasa con los competi
dores de Microsoft. En realidad lo saben, porque no es un secreto. Todos los lenguajes compatibles

Las partes de .NET Framework | 7

01_PATRICK-CHAPTER_01.indd 7 17/2/10 15:18:27


con .NET convierten su cdigo fuente (lo compilan) en lenguaje intermedio de Microsoft (MSIL,
MicroSoft Intermediate Language, que suele pronunciarse misil y que se abrevia con frecuencia
slo como IL). Para quienes estn familiarizados con el lenguaje ensamblador, se parece mucho a
ste. Para quienes no estn familiarizados con l, parece un conjunto de galimatas. Por ejemplo,
he aqu algn cdigo fuente de Visual Basic para una aplicacin de consola (un programa que
funciona con texto y que no es de Windows, como los viejos programas de MS-DOS) que sim
plemente da salida a las palabras Hola, mundo de un procedimiento llamado Main:
Module Module1
Sub Main()
Console.WriteLine("Hola, mundo.")
End Sub
End Module

se es todo el programa de .NET. Cuando el compilador de Visual Basic lo convierte en MSIL,


el procedimiento Main tiene este aspecto (ligeramente modificado, para que se acomode a la
pgina):
.method public static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.
STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr "Hola, mundo."
IL_0005: call
void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret
} // end of method Module1::Main

S, todo un galimatas. Pero es correcto, porque satisface los requisitos de la Asociacin Interna
cional de Libros de Cmputo de que todos los captulos 1 incluyan el ejemplo de cdigo Hola,
mundo. Adems, el CLR lo comprende, y eso es lo que realmente cuenta en .NET. Siempre y
cuando tenga su cdigo en IL, .NET lo procesar. El compilador de Visual Basic slo genera el IL
automticamente. Otros compiladores de lenguaje .NET, incluido C#, tambin producen IL. In
cluso puede escribir su propio cdigo IL, pero es probable que est leyendo el libro equivocado para
eso. Slo ponga a descansar su mente, ste ser el ltimo fragmento de IL que ver en este libro.

La especificacin de lenguaje comn


Los lenguajes que aseguran que son compatibles con .NET no pueden afirmarlo por ninguna de
las viejas razones. En realidad tienen que ser compatibles con .NET y su funcionamiento. Esto
lo hace mediante la especificacin de lenguaje comn (CLS, Common Language Specification). La
CLS define un conjunto mnimo de caractersticas que un lenguaje debe implementar antes de
que se considere compatible con .NET o, ms exactamente, con CLS.
Un lenguaje puede rebasar ese mnimo, si lo desea, y .NET incluye muchas opciones adicio
nales sobre las que pueden construirse caractersticas especficas del lenguaje. Un lenguaje que

8 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 8 17/2/10 15:18:27


slo implementa las funciones mnimas especificadas de CLS tal vez no pueda interactuar por
completo con componentes que exceden la especificacin mnima. Por supuesto, Visual Basic es
compatible con CLS, y en realidad supera ese mnimo.

El sistema comn de tipos


Debido a que CLR est controlando de todas maneras su cdigo fuente, Microsoft pens que
sera bueno hacer que controle tambin los datos del cdigo fuente. Para esto, .NET Framework
utiliza su sistema comn de tipos (CTS, Common Type System), que define todos los tipos y los
mecanismos de datos esenciales usados en los programas de .NET. Esto incluye todos los tipos
numricos, de cadena y booleanos. Tambin define el objeto, la unidad esencial de administra
cin de datos en .NET.
El CTS divide todos los objetos en compartimientos. El primero de stos, llamado tipos de va-
lor, almacena datos reales en el compartimiento. Si tiene un valor entero de 32 bits, se coloca
en ese compartimiento de tipo de valor, listo para su uso inmediato. El otro compartimiento
contiene tipos de referencia. Cuando observa en este compartimiento, se distingue un mapa que
le indica dnde encontrar los datos reales en algn otro lugar de la memoria de la computadora.
Al parecer, los tipos de valor son ms fciles de usar, y en realidad lo son, pero tienen algunas
restricciones no impuestas a los tipos de referencia.
Los programas y componentes escritos con el estndar CTS pueden intercambiar datos entre s,
sin obstculos ni limitaciones. (Algunos tipos de datos de .NET caen fuera de los tipos esencia
les de CTS, pero necesita evitarlos cuando quiera interactuar especficamente con componentes
que slo pueden usar los tipos esenciales de CTS.)
Cuando escriba sus aplicaciones en Visual Basic, casi todo su cdigo aparecer en clases. Las cla
ses son tipos de referencia que incluyen valores de datos y cdigo asociado. Los valores de datos
incluidos en una clase son, con ms frecuencia, los tipos de datos esenciales de CTS, pero tam
bin pueden contener objetos que usted designe en cualquier otro lugar de su aplicacin. Visual
Basic tambin incluye estructuras, el hermano ms dbil pero rpido de las clases. Las estructuras
implementan tipos de valor, y tambin incluyen datos y cdigo.
Las clases y estructuras slo son dos tipos de datos/cdigo disponibles en Visual Basic. Las inter-
faces son esqueletos de clases y estructuras; incluyen detalles de diseo de lo que debe aparecer en
una clase o estructura relacionada, pero no incluyen ninguna implementacin real o cdigo que
funcione. Los delegados definen una firma de procedimiento sin implementacin, y se usan
para dar soporte a eventos, que son las acciones (iniciadas por el usuario, por el sistema operativo
o por su cdigo) que le dicen a su cdigo Ponte a trabajar ahora! Las nutrias marinas son ma
mferos acuticos que estn curiosamente relacionados con las comadrejas y que prefieren comer
erizos de mar. Los mdulos son bloques de cdigo y datos, pero, a diferencia de las clases y estruc
turas, no pueden crear objetos independientes a partir de ellos. Las enumeraciones agrupan un
conjunto de valores de enteros relacionados, generalmente para usarlo como listas de opciones.
En la terminologa de .NET, todos estos trminos (clase, estructura, interfaz, delegado, mdulo y
enumeracin, pero no nutria marina) son conocidos de manera colectiva como tipos. Tal vez ya sepa

Las partes de .NET Framework | 9

01_PATRICK-CHAPTER_01.indd 9 17/2/10 15:18:27


que .NET tena algunos elementos confusos; no comprara un libro sobre l si fuera fcil. Pero a
pesar de toda la tecnologa compleja, es sta simple palabra, tipo, la que causa la mayor confusin.
Tal vez experimentar angustia en todo este libro cada vez que la lea. El problema es que resulta
demasiado general. No slo alude a estos elementos centrales del CTS, sino que tambin se usa
cuando se habla slo de tipos de valores especficos de Visual Basic (con ms frecuencia llamados
tipos de datos de Visual Basic). El apodo de las estructuras es tipos definidos por el usuario, otro
uso confuso de tipo. Los programadores que usaron Visual Basic antes de su encarnacin de .NET
tambin recuerdan a Tipo como la instruccin de lenguaje usado para crear tipos definidos por el
usuario. Nooo! Microsoft debi usar alguna palabra diferente de tipo para el mundo de clases, inter
faces, enumeraciones, etc. Pltano hubiera sido una mejor opcin porque slo en ocasiones se usa
para analizar el software. Pero tipo es la palabra, de modo que mejor vaya acostumbrndose a verla.
Tratar de incluir la mayor cantidad de contexto posible cuando use la palabra en este volumen.
Por lo general, los miembros de un tipo suelen ser simples campos de datos y procedimientos de c
digo. Es decir, una clase puede incluir una clase anidada, si la necesita. Slo ciertos tipos dan soporte
a anidamiento (consulte el captulo 8 para conocer ms detalles; en ese captulo tambin se expon
drn los niveles de acceso). Cada miembro tiene un nivel de acceso que indica cul cdigo puede usar.
Hay cinco niveles de acceso, que van de pblicos (cualquier persona y sus hermanos pueden usar el
miembro) a privados (tiene que estar dentro del tipo para saber que est all).
En el captulo 6 se analiza el sistema de tipos de .NET con mayor detalle, as como la informa
cin que obtiene de clases, estructuras y otras frutas.

Bibliotecas de clases de .NET


Las computadoras son en realidad muy estpidas. Mientras que yo puedo contar hasta 17,
una computadora llega hasta 1; slo conoce los dgitos 0 y 1. La CPU incluye un conjunto de
operadores simples empleados para manipular los dgitos 0 y 1, y unos cuantos operadores ms
que comparan los 1 y 0 de maneras complejas. El ltimo gran truco de la computadora es su
capacidad de introducir 0 y 1 en la memoria, y de extraerlos de ella, pero lo logra de manera
espectacular. Seguramente hace estas cosas casi a la velocidad de la luz, aunque puede calcular
a 3 millones de posiciones decimales?
Bueno, en realidad puede hacerlo. Las computadoras no saben nada acerca de las letras del alfa
beto, y en realidad slo pueden manejar los dgitos 0 y 1, pero aqu estoy usando una compu-
tadora para escribir un libro que ganar premios. Es la capacidad de combinar los valores de
datos y operadores de 1 bit en bibliotecas de funcionalidad cada vez ms compleja lo que hace
que las computadoras resulten tiles.*
.NET Framework est basado en dcadas de funcionalidad cada vez ms compleja. Cuando
instala .NET Framework, el CLR y su sistema de tipos asociado representa el ncleo del marco

* Si quiere leer un libro realmente fascinante acerca de cmo se forman las operaciones complejas de software y hardware a
partir de los usos ms bsicos de 0 y 1, lea Code: The Hidden Language of Computer Hardware y Software, de Charles Petzold
(Microsoft Press).

10 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 10 17/2/10 15:18:27


conceptual. En s mismo, ste incluye toda la funcionalidad bsica necesaria para dejar que
sume 2 y 2 y obtenga correctamente 4. Y como desarrollador de aplicaciones de negocios, usted
dedica mucho tiempo a hacer eso. Pero qu pasa si quiere hacer algo ms complejo, algo que
sabe que algn otro programador ya ha hecho, como ordenar una lista de nombres o dibujar un
crculo de colores en un formulario? Para obtener esa respuesta, vaya a las bibliotecas de clases,
las .NET Class Libraries. Estas bibliotecas, instaladas con el marco conceptual, incluyen gran
cantidad de funcionalidad escrita de antemano (y cada vez ms compleja) que no tiene que crear
desde cero.
Hay dos bibliotecas de clases en .NET: la biblioteca bsica de clases (BCL, Base Class Library) y
la biblioteca de clases de Framework (FCL, Framework Class Library). La BCL es ms pequea
y contiene las caractersticas ms esenciales que no pueden faltar en un programa. Incluye slo
las clases que son obligatorias para dar soporte a aplicaciones en el marco conceptual, si Micro
soft fuera a llevar, por decir algo, el marco conceptual a Linux.
La FCL es ms grande e incluye todo lo dems que Microsoft considera que le gustara tener en
sus programas, pero que no era absolutamente esencial tener en la BCL. Ni siquiera pregunte
cuntas clases hay en la FCL; no querr saberlo. Apuesto a que ni siquiera Microsoft conoce real
mente el nmero completo. Estoy convencido de que esos malvados bromistas de Microsoft han
incluido clases de broma en la FCL, pero estn enterradas de manera tan profunda que pocos
programadores las han encontrado.
Con miles (s, miles!) de clases, enumeraciones, interfaces y otros tipos incluidos en las BCL y
FCL, pensara que sera difcil encontrar slo la clase que necesite. Pero no es tan difcil, al menos
no tan abrumadoramente difcil. .NET Framework incluye una caracterstica llamada espacios de
nombres. Todos los tipos en .NET aparecen en una jerarqua (estructura en forma de rbol), que
incluye slo unas cuantas entradas en la raz. Cada nodo de la jerarqua es un espacio de nom
bres. Usted identifica de manera nica cualquier clase u otro tipo en las bibliotecas al asignar un
nombre a todos los espacios de nombre, de la raz hacia el espacio de nombres local que contiene
la clase, separando cada nodo con un punto (.).
A diferencia de la mayor parte de las jerarquas, cuyas ramas empiezan en un solo nodo raz, la
jerarqua de espacios de nombres de .NET tiene varios nodos raz. El espacio de nombres raz
ms largo recibe el nombre System. Incluye muchas clases, pero tambin varios nodos de jerar
qua de la siguiente capa (espacios de nombres). Debido a que el marco conceptual incluye ca
ractersticas para el desarrollo de aplicaciones de Windows y Web, hay espacios de nombres que
contienen las caractersticas de desarrollo especficos de Windows y Web. stos aparecen dentro
del espacio de nombres System, y se les denomina Windows y Web. Todo el cdigo relacionado
con formularios en pantalla en el espacio de nombres Windows aparece en el espacio de nombres
Forms, y dentro de ste se encuentra la clase real que implementa un formulario, denominado
Form. En la figura 1-3 se presenta una imagen de este subconjunto de espacios de nombres.
En Visual Basic se identifica una clase al calificarla con todos sus espacios de nombres, a partir
de la raz. La clase Form tiene el siguiente nombre plenamente calificado:
System.Windows.Forms.Form

Las partes de .NET Framework | 11

01_PATRICK-CHAPTER_01.indd 11 17/2/10 15:18:27


System = Espacio de nombres
= Clase
Web

Windows

Forms

Form

Figura 1-3. Una jerarqua de espacios de nombres y clases.

Todas las clases y los tipos existen en algn lugar de la jerarqua, aunque no todas las clases des
cienden de System. Muchas de las caractersticas de soporte especficas de Visual Basic aparecen
en el espacio de nombres Microsoft.VisualBasic, que tiene Microsoft como nodo raz
en lugar de System. Cuando crea proyectos nuevos en Visual Basic, el nombre del proyecto
es, como opcin predeterminada, un nuevo nodo de nivel superior en la jerarqua. Si crea una
nueva aplicacin de Windows llamada WindowsApplication1, el formulario Form1 prede
terminado tiene el siguiente nombre plenamente calificado:
WindowsApplication1.Form1
Este nuevo espacio de nombres de la aplicacin no slo es un apndice de segunda clase que
cuelga del espacio de nombres System. Est plenamente integrado en la jerarqua completa de
espacio de nombres de .NET; el espacio de nombres WindowsApplication1 es un nodo raz,
al igual que los nodos raz System y Microsoft. Visual Basic incluye caractersticas que le per
miten modificar el espacio de nombres predeterminado para su aplicacin, o coloca una de las
clases de la aplicacin en un espacio de nombres especfico. Incluso puede colocar las clases de
su aplicacin en la rama del espacio de nombres System. Al cambiar WindowsApplication1 a
System.MiSuperApl se mueve Form1 a:
System.MiSuperApl.Form1
Si su aplicacin es, en realidad, una biblioteca o un componente destinado para usar en progra
mas, las clases de su aplicacin aparecern en el espacio de nombres que especifique cuando el
otro programa cargue su componente en el rea de su aplicacin. Su cdigo parecer parte de los
espacios de nombres proporcionados por Microsoft. No es estupendo?
Aunque puede agregar sus clases al espacio de nombres System, terminar con la misma mo
lestia que otros programadores de .NET. Se supone que el espacio de nombres System es para
las caractersticas del sistema (lase: proporcionadas por Microsoft), y eso es todo. Adems,
es posible que dos vendedores usen la misma ruta del espacio de nombres. As que, para evitar
posibles conflictos de espacio de nombres y miradas indiscretas de otros programadores, debe
asignar a las clases de su aplicacin el siguiente nombre:
NombreEmpresa.NombreAplicacin.NombreClase

12 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 12 17/2/10 15:18:28


Una sola clase u otro tipo no puede dividirse entre varios espacios de nombres, aun dentro de
la misma rama de una jerarqua. Sin embargo, dos clases o tipos pueden compartir un nombre
comn en diferentes espacios de nombres, aun dentro de la misma rama.
Todas las clases de la BCL y la FCL aparecen entremezcladas en toda la jerarqua de espacios de
nombres. Esto significa que no necesariamente sabe si una clase determinada es de la BCL o la
FCL. Para ser franco, en realidad no importa; a su cdigo no le interesa de qu biblioteca provie
ne una clase, siempre y cuando est disponible para usarla en la estacin de trabajo del usuario.
Justo antes del lanzamiento de Visual Studio 2008, Microsoft anunci que pondra a disposicin
de todos el cdigo fuente de gran parte de la biblioteca de clases de Framework, versin 3.5,
para que los desarrolladores lo revisen. Esto significa que los programadores que quieren saber
cmo ordena Microsoft una lista de nombres en memoria o dibuja un crculo de colores en un
formulario obtendrn por lo menos un vistazo parcial de la manera en que se hace.

Ensamblados y manifiestos
Un ensamblado es una unidad de implementacin de las partes de la aplicacin o biblioteca
.NET. En 99.9% de los casos, un ensamblado es simplemente un archivo ejecutable de .NET (un
archivo .exe) o una biblioteca de clases de .NET y de otros tipos (un archivo .dll). Es posible dividir
un ensamblado entre varios archivos, pero por lo general se dedica un archivo a un ensamblado.
Lo que convierte a un archivo .exe o .dll ordinario en un ensamblado es la presencia de un
manifiesto. En el caso de ensamblados de un solo archivo, el manifiesto aparece en el archivo;
tambin puede aparecer en un archivo independiente. El manifiesto es un fragmento de datos que
presenta una lista de detalles importantes acerca del ensamblado, incluido su nombre, informacin
de versin, datos culturales predeterminados, informacin sobre ensamblados y tipos externos de
referencia, y una lista de todos los archivos contenidos en el ensamblado. El CLR no reconocer
un ensamblado sin su manifiesto, de modo que no lo pierda.
Los ensamblados pueden incluir un nombre fuerte opcional. Esto ayuda a asegurar la integridad
y autenticidad de un ensamblado mediante una firma digital adjunta al manifiesto. El nombre
fuerte utiliza criptografa de clave pblica para garantizar que el ensamblado es nico y no se ha
modificado. Visual Studio y .NET Framework incluyen herramientas que permiten agregar un
nombre fuerte a un ensamblado.
Cuando implemente su aplicacin, por lo general colocar todos los archivos del ensamblado,
de configuracin y relacionados y especficos de su aplicacin en el directorio de instalacin de
la aplicacin, al igual que en los das del Jursico antes de .NET. Los ensamblados compartidos
que estn diseados para que los use ms de una aplicacin en una sola mquina puede almace
narse en la cach global de ensamblados (GAC, Global Assembly Cache). Todos los ensamblados
colocados en la GAC deben tener nombres fuertes. Algunos sistemas permiten que slo los ad
ministradores del sistema agreguen ensamblados a la GAC.

Metadatos y atributos
Los ensamblados estn determinados por la letra m. Adems de manifiestos y miembros de
tipos, tambin pueden contener metadatos. El cdigo de la aplicacin y los elementos de datos

Las partes de .NET Framework | 13

01_PATRICK-CHAPTER_01.indd 13 17/2/10 15:18:28


almacenados en un ensamblado son paralelos al cdigo y los elementos de datos encontrados
en el cdigo fuente relacionado de Visual Basic; para cada tipo y miembro de su cdigo fuente,
hay cdigo ejecutable asociado en el ensamblado implementado. Esto tiene sentido y no cambia
mucho de las implementaciones previas a .NET. La diferencia es que ahora el compilador de
Visual Basic adjunta informacin adicional (metadatos) a cada tipo y miembro del ensamblado.
Estos metadatos documentan el nombre del contenido asociado, informacin acerca de los tipos
de datos requeridos, informacin sobre la herencia de clase del elemento, y permisos de seguri
dad antes de que el usuario u otro software usen el elemento.
Su cdigo fuente de Visual Basic puede mejorar los metadatos de cualquier elemento de su en
samblado mediante atributos. Los metadatos generados por un atributo son ms que slo algn
nmero de ID. Los atributos implementan clases .NET completas, con sus propios valores de
datos y su lgica asociada. Cualquier cdigo .NET que sabe cmo procesar atributos puede exa
minar los atributos en busca de un tipo o miembro y tomar las acciones necesarias. Esto incluye
Visual Studio, el compilador de Visual Basic y sus propias aplicaciones personalizadas.
He aqu un ejemplo mundano: .NET Framework incluye un atributo denominado Obsole-
teAttribute. Este atributo le permite marcar tipos de miembros de su ensamblado como
obsoleto o ya no soportado. (Visual Studio usa este atributo para desplegar una advertencia cada
vez que intenta usar una caracterstica caduca de BCL o FCL.) Para usar el atributo, se agrega a
un miembro de su aplicacin empleando picoparntesis:
Class MiClaseConMiembrosObsoletos
<ObsoleteAttribute> Sub HaceAlgo()
End Sub
End Class

Este cdigo define una sola clase (MiClaseConMiembrosObsoletos) con un solo procedimien
to de miembro (HaceAlgo), un procedimiento que evidentemente realiza alguna tarea. El pro
cedimiento se marca con el atributo ObsoleteAttribute. Por costumbre, todos los nombres
de atributos terminan con la palabra Attribute. Puede quitar esta parte de la palabra, si lo desea,
siempre y cuando la palabra resultante no entre en conflicto con ninguna palabra clave del len
guaje Visual Basic:
Class MiClaseConMiembrosObsoletos
<Obsolete> Sub HaceAlgo()
End Sub
End Class

Cuando compila la clase y la almacena en un ensamblado, el atributo <ObsoleteAttribute>


se almacena como parte de la definicin de HaceAlgo. Ahora puede escribir una aplicacin de
Visual Basic separada que rastree un ensamblado y d salida al nombre y el estado de cada tipo
de miembro que encuentre. Cuando ese programa de anlisis encuentre el miembro obsoleto,
detectar ObsoleteAttribute en los metadatos y dar salida al estado:
HaceAlgo Procedure: Obsolete, don't use it!

Casi todos los atributos estn diseados con un propsito especfico en mente. Algunos atributos
instruyen a Visual Studio para que despliegue los miembros de una clase de maneras especficas.

14 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 14 17/2/10 15:18:28


Estoy hablando
de esta rea
Propiedades.

Figura 1-4. El panel Propiedades en Visual Studio.

Tal vez ya haya jugado con las caractersticas de edicin de formularios de Visual Studio para
disear una aplicacin simple de escritorio de Windows. Cuando agrega un control (como un
botn o un cuadro de lista) a un formulario y selecciona ese control, Visual Studio le permite
editar detalles de ese control mediante el rea del panel Propiedades (vase la figura 1-4).
El control Button est implementado como una clase, y muchos de sus miembros de clase apa
recen en el panel Propiedades, pero no todos ellos. Cuando se dise la clase Button, se agrega
ron atributos a sus miembros para indicarle a Visual Studio cules miembros deben aparecer en
el panel Propiedades y cules no. De manera obediente, Visual Studio examina estos atributos y
slo despliega las propiedades solicitadas.

Definicin de la versin
Como las suyas, mis aplicaciones son perfectas desde su lanzamiento inicial, y nunca tengo una
razn para modificarlas o agregar caractersticas. Pero hay organizaciones de desarrollo de software
(incluida una empresa grande a la que har referencia por su letra inicial M, para evitarle la pena)
que sienten la necesidad de estar por encima de sus competidores con versiones mejoradas de
sus ofrecimientos de software. Digamos que M tiene un procesador de palabras popular que
incluye la versin 1.0 de un componente de revisin ortogrfica. M tambin vende una herra
mienta de correo electrnico que depende especficamente de la versin 1.0 de ese mismo com
ponente compartido. Si, en una muestra de machismo competitivo, M lanza una actualizacin
del procesador de palabras y del componente de revisin ortogrfica (ahora la versin 2.0), qu
sucede a la capacidad de revisin ortogrfica de la herramienta de correo electrnico?

Las partes de .NET Framework | 15

01_PATRICK-CHAPTER_01.indd 15 17/2/10 15:18:29


No afirmo que esto pase en la vida real. Pero si as fuera, el reemplazo de un componente vital
compartido con una versin ms reciente pero de alguna manera incompatible podra causar
problemas reales. Un problema relacionado es la implementacin de varias versiones de un solo
componente en la misma estacin de trabajo, todas en diferentes directorios. Pueden borrarse
de manera segura algunas de ellas?
.NET resuelve estos problemas mediante la definicin de la versin. Todos los ensamblados que
usan componentes compartidos identifican de manera exacta cules versiones de los compo
nentes compartidos se necesitan. Aunque puede reconfigurarse una aplicacin para que use la
versin ms reciente, slo usar, como opcin predeterminada, la versin de un componente
especificada originalmente.
Varias versiones de un solo componente compartido pueden agregarse a la GAC, una caracte
rstica llamada implementacin lado a lado. El CLR asegura que la aplicacin correcta se vincula
con el componente correcto. Incluso puede ejecutar aplicaciones de manera simultnea que usan
diferentes versiones del mismo componente.

Del cdigo fuente a EXE


Ahora ya sabe gran parte de lo que hay que saber acerca de .NET, excepto por esa cosa molesta
de la programacin. Antes de profundizar en algn cdigo real, tomemos un breve descanso y
examinemos el tiempo de vida de una aplicacin, de principio a fin (vase la figura 1-5).
Por tanto, he aqu lo que sucede, paso a paso:
1. Usted, como programador, es responsable de preparar los ingredientes bsicos (a) de la aplicacin.
En el caso de los programas de Visual Basic, esto significa crear uno o ms archivos de cdigo fuen
te con una extensin .vb. Sus ingredientes tambin pueden incluir otros archivos de apoyo, como
archivos de recursos (de texto e imagen, a menudo utilizados para soporte de varios idiomas).

(a) (b) (c) (e)

(d)
Figura 1-5. El proceso de desarrollo real de Visual Basic.

16 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 16 17/2/10 15:18:29


2. El compilador de Visual Basic cocina su aplicacin (b). El resultado es un ensamblado, junto con
un manifiesto y metadatos. La salida en realidad es un MSIL semicompilado e incluye versiones
listas para ejecutarse de los tipos y miembros del cdigo fuente, incluidos todos los nombres de
miembros y tipos. Todo este contenido puede descompilarse (regresarlo a MSIL completo, aun
que no a Visual Basic completo) usando una herramienta llamada ildasm.exe (el desensamblador
de lenguaje intermedio de Microsoft), que se incluye con .NET Framework. Debido a que tal
vez no quiera que nadie desensamble su aplicacin y revise el cdigo, Microsoft (y otros) tambin
proporcionan un obfuscador, que revuelve el contenido de su cdigo de tal manera que resulte lo
suficientemente difcil como para desalentar a los ojos indiscretos.
3. El ensamblado (c) se implementa en la estacin de trabajo del usuario. Se utilizan unos cuantos
mtodos diferentes para implementar la aplicacin, incluidos 1) generar un paquete de instalacin
para el Windows Installer; 2) generar una implementacin de ClickOnce, o 3) realizar una instala
cin de xcopy, que slo requiere copiar el propio ensamblado EXE en la mquina de destino. No
importa el mtodo de implementacin que elija, el motor de tiempo de ejecucin de .NET
(d) debe estar instalado en la estacin de trabajo del usuario.
4. El usuario come (quiero decir, ejecuta) el programa (e). El CLR hace una compilacin justo a
tiempo (JIT, just-in-time) del ensamblado MSIL para prepararlo para usarse en la plataforma local.
Luego presenta la aplicacin al usuario y administra todos los aspectos de la aplicacin mientras la
ejecuta. El usuario experimenta un nivel de alegra y satisfaccin que rara vez se encuentra cuando
se usan otras aplicaciones de software.
Al igual que con la preparacin de una comida para un da festivo, el proceso de desarrollo real
est de alguna manera relacionado con la lectura de un prrafo (o un libro de recetas) sobre l.
Pero no es tan difcil como para que no pueda incluirse en un libro como ste.

Temas relacionados con Visual Studio y Visual Basic


Espere un minuto: qu pasa con Visual Studio? En la ltima seccin ni siquiera se mencion.
Y no era necesario, porque no requiere usarlo para desarrollar, compilar, implementar o ejecutar
aplicaciones de Visual Basic. Todo .NET Framework (incluido el compilador de Visual Basic)
est disponible, de manera gratuita, en el sitio Web de Microsoft; descrguelo y selo para
desarrollar e implementar aplicaciones que son tan poderosas y complejas como las de Visual
Studio.
La edicin de julio de 1983 de la revista Datamation incluye un artculo de un valeroso lector, Ed
Post, titulado Real Programmers Dont Use Pascal (Los programadores reales no usan Pascal).*
Recomiendo que lea este artculo, porque le ayudar a separar rpidamente a los programadores
reales de los comedores de pays. Y cuando lo haga, aljese lo ms rpido que pueda de los

* Datamation 29 (7): julio de 1983, pp. 263-265. Tambin encontr el texto del artculo en Internet al hacer una bsqueda
con el ttulo. Una versin similar del texto, con unos cuantos cambios editoriales, tambin se encuentra bajo el ttulo Real
Programmers Dont Write Pascal (Los programadores reales no escriben en Pascal).

Temas relacionados con Visual Studio y Visual Basic | 17

01_PATRICK-CHAPTER_01.indd 17 17/2/10 15:18:29


programadores reales. Por supuesto, pueden reconstruir su cdigo fuente del ensamblado .NET
obfuscado, pero sern intiles en un proyecto de equipo en que se usa Visual Studio.
Un programador real podra codificar cualquier aplicacin de .NET empleando el Bloc de
notas, y ejecutarlo. En realidad, los programadores reales usaran Emacs o vi en lugar del Bloc
de notas (porque Windows no incluye una interfaz para teclear), pero los resultados seran los
mismos. Gruiran mientras usted escribe con toda alegra en la interfaz de usuario elegante,
bien diseada y plenamente personalizable de Visual Studio. Ellos se quejaran mientras usted
utiliza las caractersticas IntelliSense y autocompletar integradas en el editor de cdigo de Visual
Studio. Consumiran otra rebanada de pizza mientras usted arrastra y coloca interfaces de usua
rio de Windows y Web.
S, el programador real podra generar aplicaciones completas con slo un editor de texto (o hex)
y un compilador de .NET, pero usted alcanzara la gloria, porque lo hara en una fraccin del
tiempo que le tomara al enamorado de FORTRAN terminar su cdigo.

Visual Studio 2008


Debido a que ste es un libro sobre desarrollo de Visual Basic y no de uso de Visual Studio, no
me adentrar mucho en las caractersticas de Visual Studio ni en los elementos de su interfaz. Es
una aplicacin estupenda y su fuerte integracin con .NET Framework hace que sea la mejor
herramienta para desarrollar aplicaciones con .NET. Pero como el programador real le dira, slo
es un editor de texto ensalzado. Visual Studio oculta gran parte de la complejidad del cdigo
.NET, y su generacin automtica del cdigo necesario para construir la interfaz de usuario de
su aplicacin es casi obligatoria. La mayora de sus caractersticas estn all para simplificar el
proceso de agregar cdigo a su aplicacin.
Aunque no estar incluyendo una revisin de 20 pginas de Visual Studio aqu, encontrar
imgenes de Visual Studio en todo el libro, colocadas para ayudarle a comprender mejor los
temas que se analizan en cada captulo. Cuando inicia Visual Studio por primera vez, despliega
la Pgina de inicio. (Vase la figura 1-6. Las capturas de pantalla de este libro se tomaron de la
Professional Edition de Visual Studio 2008.)
Visual Studio 2008 es la cuarta versin del producto desde la introduccin de .NET en 2002.
Cada versin (en 2002, 2003, 2005 y 2008) corresponde a una versin relacionada de .NET
Framework (1.0, 1.1, 2.0 y 3.5, respectivamente) y de la implementacin de .NET de Visual
Basic. La versin 2008 de Visual Studio es importante. Est empaquetada con nuevas caracters
ticas de uso y viene en cuatro deliciosos sabores:
Visual Studio 2008 Express Edition
Este producto de nivel inicial est orientado al aficionado casero o al programador de fin
de semana que quiere aprender .NET y uno de sus lenguajes de programa centrales, pero
que no lo usar todos los das. Visual Studio 2008 Express Edition es en realidad un con
junto de las ediciones exprs de varios productos de lenguaje promovidos juntos, incluida
la Visual Basic 2008 Express Edition. El objetivo de Microsoft es llevar a la mayor cantidad

18 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 18 17/2/10 15:18:29


Figura 1-6. La Pgina de inicio de Visual Studio.

posible de personas a disfrutar las alegras de programar en .NET, de modo que ofrece la
Express Edition sin costo alguno. Esta edicin incluye una interfaz de usuario simplificada,
similar a la de Visual Studio, pero impone algunas restricciones a la capacidad de elaborar
programas. Aun puede editar directamente el cdigo fuente y crear aplicaciones de cualquier
complejidad, pero la interfaz de usuario no siempre le ayudar con esto. Por ejemplo, no
puede desarrollar aplicaciones Web con Visual Basic Express, a menos que instale el produc
to separado Visual Web Developer 2008. Adems, Express no incluye mucho soporte para
la implementacin; por lo general, se espera que las aplicaciones diseadas con la Express
Edition slo se usen en su propia estacin de trabajo.
Visual Studio 2008 Standard Edition
La edicin estndar de Visual Studio es como la Express Edition, con algunas adiciones,
como soporte a varios lenguajes, herramientas de desarrollo Web y soporte a implementa
cin mediante los mtodos ClickOnce y Windows Installer. Se incluye SQL Server 2005
Express Edition.
Visual Studio 2008 Professional Edition
ste es el nivel mnimo requerido por los programadores que desarrollarn aplicaciones
todos los das por dinero. Es la versin que uso e incluye todas las caractersticas avanzadas
que necesita un solo programador para desarrollo de aplicaciones para computadoras de

Visual Studio 2008 | 19

01_PATRICK-CHAPTER_01.indd 19 17/2/10 15:18:30


escritorio y Web. La interfaz de usuario simple de la edicin exprs ya no existe, y es reem
plazada por el poderoso entorno de desarrollo integrado (IDE, Integrated Development
Environment) de Visual Studio y toda su documentacin. Tambin se incluyen herramien
tas especiales que ayudan a desarrollar aplicaciones para Microsoft Office y para dispositivos
mviles. Pero espere, hay ms. Tambin obtiene la SQL Server 2005 Developer Edition.
Todas las instrucciones de este libro que se relacionan con el uso de un entorno de desarrollo
se refieren a la Professional Edition. Pero si sigue usando la Express o la Standard Edition,
no tendr muchos contratiempos, porque las interfaces son muy similares.
Visual Studio Team System 2008
La lite de la lnea de productos de Visual Studio es la versin Team System. Incluye carac
tersticas necesarias para los equipos de desarrollo que trabajan proyectos en equipo, como
herramientas de administracin de proyectos y control de cdigo fuente. Es posible instalar
Visual Studio Team System 2008 Team Foundation Server, un producto separado, en un
servidor compartido y mejorar las caractersticas del paquete Team System.
SQL Server 2008, la ms reciente edicin del producto de base de datos insignia de Microsoft,
fue lanzado oficialmente el mismo da que Visual Studio 2008. Por desgracia, lanzar tiene dos
significados diferentes, dependiendo de cul de los productos est hablando. En el caso de Visual
Studio 2008, lanzar signific que poda descargar el producto del sitio Web de Microsoft varios
meses antes del evento de lanzamiento. Para SQL Server se us un sitio de espejo para permitir
el acceso al producto varios meses despus del evento. Esa diferencia bast para evitar que SQL
Server 2008 fuera la base de datos incluida con Visual Studio. Pero s obtiene SQL Server 2005
en su bolsa de golosinas de Visual Studio, y siempre puede actualizarlo, si lo desea.
Ms all del soporte a bases de datos, Visual Studio 2008 ha sido respaldado con varias mejoras
de uso y nuevas caractersticas:
Caractersticas especficas de LINQ
Analizaremos la nueva caracterstica LINQ en el captulo 17. Ms all de los cambios de
cdigo agregados a .NET para dar soporte a LINQ, Visual Studio incluye diseadores espe
ciales que le ayudan a programar con LINQ.
Soporte a proyectos de Windows Presentation Foundation
Windows Presentation Foundation, que antes tena el nombre de cdigo Avalon, es un
nuevo sistema de interfaz de usuario XML que cuenta con soporte en Windows para apli
caciones de escritorio y Web. Visual Studio 2008 le permite crear aplicaciones de WPF o
proyectos de control. En este libro se analiza brevemente Windows Presentation Founda
tion en el captulo 18.
Editor mejorado de HTML (pginas Web)
El nuevo editor HTML es una mejora sobre las ediciones anteriores encontradas en las
primeras versiones de Visual Studio. La versin 2008 incluye un nuevo editor de vista divi
dida que muestra vistas HTML y WYSIWYG de manera simultnea (vase la figura 1-7).
Las hojas de estilo en cascada (CSS, Cascading Style Sheets) finalmente reciben respeto con
el nuevo editor de estilos CSS y el soporte de IntelliSense para el contenido de CSS.

20 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 20 17/2/10 15:18:30


Figura 1-7. Tiene ambas cosas: marcado HTML y despliegue de ste.

Soporte a bibliotecas anteriores


Versiones iniciales de Visual Studio estaban unidas de cerca con el lanzamiento relacionado de
.NET. Visual Studio 2008 sigue esa tradicin mediante su sociedad con la versin 3.5 de .NET
Framework. Sin embargo, ahora puede tomar como destino versiones anteriores de .NET (has
ta la 2.0) en Visual Studio 2008 con slo un clic del ratn.
Soporte mejorado a depuracin
Visual Studio 2008 incluye mejor soporte para depuracin remota, sobre todo en Windows
Vista. Pero lo ms sorprendente de las nuevas caractersticas de depuracin es la capacidad
de recorrer paso a paso el cdigo de las bibliotecas de .NET Framework, y Visual Studio
obtiene de manera dinmica la versin correcta del cdigo con base en su tipo de proyecto
y la versin de su marco conceptual.
IntelliSense transparente
IntelliSense es una herramienta de productividad que ayuda a acelerar su frenes por crear
cdigo. Pero en ocasiones la ventana de IntelliSense que apareca ocultaba parte de su cdigo
fuente. Ahora Visual Studio 2008 le permite revisar la ventana de lista de IntelliSense con
slo mantener oprimida la tecla Ctrl (vase la figura 1-8).
Soporte a IntelliSense y depuracin de JavaScript
Aunque Visual Studio fingi alguna vez amnesia en relacin con Java y JavaScript, ahora in
cluye por completo al ltimo. Este entorno mejorado de JavaScript simplifica la creacin de
las nuevas aplicaciones de Ajax. Aunque no es especficamente necesario para Visual Basic,
este nuevo soporte es una estupenda adicin para quienes desarrollan aplicaciones Web.

Visual Studio 2008 | 21

01_PATRICK-CHAPTER_01.indd 21 17/2/10 15:18:31


Figura 1-8. Revisin directa de los trucos de Visual Studio.

A pesar de todas estas estupendas caractersticas, Microsoft an se niega a implementar la


caracterstica ms solicitada de Visual Studio: autocompletado de procedimientos, en que
Visual Studio creara todo el contenido de un procedimiento de cdigo fuente basado en el
ingreso de su nombre y el uso de la combinacin de teclas Ctrl-barra de espaciado. En cambio,
Microsoft desperdicia su tiempo en otras llamadas caractersticas de productividad. Con auto
completado de procedimientos, podra escribir aplicaciones completas en minutos. Hasta que
esa caracterstica quede disponible, usted y yo tendremos que seguir escribiendo el software,
desarrollando el cdigo de calidad que los usuarios se han acostumbrado a esperar que salga
de nuestros dedos.

Resumen
Hace casi dos dcadas, Visual Basic transform el panorama del desarrollo en Windows con su
modelo de programacin de arrastrar y colocar, y su fastuosa estructura de desarrollo orientada a
eventos. Pero Windows ha cambiado mucho desde esos das de Windows 3.x. A medida que ha
cambiado, Visual Basic lo ha hecho junto con l. Visual Basic 2008, mediante su asociacin con
.NET Framework, proporciona acceso a las herramientas de programacin necesarias para desa
rrollar aplicaciones de calidad para los equipos de escritorio de Windows, Internet y la siguiente
generacin de dispositivos mviles.
Y Microsoft no est deteniendo este avance con la versin 2008. La siguiente versin de Visual
Basic, con los nombres de cdigo VBx y Hawaii, promete incluir caractersticas an ms avan
zadas. Esa versin estar construida sobre el motor de lenguaje dinmico (DLR, Dynamic Lan
guage Runtime) de Microsoft, permitindole interactuar libremente con bibliotecas de lenguajes
como Ruby y Python.

22 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 22 17/2/10 15:18:31


Proyecto
Bienvenido a la seccin Proyecto, la parte de cada captulo donde tiene una oportunidad de
echarle el guante a Visual Studio 2008 y Visual Basic. El desarrollo del Proyecto Biblioteca, el
principal proyecto de este libro, empieza formalmente en el captulo 3, pero hay que hacer algo
de trabajo para el proyecto mientras tanto. En este captulo le presentar el cdigo fuente de
ejemplo proporcionado con este libro, y empezaremos a usarlo.
Debido a que casi todas las secciones Proyecto, incluida sta, se relacionan con Visual Studio,
asegrese de que lo tiene instalado y listo para usarlo. Adems, como cada seccin Proyecto
est diseada para que la use interactivamente con el cdigo fuente proporcionado, supondr
que lo ha descargado e instalado (consulte el apndice A para conocer las instrucciones) y que
lo est viendo con un ojo mientras lee esta seccin con el otro. Imprimir secciones del cdigo
fuente en el libro, pero como el Proyecto Biblioteca incluye decenas de miles de lneas de cdi
go fuente, no podr imprimir aqu todas las lneas. Es seguro que obtendr grandes beneficios
de cada seccin Proyecto con slo leerla, pero obtendr an ms si tiene acceso al cdigo
fuente completo.
En el proyecto de este captulo cargaremos un programa simple en Visual Studio y lo ejecuta
remos. Hay dos maneras de hacerlo. La primera es slo abrir el proyecto existente de manera
directa desde el directorio de instalacin. Vaya al directorio donde instal el cdigo fuente de
este libro, abra el subdirectorio Cap01 y haga doble clic en el archivo Cap01.vbproj. Esto abrir
directamente el proyecto en Visual Studio, listo para usarse.
La segunda manera consiste en usar las plantillas de proyecto especficas del captulo para crear
nuevos proyectos en Visual Studio. El programa de instalacin del cdigo fuente de este libro
modifica su instalacin de Visual Studio, agregando nuevas entradas a la ventana de dilogo
Nuevo proyecto. Cada una de estas nuevas plantillas de proyecto puede usarse como punto de
partida para un nuevo proyecto de Visual Basic. Para cargar el programa de ejemplo del captulo 1
empleando la plantilla, inicie Visual Studio. Aparecer la Pgina de inicio, como se mostr en la
figura 1-6. Del men Archivo, seleccione Nuevo | Proyecto, para desplegar la ventana de dilogo
Nuevo proyecto (vase la figura 1-9).
Es probable que su ventana de dilogo Nuevo proyecto difiera ligeramente, dependiendo de
las caractersticas que haya decidido instalar con Visual Studio. Los proyectos disponibles
estn agrupados por la descripcin que se encuentra en el campo Tipos de proyecto. Por
ejemplo, en la figura 1-9 se muestran los diversos tipos de proyecto predeterminados que
puede crear en Visual Basic, incluidos Aplicacin de Windows Forms (una aplicacin de escri
torio estndar para la plataforma Windows), Biblioteca de clases (una DLL de caractersticas
definidas por la clase) y Aplicacin de consola (aplicaciones de lnea de comandos, de texto).
Para crear una nueva aplicacin, seleccione primero el tipo de proyecto, la plantilla que usar
y, por ltimo, el nombre del nuevo proyecto en el campo Nombre. Al hacer clic en Aceptar se
crea un nuevo proyecto.

Proyecto | 23

01_PATRICK-CHAPTER_01.indd 23 17/2/10 15:18:31


Figura 1-9. La ventana de dilogo Nuevo proyecto: demasiadas opciones.

Para usar el proyecto de ejemplo Cap01, seleccione la entrada Programacin en Visual Basic 2008
dentro del tipo de proyecto Visual Basic, y luego seleccione Cap01 Ejemplo del campo Plantillas
(vase la figura 1-10). Por ltimo, haga clic en Aceptar para crear el nuevo proyecto de ejemplo.
Una vez que el proyecto se carga, acceda al formulario principal del programa al hacer clic en el
archivo Form1.vb del Explorador de soluciones (vase la figura 1-11).
Esta presentacin predeterminada de la Visual Studio Professional Edition incluye tres compo
nentes de edicin: 1) el rea de edicin principal, donde aparece la vista de Form1; 2) el panel
Explorador de soluciones, que proporciona acceso a todos los archivos incluidos en el proyecto,
y 3) el panel Propiedades, que le permite editar varios aspectos del elemento seleccionado en el
rea del editor principal o cualquier otro lugar de la interfaz de usuario.
El proyecto de ejemplo es muy bsico. Incluye un formulario con un solo botn de accin. Al
hacer clic en este botn cuando se ejecuta la aplicacin, se despliega un mensaje simple. Ejecute
el proyecto al oprimir la tecla F5. Cuando aparece el formulario principal, al hacer clic en el
botn Vamos, haz clic en m!, se despliega el mensaje de la figura 1-12 (gol, dulce gol).

Figura 1-10. Seleccin del proyecto Cap01 Ejemplo.

24 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 24 17/2/10 15:18:32


Figura 1-11. El formulario principal de la aplicacin de ejemplo.

Entonces, qu hay con todo ese cdigo complejo que tuve que escribir para desarrollar esta
aplicacin de varias facetas? Todo est all, a la vista. En el panel Explorador de soluciones, haga
clic con el botn derecho en la entrada Form1.vb y seleccione Ver cdigo del men contextual.
(Al igual que con la mayora de los ejemplos de cdigo fuente presentados en este libro, he te
nido que ajustar ligeramente el texto para que se despliegue de manera apropiada en la pgina
impresa. Por lo general, esto incluye la divisin de una lnea lgica larga en dos o ms lneas
cortas.)
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
MsgBox("Hola, mundo!")
End Sub
End Class

Figura 1-12. Hola, mundo, de nuevo!

Proyecto | 25

01_PATRICK-CHAPTER_01.indd 25 17/2/10 15:18:33


En captulos posteriores revisaremos las peculiaridades de este cdigo, pero he aqu lo ms im
portante:
El formulario principal, Form1, est representado en cdigo por una clase, llamada
Form1.
El formulario incluye un botn de comando llamado Button1 que expone un evento Click.
Este evento es manejado por el procedimiento Button1_Click, un miembro de la clase
Form1.
El manejador de eventos, Button1_Click, incluye una sola instruccin, MsgBox. Esta
instruccin realiza la pesada tarea de presentar el cuadro de mensaje siempre amigable al
mundo.
se es todo el cdigo que escrib para Form1.vb. De seguro parece muy corto para todo el traba
jo que hace. Tiene que haber ms cdigo oculto por all. Y de seguro, tambin, hay una media
docena de archivos adicionales incluidos en el proyecto. Visual Studio oculta stos como opcin
predeterminada, porque administra parte o todo el contenido de estos archivos. Para verlos,
haga clic en el botn Mostrar todos los archivos (el segundo botn, de izquierda a derecha, en la
barra de herramientas del panel Explorador de soluciones). Vea todos esos archivos! Para revisar
los archivos adicionales asociados con Form1, expndalo al hacer clic en el signo ms (+) que se
encuentra a la izquierda (vase la figura 1-13).
Haga doble clic en la entrada Form1.Designer.vb para ver el cdigo que Visual Studio escribi
automticamente para este formulario. (Pausa dramtica.) Guau! Vea todo ese cdigo intimi
dante. En realidad, no es tan malo. Al final de este libro conocer todo acerca de l. Aqu, en el
captulo 1, en realidad no es necesario comprenderlo todo, pero hay algunas lneas interesantes.
Estoy incluyendo nmeros de lnea para facilitar la localizacin del cdigo coincidente en Visual
Studio. Si quiere ver nmeros de lnea en Visual Studio (aqu aparecen las instrucciones para la
Professional Edition):

Haga clic aqu

Y luego aqu

Figura 1-13. Vista de los archivos ocultos mediante el Explorador de soluciones.

26 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 26 17/2/10 15:18:34


1. Seleccione el men Herramientas Opciones para desplegar las opciones de Visual Stu
dio.
2. Seleccione Editor de texto Basic Editor, de la vista de rbol que se encuentra a la
izquierda. Si el campo Mostrar todos los valores est marcado, el ltimo componente en
que debe hacer clic en la vista de rbol ser General, no Editor.
3. Seleccione (marque) el campo Nmeros de lnea, a la derecha.
4. Haga clic en Aceptar para aplicar los cambios.
Si es nuevo en la programacin en Visual Basic o .NET, no se preocupe ahora si este cdigo no
tiene sentido; se volver ms claro a medida que recorra las pginas de este libro.
01 <Global.Microsoft.VisualBasic.CompilerServices. _
DesignerGenerated()> _
02 Partial Public Class Form1

06 <System.Diagnostics.DebuggerNonUserCode(
)> _
07 Protected Overloads Overrides Sub Dispose _
(ByVal disposing As Boolean)

Estas lneas muestran atributos en accin. Estos dos atributos (DesignerGenerated y Debug-
gerNonUserCode) son un tanto parecidos al atributo Obsolete analizado antes, porque pro
porcionan cierta identidad de informacin al cdigo relacionado. DesignerGenerated modi
fica toda la seccin de cdigo de Form1, mientras que DebuggerNonUserCode slo modifica
al miembro Dispose. Para mayor claridad, ambos atributos incluyen sus rutas completas de
espacio de nombres. La palabra clave Global al principio del atributo DesignerGenerated es,
en realidad, una palabra clave de Visual Basic que indica Empieza en la parte ms elevada de la
jerarqua del espacio de nombres; sta no es una ruta relativa.
02 Partial Public Class Form1

Vio la palabra Partial en la lnea 02? S que la vio. Hey, espere un minuto; Public Class Form1
tambin apareci en el archivo Form1.vb, pero sin la palabra clave Partial. Visual Basic 2008
incluye una caracterstica que le permite dividir una sola clase (Form1 en este caso) entre varios
archivos de cdigo fuente al incluir la palabra clave Partial con una de sus partes, por lo me
nos. Estupendo, no? Permite a Visual Studio agregar cdigo de inicializacin complejo a su
formulario (como el que se encuentra en este archivo Form1.Designer.vb) sin preocuparse del
archivo de cdigo fuente (Form1.vb).
03 Inherits System.Windows.Forms.Form

La palabra clave Inherits define la relacin de herencia entre esta nueva clase Form1 y la clase
System.Windows.Forms.Form escrita antes. Form es la clase base y Form1 es la clase deri
vada; Form1 hereda toda la funcionalidad de la clase Form, incluido su aspecto inicial. En el
captulo 8 se analizarn con ms detalle estas relaciones entre clases.
44 Friend WithEvents Button1 As System.Windows.Forms.Button

Proyecto | 27

01_PATRICK-CHAPTER_01.indd 27 17/2/10 15:18:34


La lnea 44 define el botn Vamos, haz clic en m! que aparece en el centro del formulario.
Todos los controles que aparecen en su formulario son instancias separadas de clases. (Friend
es una instruccin de declaracin descrita en el captulo 6.) La palabra clave WithEvents indica
que esta instancia de la clase Button responder a eventos, como el hecho de que el usuario haga
clic con el ratn. En realidad, esta lnea no crea una instancia de la clase Button; eso sucede en
la lnea 22.
22 Me.Button1 = New System.Windows.Forms.Button

La palabra clave New crea nuevas instancias de clases. En este caso, esa nueva instancia est asig
nada al miembro de la clase Button1 definido en la lnea 44. En este momento, Button1 es una
instancia predeterminada de la clase Button; no tiene ninguno de sus valores personalizados,
como su tamao y posicin, o el texto de despliegue Vamos, haz clic en m! Todo esto se es
tablece de la lnea 27 a la 31:
27 Me.Button1.Location = New System.Drawing.Point(64, 104)
28 Me.Button1.Name = "Button1"
29 Me.Button1.Size = New System.Drawing.Size(152, 23)
30 Me.Button1.TabIndex = 0
31 Me.Button1.Text = "Vamos, haz clic en m!"

Por ltimo, el botn se pega al formulario en la lnea 38:


38 Me.Controls.Add(Me.Button1)

Esto agrega la instancia Button1 a la lista de Controls administrado por Form1. La palabra cla
ve Me usada en todo este cdigo alude a la propia clase Form1, de modo que Me.Button1 alude
al miembro de la clase Button1 que se encuentra especficamente en la clase Form1 actual.
La mayor parte del cdigo de este archivo aparece en el procedimiento del miembro Initia-
lizeComponent:
21 Private Sub InitializeComponent()
...
43 End Sub

Cuando Visual Basic crea una instancia de Form1 para desplegarlo en la pantalla, llama al pro
cedimiento InitializeComponent para hacer el trabajo de agregar los controles al formulario.
En realidad, Visual Basic llama al constructor del formulario, que, a su vez, llama a Initiali-
zeComponent. Los constructores son miembros de clase especiales que realizan cualquier ini
cializacin necesaria en la instancia de clase. Son llamadas automticamente por .NET cada vez
que se crea una instancia de clase. En Visual Basic, todos los constructores usan el nombre New,
como en el siguiente cdigo:
Friend Class ClassWithConstructor
Public Sub New()
' ----- Aqu va todo el cdigo de inicializacin.
End Sub
End Class

28 | Captulo 1: Introduccin a .NET

01_PATRICK-CHAPTER_01.indd 28 17/2/10 15:18:34


Hablar mucho ms acerca de los constructores en el captulo 8, pero por ahora localice el cons
tructor del cdigo de Form1. (Pausa muy larga.) Qu? No hay constructor? Entonces, si no hay
un constructor, cmo se llama siquiera al miembro InitializeComponent?
Eso es lo que me gustara saber. En realidad, cuando el compilador de Visual Basic genera el c
digo MSIL para Form1, agrega en silencio un constructor, al que llama InitializeComponent.
Qu tal! Por qu Microsoft no incluye simplemente el cdigo del constructor en el cdigo
fuente? Es una cosa de simplicidad para el programador. Microsoft necesitaba tener un cons
tructor predeterminado al que llamara InitializeComponent, pero no quera que surgiera un
conflicto si usted agregaba su propio constructor predeterminado en el archivo que no es Desig
ner. De modo que ocult todo el cdigo hasta que llegara el momento de compilar realmente el
formulario. Es evidente que ya todo est dicho con esto, as que sigamos adelante.
Bueno, eso es casi todo el cdigo, por lo menos la parte que nos importa por ahora. Aunque
raramente examinaremos el cdigo generado por Visual Studio para los formularios del Proyecto
Biblioteca, es bueno ver lo que hay tras bambalinas. Si alguna vez program en Visual Basic 6,
tal vez revis el cdigo fuente de sus formularios en el Bloc de notas de vez en cuando. Si lo hizo,
observ que el formulario y todos sus controles estaban definidos con una jerarqua de coman
dos especiales, y no con cdigo real de Visual Basic. En .NET, todo eso cambi; el formulario
y todos sus controles estn creados con cdigo ordinario de Visual Basic, de modo que puede
acceder a l totalmente y ver lo que en realidad est pasando.
Ahora, pase al captulo 2, donde ahondaremos en el propio lenguaje de Visual Basic.

Proyecto | 29

01_PATRICK-CHAPTER_01.indd 29 17/2/10 15:18:34


Captulo 2
Introduccin a Visual Basic

Era una noche oscura y tormentosa. Hctor miraba cansado con sus ojos enrojecidos, a travs
de sus lentes con armazn negro, y a travs de la neblina de las luces fluorescentes de la pantalla
enriquecida con fsforo. En realidad haban pasado cuatro meses desde que empez el proyecto
de seis meses? En realidad su jefe haba amenazado con correrlo despus de ver sus avances?
Pareca como si todos esos programas de MS-DOS que haba escrito para la compaa durante
aos no significaran nada. Por qu prometi llevar el sistema interno de la compaa a Win-
dows? En un momento de desesperacin, las lgrimas resbalaron por sus mejillas, diluyendo su
ltima lata de Jolt Cola.
Son las 8:00 a.m. Un fuerte golpe en el escritorio de Hctor lo saca de pronto de su sueo,
mientras la saliva an resbala por la comisura de sus labios. Qu fue eso? Qu es esa caja en
su escritorio? V-i-s-u-a-l B-a-s-i-c? Una nota en la caja dice que reescriba su cdigo en esto.
Desesperado por probar lo que sea, Hctor instala los tres disquetes en su poderosa 386.
Seis semanas despus, Hctor ha completado el proyecto, adelantndose al calendario, con las
caractersticas completas y con los elogios de su jefe y su departamento. Y todo gracias a Visual
Basic. Pero VB no slo mejor su vida de programacin. En general, es ms feliz, ha abandonado
el hbito de la cafena, puede levantar 120 kilos, ya no cojea, ha aumentado su libido y tiene los
dientes ms blancos. Gracias, Visual Basic 1.0!

La historia de la revolucin de Visual Basic


Es posible que est equivocado en algunos detalles de la vida de Hctor. Pero para muchos
desarrolladores, Visual Basic 1.0 fue una bocanada de aire fresco. No significa que se pudiera
hacer ms con Visual Basic; los programas escritos en C eran ms poderosos y tenan mayor
flexibilidad. Pero los programadores no siempre necesitaban esa flexibilidad en la transicin des-
de MS-DOS. Slo deseaban administrar datos y no queran preocuparse por la manera en que
se presentaba cada pxel en la pantalla. Visual Basic proporcion las herramientas para escribir
aplicaciones rpidamente y con mucho menos esfuerzo que los necesarios por otras herramientas
de desarrollo y lenguajes de Windows.

30

02_PATRICK-CHAPTER_02.indd 30 17/2/10 15:19:18


La simplicidad de Visual Basic fue acogida por todos los desarrolladores de todas partes, pero la
luna de miel se acab pronto. Dada la velocidad a la que los programas de calidad razonable
podan ensamblarse con Visual Basic, los programadores y las empresas empezaron a exigir
ms. Y Microsoft respondi. Visual Basic 2.0 y 3.0 se lanzaron en rpida sucesin, en 1992 y
1993, proporcionando integracin mejorada con bases de datos y caractersticas adicionales
de desarrollo visual. La versin 4.0, lanzada en 1996, introdujo la programacin en 32 bits al
lenguaje, y soporte para la ya popular plataforma de Windows 95. Dos versiones rpidas ms
(Visual Basic 5.0 en 1997 y Visual Basic 6.0 en 1998) agregaron an ms caractersticas y com-
plejidad al de otra manera lenguaje bsico, las que daban soporte a algunas pero no a todas
las tcnicas de programacin orientada a objetos, desarrollo de controles ActiveX y codificacin
lgica para Web. Microsoft incluso haba integrado el motor central de Visual Basic (bautizado
como Visual Basic para Aplicaciones o VBA) en su suite de productos de Office, declarndolo
como el nuevo lenguaje oficial para macros y poniendo el motor a disposicin de terceros que
quisieran hacer lo mismo.
Siete aos despus de su presentacin, Visual Basic haba tomado el mundo de la programacin
por asalto. Millones de desarrolladores estaban usando el lenguaje, incluidos los que trabajaban
en las 500 compaas ms importantes del mundo, de acuerdo con la revista Fortune, escribien-
do aplicaciones que daban soporte a las funciones esenciales de los negocios. VB an retena algo
del sabor del lenguaje BASIC original (un lenguaje de programacin para principiantes desa-
rrollado por John Kemeny y Thomas Kurtz en el Dartmouth College en 1963). Esto provocaba
interminables risitas a los desarrolladores que usaban C y C++ y a otros adictos a los refrescos de
cola. Pero los programadores de VB podan ver un poderoso futuro para el lenguaje que haban
elegido.
Entonces sucedi lo impensable. Microsoft anunci que ya no mejorara el motor central de Vi-
sual Basic. En cambio, reescribira y reimplantara Visual Basic empleando su plataforma de
desarrollo .NET que lanzara pronto. S, Visual Basic sera dotado con todo el poder prometido
para el nuevo lenguaje parecido a C y Java, C#. Pero para muchos desarrolladores de corazn
de VB, estaba equivocado, muy equivocado. Se intercambiaron palabras. Se hicieron peticiones.
Cartas al editor apelaron a la fe en Visual Basic, apremindolos a nunca jams escribir una sola
lnea de cdigo .NET para Visual Basic. Frustrado, un grupo de usuarios de Visual Basic prendi
fuego a todo el campus de Microsoft en Redmond.
Bueno, eso no pas. En realidad, no sucedi nada malo. Visual Basic .NET result ser una
maravilla de software, proporcionando capacidad y caractersticas que sobrepasaron en mucho
todo lo disponible en Visual Basic 6.0. Su lanzamiento inicial en 2002 fue muy valiente. Visual
Basic .NET 2002 era poderoso, pero resultaba un poco difcil de usar, al menos comparado con
la versin 6.0, y sobre todo cuando se le comparaba con el producto original 1.0. Visual Basic
.NET 2003, lanzado un ao despus (obviamente), fue una actualizacin relativamente menor
sin muchas cosas nuevas ni funciones ms fciles.
Visual Basic 2005 marc un regreso a los das ms simples del desarrollo de Visual Basic, das de
armona y paz entre novatos y su lenguaje de programacin de propsito general. Microsoft no
slo elimin el trmino .NET del nombre del producto, sino que tambin suprimi algunas

La historia de la revolucin de Visual Basic | 31

02_PATRICK-CHAPTER_02.indd 31 17/2/10 15:19:18


barreras que evitaban que los programadores bisoos se acercaran al lenguaje. Caractersticas
previas a .NET, como Editar y Continuar y el despliegue de formularios mediante el uso simple
del nombre del formulario, una vez ms se abrieron paso en el lenguaje y en los corazones de
los ingenieros de software. Visual Basic retuvo todo el poder que gan con .NET, pero incluy
verdaderas mejoras en capacidad de uso. Fue como cuando se agrega una etiqueta a su pasta
dental que dice Nuevo empaque, mismo excelente sabor! Excepto que el sabor de Visual Basic
tambin mejor. Visual Basic era accesible una vez ms para los desarrolladores primerizos.
Desde el lanzamiento en 2005, Microsoft no se ha sentado en sus laureles, por muy doloroso que
sea. Se meti de lleno en su bolsa de trucos con las dos manos y sali con Visual Basic 2008, la
ms reciente presentacin de VB. Conocido antes con el nombre de cdigo Orcas, Visual Basic
2008 trajo capacidad y simplicidad adicionales (s, ambas cosas) al lenguaje. La nueva caracters-
tica ms estupenda, LINQ, facilit el acceso a los datos, permitindole indicar al sistema cules
datos desea en lugar de detallar la manera de obtenerlo. El lenguaje tambin proporciona acceso
ms directo a nuevas tecnologas, como Ajax y la base de presentaciones de Windows (WPF,
Windows Presentation Foundation).

Visual Basic de adentro hacia fuera


Como lenguaje de desarrollo de propsito general, Visual Basic incluye fragmentos de caracte-
rsticas que le permiten desarrollar casi cualquier tipo de aplicacin soportada por la plataforma
de Microsoft Windows. Por tanto, no podran cubrirse todas sus caractersticas en un captulo
conciso de 20 o 30 pginas, y no tratar de hacerlo. Lo que har en este captulo es presentarle
los fundamentos del lenguaje y sus caractersticas esenciales. Caractersticas no cubiertas en este
captulo se analizan en todo el resto del libro. Tiene que ser de esa manera, porque no quiero
que termine este captulo y luego diga: Ese Tim Patrick es tan sorprendente. Aprend todo lo
necesario acerca de Visual Basic en un captulo; ni siquiera tuve que leer el resto del libro. Mi
editor no quedara complacido.
En el resto de este captulo tomar el mtodo de adentro hacia fuera, empezando el anlisis
con los conceptos centrales de la lgica y los datos, y agregando capas de funcionalidad de Visual
Basic a medida que da vuelta a las hojas.
Pero basta de presunciones. Empecemos a aprender el lenguaje.

Los fundamentos de la lgica y los datos


Para que no lo olvide, permtame recordrselo una vez ms: en realidad las computadoras no son
muy inteligentes. Slo saben cmo hacer las tareas ms simples. Si quiere que hagan algo remo-
tamente complejo, tiene que darles instrucciones precisas, paso a paso, de la manera de mover
bits individuales de datos (slo 1 y 0, recurdelo) en la memoria.

32 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 32 17/2/10 15:19:18


Por fortuna, casi todo el cdigo que necesitar en el nivel inferior ya se ha escrito y se ha in-
corporado en el sistema operativo Windows y en .NET Framework. Las bibliotecas de cdigo
proporcionadas por Microsoft y terceros le dan una gran cantidad de funcionalidad previamente
escrita, que est disponible para usarse en sus propios programas. Y eso es bueno, porque pre-
ferira que lo lanzaran al vaco en un gigantesco bungee que tener que escribir aplicaciones de
negocios en el nivel de cdigo mquina todo el da.
Aunque tenga todo este cdigo previamente escrito en su arsenal, an debe indicarle a la compu-
tadora lo que quiere que haga, en detalles finos, o no lo har. Y aqu es donde entran en escena
los lenguajes de nivel superior como Visual Basic. Proporcionan la gramtica que necesita para
comunicarse con la computadora. Para cualquier tarea dada que es necesario que el equipo de
cmputo realice, su tarea como programador consiste en determinar los pasos individuales que
se deben dar para completar esa tarea (la lgica) y traducir esos pasos en un lenguaje que com-
prenda la computadora empleando el lenguaje de programacin.
Como ejemplo, digamos que recibe una solicitud del departamento de ventas que pide un pro-
grama que invertir las letras en cualquier fragmento de texto que se proporcione al programa.
Nuestros clientes estn reclamando esto; lo necesitamos para el martes, dicen. Muy bien, as
que primero determina la lgica y luego la implementa en Visual Basic. Empleando seudocdigo,
un lenguaje de programacin artificial que desarrolla para uso personal como ayuda para escribir
programas, puede esquematizar las bases de esta tarea (con nmeros de lnea iniciales):
01 Obtener el texto original (o la cadena) del usuario.
02 Si el usuario no proporciona contenido, salir ahora.
03 Preparar un destino para la cadena invertida, vaco por ahora.
04 Repetir lo siguiente hasta que la cadena original est vaca:
05 Copiar el ltimo carcter de la cadena original restante.
06 Poner ese carcter al final de la cadena de destino.
07 Acortar la cadena original, eliminado el ltimo carcter.
08 [Final de la seccin que se repite]
09 Mostrar al usuario la cadena de destino.

Usted podra escribir esta lgica de muchas maneras; ste es slo un ejemplo. Ahora debe con-
vertir este seudocdigo en su lenguaje preferido; en este caso, Visual Basic (no se preocupe por
ahora por los detalles de la sintaxis):
01 textoOriginal = InputBox("Ingrese el texto que se invertir.")
02 If (Len(textoOriginal) = 0) Then Return
03 textoFinal = ""
04 Do While (textoOriginal <> "")
05 unCaracter = Right(textoOriginal, 1)
06 textoFinal &= unCaracter
07 textoOriginal = Left(textoOriginal, _
Len(textoOriginal) - 1)
08 Loop
09 MsgBox("El texto invertido es: " & textoFinal)

Los fundamentos de la lgica y los datos | 33

02_PATRICK-CHAPTER_02.indd 33 17/2/10 15:19:18


Este cdigo fuente est listo ahora para usarse en un programa de Visual Basic. Y tambin de-
muestra varios aspectos esenciales de la codificacin:
A los pasos individuales de las instrucciones paso a paso se les denomina instrucciones. En
Visual Basic, cada instruccin aparece en una lnea independiente. Puede dividir instruccio-
nes largas en varias lneas al conectarlas con un guin de subrayado, como se muestra en la
lnea 07 del cdigo. Cuando una sola instruccin abarca varias lneas de esta manera, a toda
la instruccin suele llamrsele lnea lgica. Debido a que una sola lnea lgica suele incluir
slo una accin primaria de Visual Basic (como la accin If o Do, o las diversas acciones
de asignacin que usan los signos de igual [=]), a estas acciones tambin se les denomina
instrucciones.
Las instrucciones del cdigo se procesan de una en una, de arriba hacia abajo. Sin embargo,
ciertas instrucciones alteran este flujo normal del programa, como sucede con el bloque Do
While...Loop de las lneas 04 y 08 del cdigo de ejemplo. A estas instrucciones tambin
se les denomina instrucciones de control de flujo, e incluyen bucles (repeticin de un bloque
de cdigo), condiciones (procesar de manera opcional un bloque de cdigo basado en una
comparacin o el resultado de un clculo) y saltos (pasar de inmediato a otra seccin del
cdigo).
Los datos pueden almacenarse en variables, a las que se denomina contenedores de valores
de datos. El bloque de cdigo de ejemplo incluye tres variables: textoOriginal, unCa-
racter y textoFinal, y todas ellas almacenan datos de texto (cadenas). El sistema comn
de tipos (CTS, Common Type System) de .NET permite crear variables para cuatro tipos
primarios de valores de datos bsicos: texto (caracteres individuales y cadenas ms largas),
nmeros (valores enteros y decimales), fechas (y horas) y booleanos (valores de verdadero o
falso). Tambin puede construir tipos de datos ms complejos al agrupar los tipos bsicos.
Los datos se almacenan en una variable mediante una asignacin. Por lo general, esto incluye
la colocacin del nombre de una variable a la izquierda de un operador de asignacin =, y
colocar los datos o los clculos que se almacenarn en esa variable a la derecha del mismo
signo de igual. La instruccin textoFinal = "" de la lnea 03 almacena una cadena vaca
("") en la variable textoFinal. La instruccin de asignacin &= de la lnea 06 muestra una
sintaxis de asignacin un poco diferente.
Las instrucciones pueden incluir llamadas a funcin, bloques de funcionalidad escritos pre-
viamente, condensados en un solo nombre. Las llamadas a funcin hacen muchas cosas y
luego regresan un resultado final. Las llamadas a funcin son seguidas por un conjunto de
parntesis, que pueden incluir cero o ms argumentos, valores de datos adicionales propor-
cionados por el cdigo que llama y que la funcin utiliza para generar su resultado.
El cdigo de ejemplo incluye muchos casos de llamadas a funcin, como la funcin Right
de la lnea 05. Esta funcin devuelve una copia de los caracteres del extremo derecho de otra
cadena de texto. Acepta dos parmetros: la cadena original de la que se extraen los caracteres
del extremo derecho, y un valor entero que indica el nmero de caracteres que se regresar.
El cdigo Right(textoOriginal, 1) devuelve una copia del carcter nico del extremo
derecho (1) de textoOriginal.

34 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 34 17/2/10 15:19:18


Cuando utiliza una funcin en su cdigo fuente, acta de manera parecida a una variable;
todo el texto de la llamada a funcin, desde el inicio de su nombre hasta el final de su parn-
tesis de cierre, puede reemplazarse con una variable que contiene los mismos datos resultan-
tes. Las llamadas a funcin no pueden aparecer en el extremo izquierdo de una instruccin
de asignacin, pero s lo pueden hacer casi en cualquier otro lugar en que puede aparecer
una variable. Por ejemplo, pueden usarse las dos lneas siguientes para reemplazar a la lnea
02 del ejemplo:
' Reemplazar --> If (Len(textoOriginal) = 0) Then Return
longitudDeTexto = Len(textoOriginal)
If (longitudDeTexto = 0) Then Return

Adems de las funciones, Visual Basic tambin incluye procedimientos. Los procedimientos
empaquetan cdigo previamente escrito en un paquete con nombre, como las funciones,
pero no devuelven un valor. Deben usarse como instrucciones independientes; no puede
usarlas donde usara una variable o una llamada a funcin. La llamada a MsgBox en la lnea
09 es un ejemplo tpico de una llamada a procedimiento en uso. (MsgBox es en realidad una
funcin, pero en este cdigo est enmascarado como un procedimiento; se analizar con
ms detalle en pginas posteriores.)
El cdigo de ejemplo anterior podra ser un poco ms eficiente. En realidad, es posible que Mi-
crosoft obtuviera un borrador inicial de este libro, porque incluy una caracterstica de inversin
de caracteres en Visual Basic, y la llam StrReverse:
textoOriginal = InputBox("Ingrese el texto que se invertir.")
If (Len(textoOriginal) = 0) Then Return
textoFinal = StrReverse(textoOriginal)
MsgBox("El texto invertido es: " & textoFinal)

Muy bien; Visual Basic ya incluye una caracterstica de inversin de caracteres, parte de ese
cdigo de biblioteca previamente escrito del que sigo hablando. Visual Basic incluye muchas
funciones intrnsecas que se consideran parte del lenguaje y que empaquetan mucha funcionali-
dad til ya escrita. Muchas de estas funciones aparecen en el espacio de nombres Microsoft.
VisualBasic, que queda automticamente disponible para su cdigo fuente de Visual Basic
cuando crea un nuevo proyecto de VB.

Tipos de datos y variables


Toma mis datos por favor! Ja, ja, alguien siempre quiere que diga esto. Pero es en realidad lo
que pido que mi aplicacin de Visual Basic haga: tomar datos de una fuente (teclado, disco duro,
Internet, etc.) y presentarlos de alguna manera til. Todos los programas que escribo en realidad
administran de manera activa por lo menos algunos datos en memoria. Cada valor de datos
est almacenado en un rea especfica de la memoria de la computadora, como lo determin el
motor comn en tiempo de ejecucin del lenguaje (CLR, Common Language Runtime). Las
instrucciones en Visual Basic existen, sobre todo para administrar y manipular estos datos de
maneras tiles y complejas.

Tipos de datos y variables | 35

02_PATRICK-CHAPTER_02.indd 35 17/2/10 15:19:18


Figura 2-1. Todos los tipos de tazas y datos.

Todos los datos administrados por el CLR estn almacenados en la memoria de la computadora,
y cada valor de datos est separado y protegido de los dems. Es como si cada valor de datos
tuviera su propia taza individual, como se muestra en la figura 2-1.
Todos los valores de datos administrados por el CLR tienen contenido y tipo. El contenido son los
datos reales: la cadena de texto abc, el nmero 5, una factura, t negro, de naranja. Cualquier
cosa que ponga en la taza, se es el contenido. En algunos casos, .NET no permite almacenar
algo en la taza (los tipos de referencia se analizarn en breve y los tipos de valor nulos se des-
cribirn en el captulo 6).
Los tipos indican la clase de contenido almacenado en la taza. Esto se muestra en la figura 2-1
con la forma de cada taza. Cada una de ellas tiene lmites en el tipo de datos que puede verterse
en ella: una cadena de texto, un nmero entero o una factura para el cliente.

Literales
Algunos valores bsicos de datos, como nmeros y cadenas de texto, pueden ingresarse en su
cdigo fuente y usarse tal como estn. Por ejemplo, el procedimiento MsgBox despliega una
ventana con un mensaje de texto. La instruccin
MsgBox("La respuesta es " & 42)

incluye una cadena literal, La respuesta es y un valor entero literal, 42. (El smbolo & es un
operador que une los dos valores en una nueva cadena.) Las literales se usan una vez y desapare-
cen. Si quiere mostrar el mismo mensaje La respuesta es 42 de nuevo, tendr que escribir una
vez ms los mismos valores de literal en una parte diferente del cdigo fuente.
Visual Basic da soporte a varios tipos de literales bsicas. Las literales de cadena estn siempre
entre comillas. Si quiere incluir una comilla en medio de una cadena, debe incluir dos comillas
en lugar de una:
"Esto es ""literalmente"" un ejemplo."

Las literales de cadena pueden ser realmente largas, hasta de dos mil millones de caracteres de
longitud; si escribiera un carcter por segundo, le tomara 63 aos alcanzar la longitud mxima
de la cadena. Visual Basic tambin incluye una literal de carcter que es exactamente de un ca-

36 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 36 17/2/10 15:19:19


rcter de largo; si slo escribiera un carcter por segundo, bueno, no importa. Esas literales de
carcter son reconocidas porque tienen una c despus de la cadena. La literal de carcter A
se ingresara como:
"A"c
Las literales de fecha y hora estn entre signos de nmero en lugar de comillas. La fecha o la hora
(o ambas) que incluya pueden estar en cualquier formato reconocido por Microsoft Windows
en su regin especfica. Si est usando Visual Studio, cambiar el formato de su fecha cuando
escriba en la literal:
#7/4/1776#
Once tipos diferentes de valores de datos numricos (valores enteros y de punto flotante) in-
tegran el conjunto central de tazas numricas. Y quin necesita ms de 11? Con estas tazas
puede administrar nmeros desde cero hasta 1 10300 y ms all. Para usar una literal numrica,
escriba el nmero correcto en su cdigo, como 27, o 3.1415926535. Visual Basic tambin le
permite especificar cul de las 11 tazas numricas usar para un nmero, al aadir un carcter
especial al final del nmero. Por lo general, 27 es el entero 27. Para un decimal de moneda,
aada el signo de arroba (@):
27@
Cuando hable de los tipos de datos con todo detalle, en el captulo 6, presentar una lista de
los diferentes caracteres especiales, como @, que establecen el tipo de datos para los nmeros
literales.
El cuarto y quinto tipos de literales de Visual Basic es la literal booleana. Los valores boolea-
nos representan el tipo ms simple de datos de computadora: el bit. Los valores booleanos son
verdaderos o falsos, encendido o apagado, s o no, delicioso o molesto, perros o gatos, cero o
no cero. Los booleanos siempre representan cualquiera de dos valores o estados opuestos. En
el siglo xviii, George Boole invent el lgebra booleana, un lenguaje que us para representar
instrucciones lgicas como ecuaciones matemticas. Slo sucedi que a las computadoras les
encanta el lgebra booleana. Todas las operaciones bsicas de una computadora, como la suma,
se implementan utilizando funcionalidad booleana.
Visual Basic incluye las literales booleanas True y False. No hay comillas, ni signos de nmero,
slo las palabras True y False. Pregunta: est Tim Patrick diciendo la verdad sobre esto? Respuesta:
True
En ciertos casos, puede tratar a los nmeros como valores booleanos. Hablar de esto ms ade-
lante, pero por ahora basta con que sepa que False es igual a cero (0) y True es igual a todo lo
dems (aunque 1 suele usarse para todo lo dems).

Variables
Todos los valores de datos literales son buenos y malos, pero slo resultan tiles una vez y se van.
Cada vez que quiera usar un valor de literal, debe volver a escribirlo. Es como si los valores de
datos estuvieran almacenados en tazas desechables, en lugar de que sean de fina porcelana china.

Tipos de datos y variables | 37

02_PATRICK-CHAPTER_02.indd 37 17/2/10 15:19:19


Adems, slo los programadores ingresan valores de literal, no los usuarios, de modo que su uso
es limitado en la administracin de los datos de usuario.
Las variables no son simples tazas desechables; son reciclables. Puede seguir poniendo el mismo
tipo de t una y otra vez en la taza. Una taza de variable de cadena puede contener una cadena
para reciclaje una y otra vez. Por ejemplo, en este bloque de cdigo, respuesta contiene las
diversas cadenas que se le asignan:
01 respuesta = "A"
02 MsgBox("Dame una 'A'!")
03 MsgBox(respuesta)
04 MsgBox("Dame otra 'A'!")
05 MsgBox(respuesta)
06 MsgBox("Qu dice?")
07 respuesta = StrDup(2, "A")
08 MsgBox(respuesta)

La variable respuesta se asigna dos veces con dos cadenas diferentes: una A (lnea 01) y luego
AA (lnea 07). Conserva cualquier valor que se le haya asignado al final; ambas lneas 03 y 05
despliegan A en una ventana de cuadro de mensaje. Y no tiene que asignar slo cadenas de
literal; es posible asignar a respuesta el resultado de cualquier cosa que genere una cadena. La
lnea 07 usa una funcin integrada Visual Basic, StrDup, para devolver la cadena de dos carac-
teres AA y asignarla a respuesta.
El uso de variables es un proceso de dos pasos. En primer lugar, debe declarar la variable y luego
debe asignarle un valor. La instruccin Dim se ocupa de la parte de la declaracin; le permite
indicar el nombre y el tipo de una variable. Su sintaxis bsica es muy sencilla:
Dim respuesta As String

donde respuesta es el nombre de la variable y String es su tipo. La asignacin ocurre usando


el operador de asignacin =:
respuesta = "La respuesta"

Una sola variable puede tener nuevos valores asignados una y otra vez. Para esas ocasiones en
que quiere que su variable tenga un valor especfico inmediatamente despus de la declaracin,
puede combinar una declaracin y una asignacin en una sola instruccin:
Dim respuesta As String = "La respuesta"

Por supuesto, no est limitado a una sola declaracin; puede crear todas las variables que necesite
en su cdigo. Cada una suele usar su propia instruccin Dim:
Dim pregunta As String
Dim respuesta As String

Tambin puede combinarlas en una sola instruccin, aunque creo que es horrible:
Dim pregunta As String, respuesta As String

Lo ve, le dije que era horrible. Esto es slo el principio de lo que es posible con la instruccin
Dim. Entrar en ms detalles a medida que avance el captulo.

38 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 38 17/2/10 15:19:19


Tipos de valor y de referencia
En el captulo 1 habl de los tipos de valor y los tipos de referencia. Las variables de tipos de valor
almacenan un valor real; el t en una taza de tipo de valor es el propio contenido. Todos los va-
lores de datos de literal que ya mencion, excepto las cadenas, son tipos de valor.
Las variables de tipos de referencia almacenan una referencia a los datos reales, los que se en-
cuentran en algn lugar de la memoria. Cuando mira en una taza de tipo de referencia, tiene que
leer las hojas de t en la parte inferior para determinar dnde residen los datos reales.
Los tipos de referencia contienen datos o no. En ausencia de datos, un tipo de referencia tiene
un valor Nothing, una palabra clave de Visual Basic que indica que no hay datos. Los tipos de
valor nunca son Nothing; siempre contienen algn valor, posiblemente el predeterminado para
ese tipo (como cero, para los tipos numricos). Un tipo especial que puede ser nulo le permite
asignar Nothing a un tipo de valor, permitindole implementar la misma lgica hay algunos
datos aqu? que existe con los tipos de referencia. En el captulo 6 me referir a los tipos que
pueden ser nulos.

Tipos de datos
El tipo de datos String es til, pero slo representa una de las formas de taza que estn a su dis-
posicin. .NET Framework define varios tipos de datos centrales. Cada tipo se implementa como
una clase especfica dentro del espacio de nombres System. El tipo de datos ms bsico, una taza
grande que puede contener cualquier tipo de datos, es denominado Object. Ms que nada, se
trata de un objeto con O mayscula. En la jerarqua del espacio de nombres de la biblioteca de
clases de .NET, se localiza en System.Object. Es la madre de todas las clases en .NET; todas las
dems clases, estructuras, enumeraciones y delegados, sin importar su posicin en la jerarqua
de espacio de nombres, sean escritas por Microsoft o por usted, derivan de System.Object. No
hay vuelta de hoja; no puede crear un tipo que derive de algo diferente.
As que regrese a estos tipos de datos centrales sobre los que he estado hablando. Coinciden
con los cuatro tipos de valores de datos de literal que enumer antes: valores de cadena, fecha,
nmero y booleanos. En la tabla 2-1 se presenta una lista de estos tipos de datos centrales. Cada
tipo tambin tiene un nombre especfico de Visual Basic que puede (y debe) usar en cambio.

Tabla 2-1. Tipos de datos centrales de .NET y Visual Basic.

Nombre de VB Nombre de .NET Descripcin


Boolean Boolean El tipo de datos Boolean da soporte slo a valores de True y False. Es posible con-
vertir nmeros a valores booleanos: 0 se vuelve False y todo lo dems se vuelve True.
Cuando convierte un booleano en un nmero, False se vuelve 0 y True 1.a
Byte Byte Un tipo de datos numrico, Byte, almacena enteros sin signo de un solo byte (8 bits), que
van de 0 a 255. El tipo de datos Byte es muy til para trabajar con datos que no son de
texto, como imagen.

Tipos de datos y variables | 39

02_PATRICK-CHAPTER_02.indd 39 17/2/10 15:19:19


Tabla 2-1. Tipos de datos centrales de .NET y Visual Basic (continuacin).

Nombre de VB Nombre de .NET Descripcin


Char Char El tipo de datos Char contiene exactamente un carcter de texto. Cada valor de datos de
Char representa dos bytes (16 bits) de almacenamiento, de modo que puede administrar
conjuntos de caracteres de doble byte, proporcionando soporte para idiomas como el japo-
ns, que tienen un nmero grande de caracteres. Aunque se usa para almacenar caracteres
de texto simple, internamente el tipo de datos Char mantiene los caracteres como valores
enteros, que van de 0 a 65 535.
Date DateTime Este tipo de datos de fecha y hora maneja todos los datos entre el 1 de enero de 1 y el 31 de
diciembre de 9999 de nuestra era, en el calendario gregoriano. Tambin puede incluirse la
hora; no se especifica sta, se usa la medianoche. En el funcionamiento interno, el tipo de
datos Date almacena la fecha y la hora como el nmero de tics desde la medianoche del
1 de enero del ao 1 de nuestra era. Cada tic corresponde a 100 nanosegundos.
Decimal Decimal El tipo de datos Decimal est diseado con las monedas en mente. Es muy exacto en
clculos matemticos y tiene un rango muy bueno, dando soporte a nmeros que van
ms all de 79 000 trillones. (Dijo 79 000 trillones?) Eso tiene 29 dgitos de largo, y es
importante recordar eso, porque slo obtiene 29 dgitos en total en ambos lados del punto
decimal. Ese nmero de 79 000 trillones viene con la limitacin de que no debe haber
dgitos a la derecha del punto decimal. Si quiere una posicin decimal, tiene que ceder uno
a la izquierda (la mantisa) y slo conserva nmeros hasta los 79 000 trillones. Si quiere 29
dgitos despus del punto decimal, obtiene un enorme cero para la mantisa. Si sola usar
Visual Basic 6.0, Decimal es similar al subtipo de datos Currency.
Double Double El tipo de datos Double maneja los nmeros ms largos posibles de todos los tipos de
datos numricos centrales. Su rango es de 4.94 10324 a 1.798 10+308 en el caso
de los nmeros positivos, con un rango similar para valores negativos. Aunque pudiera
pensar que est en el paraso de los nmeros gigantes, no todo es arpas y alas. El tipo
de datos Double es notoriamente inadecuado en clculos complejos. En ocasiones, un
clculo que debe dar como resultado cero en realidad se calcular como algo parecido a
0.00000000000005434, que es muy cercano. Pero las comparaciones de este nmero con
cero fallarn, porque no es cero.
Integer Int32 El tipo de datos Integer es un tipo entero con signo de 4 bytes (32 bits). Maneja nmeros de
2 147 483 648 a 2 147 483 647. Si es un programador de los das previos a .NET Visual Basic,
este nuevo tipo de datos Integer es equivalente a la versin 6.0 del tipo de datos Long.
Long Int64 El tipo de datos Long es an ms grande que Integer; es un tipo entero con signo de 8
bytes (64 bits). Maneja nmeros de 9 223 372 036 854 775 808 (guau!) a
9 223 372 036 854 775 807 (reguau!). No es lo mismo que el viejo tipo de datos Long de
Visual Basic 6.0, porque tiene el doble de su capacidad de almacenamiento.
Object Object Object es el tipo central de todos los tipos de .NET. Est en la parte superior de la jerar-
qua de clases y tipos; es la clase base definitiva para todas las dems clases. Es un tipo de
referencia, aunque al final los tipos de valor tambin se derivan de ella.
SByte SByte Un tipo de datos numrico, SByte, almacena enteros con signo de un solo byte (8 bits),
que van de 128 a 127. Es la versin con signo del tipo de datos sin signo Byte.
Short Int16 El tipo de datos Short es un tipo con signo de 2 bytes (16 bits). Almacena nmeros de
32 768 a 32 767. Si es un programador de Visual Basic antes de .NET, este nuevo tipo de
datos Short es equivalente a la versin 6.0 del tipo de datos Integer.

40 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 40 17/2/10 15:19:19


Tabla 2-1. Tipos de datos centrales de .NET y Visual Basic (continuacin).

Nombre de VB Nombre de .NET Descripcin


Single Single El tipo de datos Single es muy parecido al tipo de datos Double, slo que ms peque-
o. Su rango de nmeros positivo es de 1.4 1045 a 3.4 10+38, con un rango similar
para nmeros negativos. Como el tipo de datos Double, Single padece de ligeras
inexactitudes durante los clculos.
String String El tipo de datos String es un tipo de referencia que almacena hasta 2 000 millones de
caracteres de texto. Almacena caracteres Unicode, que son caracteres de 2 bytes (16 bits)
capaces de almacenar caracteres de casi todos los idiomas del mundo, incluidos algunos
con alfabetos grandes, como el chino.
UInteger UInt32 UInteger almacena enteros sin signo de 4 bytes (32 bits), que van de 0 a 4 294 967 295.
Es la versin sin signo del tipo de datos con signo Integer.
ULong UInt64 ULong almacena enteros sin signo de 8 bytes (64 bits), que van de 0 a
18 446 744 073 709 551 615. Es la versin sin signo del tipo de datos con signo Long.
UShort UInt16 UShort almacena enteros sin signo de 2 bytes (16 bits), que van de 0 a 65 535. Es la
versin sin signo del tipo de datos con signo Short.
a
Esto slo es cierto en Visual Basic. En otros lenguajes de .NET, como C#, False se vuelve 0, pero True se vuelve 1, no 1. Si conserva un valor
booleano como Boolean, por lo general no tendr problemas. Pero si convierte primero sus valores booleanos en nmeros y luego empieza a
pasarlos de manera forzada entre cdigo de diferentes lenguajes de .NET, podra obtener resultados sorprendentes.

Los desarrolladores de Microsoft a cargo de los tipos de datos de Visual Basic tuvieron suerte en
ese trabajo porque todos los tipos de datos centrales de Visual Basic son simples envolturas para
tipos de datos especficos implementados por .NET. Los nombres de Visual Basic dados para cada uno
de estos tipos de datos centrales son completamente intercambiables con los nombres de .NET.
Por ejemplo, Integer es equivalente por completo a System.Int32. En realidad, cuando escribe
cdigo de Visual Basic, es mejor usar sinnimos de Visual Basic, porque la mayora de los desarro-
lladores de Visual Basic esperan estos nombres de tipos de datos en el cdigo que leen y escriben.
Excepto por Object y String, todos estos tipos de datos son tipos de valor. Todos los tipos de
valor se derivan de System.ValueType (que, a su vez, deriva de System.Object).
Los tipos de datos SByte, UInteger, ULong y UShort se agregaron a Visual Basic con su versin
2005, aunque sus equivalentes del espacio de nombres System han estado en .NET desde sus
inicios. A diferencia de los dems tipos de datos centrales, estos cuatro tipos no son compatibles
con CLS; es decir, no pueden usarse para interactuar con componentes de .NET y lenguajes
que se reducen a las caractersticas esenciales necesarias de .NET. Por lo general, esto no suele ser
una limitacin, pero est prevenido cuando trabaje con componentes o lenguajes de terceros.

Declaracin avanzada
Cuando mencion la necesidad de declarar y asignar variables, realmente me estaba concen-
trando en los tipos de valor. Los tipos de referencia requieren un paso adicional: la creacin de
instancias. Considere las siguientes instrucciones de declaracin:

Tipos de datos y variables | 41

02_PATRICK-CHAPTER_02.indd 41 17/2/10 15:19:19


Dim valorPredeterminado As Integer
Dim valorNoPredeterminado As Integer = 5
Dim referenciaPredeterminada As Object

Estas lneas declaran tres variables separadas: dos tipos de valor (Integer) y un tipo de referencia
(Object). Aunque slo una variable tiene una asignacin explcita de datos, los tres tienen en
realidad asignado algo, explcita o implcitamente. Veamos de nuevo estas instrucciones y revise-
mos lo que en realidad est asignado a cada variable.
Dim valorPredeterminado As Integer = 0
Dim valorNoPredeterminado As Integer = 5
Dim referenciaPredeterminada As Object = Nothing

Ya ocurrieron la declaracin y la asignacin para todas las variables, al usar la instruccin Dim.
La variable valorPredeterminado, con su asignacin predeterminada de 0, puede usarse de
inmediato en ecuaciones. Sin embargo, la variable de tipo de referencia referenciaPredeter-
minada es slo una taza vaca, sin datos predeterminados que manipular. Son caractersticas de
Visual Basic que le permiten comparar un tipo de referencia con Nothing, y podra hacer esto
de inmediato, pero en realidad no son datos. Y recuerde que las variables viven para administrar
datos.
Los valores de datos de referencia necesitan la creacin de instancias, y sta requiere la palabra
clave New:
Dim referenciaPredeterminada As Object = New Object

Ahora referenciaPredeterminada seala a un objeto real; y ya que esta taza tiene algo con-
sumible dentro, aunque slo sea algo de System.Object, no queda mucho por saborear. Las
cadenas son un poco ms interesantes y tambin tienen constructores ms interesantes.
Como recordar del captulo 1, un constructor es un bloque de cdigo de inicializacin que
se ejecuta cuando crea un nuevo valor de datos o un objeto. Algunos objetos le permiten pro-
porcionar informacin adicional que se usa en el proceso de inicializacin. Un constructor pre-
determinado no le permite proporcionar ninguna informacin adicional; slo funciona por su
cuenta, inicializando datos como si no fuera el trabajo de nadie. Hay un lmite en el nmero de
constructores en una clase, pero a cada uno debe pasrsele un tipo diferente de informacin.
As que regresemos a las cadenas. El constructor predeterminado para una cadena simplemente
crea una cadena en blanco, de longitud cero:
Dim cadenaMasAbuirridaDelMundo As String = New String

Ahora, nadie hace esto, porque la siguiente instruccin tambin funciona:


Dim cadenaMasAbuirridaDelMundo As String = ""

Esto es porque Visual Basic trata de manera especial a las cadenas. Las literales de cadena en
realidad son instancias de los valores de datos String; es como si creara una nueva instancia
de String empleando la clase System.String. Por lo menos, eso es cierto cuando se usa el
constructor predeterminado del tipo de datos String. Pero String tambin tiene constructores
interesantes. (Entrar en los detalles de los constructores en el captulo 8.) Uno de los construc-

42 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 42 17/2/10 15:19:20


tores crea una nueva instancia de String inicializada con un carcter especfico repetido varias
veces. Por ejemplo, para crear una instancia de String con una cadena de 25 caracteres de la letra
M, use la siguiente sintaxis:
Dim mmBueno As String = New String("M"c, 25)

Si va a usar el mismo tipo de datos despus de la palabra clave As que utiliza despus de la pala-
bra clave New, puede usar una sintaxis reducida:
Dim mmBueno As New String("M"c, 25)

Al igual que con los tipos de valor, tambin puede dividir la instruccin en instrucciones de
declaracin y asignacin:
Dim mmBueno As String
mmBueno = New String("M"c, 25)

Constantes
Las literales no cambian, pero puede usarlas slo una vez en su cdigo. Las constantes son
una cruza entre una literal y una variable; tienen un solo valor que nunca cambia, como las
literales de datos, pero tambin tienen un nombre que puede usar una y otra vez, como las va
riables.
Las constantes se declaran empleando la palabra clave Const en lugar de Dim:
Const VelocidadDeLaLuz As Integer = 300000

La asignacin real del valor a la constante ocurre en la propia instruccin, con el valor despus
del operador =. Una vez que se declara y asigna su constante, est disponible para usarla en ins-
trucciones reales de su cdigo real:
MsgBox("La velocidad de la luz en kilmetros/segundo: " & VelocidadDeLaLuz)

Declaracin local y campos


En la realidad, necesita mantener algunos datos en privado, slo para su uso. Sus vecinos tienen
otros jugosos fragmentos de datos e informacin que comparten entre s. Y luego hay datos
pblicos que no se ocultan a nadie. Pero no es como en la realidad; en el mundo falso de Visual
Basic hay diferentes niveles de acceso y privacidad para sus datos.
Un poco ms adelante, en este captulo, veremos que el cdigo de la lgica de su aplicacin
siempre aparecer en procedimientos, bloques con nombre de cdigo fuente. Las variables
locales (y las constantes) se declaran en los mismos procedimientos cuando necesita una va-
riable de vida corta y personal que slo se vaya a usar dentro de un solo procedimiento. Otras
variables (y constantes) pueden aparecer fuera de los procedimientos, pero an dentro del
contexto de una clase o tipo similar. Estos campos, sean variables o constantes, estn inme-
diatamente disponibles para todos los procedimientos diferentes que tambin llaman a la
clase de inicio actual.

Tipos de datos y variables | 43

02_PATRICK-CHAPTER_02.indd 43 17/2/10 15:19:20


Todas las variables locales se definen usando la palabra clave Dim. La instruccin Dim funciona
con definiciones de campo, pero es ms comn usar, en cambio, las palabras clave de modifi
cador de acceso. Estos modificadores determinan cul cdigo puede acceder a los campos, desde
Private (usado slo por el cdigo dentro de la clase) hasta Public (tambin disponible fuera
de la clase):
Private ParausarSoloEnLaClase As Integer

Hay cinco modificadores de acceso. En el captulo 6 hablar ms acerca de ellos y de los campos
en general.

Intermedio
Ya fue demasiado. Hacerse una idea acerca de datos y variables es probablemente la parte ms
compleja de la programacin en Visual Basic. Una vez que tenga los datos en las variables, ser
muy fcil manipularlos.
Aunque la idea de una taza de t puede hacer que salga de la habitacin como un luntico de-
lirante, tal vez quiera darse unos minutos, tomar una copa, un vaso, un plato o un tarro de su
bebida preferida y relajarse. Lo ver en 20 o 30 minutos.

Comentarios
Si usted es un fantico de la pera, sabe lo excitante que puede ser una buena pera, sobre todo
un trabajo clsico presentado con el libreto original en idioma extranjero. Si no lo es, sabe lo irri-
tante que puede ser escuchar varias horas de un libreto en idioma extranjero. Con el advenimien-
to de los subttulos que describen el contenido en el idioma del espectador, quienes hasta ahora
han extrado poca alegra de la experiencia de la pera an la encontrarn repulsiva, slo que esta
vez en su lengua nativa. Pero por lo menos ahora sabrn por qu no disfrutan la historia.
Eso es realmente lo que hacen los comentarios: le indican en su propio idioma lo que en realidad
est pasando en un idioma extranjero. En este libro, el idioma extranjero es Visual Basic, y el
espaol es el habla comn. Tal vez resulte que un bloque determinado de cdigo de Visual Basic
est mal escrito o incluso sea detestable, pero si los comentarios que lo acompaan son exactos,
puede resultar molesto en su propio idioma, mientras comprende el proceso en un idioma com-
prensible para los seres humanos.
Por lo general, los comentarios aparecen en lneas individuales, pero tambin puede adjuntar un
comentario al final de una lnea de cdigo existente. Si una lnea lgica est dividida en varias
lneas fsicas usando el carcter de continuacin de lnea _, un comentario final slo es vlido
al final de la lnea fsica:
' ----- ste es un comentario independiente, en una lnea individual.
Dim contador As Integer ' ste es un comentario al final.
MsgBox("El contador empieza en " & _ ' COMENTARIO NO VLIDO!
contador) ' Pero ste s es vlido.

44 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 44 17/2/10 15:19:20


Los comentarios empiezan con el carcter de comentario, el carcter estndar de una sola comilla
('). Cualquier texto que sigue a este carcter es un comentario y se ignora cuando se compila en
una aplicacin que se puede usar. Ninguna comilla sencilla que aparezca dentro de una cadena
de literal se usa como marcador de comentario.
MsgBox("No hay 'comentarios' en este texto.")

Los comentarios tambin empiezan con la palabra clave REM (de REMark, comentario), pero
la mayora de los programadores usan, en cambio, la variacin de una sola comilla.

Instrucciones Option
En unos ejemplos de cdigo anteriores vio que Visual Basic proporcionara una asignacin pre-
determinada a una variable (por lo menos para tipos de valor) si no inclua una. En ciertos casos,
Visual Basic tambin proporcionar la declaracin si la deja fuera. En la instruccin:
valorNuevo = 5

si no hay una instruccin Dim que defina valorNuevo, Visual Basic declarar la variable en
su nombre, asignndole el tipo de datos Object. No deje que esto suceda! No sabe qu tipo de
problema tendr si permite estas prcticas en su cdigo. Rpidamente encontrar su cdigo
lleno de misteriosos errores de lgica, problemas esotricos con los datos, piojos recurrentes,
etctera.
El problema es que Visual Basic no se quejar si escribe mal el nombre de su variable autodecla-
rada. Si se deja sin revisar, tales prcticas podran llevar a un cdigo como ste:
valorNuevo = 5
MsgBox(valorNeuvo)

Vea ese error de escritura en la segunda lnea. Qu? Visual Basic compilaba sin errores? Y
ahora su cuadro de mensaje despliega nada, en lugar de 5? Podra evitar ese trauma mediante
el uso juicioso de las instrucciones Option incluidas en el lenguaje Visual Basic. Hay cuatro de
esas instrucciones:
Option Explicit On
Esta instruccin le obliga a declarar todas las variables usando Dim (o una instruccin si-
milar) antes de usarla. Es posible reemplazar On con Off en la instruccin, pero no lo
haga.
Option Strict On
Visual Basic har algunas conversiones simples de datos cuando las necesite. Por ejemplo,
si asigna un valor de datos Long de 64 bits a una variable Integer de 32 bits, Visual Basic
convertir normalmente esos datos a un tamao ms pequeo, quejndose slo si los datos
no corresponden. Este tipo de conversin (una conversin de estrechamiento) no siempre
es seguro porque en ocasiones los datos de origen fallarn al acomodarse al destino. (Una
conversin de ensanchamiento, como cuando se almacenan datos Integer en Long, siempre
funciona, porque el destino siempre puede contener el valor de origen.) La instruccin

Instrucciones Option | 45

02_PATRICK-CHAPTER_02.indd 45 17/2/10 15:19:20


Option Strict On desactiva el procesamiento automtico de conversiones de estrecha-
miento. Ser forzado a usar funciones de conversin explcita para realizar conversiones de
estrechamiento. Esto es bueno, porque lo fuerza a pensar en el tipo de datos que contendrn
sus variables. Puede reemplazar On con Off en esta instruccin, pero si ya lo previne
una vez, he de prevenirlo dos veces: ni siquiera lo intente!
Option Infer On
Esta nueva instruccin de Visual Basic 2008 le indica al compilador que adivine el tipo de
datos que desea que use una variable cuando no lo indica de manera especfica. En el captu-
lo 6 analizar la inferencia de tipos, as que no entrar en detalles por ahora. Por lo general,
querr mantener esta opcin establecida en On.
Option Compare Binary y Option Compare Text
Estas dos variaciones de la instruccin Option Compare instruye a su cdigo para usar
reglas de ordenamiento especficas para ciertas caractersticas de comparacin de cadena.
En general, las comparaciones Binary son sensibles a maysculas y minsculas, mientras
que las Text no lo son. Usted decide cul mtodo quiere usar; la opcin predeterminada
es Binary.
Estas instrucciones aparecen en la parte superior de cada archivo de cdigo fuente en su proyec-
to, antes de cualquier otro cdigo:
Option Explicit On
Option Strict On

O, para ahorrar precioso espacio en disco, establezca los valores predeterminados que se aplicarn
a todo su proyecto a travs de las propiedades de ste. En Visual Studio, seleccione el comando
de men Proyecto Propiedades. En la ventana de propiedades del proyecto que aparece, se-
leccione la ficha Compilar, y establezca sus opciones para los campos Option explicit, Option
strict, Option compare y Option infer (vase la figura 2-2).

Figura 2-2. Opciones, opciones por todos lados.

46 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 46 17/2/10 15:19:21


Operadores bsicos
Visual Basic incluye varios operadores bsicos que le permiten hacer lo que realmente quiere que
haga su cdigo: manipular datos. Para usarlos, slo marque cero desde su telfono. No, espere;
esos operadores le permiten colocar llamadas asistidas por el operador por slo 2.73 dlares el
primer minuto. Los operadores de Visual Basic le permiten realizar funciones de administracin
matemtica, lgica, en el nivel de bits y de cadena, sin costo adicional.
El operador ms bsico es el de asignacin, representado por el signo de igual (=). Ya ha visto
este operador en uso en este captulo. selo para asignar algn valor a una variable (o constante);
cualquier cosa que aparezca a la derecha del operador se asigna a la variable del tipo de referencia
o de valor de la izquierda. La instruccin
cincoAlCuadrado = 25

asigna un valor de 25 a la variable cincoAlCuadrado.


Casi todos los operadores son operadores binarios: operan sobre dos valores distintos, uno a la
izquierda del operador y otro a la derecha; el resultado es un solo valor calculado. Es como si el
clculo fuera reemplazado por completo por el resultado calculado. Por ejemplo, la operacin
de suma:
siete = 3 + 4

se vuelve:
siete = 7

antes de la aplicacin final del operador de asignacin (=). Un operador unario aparece a la dere-
cha de su operando. Por ejemplo, el operador de negacin unario convierte un nmero positivo
en uno negativo:
sieteNegativo = 7

En el captulo 6 comentar cada operador de manera detallada. Pero ahora necesitaremos un


rpido resumen para poder manipular datos antes de llegar a ese captulo. En la tabla 2-2 se
presentan los operadores principales de Visual Basic y se describe brevemente el propsito de
cada uno.

Tabla 2-2. Operadores de Visual Basic.

Operador Descripcin
+ El operador de suma adiciona dos nmeros.
+ El operador unario de ms retiene el signo del valor numrico. No es muy til hasta que sobrecarga el operador, algo
que se aborda en el captulo 12.
El operador de resta sustrae el segundo operando del primero.
El operador unario de negacin invierte el signo de su operando numrico asociado.

Operadores bsicos | 47

02_PATRICK-CHAPTER_02.indd 47 17/2/10 15:19:21


Tabla 2-2. Operadores de Visual Basic (continuacin).

Operador Descripcin
* El operador de multiplicacin multiplica dos valores numricos.
/ El operador de divisin divide el primer operando numrico entre el segundo, regresando el cociente, incluido cual-
quier sobrante decimal.
\ El operador de divisin entero divide el primer operando numrico entre el segundo, regresando el cociente, pero con
el sobrante decimal truncado.
Mod El operador mdulo divide el primer operando numrico entre el segundo, y slo devuelve el sobrante como un valor
entero.
^ El operador exponencial eleva el primer operando (la base) a la potencia del segundo (el exponente).
& El operador de unin de cadenas une dos operandos de cadena y devuelve una nueva cadena con los resultados
combinados.
Anda El operador de conjuncin devuelve True si ambos operandos booleanos tambin son True.
AndAlso Este operador es como And, pero no examina ni procesa el segundo operando si el primero es False.
Or a
Este operador de disyuncin devuelve True si cualquiera de los operandos tambin es True.
OrElse Este operador es como Or, pero no examina ni procesa el segundo operando si el primero es True.
Nota El operador de negacin devuelve el opuesto de un operando booleano.
Xor a
El operador or excluyente devuelve True si exactamente uno de los operandos tambin es True.
<< El operador de desplazamiento a la izquierda desplaza los bits individuales de un operando entero que se encuentra a
la izquierda en el nmero de posiciones de bits en el segundo operando.
>> El operador de desplazamiento a la derecha desplaza los bits individuales de un operando entero que se encuentra a
la derecha en el nmero de posiciones de bits en el segundo operando.
= El operador de comparacin igual a devuelve True si los operandos son iguales entre s.
< El operador de comparacin menor que devuelve True si el primer operando es menor que el segundo.
<= El operador de comparacin menor que o igual a devuelve True si el primer operando es menor que o igual a el
segundo.
> El operador de comparacin mayor que devuelve True si el primer operando es mayor que el segundo.
>= El operador de comparacin mayor que o igual a devuelve True si el primer operando es mayor que o igual a el
segundo.
<> El operador de comparacin no es igual a devuelve True si el primer operando no es igual a el segundo.
Like El operador de comparacin de patrn devuelve True si el primer operando coincide con un patrn de cadena
especificado por el segundo operando.
Is El operador de comparacin de objetos igual a devuelve True si ambos operandos realmente representan la misma
instancia de un valor de datos en la memoria. El establecimiento del segundo operando en Nothing le permite
probar una referencia a variable para ver si contiene datos.
IsNot El operador de comparacin de objetos no es igual a es el opuesto al operador Is.
a
Los operadores And, Or, Not y Xor tambin funcionan como operadores en el nivel de bits. En el captulo 6 me referir a eso en Operadores.

48 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 48 17/2/10 15:19:21


Tan poderosos como son los operadores, poseen an ms poder cuando los combina. Esto fun-
ciona porque cualquiera de los operandos puede ser una expresin compleja que incluye sus
propios operandos. Los parntesis agrupados alrededor de las clusulas en operandos aseguran
que los valores se procesan en el orden que usted espera.
reaDelCirculo = pi * (radio ^ 2)

En esta instruccin, el segundo operando del operador de multiplicacin * es otra expresin, que
incluye su propio operador.

Uso de funciones y subrutinas


Hace aos trabaj para una compaa de software que en ocasiones publicaba software desa-
rrollado fuera de la organizacin, todo para una plataforma que no era de Windows. Mientras
que la mayor parte de estos programas estaban escritos en el lenguaje C, tambin publicamos
software escrito en Pascal, lenguaje ensamblador, y el bueno y antiguo BASIC. Hered una de
esas aplicaciones externas escritas por completo en BASIC, un programa que ayudaba al usuario
en modelado y representacin de imgenes 3D. Era un programa complejo que contena casi
30 000 lneas de cdigo fuente. El problema era que se trataba de un bloque grande de 30 000
lneas de cdigo fuente. Sin comentarios, ni nombres de variables de ms de unos cuantos carac-
teres, ni algn producto analgsico ultrapotente. Slo miles de lneas de cdigos con instruccio-
nes de control de flujo que saltaban aqu y all. Y, por supuesto, tena un error.
Tuve la capacidad de superar ese acontecimiento de mi vida sin demasiada terapia, pero en
esa poca fue un choque ver un cdigo en esas condiciones. Y era tan innecesario, porque ese
sabor de BASIC era un lenguaje procedimental, como C y Pascal. Los lenguajes procedimenta-
les le permiten dividir su cdigo en bloques de lgica con nombre, llamados procedimientos.
Esos procedimientos le permiten usar el mtodo Divide y vencers para programar; usted
escribe procedimientos que cumplen una porcin lgica especfica del cdigo dentro de toda
su aplicacin, y luego accede a esos procedimientos desde otros procedimientos.
Visual Basic incluye tres tipos de procedimientos:
Subrutinas
Estos procedimientos, tambin llamados subprocedimientos, hacen mucho trabajo y luego
regresan al procedimiento que los llama. Los datos pueden enviarse en la subrutina median-
te su lista de argumentos y algunos valores pueden regresar mediante esa misma lista, pero el
procedimiento no enva un resultado final oficial. Una subrutina hace su trabajo y, una vez
completado, el cdigo que llama sigue su feliz camino.
Funciones
Las funciones son como subrutinas, con una caracterstica adicional: usted puede regresar
un solo valor o instancia de objeto de la funcin como resultado oficial. Por lo general,
el cdigo que llama toma en consideracin su valor de regreso cuando completa su propia
lgica.

Uso de funciones y subrutinas | 49

02_PATRICK-CHAPTER_02.indd 49 17/2/10 15:19:21


Propiedades
Cuando se usan, las propiedades en realidad tienen el aspecto de variables. Usted asigna
valores a propiedades y los recupera como lo hara con una variable. Sin embargo, las pro-
piedades incluyen cdigo oculto, a menudo usado para validar los datos asignados a la
propiedad.
Subrutinas, funciones y propiedades son los miembros de cdigo de cada clase o tipo similar.
Demorar el anlisis de las propiedades a pginas posteriores de este captulo. Por ahora, disfru-
temos las funciones y las subrutinas, que, en conjunto, son conocidas como mtodos. Empece-
mos con las subrutinas. Para llamar a una, escriba su nombre como una instruccin, seguido por
un conjunto de parntesis. Cualquier dato que necesite enviar a la subrutina va entre parntesis.
Por ejemplo, la siguiente llamada a subrutina hace algo de trabajo, pasando el nmero de ID de
un cliente, y una fecha de inicio:
HaceAlgo(idCliente, fechaInicio)

Cada subrutina define el tipo de datos y el orden de los argumentos que pasa. Esta lista de argu-
mentos puede incluir uno o ms argumentos opcionales, que son valores predeterminados asigna-
dos si no los incluye. Una subrutina tambin podra sobrecargarse, definiendo diferentes listas de
argumentos posibles con base en el nmero y tipo de datos de los argumentos. Encontraremos
gran cantidad de stos ms adelante.
Las funciones son un poco ms interesantes porque devuelven un valor til. A menudo, este
valor se asigna a una variable:
Dim saldoVencido As Boolean
saldoVencido = TieneSaldoExcepcional(idCliente)

Entonces puede hacer algo con este resultado. Si quiere, puede ignorar el valor que devuelve
una funcin, y ya lo hicimos. La funcin MsgBox usada antes devuelve la identidad del botn
en pantalla en que el usuario hizo clic para cerrar el cuadro de mensaje. Si slo incluye un
botn Aceptar (la opcin predeterminada), tal vez no le preocupe en qu botn haga clic el
usuario.
MsgBox("Vamos, haz clic en el botn Aceptar.")

Pero tambin puede capturar el resultado del botn:


cualBoton = MsgBox("Haz clic en s o no.", MsgBoxStyle.YesNo)

En este caso, cualBoton ser MsgBoxResult.Yes o MsgBoxResult.No, dos de los posibles


resultados definidos por la funcin MsgBox.

Condiciones
En ocasiones tiene que hacer alguna eleccin, y las expresiones condicionales le ayudarn a to-
marlas. Visual Basic incluye soporte para condiciones, que usan pruebas de datos para determinar
cul cdigo debe procesarse a continuacin.

50 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 50 17/2/10 15:19:21


Instrucciones If
La instruccin condicional ms comn es If. Es equivalente en ingls a las preguntas de la forma
Si tal y tal es cierto, entonces haz esto y lo otro. Por ejemplo, puede manejar Si tienes $20,
entonces puedes invitarme a comer, pero no Si un tren parte de Chicago a 70 kilmetros por
hora, cundo se quedar sin carbn?
Las instrucciones If tienen sintaxis que abarca varias lneas de cdigo fuente:
01 If (tuveUnMartillo = True) Then
02 UsarMartillo(enlaManana, porTodaLaTierra)
03 UsarMartillo(inTheEvening, porTodaLaTierra)
04 ElseIf (hadAShovel = True) Then
05 UsarPala(aMediodia, porTodaLaTierra)
06 Else
07 TomarSiesta(todoElTiempo, enMiSofa)
08 End If

La instruccin If le permite definir ramas de su cdigo con base en condiciones. Se construye


con tres componentes:
Condiciones
La expresin que se encuentre entre las palabras clave If (o ElseIf) y Then es la condicin.
El ejemplo incluye dos condiciones, en las lneas 01 y 04. Las condiciones pueden ser sim-
ples o complejas, pero siempre deben dar un valor booleano True o False. Pueden incluir
llamada a otras funciones y varios operadores lgicos y de comparacin.
If ((JugadoresEnEquipo(equipoLocal) >= 9) Y _
(JugadoresEnEquipo(equipoVisitante) >= 9)) O _
(soloPracticando = True) Then
EmpezarJuego()
Else
LucesEstadio(apagar)
End If

La condicin original siempre sigue a la palabra clave If. Si esa condicin falla, puede especifi-
car condiciones adicionales despus de una palabra clave ElseIf, como en la lnea 04. Puede
incluir todas las clusulas ElseIf que necesite. La condicin opcional Else no le permite
especificar una expresin de prueba. En cambio, compara todo lo que an no se captura con
las clusulas If o ElseIf. Slo una clusula Else se permite por instruccin If.
Ramas
La palabra clave Then de cada condicin es seguida por una o ms instrucciones de Visual
Basic que son procesadas si la condicin asociada se evala como True. Todas las instruccio-
nes, hasta la siguiente Else, ElseIf o End If, se incluyen en el bloque de instrucciones de
esa rama. Puede incluir cualquier cantidad de instrucciones en un bloque de rama, incluidas
instrucciones If subordinadas. En el cdigo de ejemplo, las lneas de rama 02 y 03 se pro-
cesan si la condicin original tuveUnMartillo es verdadera. En cambio, se procesa la lnea
05 si la condicin original falla, pero pasa la segunda condicin tuveUnaPala. Si ninguna
de las condiciones es True, se ejecuta la rama de Else, en la lnea 07.

Condiciones | 51

02_PATRICK-CHAPTER_02.indd 51 17/2/10 15:19:21


Palabras clave de instruccin
La instruccin If es una de varias instrucciones de mltiples lneas en Visual Basic; todas
ellas terminan con la palabra clave End seguida por la palabra clave de instruccin (If, en
este caso). Las palabras clave de la instruccin If, que dan su estructura a la instruccin,
son, entre otras, If, Then, ElseIf, Else y End If. Todas las clusulas ElseIf y Else y
las ramas relacionadas son opcionales. La instruccin If ms simple slo incluye una rama
If.

If (longitudNumeroTelefonico = 10) Then


MarcarNumero(NumeroTelefonico)
End If

En el caso de condiciones con ramas de una sola instruccin y sin clusulas ElseIf, una
opcin de una sola lnea puede mantener su cdigo con aspecto limpio.
If (GuardarDatos() = True) Then MsgBox("Datos guardados.")
If (HoraDelDia >= #13:00#) _
Then estadoActual = EstadoTrabajo.IrACasa _
Else estadoActual = EstadoTrabajo.OcupadoTrabajando

Las instrucciones If son estupendas porque hacen que su cdigo sea un poco ms que un con-
junto aburrido de instrucciones lineales paso a paso que nunca se desvan por ninguna razn. El
software se escribe para dar soporte a algn proceso real, y los procesos reales muy pocas veces
son lineales. La instruccin If permite que su cdigo reaccione a diferentes condiciones de da-
tos, tomando la rama apropiada cuando es necesario.
Una vez que todo el bloque If...End If se completa, el procesamiento contina con la si-
guiente instruccin que sigue a End If.

Instrucciones Select Case


En ocasiones podra escribir una instruccin If que pruebe una variable contra un valor posible,
luego otro, otro ms, etctera:
If (valorBillete = 1) Then
nombrePresidente = "Washington"
ElseIf (valorBillete = 2) Then
nombrePresidente = "Jefferson"
ElseIf (valorBillete = 5) Then
nombrePresidente = "Lincoln"
...

Y as, a travs de muchas clusulas ElseIf ms. Es efectivo, pero un poco tedioso, porque su
cdigo debe probar cada caso de manera especfica. La instruccin Select Case proporciona
una opcin ms limpia para valores de comparacin simples contra una lista:
01 Select Case valorBillete
02 Case 1

52 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 52 17/2/10 15:19:21


03 nombrePresidente = "Washington"
04 Case 2
05 nombrePresidente = "Jefferson"
06 Case 5
07 nombrePresidente = "Lincoln"
08 Case 20
09 nombrePresidente = "Jackson"
10 Case 50
11 nombrePresidente = "Grant"
12 Case 10, 100
13 nombrePresidente = "!! No hay presidente"
14 Case > 100
15 nombrePresidente = "!! Valor demasiado largo"
16 Case Else
17 nombrePresidente = "!! Valor no vlido"
18 End Select

A diferencia de la instruccin If, que revisa un resultado booleano, Select Case compara un
solo valor contra un conjunto de valores de caso de prueba. En el ejemplo, la variable valor-
Billete se compara contra los diferentes valores identificados por cada clusula Case. Todo el
cdigo que sigue a una clusula Case (hasta la siguiente clusula Case) es la rama que se procesa
cuando se encuentra una coincidencia. Una condicin opcional Case Else (lnea 16) captura
cualquier cosa que no coincide con ningn otro Case. Por lo general, las clusulas Case presen-
tan listas de valores individuales para comparacin. Tambin pueden incluir una lista de valores
de comparacin separados por comas (lnea 12), o expresiones de comparacin de rango simple
(lnea 14).

Funciones IIf e If
Visual Basic incluye dos variaciones de la instruccin If para uso en lnea. Considere la si-
guiente instruccin:
If (genero = "F") Then generoCompleto = "Femenino" _
Else generoCompleto = "Masculino"

Empleando la funcin IIf, esta instruccin se comprime en una sola instruccin de asignacin
con una condicin incrustada:
generoCompleto = IIf(genero = "F", "Femenino", "Masculino")

La funcin IIf tiene tres argumentos delimitados por comas. El primero es la condicin, que
debe dar como resultado un valor booleano True o False. El segundo argumento es devuelto
por la funcin si la condicin es True; un resultado de condicin False devuelve el tercer ar-
gumento. En el caso de condiciones simples que estn destinadas a regresar valores nicos a una
variable comn, es realmente una funcin til. Pero como con cualquier cosa realmente til, deben
tomarse precauciones. La advertencia con IIf es que se procesar cualquier cosa que aparezca den-
tro de la instruccin IIf, aunque no se devuelva como resultado. He aqu un ejemplo peligroso:
resultadoPurga = IIf(nivel = 1, ConjuntoPurga1(
), ConjuntoPurga2(
))

Condiciones | 53

02_PATRICK-CHAPTER_02.indd 53 17/2/10 15:19:22


La instruccin devolver correctamente el resultado de ConjuntoPurga1() o ConjuntoPur-
ga2() con base en el valor de nivel. El problema, o posible problema, es que se llamar a las
dos funciones, ConjuntoPurga1() y ConjuntoPurga2(); si el nivel es 1, se llamar a Con-
juntoPurga1( ) y ConjuntoPurga2( ), aunque slo se regresar el resultado de la funcin de
ConjuntoPurga1( ).
Como ayuda para evitar estos efectos colaterales, Visual Basic 2008 agreg el nuevo operador If.
Tiene el mismo aspecto que la funcin IIf, excepto porque la palabra clave If reemplaza a IIf:
resultadoPurga = If(nivel = 1, ConjuntoPurga1(
), ConjuntoPurga2(
))

Ahora slo se llamar a ConjuntoPurga1() o ConjuntoPurga2() con base en la condicin,


pero no a ambas. Aunque el operador If parezca una funcin, es un operador real, conocido
como operador ternario. En tiempo de compilacin, Visual Basic trata a ste y sus argumentos
como operador y operandos y genera la lgica apropiada.
Una variacin del operador If toma slo dos argumentos, excluido el argumento booleano
inicial.
objetoReal = If(objeto1, objeto2)

En esta versin del operador If, si el primer argumento se evala como Nothing, el operador
devuelve el segundo argumento. Si el primero no es Nothing (es decir, si en realidad tiene algo),
el operador devuelve, en cambio, el primer argumento. El objetivo es devolver algo que no sea
Nothing, aunque se trate de una doble negacin.

Bucles
Visual Basic incluye tres tipos principales de bucles: For...Next, For Each...Next y Do...
Loop. Al igual que las condiciones le permiten dividir la monotona secuencial de su cdigo
mediante ramas, los bucles agregan algo a la utilidad de su cdigo al dejar que repita un bloque
especfico de lgica un nmero fijo o variable de veces.

Bucles For . . . Next


El bucle For...Next usa un contador numrico que aumenta de un valor inicial a uno final,
procesando el cdigo dentro del bucle una vez para cada valor aumentado.
Dim cualMes As Integer
For cualMes = 1 To 12
procesarDatosMensualmente(cualMes)
Next cualMes

Este ejemplo se repite 12 veces (1 To 12), una vez para cada mes. Puede especificar cualquier
valor de inicio y final que desee; este rango tambin puede especificarse utilizando variables o
funciones que devuelven valores numricos. Una vez que se obtienen los valores iniciales y fina-
les, vuelven a calcularse cada vez a travs del bucle, aunque se use una llamada a funcin para
obtener uno o ambos lmites.

54 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 54 17/2/10 15:19:22


' ----- Mes(Hoy) devuelve el mes numrico
' para la fecha actual.
For cualMes = 1 To Mes(Hoy)
procesarDatosMensualmente(cualMes)
Next cualMes

Por lo general, el bucle aumenta en uno (1) cada vez. Puede modificar este comportamiento
predeterminado al adjuntar una clusula Step al final de la lnea de la instruccin For:
For cuentaHaciaAbajo = 60 To 0 Step -1
...
Next cuentaHaciaAbajo

Una variante adicional a la sintaxis le permite declarar la variable del contador del bucle dentro
de la propia instruccin. Estas variables slo estn disponibles dentro del bucle y dejan de existir
una vez que se sale del bucle.
For cualMes As Integer = 1 To 12
procesarDatosMensualmente(cualMes)
Next cualMes

Bucles For Each . . . Next


Una variacin del bucle For, el bucle For Each...Next, rastrea un conjunto de elementos or-
denados y relacionados, desde el primer elemento hasta el ltimo. Las matrices y los objetos de
coleccin tambin funcionan, al igual que cualquier objeto que d soporte a la interfaz IEnume-
rable (todos estos temas se cubren en el captulo 6). La sintaxis es muy similar a la instruccin
For estndar:

For Each unRegistro En conjuntoDeRegistros


procesarRegistro(unRegistro)
Next unRegistro

Bucles Do . . . Loop
En ocasiones querr repetir un bloque de cdigo, siempre y cuando cierta condicin sea verdade-
ra, o slo hasta que lo sea. La estructura Do...Loop realiza ambas tareas. La instruccin incluye
una clusula While o Until que especifica las condiciones para el procesamiento continuo del
bucle. Por ejemplo, la siguiente instruccin hace algo de procesamiento para un conjunto de
fechas, de una inicial a una final:
Dim fechaProceso As Date = #1/1/2000#
Do While (fechaProceso < #2/1/2000#)
' ----- Realizar procesamiento para la fecha actual.
ProcesarContenido(fechaProceso)

' ----- Avanza a la siguiente fecha.


fechaProceso = fechaProceso.AgregarDias(1)
Loop

Bucles | 55

02_PATRICK-CHAPTER_02.indd 55 17/2/10 15:19:22


El procesamiento de este ejemplo continuar hasta que la variable fechaProceso sea o exceda
2/1/2000, que indica el final del procesamiento. La versin de la clusula Until es un poco
similar, aunque con un resultado de condicin invertido:
Do Until (fechaProceso >= #2/1/2000#)
...
Loop

Puede hacer que la condicin incluida sea tan simple o compleja como lo desee. Al poner la
clusula Until o While en la parte inferior del bucle garantiza que las instrucciones dentro del
bucle siempre se procesen, aunque sea una vez:
Do
...
Loop Until (fechaProceso >= #2/1/2000#)

Si la condicin del bucle nunca se cumple, ste continuar eternamente. Por tanto, si quiere que
se salga de un bucle en alguna parte (y por lo general lo hace), asegrese de que la condicin se
pueda cumplir en algn momento.
Hay otro bucle similar a Do...Loop, llamado While...End While. Sin embargo, slo existe
para compatibilidad con versiones anteriores. Use, en cambio, la instruccin Do...Loop.

Instrucciones de salida
Por lo general, cuando ingresa en un bucle, tiene todas las intenciones de recorrerlo por com-
pleto el nmero de veces especificado en las condiciones iniciales. En el caso de los bucles For,
espera seguir durante todo el rango numrico o la coleccin de elementos. En los bucles Do,
planea mantener el bucle ejecutndose mientras la condicin de salida no se cumpla. Pero puede
haber bucles de los que desee salir antes. Logra esto empleando la instruccin Exit.
Hay dos instrucciones Exit especficas de bucles:
Exit For
Sale de un bucle For...Next o For Each...Next de inmediato
Exit Do
Sale de una instruccin Do...Loop de inmediato
Cada instruccin Exit sale del bucle que contiene la instruccin; el procesamiento contina en
la lnea que sigue de inmediato al bucle:
For cualMes = 1 To 12
If (procesarDatosMensualmente(cualMes) = False) Then Exit For
Next cualMes
' ----- El cdigo sigue aqu sin importar cmo se salga del bucle.

El cdigo de ejemplo est diseado para recorrer en bucle los 12 meses. Sin embargo, una falla
en el procesamiento en cualquiera de los 12 meses har que se salga de inmediato del bucle,
abandonando todas las acciones de procesamiento de los meses restantes. La instruccin Exit
Do hace que se salga de inmediato del bucle Do...Loop de manera similar.

56 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 56 17/2/10 15:19:22


En una instruccin del bucle Exit dentro de bucles anidados (donde un bucle aparece dentro de
otro), slo se sale del bucle coincidente que contiene de manera inmediata la instruccin:
For cualMes = 1 To 12
For cualDia = 1 to DasInMes(cualMes)
If (ProcesarDatosDiariamente(cualMes, cualDia) = False) _
Then Exit For
Next cualDia
' ----- La instruccin Exit For salta a esta lnea.
' El procesamiento contina en el siguiente mes.
Next cualMes

Instrucciones Continue
Debido a que cuando se sale de un bucle se abandonan todos los pasos restantes del bucle, podra
omitirse un procesamiento importante que se hubiera dado en pasos posteriores. Visual Basic
incluye una instruccin Continue que le permite abandonar slo el paso actual del bucle.
Hay diferentes variaciones de las instrucciones Continue para cada tipo de bucle:
Continue For
Salta de inmediato al final del bucle For...Next o For Each...Next y prepara para el
siguiente paso. La variable del bucle se aumenta y se compara con el rango o los lmites de
la coleccin.
Continue Do
Salta de inmediato al final de la instruccin Do...Loop y prepara el siguiente paso. Se vuel-
ve a evaluar la condicin Until o While.
Debido a que las condiciones de bucle se vuelven a evaluar cuando se usan las instrucciones
Continue, hay ocasiones en que Continue puede causar la salida del bucle, cuando ya se ha
hecho el paso final por el bucle.
En este ejemplo, la instruccin Continue For omite el procesamiento de meses que no tienen
datos para procesarse:
For cualMes = 1 To 12
If (DatosDisponibles(cualMes) = False) Then Continue For
RecuperarDatos(cualMes)
ProcesarDatos(cualMes)
GuardarDatos(cualMes)
Next cualMes

Creacin de procedimientos propios


Todas las instrucciones lgicas de su cdigo deben aparecer dentro de un procedimiento, sea
una subrutina, una funcin o una propiedad. Aunque hay miles de procedimientos escritos
previamente para que los elija en las bibliotecas de .NET Framework, tambin puede agregar
procedimientos propios.

Creacin de procedimientos propios | 57

02_PATRICK-CHAPTER_02.indd 57 17/2/10 15:19:22


Subrutinas
Las subrutinas empiezan con una instruccin de declaracin Sub y terminan con una instruc-
cin End Sub. Toda la lgica de su subrutina aparece entre estas dos poderosas mandbulas.
01 Sub MostrarIngredientes(ByVal genero As Char)
02 Dim elMensaje As String = "Desconocido."
03 If (genero = "M"c) Then
04 elMensaje = "Cosas cortadas y caracoles y colas de perritos."
05 ElseIf (genero = "F"c) Then
06 elMensaje = "Azcar y especias y todo lo sabroso."
07 End If
08 MsgBox(elMensaje)
09 End Sub

En la lnea 01 se muestra la lnea de declaracin de la subrutina en su forma ms simple; en todo


el libro encontrar que hay palabras clave adicionales que decoran declaraciones de procedi-
mientos para cambiar su comportamiento. La instruccin empieza con la palabra clave Sub (de
subrutina), seguida por el nombre del procedimiento, MostrarIngredientes.
El parntesis que sigue a este nombre contiene los parmetros de la subrutina. Los parmetros
permiten que otro cdigo de bloque que usar este procedimiento pase los datos al procedimien-
to y, como opcin, reciba de regreso los datos. Puede incluir cualquier cantidad de parmetros
en la definicin de la subrutina; simplemente seprelos con comas. Cada parmetro especifica
el nombre, tal como se usar en el procedimiento (genero en el ejemplo), y su tipo de datos
(Char). Los argumentos se tratan como variables declaradas dentro del procedimiento, como se
hace con genero en las lneas 03 y 05.
A los valores proporcionados al llamar al cdigo se les conoce como argumentos. Todos los ar-
gumentos se pasan por valor o por referencia. En el cdigo de ejemplo, el argumento pasado en
genero se pasar por valor, como se especifica mediante la palabra clave ByVal. La palabra clave
ByRef relacionada indica que un argumento se pasar por referencia. Si no incluye ninguna de
las dos palabras clave, se supone que se usar ByVal. Este mtodo para pasar argumentos deter-
mina si los cambios que se hacen al argumento dentro del procedimiento local se propagan de
regreso al cdigo que llama. Sin embargo, la capacidad de actualizar los datos originales tambin
se ve influida por el hecho de que los datos sean un tipo de valor o un tipo de referencia. En la tabla
2-3 se indica el comportamiento de cada combinacin de mtodo de paso y tipo de datos.

Tabla 2-3. Actualizacin de datos a la manera de .NET.

Mtodo de paso Tipo de datos Comportamiento


ByVal Tipo de valor Los cambios hechos a la versin local del argumento tienen impacto en la versin
original.
ByVal Tipo de referencia Los cambios hechos a los miembros del objeto de datos tienen impacto inmediato
en el objeto de datos original. Sin embargo, el propio objeto no puede cambiarse o
reemplazarse con un objeto de datos completamente nuevo.

58 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 58 17/2/10 15:19:22


Tabla 2-3. Actualizacin de datos a la manera de .NET (continuacin).

Mtodo de paso Tipo de datos Comportamiento


ByRef Tipo de valor Los cambios hechos a la versin local se regresan al procedimiento que llama y
tienen impacto permanente en el valor de datos original.
ByRef Tipo de referencia Los cambios hechos al objeto de datos o a sus miembros tambin cambian en el
original. Es posible reemplazar por completo el objeto enviado en el procedimiento.

En casi todos los casos, si est interesado en modificar el valor de un parmetro y hacer que los
cambios regresen al llamador, use ByRef; de otra manera, use ByVal.
De la lnea 02 a la 08 del cdigo de ejemplo se encuentra el cuerpo del procedimiento, donde
aparece toda su lgica. Cualquier variable que se usar exclusivamente en la rutina tambin se
define aqu, al igual que en la variable elMensaje de la lnea 02. La subrutina siempre concluye
con una instruccin End Sub.

Funciones
La sintaxis de una funcin slo difiere ligeramente de la usada en las subrutinas, para dar soporte
a un valor que se devuelve.
01 Function EsPrimo(ByVal origen As Long) As booleano
02 ' ----- Determina si el origen es un nmero primo.
03 Dim pruebaValor As Long
04 If (origen < 2) Then
05 Return False
06 ElseIf (origen > 2) Then
07 For pruebaValor = 2 To origen \ 2&
08 If ((origen Mod pruebaValor) = 0) Then
09 Return False
10 End If
11 Next pruebaValor
12 End If
13 Return True
14 End Function

Al igual que con las subrutinas, la lnea de declaracin de la funcin aparece primero (lnea 01),
seguida por el cuerpo (de la lnea 02 a la 13) y la instruccin de cierre End Function (lnea 14).
La lnea de declaracin incluye una definicin adicional de tipo de datos despus de la lista de
parmetros. ste es el tipo de datos del valor final que habr de regresarse al cdigo que llama.
Use este valor de resultado en el cdigo de llamada como lo hara con cualquier otro valor o
variable. Por ejemplo, la siguiente lnea llama a la funcin EsPrimo y almacena su resultado
booleano en una variable:
resultadoPrimo = EsPrimo(23)

Para indicar el valor que se regresar, use la instruccin Return (que se describe ms adelante
en el captulo). El cdigo de ejemplo hace eso en las lneas 05, 09 y 13. (Una sintaxis antigua

Creacin de procedimientos propios | 59

02_PATRICK-CHAPTER_02.indd 59 17/2/10 15:19:22


de VB 6.0 que le permite asignar el valor del resultado al nombre de la funcin y que an
funciona.)

Propiedades
Un poco antes mencion los campos, que son variables o constantes que aparecen dentro de una
clase, pero fuera de cualquier definicin de procedimiento.
01 Class RangoPorcentaje
02 Public Porcentaje As Integer
03 End Class

Las propiedades son similares a los campos; se usan como variables o constantes en el nivel de la
clase. Pero estn programadas como las funciones, aceptan parmetros, tienen valores de resulta-
do e incluyen toda la lgica que necesite.
Las propiedades suelen usarse para proteger datos de una clase privada con lgica que deja fuera
valores no apropiados. La siguiente clase define una sola propiedad de acceso que proporciona
acceso a los campos relacionados ocultos:
01 Class RangoPorcentaje
02 ' ----- Almacena un porcentaje que slo va de 0 a 100.
03 Private porcentajeGuardado As Integer
04 Public Property Porcentaje() As Integer
05 Get
06 Return porcentajeGuardado
07 End Get
08 Set(ByVal value As Integer)
09 If (valor < 0) Then
10 porcentajeGuardado = 0
11 ElseIf (valor > 100) Then
12 porcentajeGuardado = 100
13 Else
14 porcentajeGuardado = valor
15 End If
16 End Set
17 End Property
18 End Class

La propiedad Porcentaje (lneas 04 a 17) protege el acceso al campo porcentajeGuardado


(lnea 03), corrigiendo cualquier valor proporcionado por el llamador que exceda el rango de 0
a 100. Las propiedades incluyen componentes separados de asignacin y recuperacin, tambin
denominados accesores. El accesor Get (lneas 05 a 07) devuelve al llamador el valor monitoreado
de la propiedad. El accesor Set (lneas 08 a 16) permite que el llamador modifique el valor de
la propiedad.
La instruccin de declaracin de la propiedad (lnea 04) incluye un tipo de datos que coincide
con el pasado en el accesor Set (lnea 08). ste es el tipo de datos del conjunto de valores o recu-
perado por el llamador. Para usar la propiedad Porcentaje de este ejemplo, cree una instancia
de la clase RangoPorcentaje y luego use la propiedad:

60 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 60 17/2/10 15:19:22


Dim porcentajeActivo As New RangoPorcentaje
porcentajeActivo.Porcentaje = 107 ' Entero fuera del rango
MsgBox(porcentajeActivo.Porcentaje) ' Despliega "100", no "107"

Puede crear propiedades de slo lectura o slo escritura al incluir la palabra clave ReadOnly o
WriteOnly antes de la palabra clave Property en la instruccin de declaracin (lnea 04) y
dejando fuera el accesor innecesario.
No es necesario que las propiedades estn unidas a campos. Puede usar propiedades para obtener y
establecer cualquier tipo de valor, y almacenarlo o actuar sobre l de cualquier manera que desee.

Dnde colocar sus procedimientos


En los viejos y buenos das de Visual Basic 6.0, los procedimientos podan aparecer en cualquier
lugar de sus archivos de cdigo fuente. Abra un archivo de origen, escriba una funcin y ya; era
as de fcil. Con el paso a .NET, ahora todos los procedimientos de Visual Basic deben aparecer
dentro de una clase definida (o una estructura o un mdulo).
Class Empleado
Sub IniciarVacaciones()
...
End Sub

Function TotalVacacionesTomadas() As Double


...
End Function
End Class

Cuando cree instancias de su clase ms adelante en el cdigo, los mtodos pueden llamarse di-
rectamente mediante la instancia de objeto.
Dim ejecutivo As New Empleado
...
ejecutivo.IniciarVacaciones()

En el captulo 8 se muestra cmo usar y construir clases.

Otras caractersticas de control de flujo


Los bucles y las instrucciones condicionales disponibles en Visual Basic le permiten volver a en-
rutar su cdigo con base en los datos. El lenguaje incluye unas cuantas instrucciones adicionales
que le permiten controlar la accin de manera ms directa.

La instruccin GoTo
La instruccin GoTo le permite saltar de inmediato a otra ubicacin dentro del procedimiento
actual. El destino de un salto es siempre una etiqueta de lnea, la posicin de una lnea con nom-
bre en el procedimiento actual. Todas las etiquetas de lnea aparecen al principio de una lnea
lgica y terminan con dos puntos.

Otras caractersticas de control de flujo | 61

02_PATRICK-CHAPTER_02.indd 61 17/2/10 15:19:22


IndicadorDelUsuario:
ObtenerValoresDelUsuario(numerador, denominador)
If (denominador = 0) Then GoTo IndicadorDelUsuario
cociente = numerador / denominador

En este ejemplo, la instruccin GoTo salta de regreso a la etiqueta IndicadorDelUsuario cuan-


do el cdigo detecta datos no vlidos. El procesamiento contina con la lnea que sigue de inme-
diato a la etiqueta IndicadorDelUsuario. No puede usar la misma etiqueta con nombre dos
veces en el mismo procedimiento, aunque puede reciclar los nombres de etiqueta en diferentes
procedimientos. Si lo desea, incluya otra instruccin lgica en la misma lnea que su etiqueta,
justo despus de los dos puntos, aunque su cdigo ser, de alguna manera, ms fcil de leer si
mantiene las etiquetas en sus propias lneas.
EtiquetaSolo:
MsgBox("Est solo.")
EtiquetaYCodigo: MsgBox("Juntos de nuevo.")

Es correcto incluir todas las etiquetas que necesite en su cdigo, pero la instruccin GoTo es
uno de esos elementos de Visual Basic que es monitoreado de cerca por las molestas agencias
internacionales de software, como el International Committee To Keep GoTo Always Gone
(ICK-GAG). Ese grupo tambin rastrea los libros de computacin en busca de referencias pe-
yorativas al nombre de su organizacin (en espaol: Comit Internacional para Mantener GoTo
Siempre Ausente), pero no encontrar nada de eso en este libro. Sin embargo, su problema
bsico es que el abuso de las instrucciones GoTo puede llevar a cdigo en forma de espagueti como
el siguiente:
Dim mensajeImportante As String = "Aba"
GoTo Step2
Step6: mensajeImportante &= "AG!"
GoTo Step7
Step3: mensajeImportante &= "co"
GoTo Step4
Step2: mensajeImportante &= "jo "
GoTo Step3
Step5: mensajeImportante &= "CK-G"
GoTo Step6
Step4: mensajeImportante &= "n I"
GoTo Step5
Step7: MsgBox(mensajeImportante)

Algunas personas dicen que este tipo de cdigo es difcil de leer. Otras lo llaman seguridad en el tra-
bajo. No importa cmo lo llame, dificulta en gran medida el mantenimiento y la revisin del cdi-
go. Tal vez debe echar un ojo a su uso de las instrucciones GoTo; si no, alguien ms podra hacerlo.
El propio Visual Basic coloca algunos lmites al uso de GoTo. No puede saltar a ciertas instruc-
ciones de varias lneas que podran producir cdigo o valores de datos inicializados de manera
impropia. Por ejemplo, no puede saltar a la mitad de una instruccin For...Next desde el
exterior de la instruccin, porque no se inicializaran de manera apropiada la variable contadora
del bucle y los rangos de inicio y final.
' ----- Esta instruccin GoTo fallar.

62 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 62 17/2/10 15:19:22


GoTo DentroDelBucle
For contador = 1 to 10
DentroDelBucle:
MsgBox("Nmero de bucle: " & contador)
Next contador

Sin embargo, una vez que se encuentre en el interior del bucle, puede saltar a las etiquetas de
una lnea que tambin aparecen en el bucle, y es aceptable un salto fuera del bucle usando GoTo.
Algunas otras estructuras de varias lneas imponen restricciones similares.

La instruccin Return
No slo puede saltar por un procedimiento empleando GoTo, sino que tambin puede saltar
fuera de un procedimiento en cualquier momento que quiera empleando la instruccin Return.
Por lo general, se sale de un procedimiento cuando el procesamiento alcanza la ltima lnea de
cdigo en el procedimiento; luego contina con el cdigo que llam al procedimiento. La ins-
truccin Return proporciona una manera de salir del procedimiento antes de llegar al final.
En subrutinas, la instruccin Return aparece por s sola como una instruccin independiente:
Return

En funciones, la instruccin debe incluir el valor que se devolver al cdigo de llamada, una
variable, una literal o una expresin que debe coincidir con el tipo de datos del valor de retorno
especificado de la funcin.
Return 25

En versiones anteriores a .NET de Visual Basic se usaba una instruccin Exit para dejar de
inmediato un procedimiento. An tiene soporte en .NET. Existen tres variaciones:
Exit Sub
Sale de una subrutina
Exit Funcin
Sale de una funcin
Exit Property
Sale de una propiedad

Cuando se sale de una funcin, la instruccin Exit Function no incluye una forma para espe-
cificar un valor de retorno. Debe configurar el valor de retorno individualmente asignando un
valor de retorno al nombre de la funcin.
Function DividirConSeguridad(ByVal numerador As Double, _
ByVal denominador As Double) As Double
' ----- El signo "#" hace que un nmero sea Double.
If (denominador = 0#) Then
' ----- Devuelve 0 en una divisin no vlida.
DividirConSeguridad = 0#
Exit Function
End If
Return numerador / denominador
End Function

Otras caractersticas de control de flujo | 63

02_PATRICK-CHAPTER_02.indd 63 17/2/10 15:19:23


Las instrucciones End y Stop
Las instrucciones End y Stop detienen de inmediato su aplicacin de Visual Basic. La instruc-
cin End hace que se salga de su programa al instante, abortando todo el procesamiento adicio-
nal de cdigo y datos (aunque se limpian ciertos recursos adquiridos).
La instruccin Stop suspende el procesamiento slo cuando est ejecutando su aplicacin den-
tro de un depurador, como el entorno de desarrollo de Visual Studio. Stop devuelve el control
al entorno, permitiendo que el desarrollador examine y tal vez modifique los datos y el cdigo
antes de seguir con el programa. Si se encuentra un Stop en una aplicacin independiente que
se ejecuta fuera del depurador, le indica al usuario que depure la aplicacin empleando cualquier
depurador instalado en la estacin de trabajo. No est de ms decir que el usuario no quedar
encantado.

Eventos y manejador de eventos


Visual Basic es un lenguaje orientado a eventos. Esto suele ser especialmente cierto en programas
escritos para ejecutarse en una computadora de escritorio de Windows. Despus de alguna inicia-
lizacin importante, el usuario suele tener el control de todas las acciones del programa. Quin
sabe lo que har el loco usuario. Podra hacer clic aqu. O all. Podra ser todo violencia y locura.
Pero no importa lo que haga el usuario, su programa sabr lo que hace mediante eventos.
Desde los primeros das de Windows, los programas de escritorio han usado una bomba de men-
sajes para comunicar las acciones del usuario y el sistema a su cdigo. La entrada del ratn y el
teclado, las acciones generadas por el sistema y otras notificaciones de origen externo fluyen en
la cola de mensajes comn de un programa. La bomba de mensajes obtiene stos de uno en uno,
los examina y los alimenta a las reas apropiadas de su cdigo.
En la programacin tradicional de Windows, usted construye la bomba de mensajes, incluyendo
un cdigo que hace las llamadas directas a procedimientos de manejo de eventos basados en el
tipo de mensaje. En un programa de Visual Basic (de .NET y anterior), el lenguaje proporciona
la bomba de mensajes. Analiza el mensaje mientras se bombea a la cola de mensajes y los dirige
al cdigo apropiado. En .NET, este cdigo aparece dentro de clases. Una vez que una clase tiene
una oportunidad de analizar el mensaje, puede generar un evento, que es procesado al final por
un manejador de eventos, una subrutina que usted escribe como respuesta a la accin. Esta llama-
da al manejador de eventos es conocida como disparo de un evento. Por tanto, un evento tiene
dos partes: 1) algn cdigo que decide el disparo del evento y 2) un manejador de eventos que
responde al evento disparado.
Los eventos slo son, en realidad, llamadas indirectas a un procedimiento. En lugar de hacer que
el cdigo principal llame directamente a otra subrutina, le pide a .NET que la llame, pasando
argumentos especficos que tal vez el cdigo que llama desee incluir. Entonces, por qu querra
hacer esto en lugar de slo llamar directamente a la subrutina? Por una cosa: este mtodo indi-
recto le permite agregar manejadores de eventos mucho despus de que se haya escrito el cdigo
inicial de disparo del evento. Esto es bueno, porque el cdigo de disparo del evento podra ser

64 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 64 17/2/10 15:19:23


un ensamblado de un tercero que se escribi hace aos. Un segundo beneficio es que un evento
puede tener como destino varios manejadores de eventos. Cuando se dispara el evento, se lla-
mar a cada manejador y cada uno de ellos puede ejecutar cualquier lgica personalizada en la
subrutina del manejador.
El cdigo que dispara el evento pasa datos especficos del evento al manejador de eventos de
destino mediante la lista de parmetros del manejador. Para que funcione la subrutina indirecta
es necesario que el manejador de eventos contenga el nmero correcto de argumentos, en el or-
den correcto, cada uno de ellos de un tipo de datos especfico y esperado. La instruccin Event
define este contrato entre el evento y el manejador.
Public Event SalarioCambiado(ByVal NuevoSalario As Decimal)

Esta instruccin Event define un evento llamado SalarioCambiado con un solo argumento,
un valor Decimal. Cualquier manejador de eventos que desee monitorear el evento debe hacer
que coincida la firma de este argumento.
Sub PagoEmpleadoCambiado(ByVal salarioActualizado As Decimal)...

Los eventos pueden ocurrir por cualquier razn que considere necesaria; deben unirse a las
acciones del usuario o el sistema. En esta clase de ejemplo, un evento se dispara cada vez que se
hace un cambio al salario del empleado. La instruccin RaiseEvent realiza el disparo real del
evento, especificando el nombre del evento que se disparar, y un conjunto de argumentos entre
parntesis.
Public Class Empleado
Public Nombre As String
Private salarioActual As Decimal

Public Property Salario() As Decimal


Get
Return salarioActual
End Get
Set(ByVal valor As Decimal)
salarioActual = valor
RaiseEvent SalarioCambiado(salarioActual)
End Set
End Property

Public Event SalarioCambiado(ByVal NuevoSalario As Decimal)


End Class

Los manejadores de eventos no se agregan directamente a la clase. En cambio, se adjunta a una


instancia de la clase. La instancia, declarada como un campo de clase, debe definirse empleando
la palabra clave especial WithEvents, que le indica a Visual Basic que esta instancia procesar
eventos.
Public WithEvents EmpleadoMonitoreado As Empleado

Los manejadores de eventos son subrutinas ordinarias, pero incluyen la palabra clave Handles
para indicar cul evento se est manejando.

Eventos y manejador de eventos | 65

02_PATRICK-CHAPTER_02.indd 65 17/2/10 15:19:23


Private Sub PagoEmpleadoCambiado( _
ByVal salarioActualizado As Decimal) _
Handles EmpleadoMonitoreado.SalarioCambiado
MsgBox("El nuevo salario de " & _
EmpleadoMonitoreado.Nombre & " es " & salarioActualizado)
End Sub

Todo lo que necesita es algo que desencadene una accin.


Public Sub ContratarAFred()
EmpleadoMonitoreado = New Empleado
EmpleadoMonitoreado.Nombre = "Fred"
EmpleadoMonitoreado.Salario = 50000 ' Desencadena evento
End Sub

Cuando se establece el salario, la propiedad Salario de la clase Empleado dispara el evento Sa-
larioCambiado utilizando el comando de Visual Basic RaiseEvent. Esto genera una llamada
al manejador de eventos PagoEmpleadoCambiado, que por ltimo despliega el mensaje.
Los eventos construidos en las clases de Windows Forms en .NET trabajan as, pero en lugar de
buscar conmigo un aumento del salario, revisan los clics del ratn y los clacs del teclado. Todos
estos eventos del sistema usan una firma de argumento comn.
Event NombreEvento(ByVal sender As System.Object, _
ByVal e As System.EventArgs)

El argumento sender identifica la instancia del objeto que est disparando el evento, en caso de
que el llamador necesite un examen de sus miembros. El argumento e es un objeto que permite
al llamador enviar datos especficos del evento al manejador mediante una sola instancia de clase.
La clase System.EventArgs no se interpone mucho entre los miembros, pero muchos eventos
usan una clase sustituta que se deriva de System.EventArgs.
A medida que recorramos los captulos de este libro, no habr fin en el nmero de ejemplos de even-
tos que ver y experimentar. Guardar hasta entonces los ejemplos ms complejos e interesantes.

Espacios de nombres
Clases, estructuras, mdulos, enumeraciones, interfaces y delegados (los principales tipos de
.NET) no slo flotan en el cdigo de su aplicacin. Deben agruparse y administrarse en espacios
de nombres. Como se describi en el captulo 1, los espacios de nombres proporcionan una jerar-
qua a sus tipos, una especie de condominio en forma de rbol donde cada tipo tiene un hogar.
Algunos de estos hogares (o nodos), como System, estn habitados por todas esas familias de
tipos que viven all. Otros, como System.Timers, slo pueden tener unos cuantos tipos moran-
do en sus amplios aposentos. Pero cada tipo debe vivir en la jerarqua; ninguno de estos tipos es
lo suficientemente aventurero para independizarse y construir un rancho.
En la raz de la jerarqua se encuentra Global; no es un nodo, sino una palabra clave de Visual
Basic que indica la raz de todas las races. Puede incluir Global cuando haga referencia a sus
espacios de nombres, pero su uso slo es necesario cuando dejarlo fuera causara confusin entre
dos ramas de espacios de nombres.

66 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 66 17/2/10 15:19:23


Directamente bajo Global estn los pocos espacios de nombres de nivel superior, incluidos
System y Microsoft. Cada espacio de nombres de nivel superior contiene espacios de nombres
subordinados, y cada uno de ellos puede contener espacios de nombres adicionales de tercer
nivel, y as sucesivamente. Se hace referencia relativa a los nodos de espacio de nombres entre s
usando una notacin de puntos.
System.Windows.Forms

Esto especifica el espacio de nombres de tercer nivel Forms. Pudo tambin haber escrito:
Global.System.Windows.Forms

que significa lo mismo. Tambin se da soporte a espacios de nombres relativos:


Forms

Sin embargo, para usar espacios de nombres relativos, debe indicar a su cdigo de Visual Basic
que lo espere. Hay muchos espacios de nombres, y puede haber varios espacios de nombres
Forms en algn lugar de la jerarqua.

Referencia a espacios de nombres


Antes de que los espacios de nombres puedan usarse en su cdigo, debe hacerse referencia a ellos
y, como opcin, deben importarse. La referencia a un espacio de nombres identifica el archivo de
ensamblado DLL que contiene los tipos de ese espacio de nombres. Ambas acciones se realizan
en la ficha Referencias del formulario Propiedades de cada proyecto (vase la figura 2-3).

Figura 2-3. Referencias e importaciones para un proyecto.

Espacios de nombres | 67

02_PATRICK-CHAPTER_02.indd 67 17/2/10 15:19:23


En realidad, no est haciendo referencia a los espacios de nombres en la DLL, sino a los tipos,
que viven, todos ellos, en espacios de nombres especficos. Sin embargo, en el caso de las DLL de
tipos centrales proporcionadas con .NET Framework parece lo mismo. En realidad, Microsoft
incluso denomin a muchas DLL para que coincidieran con los espacios de nombres que con-
tienen. System.dll contiene tipos dentro del espacio de nombres System. System.Windows.Forms.
dll incluye tipos especficos de las aplicaciones de Windows Forms, y todos estos tipos aparecen
en el espacio de nombres System.Windows.Forms o uno de sus subordinados.
Si no hace referencia a una DLL en su proyecto, ninguno de sus tipos estar disponible en su
cdigo. Visual Studio carga automticamente varias referencias en su proyecto con base en el
tipo de proyecto que cree. En la figura 2-3 se muestran las nueve referencias predeterminadas
incluidas dentro de una aplicacin de Windows Forms: System, System.Core, System.
Data, System.Data.DataSetExtensions, System.Deployment, System.Drawing, Sys-
tem.Windows.Forms, System.Xml y System.Xml.Linq.
Una vez que haga referencia a una biblioteca de clases (u otros tipos) en su cdigo, se accede a
cualquiera de sus clases al especificar el espacio de nombres completo de esa clase. Por ejemplo,
se hace referencia a la clase de un formulario en pantalla como System.Windows.Forms.Form.
Esto se encuentra tres niveles abajo en la jerarqua, y algunas clases estn a mayor profundidad
an. Espero que su seguro mdico cubra el sndrome del tnel carpiano.
Para evitar la escritura de estos largos espacios de nombres una y otra vez, Visual Basic incluye
una caracterstica de importacin. Las importaciones son especficas del espacio de nombres; una
vez que se ha importado un espacio de nombres, puede acceder a cualquiera de sus tipos sin
especificar el nombre del espacio. Si importa el espacio de nombres System.Windows.Forms,
slo tiene que escribir Form para acceder a la clase Form. En la mitad inferior de la figura 2-3
se muestra cmo establecer estas importaciones mediante las propiedades del proyecto. La lista
Espacios de nombres importados muestra todos los espacios de nombres de referencia dispo-
nibles. Simplemente revise los que desea importar; System.Windows.Forms ya est marcado,
como opcin predeterminada, en las aplicaciones de Windows Forms.
Tambin puede importar directamente un espacio de nombres en su cdigo fuente. Use la ins-
truccin Imports al principio de un archivo de cdigo fuente:
Imports System.Windows.Forms

La instruccin Imports da soporte a abreviaturas de espacio de nombres, diminutivos que re-


presentan el espacio de nombres completo en su cdigo. El uso de la instruccin:
Imports Fred = System.Windows.Forms

le permite hacer referencia a la clase Form como Fred.Form. A diferencia de la lista de impor-
taciones en las propiedades del proyecto, que tiene impacto en todo el proyecto, la instruccin
Imports afecta slo a un archivo de cdigo fuente.

68 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 68 17/2/10 15:19:24


Espacios de nombres en su proyecto
Como opcin predeterminada, todas las clases y los tipos de su proyecto aparecen en el espacio
de nombres de nivel superior, que toma el nombre de su proyecto. En el caso de una aplicacin de
Windows Forms, este espacio de nombres predeterminado se denomina WindowsAplicacin1.
Para especificar un espacio de nombres superior diferente, modifquelo en la ficha Aplicacin
de las propiedades del proyecto, en el campo Espacio de nombres de la raz. Todos los tipos
de su proyecto aparecen en este espacio de nombres; si especifica uno existente proporcionado
por Microsoft como espacio de nombres raz de su proyecto, todos sus tipos aparecern en l
mezclados con los tipos preexistentes. En el caso de aplicaciones independientes, esta mezcla slo
estar visible para su cdigo.
A partir del espacio de nombres de la raz, puede colocar tipos dentro de espacios de nombres su-
bordinados empleando la instruccin Namespace. sta es una instruccin de bloque que termina
con la clusula End Namespace. Cualquier tipo que cree entre las clusulas Namespace y End
Namespace estar contenido en ese espacio de nombres subordinado. Por ejemplo, si su espacio de
nombres de la raz es WindowsAplicacin1, la siguiente instruccin crea una clase cuyo nombre
completo es WindowsAplicacin1.AreaTrabajo.CosasBasicas.MuchosDatos:
Namespace AreaTrabajo.CosasBasicas
Class MuchosDatos
...
End Class
End Namespace

Puede incluir todas las instrucciones de Namespace que necesite en su cdigo. Tambin se da
soporte a la anidacin de espacios de nombres:
Namespace AreaTrabajo
Namespace CosasBasicas
Class MuchosDatos
...
End Class
End Namespace
End Namespace

El espacio de nombres My
Visual Basic 2005 introdujo un nuevo espacio de nombres de nivel superior My, diseado para
simplificar tareas de programacin comunes. Microsoft lo agreg al lenguaje en parte para atraer
a los partidarios renuentes de Visual Basic 6.0 al entorno .NET. Pero no reviste mayor dificul-
tad. My recolecta caractersticas de uso comn que estn dispersas actualmente en la biblioteca
de clase de Framework (FCL, Framework Class Library) y las coloca en una minijerarqua para
acceso conveniente. En realidad no es mucho ms complicado que eso. La jerarqua est orga-
nizada adecuadamente, con secciones de informacin de usuario, aplicacin y especfica de la
computadora. Se usa como cualquier otra parte del marco conceptual, aunque no puede usar
la palabra clave Imports para acceder a sus componentes mediante una ruta relativa.

El espacio de nombres My | 69

02_PATRICK-CHAPTER_02.indd 69 17/2/10 15:19:24


En general, My es muy fcil de usar. Por ejemplo, para desplegar el nmero de versin de su
aplicacin use la siguiente instruccin:
MsgBox(My.Aplicacin.Info.Version.ToString)

Algunas reas del espacio de nombres My son dinmicas; se agregan o eliminan clases a medida
que modifica su cdigo fuente. En aplicaciones de Windows Forms, la rama My.Forms incluye
entradas para cada uno de los formularios del proyecto. A medida que agrega nuevos formula-
rios, se integran automticamente nuevas entradas. Entonces el objeto My.Forms hace referencia
a cada formulario disponible para uso en su cdigo.
My.Forms.Form1.Text = "Bienvenido"

Resumen
Es triste que este captulo haya llegado a su fin. Tal vez sienta que todo pas demasiado rpido;
tal vez sienta que en realidad no aprendi a escribir programas de Visual Basic; tal vez sienta
que un sedante suave sera muy adecuado ahora. Pero no se agobie. Este captulo sirvi como
introduccin a la sintaxis y las caractersticas principales de Visual Basic. Ahora empieza el en-
trenamiento a fondo. Mientras empezamos el eje principal del libro (el Proyecto Biblioteca),
encontrar ejemplos especficos de todas las caractersticas cubiertas slo de manera breve en
este captulo.

Proyecto
En este captulo usaremos la caracterstica de insercin de fragmentos de cdigo de Visual Studio
para insertar cdigo fuente en un marco bsico de cdigo de ejemplo. Los fragmentos de cdigo
son, en esencia, una base de datos jerrquica de texto de cdigo fuente guardado. Si ha instalado
el cdigo de este libro, encontrar code snippets de casi todos los captulos incluido ya en Visual
Studio. En el proyecto de este captulo le mostrar cmo usarlo para agregar cdigo especfico
del captulo en su proyecto.
Como no hemos iniciado oficialmente el Proyecto Biblioteca, el proyecto de este captulo sim-
plemente extender el proyecto Hola, mundo! que desarrollamos en el captulo 1, pero agre-
garemos un poco de diversin. Incluir algunas de las caractersticas del lenguaje que analizamos
en todo este captulo.

ACCESO AL PROYECTO
Cargue el proyecto de cdigo Chap02 (Antes), ya sea mediante las plantillas de Nuevo
proyecto o accediendo directamente al proyecto desde el directorio de instalacin. En
cambio, para ver el cdigo en su forma final cargue el cdigo Chap02 (Final).

El cdigo de ejemplo de cada captulo incluye una versin Antes y una Final. Esta ltima re-
presenta cmo se ver el cdigo cuando se han aplicado todos los cambios de la seccin Proyec-

70 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 70 17/2/10 15:19:24


to de ese captulo. La versin Antes no tiene incluidos ninguno de los cambios del proyecto
del captulo, slo marcadores de posicin donde insertar el cdigo, de bloque en bloque.
Como el proyecto del captulo 1, el de este captulo incluye un formulario bsico de Windows
con un solo botn. Al hacer clic en l se despliega el mismo mensaje Hola, mundo! Sin em-
bargo, esta vez el mensaje empieza en un formulario codificado, y una clase separada decodifica
el mensaje y dispara un evento que despliega el formulario.
Una vez que el proyecto est abierto, ver el cdigo fuente adjunto a Form1. Debe tener un
aspecto parecido al siguiente:
Public Class Form1
' *** Inserte aqu el fragmento de cdigo #2.

Private Sub Button1_Click(ByVal sender As System.Object, _


ByVal e As System.ArgumentosEvento) Handles Button1.Click
' *** Inserte aqu el fragmento de cdigo #3.
End Sub

' *** Inserte aqu el fragmento de cdigo #4.


End Class

' *** Inserte aqu el fragmento de cdigo #1.

En este ejemplo se usa una clase separada para procesar el mensaje desplegado. El cdigo para
esta clase aparece como fragmento nmero 1. Para insertar el fragmento, mueva el cursor justo
despus de la lnea marcadora del fragmento #1, que dice:
' *** Inserte aqu el fragmento de cdigo #1.

Para insertar un fragmento mediante mens de Visual Studio, seleccione Editar IntelliSense
Insertar fragmento de cdigo. La secuencia de teclado equivalente es Ctrl-K, Ctrl-X. O escriba un
signo de interrogacin (?) en cualquier lugar del cdigo fuente y despus oprima la tecla Tab. Cual-
quiera de estos mtodos despliega el primer nivel de fragmentos de cdigo (vase la figura 2-4).

Figura 2-4. Fragmentos, fragmentos, fragmentos.

Proyecto | 71

02_PATRICK-CHAPTER_02.indd 71 17/2/10 15:19:24


Figura 2-5. Elementos, elementos, elementos.

De la lista de fragmentos de cdigo, seleccione Programacin en Visual Basic 2008 y luego se-
leccione Cap02. Aparece una lista de elementos de fragmentos de cdigo disponibles para este
captulo (vase la figura 2-5).
Por ltimo, seleccione Elemento 1. Mgicamente aparece el contenido dentro del cdigo fuente.
Todas las inserciones de fragmentos de cdigo de este libro se presentan exactamente de esta
manera.
El fragmento de cdigo 1 inserta la clase DecirHola, parte del espacio de nombres CosasDeHo-
la, de la que aqu aparece una parte:
Namespace CosasDeHola
Friend Class DecirHola
Private mensajeSecreto As String
Private invertirMarca As booleano
Private decodificado As booleano

Public Event MensajeDecodificado( _


ByVal mensajeDecodificado As String)

Public Sub New(ByVal mensajeCodificado As String, _


ByVal invertirlo As booleano)
...

Public Sub DecodificarMensaje(ByVal factorGiro As Integer)


...

Public Sub ReportarMensaje( )


...
End Class
End Namespace

La clase DecirHola incluye tres campos privados (mensajeSecreto, invertirMarca y deco-


dificado), que monitorean el estado actual del mensaje que se muestra. Un constructor (New)
permite al usuario crear una nueva instancia de DecirHola con un texto de mensaje inicial, y
una marca que indica si el texto debe invertirse antes de desplegarlo. La subrutina MensajeCo-
dificado convierte cada letra del mensaje codificado a su forma final, al desplazar cada letra un
nmero factorGiro de lugares. Si aparece la letra E y factorGiro es 3, la letra E se desplaza
tres lugares hacia delante, a H. Un factor de rotacin negativo desplaza la letra hacia abajo en el

72 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 72 17/2/10 15:19:25


alfabeto. ste se amolda al lmite de A-Z. Slo se giran las letras, y las maysculas y minsculas
se mantienen de manera independiente.
El mtodo ReportarMensaje dispara el evento MensajeDecodificado, enviando el mensaje
previamente decodificado al evento, como argumento. Pero dnde est este manejador de even-
tos? Est adjunto a una instancia de DecirHola que se agregar a la clase Form1.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Elemento 2, Cap02.

Private WithEvent DecodificadorHola As CosasDeHola.DecirHola

La clase DecodificadorHola es una instancia de la clase CosasDeHola.DecirHola que aca-


bamos de escribir, y el fragmento de cdigo lo hace miembro de la clase Form1. La palabra clave
WithEvent dice: Esta instancia responder a eventos; de manera especfica, el evento Mensa-
jeDecodificado de la clase DecirHola.
Agreguemos el cdigo que dispara el mensaje que se mostrar cuando el usuario haga clic en el
botn del formulario. Esto ocurre en el evento clic del botn.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Elemento 3, Cap02.

DecodificadorHola = New CosasDeHola.DecirHola("!tiszr, fqtM", True)


DecodificadorHola.DecodificarMensaje (-5)
DecodificadorHola.ReportarMensaje( )

Estas tres lneas crean una instancia de la clase DecirHola, almacenndola en el campo de la cla-
se DecodificadorHola. No puede leer el primer argumento del constructor? Est codificado!
Es un secreto! Y la marca True indica que se ha invertido para que el secreto sea mayor (no sabe
lo que es!). DecodificarMensaje elimina el secreto al desplazar cada letra lo necesario, aunque
la inversin no se realiza hasta que se llama a ReportarMensaje.
El mtodo ReportarMensaje en realidad no despliega el mensaje. En cambio, dispara un even-
to que pone el mensaje no revuelto a disposicin de un manejador de eventos.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Elemento 4, Cap02.

Private Sub DecodificadorHola_MensajeDecodificado( _


ByVal mensajeDecodificado As String) _
Handles DecodificadorHola.MensajeDecodificado
' ----- Muestra el mensaje decodificado.
MsgBox(mensajeDecodificado)
End Sub

Proyecto | 73

02_PATRICK-CHAPTER_02.indd 73 17/2/10 15:19:25


La palabra clave Handles conecta la subrutina con el evento disparado. El mensaje decodificado
entra en el manejador mediante el argumento mensajeDecodificado, y es mostrado en toda la
pantalla con una simple pero poderosa llamada a la funcin MsgBox.
Esto es todo para el cdigo de ejemplo. Ahora es momento de arremangarse la camisa y embar-
carse en un proyecto completo de Visual Basic 2008.

74 | Captulo 2: Introduccin a Visual Basic

02_PATRICK-CHAPTER_02.indd 74 17/2/10 15:19:25


Captulo 3
Presentacin del proyecto

Est sentado en su oficina, surfeando quiero decir, leyendo sobre los recientes temas de la tec-
nologa que ms presionan a los desarrolladores de software. Est ocupado en sus propios asuntos,
cuando de pronto alguien llega hasta su escritorio y le ofrece pagarle por escribir un programa.
Sucede todos los das, en todas las corporaciones, y en ocasiones me hace sentir enfermo.
Pero basta de menciones a mis problemas de salud. Esta persona que est frente a usted le informa
que debe desarrollar una aplicacin de software, tal vez una aplicacin de base de datos con una
interfaz amigable para el usuario. Aunque el conjunto de caractersticas ser especificado por los
usuarios principales, usted, como programador lder (o nico), disear, documentar, desarrollar
y entregar discos que chorrearn software digital distintivo, sorprendente y dinmico. (Diantres!)
Bueno, eso es lo que me sucedi. Un cliente tena una gran coleccin de libros que necesitaba
organizar como una biblioteca tradicional. Al ver que era un arquitecto de software razonable-
mente codependiente, el cliente me pidi que desarrollara algn software para administrar los
libros y eso. De esta solicitud surgi el Proyecto Biblioteca.
A medida que lea este captulo, tendr que conservar mi trabajo diario en mente. Escribo aplica-
ciones personalizadas de Visual Basic para organizaciones pequeas y medianas. La mayor parte
de los proyectos tienen un tamao adecuado para poder completarlos solo, incluidas todas las
necesidades de diseo y documentacin, en menos de un ao. Todos mis proyectos incluyen un
usuario clave, una persona (o en ocasiones un grupo pequeo) que habla por la comunidad
de usuarios. Adems, estos proyectos incluyen a alguien que tiene autoridad para firmar, una
persona autorizada para pagar por el proyecto, o decidir sobre su existencia. Este individuo pue-
de ser el usuario clave.
Si usted estuviera desarrollando, digamos, un reemplazo para Microsoft Word, probablemente
carecera de un usuario clave. Para obtener los requisitos especficos del proyecto, tal vez tenga
que conducir entrevistas de usuario general con docenas de candidatos a usuarios. O podra crear
a una persona, un individuo ficticio que representa a su audiencia de destino. (Para Visual
Studio, Microsoft us tres personas, llamadas Einstein, Elvis y Mort.) Sin importar cul mtodo
aplique, el anlisis general debe guiarlo a la feliz conclusin: un documento de diseo que usar
para construir la aplicacin.

75

03_PATRICK-CHAPTER_03.indd 75 17/2/10 15:19:55


El Proyecto Biblioteca
Mi cliente necesitaba un programa que administrara una base de datos de libros y elementos de
medios, y controlar la manera en que estos elementos se movieron entre libreros y clientes. El
software necesitaba tener caractersticas concentradas en el cliente y el administrador. Incluira
varios informes, como la impresin de un recibo de artculos entregados por el cliente. Y, sobre
todo, necesitaba cdigos de barras de impresin y lectura.
Suena como si fuera demasiado para que lo hiciera un solo hombre, y es un proyecto de gran
tamao. Pero no tengo que hacerlo solo; usted me ayudar. Juntos, en las pginas de este libro,
usted y yo disearemos ese programa, desarrollaremos ese cdigo, llevaremos alegra a los usua-
rios y cobraremos ese cheque. En realidad, yo cobrar el cheque, aunque no le har dao pedirle
a su jefe que le pague por leer este fino libro.
En el resto de esta seccin se documentan las caractersticas clave de la aplicacin de adminis-
tracin de biblioteca.

Caractersticas del artculo Biblioteca


El sistema Biblioteca administrar un inventario de libros y otros artculos de medios, los loca-
lizar y administrar los detalles y el estatus de cada copia de un artculo. Para que esto se haga
realidad, el programa Biblioteca:
Permitir que los clientes o administradores busquen artculos que se encuentran en in-
ventario. El programa permite bsquedas basadas en varias propiedades diferentes de cada
artculo.
Dar soporte a varios mtodos de bsqueda, como por ttulo, por nombre de autor, por
tema, por alguna palabra clave, por el nombre del editor relacionado, por el nombre de una
serie o grupo que contiene el artculo, o por nmero de cdigo de barras adjunto al artculo
real.
Limitar los resultados de bsqueda por la ubicacin del artculo, o por el tipo de medio
(libro, CD, DVD, etctera).
Dar soporte a la definicin y el uso de ubicaciones fsicas distintivas. El cliente tiene libros
y medios almacenados en tres sitios diferentes dentro de su edificio, incluido un clset de
almacenamiento para artculos a los que apenas se tiene acceso.
Desplegar los detalles de un artculo recuperado en una interfaz familiar estilo explorador.
Por ejemplo, cuando busca un libro por ttulo, el usuario hace clic en el nombre del autor
para acceder a todos los dems artculos del mismo autor.
Permitir el acceso a cada artculo de la biblioteca mediante un escaneo de cdigo de barras.
Como es comn en casi todas las bibliotecas hoy en da, los artculos de la coleccin de esta
biblioteca tienen un cdigo de barras adjunto, que sirve como un identificador nico para
la copia del artculo individual.

76 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 76 17/2/10 15:19:55


Caractersticas del cliente
Adems de libros y otros artculos, el programa administra una lista de clientes, los clientes de
la biblioteca que tienen permitido retirar artculos. Para auxiliar a la interaccin con los clientes, la
aplicacin incluir estas caractersticas especficas de los clientes:
Los artculos podrn ser retirados por los clientes y regresados al inventario de la biblioteca.
Todos los clientes tendrn asignado un PIN que acta como su contrasea.
Los clientes podrn retirar artculos sin ayuda del bibliotecario y el administrador. Podrn
usar un escner de cdigo de barras para escanear una tarjeta de biblioteca del cliente y ar-
tculos de la biblioteca.
El tipo de medio de un artculo determinar la duracin de su salida (y su posterior reno-
vacin).
Los clientes podrn ver el registro de la biblioteca, incluidos todos los libros en prstamo, y
una lista de multas que se adeudan a la biblioteca.
Si est permitido para ese artculo especfico, el cliente podr renovar un artculo que retiene
en prstamo.
Habr ayuda en lnea disponible para el cliente mediante una tecla F1 estndar. Este archivo
de ayuda no incluye informacin sobre caractersticas administrativas, lo que se hace para
reducir la experimentacin.
Los clientes podrn dividirse en grupos de clientes para la conveniencia de creacin de
informes y procesamiento del personal administrativo.

Caractersticas administrativas
Los administradores son los bibliotecarios, el personal de tecnologa de la informacin y otros
usuarios que necesitan acceso avanzado a las caractersticas de la aplicacin. Son los princi-
pales usuarios del sistema, no los clientes. La aplicacin incluye las siguientes caractersticas
especficas del administrador:
Una caracterstica de inicio de sesin proporcionar acceso a las caractersticas administrati-
vas de la aplicacin. Slo usuarios autorizados podrn iniciar sesin mediante una contrasea
asignada. Por lo general, la caracterstica estar oculta de la vista de los clientes comunes.
Los administradores podrn ver detalles de los clientes, igual que stos, pero tambin ten-
drn acceso a detalles adicionales. De manera especfica, podrn agregar clientes y adminis-
trar su identidad y sus detalles demogrficos. Los administradores tambin podrn inhabi-
litar un registro de un cliente para evitar prstamos posteriores de artculos.
Los administradores cobrarn y administrarn las multas a los clientes, incluida la capacidad
de administrar archivos no estndar y omitir multas no pagadas.
Los administradores definirn los registros de cada artculo administrado en la base de datos
de inventario del sistema. Esto incluye los elementos bsicos de cada artculo, como ttulo

El Proyecto Biblioteca | 77

03_PATRICK-CHAPTER_03.indd 77 17/2/10 15:19:56


y autores. Cada artculo incluir una o ms copias, lo que representa artculos fsicos que
pueden prestarse. Las copias tienen asignados cdigos de barras.
Adems de los artculos y las copias, los administradores definirn todos los valores de apo-
yo y las listas, incluidos nombres de autores y categoras, lista de tipos de medios, editores,
nombres de las series de libros, cdigos de estatus que identifican la disposicin de la copia
de cada artculo y ubicaciones.
Los administradores designados podrn agregar, editar y eliminar las cuentas de otros admi-
nistradores. Cada cuenta incluir configuraciones especficas de la caracterstica (derechos
de grupo).
Adems de escanear los cdigos de barras, el programa podr ayudar a los administradores
a disear e imprimir los cdigos de barras del cliente y el artculo.
Un proceso simple de programa administrado permitir al personal administrativo procesar
artculos vencidos y multas de manera regular.
La aplicacin permitir que se aadan y mantengan das festivos. Cuando un cliente retire
un libro, el programa ajustar la fecha de vencimiento del archivo para evitar das festivos.
La ayuda en lnea centrada en el administrador proporcionar ayuda para las caractersticas
mejoradas de la aplicacin a travs de la misma tecla F1 disponible para los clientes.
La aplicacin incluir algunos informes administrativos bsicos y la capacidad de insertar
los informes necesarios en el futuro sin la necesidad de actualizar el propio programa.

La aplicacin como un todo


Ms all de las caractersticas bsicas del programa, como lo experimentan los clientes y admi-
nistradores, hay algunos requisitos adicionales:
El programa ser amigable con el usuario y fcil de navegar, sobre todo para los clientes,
sin mucha capacitacin o ayuda.
La aplicacin almacenar sus datos en una base de datos de SQL Server.
La distribucin de la aplicacin la har el personal administrativo que tiene privilegios
administrativos locales, de modo que bastar con el paquete de instalacin estndar de
Windows.
La configuracin de la aplicacin usar mtodos XML estndar.
Excepto por estos requisitos generales y especficos de la caracterstica, se me haba dado libertad
de diseo. Pero de dnde vena la lista de requisitos? De los usuarios, los amos de la aplicacin.
Eran sus necesidades (las necesidades de mis clientes y los suyos, quienes usaran el producto de
manera cotidiana) lo que determin la lista de requisitos.

78 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 78 17/2/10 15:19:56


Las necesidades de los usuarios
En pocas antiguas de la computacin no haba usuarios. Quin los necesitaba? Los nicos que
tenan permitido el ingreso al sagrado santuario interno de los sistemas de cmputo eran los
programadores. Slo ellos tocaban los bulbos, conectaban los cables y barajaban las tarjetas per-
foradas que proporcionaban acceso al corazn de la mquina. Estos programadores eran duros,
y sus programas, ms duros. No necesitamos usuarios era su mantra.
Luego lleg la dcada de 1980, con su actitud inspirada en el ms grande hroe estadounidense
y sus computadoras personales. Ahora haba usuarios por todas partes. Era como antes, slo
que con menos habilidades computacionales. Pero eran los amos porque la mayor parte de los
programas estaban escritos por ellos. Los programadores rara vez usaban los programas que
escriban, eran simplemente la interfaz entre el usuario y el corazn de la computadora. Los
programadores proporcionaban el elemento de control necesario para la computadora y para los
usuarios. En realidad, se es un trabajo del programador: proporcionar acceso altamente contro-
lado a la computadora y los datos que contiene.
Los usuarios tenan gran cantidad de necesidades y casi todas podan ser satisfechas por una
computadora. Y stas venan en cinco partes: datos e informacin, proceso, facilidad de uso,
uso comn y necesidades especficas del proyecto. El proceso de diseo inclua un examen de
esas necesidades y su posterior satisfaccin mediante un producto de software. Al examinar los
datos y procedimientos actuales, la conduccin de entrevistas con usuarios y la realizacin de
otros mtodos de extraccin de necesidades, se recopilaban los detalles que necesitaba para crear
la solucin correcta.

Datos e informacin
Su capacidad de proporcionar acceso conveniente y especfico a los datos y la informacin nece-
sarios para los usuarios es la que lo hace a usted, el programador, tan adorable. La mayora de los
usuarios estaban bien antes de las computadoras. Mantenan su informacin en tarjetas de ndice
de 3 5 pulgadas, en blocs o rollos de pergamino, o en tarros de mayonesa hermticamente
cerrados. Pero tenan una razn para moverse a medios de almacenamiento computarizados: la
conveniencia.
Los datos son informacin sin trabajo almacenada por su programa: nombres, nmeros, im-
genes o cualquier otro valor individual. La informacin son datos en un contexto: el registro de
un cliente, un pedido, una presentacin con diapositivas. Cuando proporciona un programa
de calidad que hace que los datos pasen al nivel de la informacin, est proporcionando el
nivel de conveniencia que el usuario necesita para pasar de los frascos de mayonesa a los chips
de silicio.

Las necesidades de los usuarios | 79

03_PATRICK-CHAPTER_03.indd 79 17/2/10 15:19:56


Proceso
Cuando el usuario exige que la computadora le regrese sus datos, tiene tres opciones:
Volcar cada byte de datos a la pantalla, la impresora o el disco y dejar que el usuario los
ordene. En realidad, ste es el sistema que algunos usuarios tenan antes de empezar a usar
una computadora.
Proteger los datos del acceso del usuario, insistiendo en que la contrasea proporcionada
no es vlida o que ha expirado, o que los datos no estn disponibles. Abortar, reintentar,
fallar? En realidad ste es el sistema que algunos otros usuarios tenan antes de que empe-
zaran a usar una computadora.
Presentar los datos como informacin, en un formato que sea til y accesible.
Aunque las dos primeras opciones son tentadoras, la tercera es la mejor. Y dada la cantidad de
datos que tal vez administrar su aplicacin, tendr que interactuar con ellos de vez en vez y en
una secuencia apropiada. Esto es el proceso.
Mediante la implementacin de un proceso vlido, se controlan no slo los datos del usuario,
sino tambin la interaccin ordenada con esos datos. La mayora de los usuarios slo necesitan
proporcionar o recuperar una pequea parte de esos datos a la vez. Pero cuando lo hacen, por lo
general estarn en el contexto de algn proceso. Por ejemplo, en una situacin de toma de pedi-
dos, el usuario: 1) ingresa o confirma la informacin de contacto del cliente; 2) ingresa o actualiza
los detalles del pedido; 3) imprime o comunica por medios electrnicos la informacin del pedido
para que pueda cumplirse. Su aplicacin (sorpresa!) administra este proceso de tres pasos.

Facilidad de uso
Si su programa presenta datos e informacin al usuario y en un orden o una organizacin es-
pecficos, pero es difcil de usar, sus usuarios lo odiarn. Lo abominarn. Esparcirn historias
horribles sobre usted, sean ciertas o no. Y cuando aparezcan en grupos, su vehemencia puede
volverse espantosa. He odo historias acerca de un grupo de usuarios de Excel pero tal vez slo
sea un rumor.
Como programador, su trabajo consiste en hacer que el uso de la computadora y el software
que se ejecuta en ella sea lo ms fcil posible. Y aunque tal vez no logre controlar muchas de las
caractersticas bsicas del sistema, usted es el rey cuando se trata de su propio software.
Cuanto ms fcil y til sea el diseo de sus programas, ms felices sern sus usuarios. Pero debo
prevenirlo: facilidad de uso para el usuario siempre significa ms trabajo para el desarrollador.
Siempre. Es una de esas injustas leyes del universo, y no hay manera de evitarla. Pero en ocasiones
lo intentamos, y ponemos al usuario en peligro.
Hace muchos, muchos aos, escrib algunos programas para demostrar la nueva versin de BA-
SIC que se ejecutaba en el procesador Motorola 6809. Esta versin poda manejar programas del
doble de tamao que la versin anterior: unos enormes 32 KB de cdigo fuente. Se me encarg
que probara el sistema, escribiendo programas grandes que demostraran la nueva funcionali-

80 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 80 17/2/10 15:19:56


dad. Me puse a trabajar en una actividad febril, pero a medida que mi programa se acerca a los
27 KB, empezaron a suceder cosas, cosas que movan la mesa y olan a humo. En serio!
Desde entonces, inconscientemente he temido el desarrollo de programas que considero que
son demasiado grandes para un sistema en particular. As, cuando empec a trabajar con Visual
Basic, llev a mis proyectos parte de mi aprehensin. Trat de hacer que mis programas fueran
fciles de usar, pero tambin me mantena reservado respecto del nmero de formularios que
poda agregar a mis proyectos. No era un miedo irracional; las versiones originales de Visual
Basic imponan lmites en el tamao del cdigo, el nmero de nombres de variables nicos y el
nmero mximo de formularios. Una vez llegu al lmite en el nmero de nombres de variable
nicos, pero nunca me acerqu al lmite en el nmero de formularios. Estaba seguro de que si
agregaba demasiado, mis usuarios requeriran atencin mdica por inhalacin de humo.
Por desgracia, mis usuarios an sufran. Tena que poner demasiados datos en cada formulario,
al punto en que ya no comunicaban informacin. Mi telfono sonaba constantemente con la
misma pregunta de parte del usuario: Cmo uso los campos en este y este formulario? Por
supuesto, siempre deca: Por qu no oprimes la tecla F1? Pero no haba una gran diferencia,
porque las pginas de mi ayuda en lnea eran tan largas y complejas como los formularios que
trataban de simplificar.
Lleg un da en que escap a mi fobia por las aplicaciones llenas de formularios. Y desde ese da
desarroll las siguientes reglas para mis propios programas:
No coloque demasiada informacin en un solo formulario. Cuando tenga dudas, pase algo
de esa informacin a otro formulario.
Presente slo la informacin y los datos ms necesarios para el usuario, como opcin prede-
terminada. Slo muestre informacin adicional si el usuario la solicita.
Facilite al usuario el acceso a los datos mejorados, pero permita que el programa se ejecute
de manera apropiada sin ellos.
Use texto, imgenes y colores para provecho del usuario.
Simplifique la aplicacin para que la documentacin para el usuario se vuelva innecesaria.
Siempre proporcione documentacin. Haga que sea lo bastante simple como para que las
llamadas a soporte tcnico se vuelvan innecesarias.
Estas reglas son lo suficientemente genricas como para que funcionen con cualquier tipo de
aplicacin, y bastante claras para hacer que tengan sentido para nosotros, los programadores, y
para ellos, los usuarios.

Uso comn
De manera constante, Microsoft presume de innovacin, y la capacidad de innovar ha hecho que
el software avance a un ritmo incomparable. Por desgracia, los usuarios slo pueden manejar
fragmentos de innovacin a la vez. Considere el telfono. Hered un viejo telfono en una caja
de roble de mis abuelos (vase la figura 3-1).

Las necesidades de los usuarios | 81

03_PATRICK-CHAPTER_03.indd 81 17/2/10 15:19:56


Figura 3-1. Qu gran telfono!

Es un telfono divertido y muy fcil de usar. Cuando alguien quiere hacer una llamada, levanta
el auricular y presiona la manija en el lado de la unidad por unos tres o cuatro segundos. Cuando el
operador toma la lnea, le dice a quin desea llamar. Qu podra ser ms simple? Qu podra
ser ms amigable con el usuario? Qu podra ser ms caro que una llamada con la ayuda del
operador? Pero era simple, y todos saban de manera instintiva cmo usarlo.
Los telfonos de hoy en da usan botones en lugar de manijas. Casi todos los botones son sim-
ples dgitos que permiten marcar directamente un nmero de telfono. Pero tambin hay otros
botones: Mute, Redial, Pause, Flash, # y *. Me da miedo oprimir el botn Flash, y qu hacen
los botones SND y CLR en los telfonos celulares? El problema no es con los propios botones,
sino que cada telfono tiene una seleccin diferente de botones. Han perdido la capacidad de uso
comn que haca que los telfonos de manija fueran fciles de usar. Seguro que tienen muchas
caractersticas ms, pero si la persona promedio no puede imaginar cmo se usa esa funcionali-
dad, cul es el beneficio?
De regreso al software: aun los programas nuevos e innovadores deben retener algunas funciones
de uso comn en el sistema operativo y con otros programas instalados. Mientras habla con los
usuarios acerca de sus necesidades y piensa en los grandes avances de la tecnologa del software
que les proporcionar, no olvide la capacidad de uso comn. No se olvide de una de las necesida-
des centrales de los usuarios: no ser sobrecargados por nuevas maneras de hacer tareas que creen
que ya pueden hacer. Los usuarios necesitan consistencia.

82 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 82 17/2/10 15:19:56


Necesidades especficas del proyecto
Ms all de las necesidades generales del usuario indispensables para todos los proyectos, hay
necesidades especficas de cada proyecto. Como diseador de una aplicacin o arquitecto de
software, aqu es donde dedica la mayor parte de su tiempo. Si tiene mucha experiencia en pro-
gramacin, podr satisfacer las necesidades de los dems sin siquiera conocer al usuario. Pero en
cuanto a las necesidades especficas del proyecto, requiere una comprensin de las tareas que el
usuario necesita realizar con la aplicacin propuesta.
Una vez que los usuarios descubren que tiene un inters real en sus necesidades, pueden abrumar-
se. Podran iniciar una lista de deseos de caractersticas, que exceden a las que realmente podran
usar. Eso est bien. Cuando escuchan cunto tiempo tomar y cunto costar implementarlo,
regresarn a unas cuantas peticiones. Lo importante es documentar todo. Anotar lo que el usuario
pide, combinarlo con un calendario razonable (siempre) y estimados de costos (si se necesitan),
y regresarlo al usuario clave para confirmacin. Si es posible, haga que el usuario firme un docu-
mento que diga que est de acuerdo con los requisitos especficos incluidos en el documento.
Es esencial que se est de acuerdo con el diseo del proyecto, por lo menos en la fase inicial o en el
lanzamiento. Debido a que las necesidades de los usuarios suelen ser variables, es vital que exista
un acuerdo sobre el proyecto en algn momento. Ms adelante, despus de que haya empezado
a trabajar en el proyecto, el usuario vendr con usted, tal vez a diario, y dir: Hey!, eso no es
lo que ped. Cuando suceda eso, seale el acuerdo y diga: Hey!, s lo es. Ocurrirn cambios;
analizar la manera de manejar stos un poco ms adelante, en este mismo captulo.

La vida de un proyecto
Los proyectos tienen un tiempo de vida propio. Algunos son de corta duracin; he escrito pro-
gramas que se usaron durante dos semanas y luego se descartaron cuando se complet el proyec-
to del negocio. Algunos programas duran para siempre, con mejoras continuas hechas sobre una
serie de iteraciones a la versin. Estoy escribiendo ahora mismo uno de esos programas.
Como desarrollador, debe estar al tanto del tiempo de vida de su proyecto. Una vez que com-
prenda ste, puede aplicar procesos de negocios a cada fase importante de la vida del proyecto.
A las habilidades necesarias para guiar un proyecto a su conclusin o a travs de cada versin
sucesiva del proyecto se les denomina de manera colectiva administracin del proyecto. Muchas
organizaciones tienen administradores de proyecto dedicados, sobre todo en el caso de proyectos
ms grandes. Si son pequeos, el programador puede bastarse para soportar la carga de la admi-
nistracin del proyecto.
Por fortuna, la mayora de los administradores de proyectos no slo hacen que las cosas avancen
(aunque me he encontrado con algunos que es lo nico que hacen). Trabajan dentro de un sistema,
un marco conceptual de la metodologa del proyecto, un sistema de administracin que mantiene el
plan del proyecto dentro de sus lmites. En el resto de este captulo tratar los puntos ms importan-

La vida de un proyecto | 83

03_PATRICK-CHAPTER_03.indd 83 17/2/10 15:19:56


Inicio/final Inicio Final

Logros
importantes
Logro
importante
Logro
importante

Figura 3-2. Dos mtodos bsicos para la administracin del proyecto.

tes de un marco conceptual tpico. Si regresa a la librera donde recibi un descuento por comprar
este libro, encontrar un estante lleno de recursos relacionados con marcos conceptuales de la meto-
dologa del proyecto. Aun Microsoft tiene sus propias recomendaciones, llamadas marco conceptual
de soluciones de Microsoft (MSF, Microsoft Solutions Framework). Debido a que casi todos los pro-
yectos que Microsoft desarrolla cambian de nombre a travs de sucesivas versiones, el MSF es cclico
o iterativo. En el caso de aplicaciones que, por lo menos ahora, slo tendrn una versin importante,
un mtodo lineal funcionar bien. (Vase la figura 3-2 para conocer ambos mtodos.)
Como este libro terminar con un proyecto completo y como mi editor no ha llegado a acuerdos
sobre los derechos de la siguiente edicin ni de la pelcula, usar el mtodo lineal. Sin importar
el mtodo que use, varios eventos importantes se presentarn entre el inicio y el final de la lnea
o iteracin, empezando con la patada inicial del proyecto.

Patada inicial del proyecto


Una vez que todos estn de acuerdo en que debe haber un proyecto, se renen en una gran junta
para empezar las cosas. Todos los que estarn a cargo de cualquier parte del proyecto se encuen-
tran all: el lder tcnico (usted), el usuario clave, el administrador del proyecto y la persona con
autoridad para firmar. Si est escribiendo un programa solo, no habr nadie ms que usted en la
sala, pero aun as puede llevar galletas. Este evento, la patada inicial del proyecto, marca el inicio
oficial del proyecto. Esta reunin de mentes suele determinar el calendario inicial para recopila-
cin de informacin y recursos.

Documentacin
Es importante documentar todo, mientras avanza por el proyecto, sobre todo en las primeras
etapas de diseo. Esto le ayudar no slo a recordar aspectos esenciales del proyecto ms adelan-
te, durante la fase de desarrollo, sino tambin a mantener informadas sobre el estado del proyec-
to a todas las partes que participan en l. Imagine esta conversacin con su jefe:

84 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 84 17/2/10 15:19:57


Jefe: La administracin me est preguntando sobre el estado del Proyecto Avellana. Tie-
ne algo actualizado que pueda informarles?
Usted: Seguro, justo aqu tengo el plan del proyecto. Le imprimir una copia.
Jefe: Estupendo. Hey!, has visto el nuevo coche que se compr Bernie el contador?
Usted: Lo saba! Cmo puede un contador comprarse un coche como se?
Jefe: Me ganaste. No me sorprendera que est cocinando los libros o algo.
Usted: Hey!, no estbamos hablando de documentacin?
Oh, s, documentacin! La documentacin apropiada y completa es importante en cualquier
proyecto. La documentacin precisa evitar que Bernie, el contador, se haga de una gran casa. Y
lo mantendr a usted dentro del proyecto desde la patada inicial hasta la entrega final.
Dependiendo del alcance del proyecto y los requisitos de su organizacin, tal vez su proyecto
necesite alguna documentacin bsica, o varias carpetas de tres pulgadas de ancho llenas con
documentos de diseo que examinan cada rincn y grieta del sistema. Algunos documentos de
administracin del proyecto requieren una firma antes de que el proyecto pueda seguir adelante.
Otros son slo para informacin. Como programador, los dos documentos ms importantes
son el documento principal de diseo del proyecto (a partir del cual construir la aplicacin) y el
calendario (que le permite medir el avance durante el proyecto).

Objetivos del proyecto


El primer elemento importante que documentar es el conjunto de objetivos del proyecto. Si un
proyecto (o una iteracin) tiene un final definido, debe ser posible identificar los logros ms im-
portantes necesarios para ese evento final. Estos objetivos deben ser amplios y relacionarse con
los elementos que se entregarn con el proyecto final. stos son los elementos que se producirn
como resultado de un proyecto. Por lo general, incluyen software, documentacin tcnica y para
el usuario, medios de instalacin y materiales relacionados. Tambin pueden incluir elementos
de administracin contractuales y del proyecto, como un calendario propuesto para la siguiente
fase o iteracin del proyecto.
Los objetivos del proyecto ayudan a determinar su alcance, la extensin de las caractersticas y los
materiales de apoyo que se producirn durante la vida del proyecto. La determinacin del alcance
es importante porque establece las restricciones, los lmites que evitarn que el proyecto se salga de
control. Aunque algunos aspectos del proyecto pueden cambiar durante este periodo, si permite
que un proyecto siga sin restricciones, terminar con algo como Windows Vista: un producto til que
sali un ao despus y que tena caractersticas demoradas hasta despus del lanzamiento.

Diseo y planeacin
Mi madre me dio hace poco un pedazo viejo de papel con el dibujo de los planos de una casa.
Cuando examin ese papel con ms detalle, encontr que el diseo coincida con la casa en que
crec, una casa que ya no es parte, por fortuna, de los bienes races de la vasta familia Patrick.

La vida de un proyecto | 85

03_PATRICK-CHAPTER_03.indd 85 17/2/10 15:19:57


Pero an es parte de las clulas de memoria de la vasta familia Patrick, y el hogar que recuerdo
de mi infancia era notablemente similar a ese simple dibujo. Algn constructor olvidado fue
capaz de llevar ese borrador, agregar madera, ventanas y puertas, y carpetas rojas rasgadas y un
refrigerador de color verde aguacate, y convertirlo en una casa.
Los constructores de casas no trabajan con borradores. Entre el borrador y el constructor est
un arquitecto, un diseador que pone en papel cada detalle preciso de la manera de construir la
casa. Un arquitecto proporciona gran cantidad de detalles, aunque no todos. El constructor an
tiene la eleccin de los materiales bsicos y la metodologa de construccin. Pero sin el plan del
proyecto (los planos) el constructor slo estara martillando tableros al azar y aadiendo carpetas
rojas donde no van.
Durante la fase de diseo, usted juega el papel del arquitecto, llevando los sueos y deseos del
usuario a un diseo que puede convertirse en una creacin de software. El nivel de detalle reque-
rido en estas especificaciones variar dependiendo del proyecto y la organizacin. Para el Proyecto
Biblioteca, los elementos incluidos en las listas con vietas, al inicio del captulo, comprenden el
grueso del detalle del diseo. (Reproducen el nivel de detalle con el que mis clientes han estado
de acuerdo en proyectos similares.) Otras organizaciones requieren detalles extenuantes, exigen
grficas de flujo y especificaciones funcionales, diagramas y seudocdigo que sea tan detallado
como el cdigo fuente final. En el caso de proyectos que incluyen a varios programadores, pro-
bablemente tendr que especificar las interfaces, los detalles de miembros de funcin o clase
que permiten que el cdigo escrito por dos programadores distintos se comunique de manera
adecuada.
Sin importar el nivel de detalle que incluya en su plan, tambin documentar ciertos eventos
clave que sucedern en el calendario de todo el proyecto. Estos puntos de referencia identifican
entregas intermedias de elementos, resultados esperados en momentos especficos de la cro-
nologa del proyecto. La comparacin del calendario de referencia contra los resultados reales
producidos durante el desarrollo proporciona una vista general de la manera en que el proyecto
est avanzando con el tiempo. Si se dejan de cumplir varias fechas lmite de referencia, tal vez sea
necesario ajustar el calendario, el costo y el alcance del proyecto.

Aprobacin del proyecto


Un documento de diseo da al programador y al usuario un punto de acuerdo. Ambos pueden
ver el diseo y decir: S, est bien; es lo que se plane. Si el programa completado es diferente
del diseo propuesto, el usuario puede decir: Hey, eso no es lo que acordamos. En ocasiones
sucede lo opuesto; el programador desarrolla la aplicacin de acuerdo con el plan, pero el usuario
asegura que solicit algo diferente. Cuando sucede esto, el programador puede sealar el diseo
y decir cortsmente: Esto es lo que acordamos y esto es lo que se construy.

86 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 86 17/2/10 15:19:57


Para proporcionar estabilidad adicional, el diseo completado suele incluir un documento de
aprobacin del proyecto. Este papel, firmado por el representante del usuario y el del desarrollo,
dice que: 1) ambas partes han ledo el documento de diseo; 2) estn de acuerdo en lo que dice,
y 3) se comprometen a ver el proyecto hasta su trmino, tal como se dise. Como cada repre-
sentante firma el documento, se comprometen a dar su apoyo al proyecto.
El proceso de aprobacin tambin cubre el costo y el calendario del proyecto. Para el propio diseo
del proyecto es importante un estimado realista del tiempo y los costos totales necesarios para
completar el proyecto. Cualquier ajuste en tiempo y costo en el tiempo de vida del proyecto
tambin puede proporcionar retroalimentacin valiosa sobre los avances hechos.

Software y otro desarrollo


El desarrollo del software suele consumir la mayor parte del tiempo de vida del proyecto. Aun-
que casi todo el trabajo lo hace el programador o el equipo de programacin, el usuario a menu-
do interviene en este paso. Al revisar los prototipos de partes especficas de la aplicacin y probar
las versiones beta del producto casi terminado, el usuario sigue siendo un participante activo en
esta larga fase del proyecto.

Cambios al proyecto
En general, los desarrolladores siempre completan a tiempo los proyectos, bajo el presupuesto
y con todas las caractersticas incluidas, y el usuario satisfecho instala gozosamente el software,
emplendolo a diario para cumplir con los exigentes retos del trabajo.
Ja, ja. Ahora que se ha redo con ganas, sigamos con el captulo. Muchos proyectos avanzan bien
y suelen apegarse al plan acordado por el usuario y el desarrollador. Pero otros no. En algn lugar
intermedio de la vida del proyecto ocurre un cambio. Tal vez se deba a dificultades para construir
el proyecto, lo que lleva a un cambio en el calendario. Tal vez se deba a nuevos requisitos en las
necesidades (o los deseos) del usuario en el proceso relacionado del negocio, lo que lleva a un
cambio en el alcance.
Tal vez se hagan cambios menores al proyecto que no preocupen demasiado al usuario ni al
programador. Pero otros cambios pueden tener un impacto significativo en el costo, el calen-
dario, o ambos. Estos cambios pueden documentarse y acordarse entre ambas partes mediante
un documento de cambio del alcance, al que en ocasiones se le denomina orden de cambio. Si el
equipo de desarrollo debe ajustar el calendario, o reducir o cambiar las caractersticas incluidas
de la aplicacin, la comunicacin de esto al usuario mediante documentos de cambio evita que
el usuario se vea sorprendido al esperado final del proyecto.

La vida de un proyecto | 87

03_PATRICK-CHAPTER_03.indd 87 17/2/10 15:19:57


Mediante el uso de documentos de cambio del alcance y la solicitud de firmas de ambas par-
tes, tambin se ayuda a evitar la deformacin del alcance, el ajuste o la expansin continuos de
las caractersticas del software incluido en el producto final. A medida que los usuarios ven
el avance que est haciendo en el proyecto y el estupendo trabajo que realiza, muestran su
confianza en usted al hacer adiciones al proyecto, asegurndose de completar el trabajo adi-
cional dentro del cronograma original. El hecho de canalizar todas las solicitudes de cambio
mediante el proceso de cambio de alcance proporciona una revisin de la realidad al usuario,
dndole la sensacin de esfuerzo (en trminos de costo y calendario), necesaria para desarrollar
software.

Prueba de los criterios de aceptacin


Llegar el da en que dir: Ya est, es la ltima lnea del cdigo que necesito escribir para este
proyecto. Por supuesto, estar equivocado, pero se sentir bien al decirlo. El ltimo da real
de codificacin no se presentar hasta varias semanas despus de que se hayan hecho todas las
pruebas.
La prueba de unidad se concentra en los componentes individuales, aun en los niveles de clases
y mtodos. Asegura que cada componente o bloque de cdigo devuelva los resultados esperados
cuando se da una entrada especfica. Se envan entradas buenas y malas a los componentes y se
analizan los resultados. La prueba de unidad es en realidad la forma de prueba ms costeable,
porque no se preocupa de las interacciones complejas entre los diversos componentes que inte-
gran todo el sistema.
La prueba de interfaz se preocupa de esas interacciones. Los componentes que interactan entre
s se prueban como grupo, para asegurarse de que funcionan y de que lo hacen bien juntos.
Los componentes que exponen interfaces pblicas tambin se pueban en busca de resultados
consistentes y de acceso seguro. La prueba del sistema da a los usuarios una oportunidad de in-
teractuar con el producto, haciendo lo posible para certificar que toda la aplicacin funciona en
un entorno real. La prueba beta es parte del proceso de prueba del sistema. La prueba del sistema
tambin puede incluir una prueba de estrs, donde el sistema se prueba en condiciones extremas
de cmputo para ver si puede soportar la carga. La prueba de varios escenarios de instalacin ase-
gura que el nuevo software no tiene un impacto negativo en otros componentes de software o el
sistema operativo. Las pruebas de regresin son una especie de doble prueba. Incluyen una nueva
prueba de cdigo previamente estable para determinar si se han introducido errores directos o
indirectos debido a cambios de codificacin posteriores.
Todas estas fases de prueba son importantes, pero hay un tipo ms de prueba que tiene impacto
directo en el avance del proyecto: la prueba de criterios de aceptacin. sta incluye una lista de
verificacin de elementos que se pueden probar y con los que el usuario y el programador estn
de acuerdo en que se deben pasar con xito antes de que el proyecto se considere completado.
Esta fase puede cubrir elementos encontrados en las dems fases de prueba, pero tambin po-

88 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 88 17/2/10 15:19:57


dran verificarse elementos y caractersticas bsicos, como la inclusin de documentacin de
calidad, o la entrega del software en ciertos medios, como un CD-ROM. Una vez que se haya
completado la prueba de criterios de aceptacin, el usuario firma esa fase y el proyecto pasa a la
aceptacin final.

Aceptacin del proyecto


Ha trabajado mucho y muy duro. Han sido horas difciles y tal vez ni siquiera estaba seguro
de que terminara algn da. Y slo estoy hablando de este captulo. Algunos proyectos toman
demasiado tiempo para completarse y al final todos deben estar listos para ver los frutos de su
trabajo. El paso final en la parte del acuerdo del proyecto es el documento de aceptacin del pro-
yecto. Este papel, firmado por el usuario, seala que el proyecto se complet tal como se pidi
(o de acuerdo con las modificaciones incluidas en las rdenes de cambio). Una vez que se firma
este documento, el proyecto est oficialmente completo. Se paga ahora amablemente al progra-
mador, quien se toma tres das merecidos de descanso.

Implementacin y distribucin
Ahora el proyecto est listo para su instalacin en la estacin de trabajo de cada usuario. El
mtodo de distribucin y entrega depende del proyecto y la audiencia de destino. Trtese de
una distribucin en la red interna, la distribucin en CD a un nmero pequeo de lugares, la
distribucin en Web al pblico en general, o el empaquetado del producto para venta en tiendas,
el equipo de programacin por lo general est limitado a la interaccin con las estaciones de
trabajo de destino. Por supuesto, esto puede cambiar rpidamente una vez que la lnea telefnica
de soporte tcnico entre en funcionamiento.

Soporte continuo
Despus de que la poblacin de usuarios ha usado el producto durante un tiempo, los informes
de errores en la aplicacin o de mejoras deseadas pueden inundar al equipo de desarrollo. stos
pueden reunirse para tomarse en cuenta en versiones futuras, o atenderse de inmediato en actua-
lizaciones de versin de servicio del producto. Como podra tener varias versiones del producto
en uso dentro de su comunidad de usuarios, es esencial que identifique y pruebe contra cual-
quier versin en particular. Los sistemas de control de cdigo fuente (incluido Microsoft Visual
SourceSafe, que se incluye en algunas ediciones de Visual Studio y Team Foundation Server) le
permiten mantener imgenes especficas de la versin en el cdigo fuente. Tambin puede man-
tener un archivo de ejecutables de versin y otros archivos para prueba posterior.
Si su aplicacin se escribi para un solo cliente o una organizacin, puede haber un periodo de
garanta en que se corregirn de manera gratuita algunos o todos los errores reportados durante
la vigencia de esa garanta.

La vida de un proyecto | 89

03_PATRICK-CHAPTER_03.indd 89 17/2/10 15:19:57


Resumen
Los proyectos son ms que slo cdigo fuente. Desde los documentos de diseo hasta las herra-
mientas de administracin de proyecto, la integracin de la ayuda en lnea o la funcionalidad
de soporte en Web, un proyecto abarca recursos que van ms all de la tarea bsica de codificar.
Si usted es un desarrollador solitario, tendr que ponerse varios sombreros para dar soporte
completo a la aplicacin. Quienes son parte de un equipo de producto ms grande no tienen de
qu preocuparse por todos los componentes posibles del proyecto, pero se perdern parte de la
alegra de trabajar en todos los aspectos de un proyecto.

Proyecto
Es necesario completar muchas tareas antes de que empiece la codificacin en un proyecto
grande. La codificacin real del Proyecto Biblioteca empezar en el captulo 5. En este captulo
completaremos el documento de acuerdo del proyecto que describe las caractersticas del Pro-
yecto Biblioteca.
En este captulo no se incluye una plantilla de proyecto de Visual Studio que pueda cargar y
examinar en Visual Studio. En cambio, debe acceder al subdirectorio del captulo 3 del directorio
de instalacin del libro. Contiene tres archivos:
Acuerdo de proyecto.doc
Es el documento principal del proyecto que identifica las caractersticas del proyecto com-
pletado. Es un acuerdo entre los representantes del desarrollador y el usuario. Las desviacio-
nes a este documento slo ocurren a travs del proceso de Orden de cambio.
Orden de cambio.doc
Es un archivo empleado para modificar el proyecto original mediante el proceso de Orden
de cambio. Cuando se usa este documento, se incluye una descripcin del cambio que se
har al proyecto, y cualquier impacto en el calendario y el costo.
Aceptacin del proyecto.doc
Este archivo se usa cuando se completa el proyecto, y el usuario est listo para aceptar el
producto terminado. Este documento combina los elementos de la Prueba de criterios de
aceptacin y Aceptacin del proyecto descritos en pginas anteriores del captulo.
Por favor, sintase con la libertad de usar estos documentos para apoyar sus propios proyectos.
Sin embargo, al equipo legal de OReilly Media le gustara recordarle que si decide usarlos, lo
debe hacer por su propia cuenta y riesgo. Estos documentos slo tienen el objetivo de servir
como ejemplos. Debe hablar con un abogado de su localidad si desea crear documentos similares
y hacer que representen responsabilidades contractuales.
En el resto de esta seccin se presenta el Acuerdo de proyecto.doc llenado con los detalles del
Proyecto Biblioteca. Su contenido principal es una copia de los elementos incluidos en la lista
con vietas de la seccin 3.1, casi al principio del captulo. Tambin documenta algunos otros
requisitos especficos del proyecto e incluye un estimado clsico de costos del proyecto. Para fines
de demostracin, use una tasa por hora de 25.00 dlares.

90 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 90 17/2/10 15:19:57


Acuerdo de proyecto
Nombre del proyecto: Biblioteca
Usuario: La Biblioteca ACME
Fecha: 27 de febrero de 2010
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Este acuerdo de proyecto define un proyecto que habr de realizar el desarrollador para el
usuario. Al firmar este acuerdo, el representante del usuario reconoce que ha ledo el acuerdo y
acepta los trminos identificados en este documento. Los trminos de este acuerdo, o los ser-
vicios proporcionados, pueden modificarse ms adelante mediante un documento de Orden
de cambio.

Representante autorizado del usuario Fecha

Representante autorizado del usuario Fecha


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Objetivo del proyecto


La compaa ACME alberga una pequea biblioteca para sus empleados, que contiene docu-
mentacin especfica del negocio. El objetivo de este proyecto es desarrollar un sistema de bi-
blioteca que lleve registro del inventario de libros y otros artculos disponibles en la biblioteca.
Los clientes (empleados) pueden pedir prestados artculos de la biblioteca. Los bibliotecarios
(administradores) tienen acceso a caractersticas adicionales de la aplicacin, incluida la capa-
cidad de administrar inventarios y multas a clientes.

Elementos que se entregarn y criterios de aceptacin


Tras completar las tareas del proyecto definidas en este acuerdo, el desarrollador proporcionar
los siguientes elementos al usuario. Tambin se incluyen en la lista los criterios de prueba que
deben cumplirse para la adecuada aceptacin del proyecto por parte del usuario.

Pgina 1

Acuerdo de proyecto | 91

03_PATRICK-CHAPTER_03.indd 91 17/2/10 15:19:58


La aplicacin Biblioteca. Esta aplicacin de Visual Basic 2008 se instalar en cada estacin
de trabajo dentro de la biblioteca, e incluir caractersticas administrativas y para el cliente.
La base de datos Biblioteca. Esta base de datos, almacenada en SQL Server 2005, adminis-
trar todo el inventario, los clientes y los datos de transacciones realizadas por la biblioteca.
Documentacin. El desarrollador proporcionar documentacin para el usuario (ayuda en
lnea, distinta para clientes y administradores) y documentacin tcnica (relacionada sobre
todo con la base de datos).
Imagen de instalacin. El desarrollador proporcionar toda la documentacin de secuen-
cias de comandos y de soporte necesaria para la instalacin de la base de datos. Para la parte
del cliente, el desarrollador proporcionar un paquete de instalacin estndar de Windows
para que se ejecute en cada estacin de trabajo. El departamento de tecnologa de la infor-
macin de ACME instalar este producto desde una unidad de red compartida o un CD.
Capacitacin para el usuario. El desarrollador proporcionar hasta cinco horas de capaci-
tacin para el administrador y el bibliotecario.

Tareas del proyecto


El desarrollador realizar las siguientes tareas para el usuario.

Caractersticas del artculo Biblioteca


Permitir que los clientes o administradores busquen artculos que se encuentran en in-
ventario. El programa permite bsquedas basadas en varias propiedades diferentes de cada
artculo.
Dar soporte a varios mtodos de bsqueda, como por ttulo, por nombre de autor, por tema,
por alguna palabra clave, por el nombre del editor relacionado, por el nombre de una serie o
grupo que contiene el artculo, o por nmero de cdigo de barras adjunto al artculo real.
Limitar los resultados de bsqueda por la ubicacin del artculo, o por el tipo de medio
(libro, CD, DVD, etctera).
Dar soporte a la definicin y el uso de ubicaciones fsicas distintivas. El cliente tiene libros
y medios almacenados en tres sitios diferentes dentro de su edificio, incluido un clset de
almacenamiento para artculos a los que apenas se tiene acceso.
Desplegar los detalles de un artculo recuperado en una interfaz familiar estilo explorador.
Por ejemplo, cuando busca un libro por ttulo, el usuario hace clic en el nombre del autor
para acceder a todos los dems artculos del mismo autor.
Permitir el acceso a cada artculo de la biblioteca mediante un escaneo de cdigo de barras.
Como es comn en casi todas las bibliotecas hoy en da, los artculos de la coleccin de esta
biblioteca tienen un cdigo de barras adjunto, que sirve como identificador nico para la
copia del artculo individual.
Pgina 2

92 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 92 17/2/10 15:19:58


Caractersticas del cliente
Los artculos podrn ser retirados por los clientes y regresados al inventario de la biblioteca.
Todos los clientes tendrn asignado un PIN que acta como su contrasea.
Los clientes podrn retirar artculos sin ayuda del bibliotecario y el administrador. Podrn
usar un escner de cdigo de barras para escanear una tarjeta de biblioteca del cliente y
artculos de la biblioteca.
El tipo de medio de un artculo determinar la duracin de su salida (y su posterior reno-
vacin).
Los clientes podrn ver el registro de la biblioteca, incluidos todos los libros en prstamo, y
una lista de multas que se adeudan a la biblioteca.
Si est permitido para ese artculo especfico, el cliente podr renovar un artculo que retie-
ne en prstamo.
Habr ayuda en lnea disponible para el cliente mediante una tecla F1 estndar. Este ar-
chivo de ayuda no incluye informacin sobre caractersticas administrativas, lo que se hace
para reducir la experimentacin.
Los clientes podrn dividirse en grupos de clientes para la conveniencia de creacin de
informes y procesamiento del personal administrativo.

Caractersticas administrativas
Una caracterstica de inicio de sesin proporcionar acceso a las caractersticas administrati-
vas de la aplicacin. Slo usuarios autorizados podrn iniciar sesin mediante una contrasea
asignada. Por lo general, la caracterstica estar oculta de la vista de los clientes comunes.
Los administradores podrn ver detalles de los clientes, igual que stos, pero tambin ten-
drn acceso a detalles adicionales. De manera especfica, podrn agregar clientes y adminis-
trar su identidad y sus detalles demogrficos. Los administradores tambin podrn inhabi-
litar un registro de un cliente para evitar prstamos posteriores de artculos.
Los administradores cobrarn y administrarn las multas a los clientes, incluida la capaci-
dad de administrar archivos no estndar y omitir multas no pagadas.
Los administradores definirn los registros de cada artculo administrado en la base de datos
de inventario del sistema. Esto incluye los elementos bsicos de cada artculo, como ttulo
y autores. Cada artculo incluir una o ms copias, lo que representa artculos fsicos que
pueden prestarse. Las copias tienen asignados cdigos de barras.
Adems de los artculos y las copias, los administradores definirn todos los valores de apo-
yo y las listas, incluidos nombres de autores y categoras, lista de tipos de medios, editores,
nombres de las series de libros, cdigos de estatus que identifican la disposicin de la copia
de cada artculo y ubicaciones.
Pgina 3

Acuerdo de proyecto | 93

03_PATRICK-CHAPTER_03.indd 93 17/2/10 15:19:58


Los administradores designados podrn agregar, editar y eliminar las cuentas de otros admi-
nistradores. Cada cuenta incluir configuraciones especficas de la caracterstica (derechos
de grupo).
Adems de escanear los cdigos de barras, el programa podr ayudar a los administradores
a disear e imprimir los cdigos de barras del cliente y el artculo.
Un proceso simple de programa administrado permitir al personal administrativo procesar
artculos vencidos y multas de manera regular.
La aplicacin permitir que se aadan y mantengan das festivos. Cuando un cliente retire
un libro, el programa ajustar la fecha de vencimiento del archivo para evitar das festivos.
La ayuda en lnea centrada en el administrador proporcionar ayuda para las caractersticas
mejoradas de la aplicacin a travs de la misma tecla F1 disponible para los clientes.
La aplicacin incluir algunos informes administrativos bsicos, y la capacidad de insertar
los informes necesarios en el futuro sin la necesidad de actualizar el propio programa.

La aplicacin como un todo


El programa ser amigable con el usuario y fcil de navegar, sobre todo para los clientes,
sin mucha capacitacin o ayuda.
La aplicacin almacenar sus datos en una base de datos de SQL Server.
La distribucin de la aplicacin la har el personal administrativo que tiene privilegios
administrativos locales, de modo que bastar con el paquete de instalacin estndar de
Windows.
La configuracin de la aplicacin usar mtodos XML estndar.

Estimado y cronograma del proyecto


En la siguiente tabla se resumen los costos estimados y el tiempo para completar el proyecto:
Descripcin de la tarea Sueldo por hora Estimado de tiempo Estimado de precio
1. Caractersticas del artculo Biblioteca $25.00 30 $750.00
2. Caractersticas del cliente $25.00 35 $875.00
3. Caractersticas administrativas $25.00 100 $2 500.00
4. Aplicacin como un todo $25.00 35 $875.00
Subtotal de las tareas 200 $5 000.00
5. SQL Server 2005 (slo estimado) $5 000.00
Total del proyecto $10 000.00

Fecha anticipada de inicio del proyecto: 1 de marzo de 2010


Fecha anticipada de final del proyecto: 30 de junio de 2010
Pgina 4

94 | Captulo 3:Presentacin del proyecto

03_PATRICK-CHAPTER_03.indd 94 17/2/10 15:19:58


Captulo 4
Diseo de la base de datos

Datos. Bases de datos. Pareciera tener sentido. Si tiene datos, necesita ponerlos en algn lugar.
Y qu mejor lugar donde ponerlos que en una base de datos?
Slo para asegurarme de que tuve todas las bases cubiertas, hice una rpida bsqueda en
Internet de una definicin til. Qu impresin. De acuerdo con casi todos los sitios Web que
encontr, una base de datos es una coleccin de datos organizados para fcil recuperacin por
parte de una computadora. Con una definicin como sa, casi todo lo que pongo en mi sistema
se almacena en una base de datos. Todos los archivos de disco estn organizados para fcil acceso.
Los correos electrnicos que he guardado puedo ordenarlos por tema, fecha de recepcin o remi-
tente, de modo que tambin deben estar en una base de datos. Incluso este documento permite
la bsqueda y puede ordenarse de cualquier manera que desee. Es una base de datos?

Bases de datos relacionales


Tal vez esa definicin sea demasiado amplia. En estos das, cuando pensamos en base de datos,
suele llegar a nuestra mente un sistema de base de datos relacional. Estas bases de datos estn
construidas sobre el modelo relacional diseado por Edgar Codd, de IBM. En 1970 public
A Relational Model of Data for Large Shared Data Banks (Un modelo relacional de datos para
grandes bancos de datos compartidos), el artculo seminal sobre el modelo relacional, y ms
adelante expandi los conceptos bsicos con C. J. Date, otro programador real. Tras leer ese
artculo de 1970 (y si tiene una tarde libre, realmente le sera benfico que dedicara tiempo a
su familia o amigos en lugar de leer ese artculo) entrar en un mundo de n registros, dominios
y conjuntos expresables. Por fortuna, no necesita saber nada acerca de esos trminos para usar
sistemas de bases de datos relacionales.
Las bases de datos relacionales que la mayora de los programadores usan recolectan datos en tablas,
cada una de las cuales almacena un conjunto especfico de registros no ordenados. Por conveniencia,
las tablas se presentan como una cuadrcula de valores de datos, y cada fila representa un solo regis-
tro y cada columna representa un campo consistente que aparece en cada registro. En la tabla 4-1 se
presenta una tabla de pedidos, con un registro separado para cada elemento de lnea en el orden.

95

04_PATRICK-CHAPTER_04.indd 95 17/2/10 15:20:38


Tabla 4-1. Muchacho, muchas personas beben caf y t.

ID de ID de ID de Nombre ID de
registro pedido cliente del cliente producto Producto Precio Cantidad
92231 10001 AA1 Juan Campos BEV01COF Caf 399 3
92232 10001 AA1 Juan Campos BRD05RYE Pan de centeno 26.80 1
92233 10002 BW3 Arturo Ramos BEV01COF Caf 39.90 1
92234 10003 BW3 Arturo Ramos BEV01COF T 39.90 2
92235 10004 CC1 Carlos Chvez CHP34PTO Papas fritas 10.90 7

Realmente es conveniente poner toda su informacin en una tabla. Los datos importantes apare-
cen a simple vista en una disposicin agradable y ordenada, y es fcil ordenar los resultados con
base en una columna determinada. Por desgracia, esta tabla de pedidos tiene muchas repeticiones.
Nombres de cliente y de productos se repiten varias veces. Adems, aunque el ID de producto
BEV01COF indica caf, una de las lneas la presenta como T. Algunos problemas adiciona-
les son inherentes en datos que estn colocados en una sola tabla de datos de archivo simple.
Mr. Codd, quien fue un brillante cientfico de la computacin, tambin vio este problema. Pero
en lugar de slo sentarse y quejarse como yo, desarroll una solucin: la normalizacin. Al dividir
los datos en tablas separadas con subconjuntos de datos, asignar un identificador nico para cada
registro/fila en cada tabla (una clave principal) y hacer algunos cuantos ajustes adicionales, los
datos podan normalizarse para eficiencia en el procesamiento e integridad de datos. En el caso
de los pedidos de ejemplo de la tabla 4-1, los datos podan normalizarse en tres tablas separadas:
una para los elementos de lnea de pedidos, otra para clientes y una ms para productos (vanse
las tablas 4-2, 4-3 y 4-4, respectivamente). En cada tabla he puesto un asterisco junto al ttulo
de la columna que acta como la columna de clave principal.

Tabla 4-2. La tabla de clientes.

ID de cliente* Nombre del cliente


AA1 Juan Campos
BW3 Arturo Ramos
CC1 Carlos Chvez

Tabla 4-3. La tabla de productos.

ID de producto* Nombre del producto Precio unitario


BEV01COF Caf 39.90
BRD05RYE Pan de centeno 26.80
BEV01COF Caf 39.90
CHP34PTO Papas fritas 10.90

96 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 96 17/2/10 15:20:39


Tabla 4-4. La tabla de elementos de lnea de pedido.

ID de registro * ID de pedido ID de cliente ID de producto Cantidad


92231 10001 AA1 BEV01COF 3
92232 10001 AA1 BRD05RYE 1
92233 10002 BW3 BEV01COF 1
92234 10003 BW3 BEV01COF 2
92235 10004 CC1 CHP34PTO 7

Para obtener resultados combinados de varias tablas a la vez, una (o vincule) sus campos coinci-
dentes. Por ejemplo, puede vincular el campo ID de cliente en la tabla de artculos de lnea
con el campo de clave principal coincidente ID de cliente en la tabla de clientes. Una vez
unidos, los detalles para un solo registro de artculo de lnea combinado pueden presentarse con
el nombre de cliente completo que coincide. Es lo mismo para uniones directas con cualquier
par de tablas que tengan campos vinculables. En la figura 4-1 se muestran las relaciones entre las
tablas de cliente, producto y lnea de pedido.

Artculos de lnea
Clientes Productos
ID de registro
ID de cliente ID de producto ID de producto
Nombre del cliente ID de pedido Precio unitario
ID de cliente
Cantidad

Figura 4-1. Tres tablas, y an funcionan como una.

Para unir tablas, las bases de datos relacionales implementan lenguajes de consulta que le permiten
manipular los datos empleando lgebra relacional (de la que se deriva el trmino base de datos re-
lacional). El ms popular de estos lenguajes, SQL, usa frases simples similares al ingls para unir,
ordenar, resumir y recuperar los valores de datos que necesita. La instruccin primaria, SELECT,
proporciona caractersticas bsicas de seleccin y recuperacin de datos. Otras tres instruccio-
nes comunes, INSERT, UPDATE y DELETE, le permiten manipular los registros almacenados en
cada tabla. Juntas, estas cuatro instrucciones integran los comandos principales del lenguaje de
manipulacin de datos (DML, Data Manipulation Language) de SQL. Adems, SQL incluye ins-
trucciones de lenguaje de definicin de datos (DDL, Data Definition Language) que le permiten
disear las tablas usadas para contener los datos, adems de otras caractersticas de base de datos.
Mostrar ejemplos de varias instrucciones SQL en pginas posteriores de este captulo.
Sistemas especficos del vendedor, como SQL Server de Microsoft, Oracle de Oracle, Access de Mi-
crosoft y DB2 de IBM, extienden estas caractersticas centrales de DDL y DML mediante herramien-

Bases de datos relacionales | 97

04_PATRICK-CHAPTER_04.indd 97 17/2/10 15:20:39


tas adicionales de anlisis y administracin de datos. Tambin batallan entre s en otras caractersticas
importantes, como la replicacin de datos, la integridad de datos a prueba de fallas, la velocidad a la
que consultas complejas devuelven los resultados solicitados, y quin tiene el jet privado ms grande.

SQL Server 2005


La principal herramienta de base de datos de nivel empresarial de Microsoft es SQL Server. Aunque
empez su vida como un derivado de Sybase (otra base de datos relacional), se le ha dado el toque
de Microsoft. A diferencia de Access (el otro producto de base de datos relacional de Microsoft),
SQL Server incluye caractersticas avanzadas de administracin y anlisis de datos, as como un
atractivo precio a cambio de las caractersticas que ofrece. Aunque Microsoft se uni un poco tarde
al juego de las bases de datos relacionales, ha hecho un trabajo muy bueno para seguir el paso.
Oracle an obtiene marcas altas, al menos en la percepcin de ser el ms robusto, ms estable y ms
independiente de la plataforma entre los diversos jugadores. Pero SQL Server tambin tiene gran-
des calificaciones, sobre todo con sus menores costos y sus herramientas visuales ms intuitivas.
Originalmente, Microsoft promovi SQL Server como una herramienta orientada a los negocios
para personas orientadas a los negocios con agendas determinadas por los negocios y sus trajes
de tres piezas de fibras peinadas y saco cruzado orientados a los negocios, y an se le ve de esa
manera. Pero Microsoft est identificando cada vez ms la base de datos como una herramienta
de desarrollo, sobre todo con el lanzamiento de 2005. No fue coincidencia que Microsoft eligie-
ra debutar con esa versin de SQL Server el 7 de noviembre de 2005, el mismo da que lanz la
versin de Visual Studio 2005. Ahora todas las versiones de Visual Studio incluyen algn sabor
de SQL Server (aun los productos de bajo perfil de Visual Studio Express Edition tienen acceso a
un complemento de SQL Server Express Edition, que, al momento de escribir este libro, estaba
disponible sin costo alguno en el sitio Web de Microsoft). Y es una relacin de dos vas entre
los productos: siempre puede usar datos de SQL Server en sus aplicaciones de .NET, pero SQL
Server 2005 ahora le permite crear procedimientos almacenados incrustados con cdigo .NET,
junto con el nativo y ms tradicional lenguaje de creacin de secuencias de comandos T-SQL.

Microsoft anunci el lanzamiento de SQL Server 2008, la ltima versin de


su producto de base de datos, en tndem con Visual Studio 2008. Sin em-
bargo, aunque los dos productos compartieron una fecha de lanzamiento, las
fechas reales de disponibilidad de los dos productos distan por varios meses;
SQL Server 2008 sali despus de Visual Studio. Debido a que no puedo
estar seguro de que usted, como lector, ya tenga acceso a SQL Server 2008,
he optado por usar SQL Server 2005 como base de datos central de este libro.
Casi todo lo que lea acerca de SQL Server 2005 en este libro funcionar de
manera idntica en SQL Server 2008. Si decide usar la versin 2008 del pro-
ducto, no debe tener dificultades para seguir el anlisis de este libro.

SQL Server, como el nombre lo indica, es un producto de servidor. Se ejecuta en segundo


plano en un sistema y se comunica con usted, el usuario, al hacer que primero establezca una

98 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 98 17/2/10 15:20:39


conexin de red estndar con el motor del servidor. Esto es cierto aunque el motor de SQL
Server se ejecute en su propia estacin de trabajo. Observar un producto de servidor es tan esti-
mulante como leer algunos de los otros libros de tutorial acerca de Visual Basic 2008 que usted
juiciosamente ha evitado, de modo que Microsoft proporciona varias herramientas de cliente
que le permiten administrar bases de datos, tablas y otras propiedades de la base de datos relacio-
nal. SQL Server Management Studio es la herramienta estndar de cliente de nivel empresarial
para la administracin de base de datos de SQL Server. Para SQL Server 2005 Express Edition,
Microsoft proporciona una herramienta reducida pero ms amigable: SQL Server Management
Studio Express (vase la figura 4-2). Esta herramienta le permite administrar bases de datos y
procesar instrucciones DDL y DML. Management Studio Express no se incluye en SQL Server
2005 Express Edition; debe descargarlo y obtenerlo por separado de Microsoft. Al momento de
escribir este libro, est disponible sin costo en el sitio Web de Microsoft.

Figura 4-2. SQL Server Management Studio Express.

Debido a que algunos lectores de Programacin en Visual Basic 2008 tal vez
slo tengan acceso a la SQL Server 2005 Express Edition (y la herramien-
ta relacionada SQL Server 2005 Management Studio Express), todos los
ejemplos de este libro estn diseados para usarse con esa edicin del motor
de la base de datos. Esto slo tiene impacto las pocas veces que me refiero
especficamente a las herramientas de cliente. Todas las instrucciones de
SQL (tanto DDL como DML) presentadas en este libro y en el cdigo
fuente del Proyecto Biblioteca funcionarn con cualquier edicin de SQL
Server 2005 o SQL Server 2008.

Aunque Microsoft sigue actualizando y vendiendo Microsoft Access, se recomienda cada vez
ms que los desarrolladores profesionales usen y distribuyan bases de datos en formato de SQL
Server. Microsoft le permitir incluso redistribuir SQL Server 2005 Express Edition con su

SQL Server 2005 | 99

04_PATRICK-CHAPTER_04.indd 99 17/2/10 15:20:40


aplicacin. Para esto, primero debe obtener una licencia de redistribucin de SQL Server 2005
Express Edition de Microsoft. Por fortuna, es gratuita y puede obtenerla solicitndola en el sitio
Web de la SQL Server 2005 Express Edition, http://www.microsoft.com/sql/express.

SQL
Hacer negocios en Japn es muy fcil, una vez que conoce el idioma. Lo mismo resulta
cierto para SQL Server: es muy fcil manipular y acceder a los datos una vez que conoce el
lenguaje. En este caso, el lenguaje es SQL o Structured Query Lenguaje (lenguaje estructu-
rado de consultas). Desarrollado originalmente por IBM, SQL se ha vuelto desde entonces
un estndar en la industria de las bases de datos. Bueno, una especie de estndar, porque al
igual que Estados Unidos e Inglaterra, SQL Server de Microsoft y Oracle de Oracle son dos
bases de datos relacionales que estn divididas por un lenguaje comn. Las partes centrales
del lenguaje SQL son muy consistentes entre vendedores, pero cada proveedor agrega gran
cantidad de caractersticas adicionales y variaciones de sintaxis diseadas por los imitadores
de Edgar Codd.
En esta seccin se describen las instrucciones DDL y DML que sern ms tiles en nuestro de-
sarrollo del programa Biblioteca. Estar contento de saber que SQL no es muy puntilloso en el
formato de las diversas instrucciones. Se ignoran las distinciones entre maysculas y minsculas;
SELECT es lo mismo que select y que SeLeCt. (El cdigo tradicional de SQL est principal-
mente en maysculas. Yo uso stas para todas las palabras clave, y las mezclo para tablas, campos
y otros elementos personalizados. No importa lo que usted elija, la consistencia es importante.)
Adems, emplee los espacios en blanco como ms le convenga. Puede poner instrucciones en
una lnea gigantesca, o colocar cada palabra en una lnea separada. La nica ocasin en que s
importan los espacios en blanco y las maysculas y minsculas es en las cadenas reales de texto
de datos; no importa lo que escriba, as se quedar.
Por lo general, las instrucciones SQL terminan con un punto y coma, pero algunas herramientas
no requieren que lo incluya, y otras imponen que lo excluya. Cuando use las herramientas vi-
suales de cliente de SQL Server (Management Studio y Management Studio Express), el punto
y coma es opcional, pero representa una buena idea incluirlo cuando est usando juntas varias
instrucciones, una tras otra. Las instrucciones de SQL usadas en cdigo de Visual Basic nunca
incluyen puntos y coma.
Ms adelante, cuando revise una secuencia de comandos de SQL que yo haya escrito, ver la
palabra GO de vez en cuando. En SQL Server este comando indica Para todas las dems instruc-
ciones que aparecen hasta ahora, sigue adelante y procsalas ahora.

Instrucciones DDL
Esto puede ser un golpe para usted, pero antes de que pueda almacenar datos en una tabla, tiene
que crear sta. SQL tiene la herramienta para hacerlo: la instruccin CREATE TABLE. Es una de
las muchas instrucciones DDL. La sintaxis bsica es muy sencilla:

100 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 100 17/2/10 15:20:40


CREATE TABLE nombreTabla
(
nombreCampo1 tipoDatos opciones,
nombreCampo2 tipoDatos opciones,
etctera...
)

Slo llene las partes que est listo para poblar (es decir, los datos). Los nombres de tablas y campos
estn conformados por letras y dgitos; puede incluir espacios y algunos otros caracteres espe-
ciales, pero dificulta la codificacin posterior (por ello, en la tabla real de nuestro proyecto no
utilizaremos acentos, aunque SQL Server los acepta). Cada vendedor tiene su propia coleccin
de tipos de datos; me apegar aqu a las versiones de SQL Server. Las opciones le permiten espe-
cificar cosas como si los campos requieren datos, si representa la clave principal de la tabla, y
otras restricciones similares. Las extensiones de la sintaxis le permiten configurar restricciones que
aplican a toda la tabla, ndices (que le permiten ordenar o buscar una columna determinada ms
rpidamente) y especificaciones de almacenamiento de datos.
He aqu una instruccin CREATE TABLE de ejemplo que podra usarse para los elementos de
lnea de pedido de la tabla (revise como referencia la tabla 4-4):
CREATE TABLE ElementosLinea
(
IDRegistro bigint IDENTITY PRIMARY KEY,
IDPedido bigint NOT NULL,
IDCliente varchar(20) NOT NULL
REFERENCES Clientes (IDCliente),
IDProducto varchar(20) NOT NULL,
Cantidad smallint NOT NULL
)

La palabra clave IDENTITY permite que SQL Server se encargue de llenar el campo IDRegistro
con datos; usar un contador secuencial para proporcionar un valor nico para IDRegistro con
cada nuevo registro. La clusula PRIMARY KEY identifica el campo IDRegistro como el valor
de identificacin nico para cada registro de la tabla. Los tipos de datos bigint y smallint
indican campos de entero de tamao apropiado, y el tipo varchar proporciona espacio para tex-
to, hasta la longitud mxima especificada entre parntesis (20 caracteres). La clusula opcional
REFERENCES identifica una relacin entre esta tabla ElementosLinea y otra llamada Clientes;
valores en el campo ElementosLinea.IDCliente coinciden con los valores clave del campo
Clientes.IDCliente. (Observe la sintaxis de punto que se usa para separar los nombres de
tabla y campo. Se presenta por todos lados en SQL.) A las referencias entre tablas se les conoce
como referencias externas.
Si necesita hacer cambios a la estructura o las opciones de una tabla o sus campos despus de crea-
da, SQL incluye una instruccin ALTER TABLE que puede cambiar casi todo en la tabla. Adems,
hay una instruccin DROP TABLE relacionada, que se usa para deshacerse de la tabla y todos sus
datos. Tal vez quiera evitarla en datos de produccin en vivo, porque los usuarios tienden a mos-
trarse un poco irritables cuando los datos desaparecen de sbito de la superficie de la Tierra.
En la tabla 4-5 se presenta un resumen de tipos de datos disponibles usados en SQL Server.

SQL | 101

04_PATRICK-CHAPTER_04.indd 101 17/2/10 15:20:40


Tabla 4-5. Tipos de datos de SQL Server.

Tipo de datos Descripcin


bigint Campo entero de 8 bytes (64 bits) para valores que van de 9,223,372,036,854,775,808 a
9,223,372,036,854,775,807.
binary Datos binarios de longitud fija, hasta 8,000 bytes de longitud. Usted especifica la longitud mediante un parme-
tro, como en binary(100).
bit Da soporte a tres valores posibles: 1,0 o NULL. Por lo general se usa para valores booleanos. Internamente,
SQL Server almacena campos de varios bits a partir de un solo registro en un campo entero combinado.
char, nchar Cadenas estndar (char) o Unicode (nchar) de longitud fija, de hasta 8,000 caracteres de largo. Se especifica
el largo mediante un parmetro, como en char(100).
cursor Este tipo de datos se usa dentro de procedimientos almacenados, y no puede utilizarse para crear una columna.
datetime Campo general de fecha y hora que va del 1 de enero de 1,753 al 31 de diciembre de 31,9999 de nuestra era. La
exactitud del tiempo para cualquier valor dado est dentro de los 3.33 milisegundos. SQL Server 2008 agrega
varios tipos de datos relacionados con fechas: date (fechas sin horas), time (horas sin fechas), datetime2
(igual que datetime, pero con un rango ms grande y exactitud de 100 nanosegundos) y datetimeoff-
set (rangos de fecha y hora).
decimal, Campo decimal de escala y precisin fija. Usted especifica el nmero mximo de dgitos que aparecern a ambos
numeric lados del punto decimal (la precisin) y el nmero mximo de esos dgitos que aparecern en el lado derecho
del punto decimal (la escala). Por ejemplo, un parmetro de decimal(10,4) crea un campo con hasta 10
dgitos totales, cuatro de los cuales aparecern despus del punto decimal. El valor de precisin mxima es 38.
numeric es un sinnimo de decimal, al igual que dec.
float Campo decimal de punto flotante con almacenamiento de variable. Puede especificar el nmero de bits usado
para almacenar el valor, hasta 53. Como opcin predeterminada, se usan los 53 bits, de modo que establecer
float es equivalente a float(53). El tipo de seudodatos real es equivalente a float(24). Los valores
almacenados estn en el orden de 1.0 x 1038; el rango exacto y la precisin varan por los bits usados para
almacenamiento. Este tipo de datos es susceptible a errores menores de clculo.
hierarchyid Este tipo de datos, nuevo en SQL Server 2008, da soporte a consultas de datos jerrquicos y con forma de rbol.
No est disponible en SQL Server 2005.
image, text, No use estos tipos de datos, porque con el tiempo se eliminarn de SQL Server.
ntext
int Un campo entero de 4 bytes (32 bits) para valores que van de 2,147,483,648 a 2,147,483,647.
money Campo de 8 bytes (64 bits) de elevada exactitud para almacenamiento de valores de moneda, con hasta
cuatro dgitos despus del punto decimal. Los datos almacenados van de 922,337,203,685,477.5808 a
922,337,203,685,477.5807.
rowversion, Este tipo de datos se usa para registrar eventos de modificacin en registros. Hay restricciones en su uso, y no
timestamp est garantizado que sea nico dentro de una tabla. timestamp es un sinnimo obsoleto de
rowversion; use este ltimo.
smalldatetime Campo general de fecha y hora que va del 1 de enero de 1,900 al 6 de junio de 2,079 de nuestra era.
La exactitud del tiempo para cualquier valor dado est dentro de un minuto.
smallint Campo entero de 2 bytes (16 bits) para valores que van de 32,768 a 32,767.
smallmoney Campo de 4 bytes (32 bits) de elevada exactitud para almacenamiento de valores de moneda, con hasta cuatro
dgitos despus del punto decimal. Los valores de datos almacenados van de 214,748.3648 a 214,748.3647.

102 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 102 17/2/10 15:20:40


Tabla 4-5. Tipos de datos de SQL Server (continuacin).

Tipo de datos Descripcin


sql_variant Tipo genrico que almacena valores de muchos otros campos especficos de tipo.
table Campo especial que almacena temporalmente los resultados de una consulta en un formato compacto de tabla. La
definicin de un campo de tabla es un poco compleja, y su uso, por razones naturales, presenta ciertas restricciones.
tinyint Campo entero sin signo de 1 byte (8 bits) para valores que van de 0 a 255.
uniqueidenti- Identificador globalmente nico de 16 bytes (GUID, Globally Unique IDentifier). La funcin NEWID relaciona-
fier da genera valores para este campo.
varbinary Datos binarios de longitud variable, de hasta 8,000 bytes de largo. Usted especifica la longitud mediante un
parmetro, como en varbinary(100). El campo slo consume espacio para el contenido real almacenado en
el campo. Un parmetro especial de varbinary(max) permite el ingreso de hasta 2,000 millones de bytes.
varchar, nvar- Cadenas estndar (varchar) o Unicode (nvarchar) de longitud variable, de hasta 8,000 caracteres de
char largo. Usted especifica la longitud mediante un parmetro, como en varchar(100). El campo slo consume
espacio para el contenido real almacenado en el campo. Un parmetro especial de varchar(max) permite el
ingreso de hasta 2,000 millones de caracteres.
xml Proporciona almacenamiento para documentos de datos XML, con tipo y sin tipo, hasta 2 GB.

Instrucciones DML
Aunque las instrucciones DDL son poderosas, no se usan mucho. Una vez que crea los objetos
de su base de datos, no hay mucho espacio para modificaciones. Las instrucciones DML son ms
tiles para navegar por datos cotidianos.
La instruccin INSERT agrega registros de datos a una tabla. Los datos se agregan a una tabla de
registro en registro. (Una variacin de INSERT le permite insertar varios registros, pero deben
provenir de otro origen de tabla existente.) Para usar la instruccin INSERT, especifique la tabla
y los campos de destino, y luego los valores individuales que se pondrn en cada campo. Un valor
de datos corresponde a cada nombre de columna de datos especificado.
INSERT INTO ElementosLinea
(IDPedido, IDCliente, IDProducto, Cantidad)
VALORES (10002, 'BW3', 'BEV01COF', 1)

Suponiendo que sta va con la instruccin CREATE TABLE escrita antes, esta accin de insertar
agregar un nuevo registro a la tabla ElementosLinea con cinco nuevos campos (cuatro
campos especificados, ms la clave principal que se agrega automticamente al campo IDRegis-
tro porque estaba marcado como IDENTITY). SQL Server tambin hace gran cantidad de
revisiones de integridad de datos. Cada campo de datos que agregue debe ser del tipo correcto,
pero usted ya esperaba eso. Como diseamos el campo IDCliente para que sea una referencia a
la tabla Clientes, la insercin fallar si el cliente BW3 no existe an en la tabla Clientes.
Pueden incluirse las literales numricas necesarias en sus instrucciones SQL sin calificacin adicio-
nal. Las cadenas de literales siempre estn entre comillas, como se hace para el cliente y el ID de
producto en esta instruccin INSERT. Si necesita incluir una comilla sencilla en la literal, ingrsela
dos veces:

SQL | 103

04_PATRICK-CHAPTER_04.indd 103 17/2/10 15:20:40


'Juan D''Silva'

Encierre los valores de fecha y hora de literal entre comillas sencillas:


'7-Nov-2005'

Estos valores de fecha y hora aceptan cualquier formato reconocido, aunque debe usar uno que
no facilite la mala interpretacin por parte de SQL Server.
Muchos tipos de campo dan soporte a un valor sin signo, un valor que indica que el campo no
contiene datos. A ese valor se le conoce como nulo, y se especifica en SQL Server con la palabra
clave NULL. No puede asignar NULL a campos de clave principal, ni a ningn campo marcado
con la opcin NOT NULL.
Para eliminar un registro previamente agregado, use la instruccin DELETE:
DELETE FROM ElementosLinea WHERE IDRegistro = 92231

La instruccin DELETE incluye una clusula WHERE (la parte WHERE IDRegistro = 92231).
Las clusulas WHERE le permiten indicar uno o ms registros en una tabla al hacer comparaciones
con campos de datos. Sus clusulas WHERE pueden incluir palabras clave Y y O para unir varias
condiciones, y parntesis para agrupar.
DELETE FROM ElementosLinea WHERE IDPedido = 10001
Y IDProducto = 'BRD05RYE'

Una instruccin DELETE puede eliminar cero, uno o 1 000 registros, de modo que la precisin
en la clusula WHERE es importante. Para eliminar todos los registros de una tabla, excluya por
completo la clusula WHERE.
DELETE FROM ElementosLinea

La instruccin UPDATE tambin usa una clusula WHERE para modificar valores en registros de
tabla existentes.
UPDATE ElementosLinea SET Cantidad = 4
WHERE IDRegistro = 92231

Las asignaciones se hacen a campos con la clusula SET; ponga el nombre de campo (Cantidad)
a la izquierda del signo de igual, y el nuevo valor a la derecha (4). Para asignar varios valores a la
vez, separe cada asignacin con una coma. Tambin puede incluir frmulas y clculos.
UPDATE ElementosLinea SET Cantidad = Cantidad + 1,
IDProducto = 'BEV02POP'
WHERE IDRegistro = 92231

Al igual que con la instruccin DELETE, UPDATE puede actualizar cero, uno o muchos registros
con base en los registros que coinciden con la clusula WHERE.
La instruccin DML final, y una de las ms usadas, es SELECT.
SELECT IDProducto, Cantidad FROM ElementosLinea
WHERE IDRegistro = 92231

SELECT rastrea una tabla (ElementosLinea), buscando todos los registros que coinciden con un
criterio determinado (IDRegistro = 92231), y devuelve una tabla ms pequea que contiene

104 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 104 17/2/10 15:20:40


slo los campos indicados (IDProducto y Cantidad) para los registros coincidentes. La consul-
ta ms bsica devuelve todas las filas y columnas.
SELECT * FROM ElementosLinea

Esta consulta devuelve todos los registros de la tabla sin un orden determinado. El asterisco (*)
significa incluir todos los campos.
La clusula opcional ORDER BY devuelve los resultados en un orden especfico.
SELECT * FROM ElementosLinea
WHERE Cantidad > 5
ORDER BY IDProducto, Cantidad DESC

Esta consulta devuelve todos los registros que tienen un valor de campo Cantidad mayor de
cinco, y ordena los resultados primero por la columna IDProducto (en orden ascendente) y
luego por la cantidad numrica (en orden descendente, especificado por DESC).
Las funciones de agregacin y las caractersticas de agrupacin le permiten resumir resultados del
conjunto ms largo de datos. La siguiente consulta documenta la cantidad total ordenada para
cada producto de la tabla:
SELECT IDProducto, SUM(Cantidad) FROM ElementosLinea
GROUP BY IDProducto

Puede usar uniones para vincular los datos de dos o ms tablas distintas. La siguiente consulta
une las tablas ElementosLinea y Cliente en sus columnas coincidentes IDCliente. Esta ins-
truccin SELECT tambin demuestra el uso de las abreviatura de tabla (los prefijos LI y CU)
agregados mediante las clusulas AS; no suelen ser necesarias, pero ayudan a que sea legible una
consulta ms compleja.
SELECT LI.IDPedido, CU.NombreCliente, LI.IDProducto
FROM ElementosLinea AS LI INNER JOIN Cliente AS CU
ON LI.IDCliente = CU.IDCliente
ORDER BY LI.IDPedido, CU.NombreCliente

Esta tabla usa una unin interna, uno de los cinco tipos principales de unin, cada uno de los
cuales regresa conjuntos diferentes de registros basados en la relacin entre la primera (izquierda)
y la segunda (derecha) tabla de la unin:
Unin interna
Devuelve slo los registros donde hay una coincidencia en los campos vinculados. Este tipo
de unin usa las palabras clave INNER JOIN.
Unin externa izquierda
Devuelve todos los registros de la tabla de la izquierda y slo los registros de la tabla de la dere-
cha en que hay una coincidencia en los campos calculados. Si un registro de una tabla a la iz-
quierda no tiene una coincidencia, acta como si todos los campos de la tabla de la derecha de
ese registro contuvieran valores NULL. Este tipo de unin usa las palabras clave LEFT JOIN.
Uno de sus usos podra ser unir las tablas Productos y ElementosLinea. Podra devolver
una lista del nombre completo del producto para todos los productos disponibles, adems

SQL | 105

04_PATRICK-CHAPTER_04.indd 105 17/2/10 15:20:41


de la cantidad total pedida de cada uno. Al poner la tabla Productos a la izquierda de una
unin externa izquierda, la consulta devolvera todos los nombres de producto, aunque
nunca se haya ordenado ese producto (y no aparezca en la tabla ElementosLinea).
Unin externa derecha
Esto funciona como una unin externa izquierda, pero se devuelven todos los registros de la
tabla de la derecha y slo los registros de la tabla de la izquierda que tienen una coincidencia.
Este tipo de unin usa las palabras clave RIGHT JOIN.
Unin externa completa
Devuelve todos los registros de las tablas de la izquierda y la derecha, tengan o no coinci-
dencias. Cuando hay una coincidencia, se refleja en los resultados. Este tipo de unin usa
las palabras clave FULL JOIN.
Unin cruzada
Tambin llamada unin cartesiana. Devuelve todas las combinaciones posibles de registros
de la izquierda y la derecha. Este tipo de unin usa las palabras clave CROSS JOIN.
La unin se concentra en la relacin que tienen dos tablas. (Este uso de relacin, por cierto, no
es la base del trmino base de datos relacional.) Algunas tablas existen en una relacin ascendien-
te-descendiente; un registro ascendiente o principal tiene uno o ms registros descendientes
o secundarios en otra tabla. Esto suele ser verdadero en los pedidos; un solo encabezado de
pedido tiene varios elementos de lnea. A este tipo de relacin se le conoce como una a varias,
porque un registro est unido a varios registros de otra tabla. Y la relacin es unidireccional; un
registro secundario determinado no se une a varios registros principales.
Una relacin una a una une un solo registro de una tabla con un solo registro de otra. Es muy
sencilla, y suele usarse para mejorar los valores encontrados en el registro original mediante un
registro complementario en una segunda tabla.
En una relacin varias a varias, un solo registro de una tabla est asociado con varios registros de
una segunda tabla, y un solo registro de esa segunda tabla est asociado con varios registros de la
primera tabla. Un ejemplo real sera la relacin entre maestros y estudiantes de una universidad.
Un maestro tiene varios estudiantes en el saln de clases, pero cada estudiante tiene varios maes-
tros cada semestre. Las implementaciones prcticas de las relaciones varias a varias en realidad
requieren tres tablas: las dos tablas relacionadas y una intermedia que las vincula. Mostrar un
ejemplo de ese tipo de tabla en la seccin Proyecto de este captulo.

Ms all del SQL bsico


Las instrucciones de ejemplo que present aqu slo rascan la superficie de las posibilidades de
manipulacin de datos disponibles mediante SQL. Pero por ahora debe haber notado que SQL
es notablemente similar a la sintaxis del ingls, de manera muy parecida a Visual Basic. En reali-
dad, el nombre original del lenguaje (SEQUEL) era un acrnimo de Structured English Query
Languaje (lenguaje estructurado de consultas en ingls). A medida que las instrucciones de

106 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 106 17/2/10 15:20:41


SQL se vuelvan ms complejas, parecern cada vez menos un ensayo de sexto ao y ms como
colecciones al azar de palabras en ingls.
El objetivo aqu no es presentarle la estructura bsica de las instrucciones de SQL. Casi todas
las que encontraremos en el Proyecto Biblioteca no sern ms complejas que las de los ejemplos
incluidos aqu. Si desea saber ms al respecto, el componente Libros en lnea instalado con
SQL Server (una descarga separada para la Express Edition) tiene excelente documentacin de
uso. Tambin estn disponibles varios buenos libros sobre los pormenores de SQL, incluidos
dialectos especficos del vendedor.

Uso de bases de datos en Visual Basic


Visual Basic puede interactuar con datos almacenados en una base de datos de varias maneras
diferentes:
Use ADO.NET, la principal tecnologa de acceso a datos incluida en .NET Framework,
para interactuar con contenido almacenado en bases de datos. ste es el mtodo utilizado en
todo el programa Biblioteca para interactuar con su base de datos. ADO.NET se analiza en el
captulo 10, con ejemplos de su uso. Tambin presentar cdigo especfico de ADO.NET en
el Proyecto Biblioteca de ese captulo.
Use las caractersticas de unin de datos disponible en Visual Basic y Visual Studio. La
unin establece una conexin entre un control de datos en pantalla u objetos similares ha-
bilitados por datos y el contenido de una base de datos. El cdigo escrito por Microsoft se
ocupa de todo el trabajo de comunicacin; incluso puede arrastrar y colocar estos tipos de
interacciones. Aunque analizar la unin de datos en el captulo 10 (porque estn basadas en
ADO.NET), tiendo a evitarlas, porque reducen la cantidad de control que el programador
puede ejercer sobre la administracin de datos de usuario. La unin de datos no se usar en
el programa Biblioteca.
Extraiga los datos de la base de datos a un archivo estndar y use las caractersticas de mani-
pulacin de archivos de Visual Basic para procesar los datos. Hummm, eso no parece muy
til, pero en realidad tena que hacerlo, sobre todo en los antiguos das en que alguna base
de datos de propietario no poda interactuar fcilmente con el cdigo de Visual Basic.
Cada vez que necesite algunos de los datos, indique al usuario que se han perdido y que debe
reingresarlos de inmediato. Si alguna vez ha tenido curiosidad de saber el aspecto que tiene
una oficina de desempleo, sta poda ser una oportunidad.
Si program en Visual Basic 6.0 (o anterior), podra pensar que sus conocimientos de ADO
se traducirn directamente en desarrollo de ADO.NET. Ja! No podra estar ms equivocado.
Aunque las dos tecnologas de datos comparten una parte de un nombre, el cdigo escrito
para usar cada mtodo vara considerablemente. No analizar la antigua tecnologa ADO en
este libro.

Uso de bases de datos en Visual Basic | 107

04_PATRICK-CHAPTER_04.indd 107 17/2/10 15:20:41


Documentacin de la base de datos
El contenido tcnico que describe las tablas y campos en la base de datos de su aplicacin repre-
senta la pieza ms importante de documentacin generada durante el tiempo de vida de su apli-
cacin. En realidad, la necesidad de una buena documentacin es la base de una de las creencias
centrales de la programacin: la documentacin del proyecto es tan importante como el cdigo
fuente y en ocasiones ms que l.
Puede pensar que bromeo acerca de esto. Aunque encontrar (espero) una gran cantidad de humor
en las pginas de este libro, esto es algo sobre lo que no bromeo. Si estuviera desarrollando una
aplicacin que se centra en contenido de usuario almacenado en la bases de datos, es obligatoria la
documentacin completa y exacta de cada tabla y campo usado en la base de datos. Cualquier falta
en esta rea llevar (no podra, ni quizs, sino llevar) a problemas en la integridad de datos y un
cronograma de desarrollo ms largo de lo necesario. En la figura 4-3 se expone de otra manera.

sta es su aplicacin. sta es su aplicacin sta es su aplicacin


sin documentacin con documentacin
de base de datos. de base de datos.

Figura 4-3. Alguna pregunta?

Por qu pienso que la documentacin de la base de datos es an ms importante que la docu-


mentacin de usuario o las especificaciones funcionales? Debido al impacto que el documento
tendr sobre los datos del usuario. Si tiene una base de datos documentada, podra hacer suposi-
ciones sobre la especificacin funcional, y tal vez lleguen a estar acertadas. Si le falta documenta-
cin de usuario, siempre puede escribirla cuando est terminado el programa (habr alguna otra
manera?). Pero si carece de documentacin de base de datos, est en un mundo de dolor.
Si no ha trabajado antes con proyectos grandes de base de datos, tal vez no me crea. Pero yo s.
Una vez hered una base de datos empresarial escrita en Visual Basic 3.0. El cdigo fuente era
muy malo, pero la base de datos asociada de 100 tablas sin documentar era una confusin de va-
lores de datos almacenados de manera inconsistente. El cdigo de procedimientos almacenados
confusos no era mucho mejor. Como no haba un conjunto claro de documentacin en cada
campo, cada uno de los seis programadores que desarrollaron originalmente el sistema tomaron
sus propias decisiones acerca del rango de datos que se permitira en cada campo, o acerca de
cules campos seran obligatorios o no.

108 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 108 17/2/10 15:20:41


No es divertido recorrer las 100 000 lneas de cdigo fuente sin documentar para determinar
o que haca cada campo, y se requirieron varios meses para completarla con exactitud. Debido a
que el cliente haba pagado por un sistema estable y coherente, y esperaba que se entregara as,
casi todo el costo adicional relacionado con el reemplazo de la documentacin que debi existir
fue cargado por mi grupo de desarrollo. No deje que esto le pase!

Resumen
Casi todas las aplicaciones de Visual Basic estn orientadas al mundo de los negocios y estn
diseadas para interactuar con algn tipo de base de datos. Es importante la comprensin del
sistema de la base de datos usada con su aplicacin; an ms importante es la documentacin de
las caractersticas especficas de la base de datos que incorpora en su aplicacin.
Debido a la influencia de las bases de datos relacionales y del lenguaje SQL en la industria de las
bases de datos, no ser difcil encontrar una gran cantidad de recursos que le ayudarn a crear
instrucciones de SQL y consultas complejas de anlisis de datos. El Proyecto Biblioteca de este
libro usa SQL Server 2005, pero debido al uso generalmente consistente de las caractersticas
centrales del lenguaje SQL, la aplicacin podra tambin usarse de manera fcil en Oracle, Mi-
crosoft Access, o cualesquiera otras bases de datos relacionales.

Proyecto
Para ayudar a mi desarrollo de proyectos de base de datos de Visual Basic, siempre escribo un do-
cumento Kit de recursos tcnicos antes de empezar la codificacin real de la aplicacin. La parte
central de este documento de procesamiento de palabras consta de la documentacin en el nivel de
la tabla y los campos para la base de datos asociada a la aplicacin. Tambin se incluyen los formatos
de todos los archivos de datos de configuracin y personalizados, un mapa de las pginas de ayuda en
lnea, e informacin acerca de productos de terceros usados en la aplicacin. Dependiendo del tipo
de aplicacin, mis expectativas para el usuario y los trminos de cualquier contrato, puedo propor-
cionar nada, algo o todo el contenido del kit de recursos para la comunidad de usuarios.
Empecemos el kit de recursos tcnicos para el Proyecto Biblioteca al disear y documentar las
tablas de la base de datos que habr de usar la aplicacin. Este kit de recursos aparece en el di-
rectorio de instalacin del libro, en el subdirectorio del captulo 4, y contiene los tres archivos
siguientes:
Kit de recursos de la biblioteca ACME.doc
Una versin en Microsoft Word de la documentacin tcnica para el proyecto.
Kit de recursos de la biblioteca ACME.pdf
Una segunda copia del kit de recursos tcnicos, esta vez en formato Adobe Acrobat (PDF).
Script de creacin de base de datos.sql
Una secuencia de comandos de base de datos de SQL Server usada para construir las tablas
y los campos reales en la base de datos.

Proyecto | 109

04_PATRICK-CHAPTER_04.indd 109 17/2/10 15:20:41


Contenido del kit de recursos tcnicos
Esta seccin incluye una lista de las tablas incluidas en la base de datos Biblioteca. Cada tabla
incluye una descripcin general para ayudarle en su comprensin de la estructura de la base de
datos. Encontrar todas estas tablas en captulos sucesivos, junto con el cdigo fuente asociado,
de modo que no se espante si alguna tabla o campo parece irreconocible ahora.

Tablas relacionadas con la seguridad


Aunque los clientes no necesitan iniciar sesin en la aplicacin para buscar elementos en la base
de datos, los administradores deben iniciarla antes de que puedan acceder a caractersticas me-
joradas del programa. Las siguientes cuatro tablas administran las credenciales de seguridad de
cada administrador. La aplicacin usa credenciales de seguridad de SQL Server o Windows slo
para acceder a la base de datos, no para restringir caractersticas.
Actividad. Esta tabla define las caractersticas de la aplicacin que puede asegurarse em-
pleando derechos de grupo. Estas actividades estn vinculadas con grupos de seguridad (de
la tabla NombreGrupo) para establecer los derechos para un grupo en particular.

Campo Tipo Descripcin


ID bigint Clave principal. Esta clave no se genera automticamente; el valor proporcionado
coincide con valores internos usados dentro de la aplicacin Biblioteca. Obligatorio.
NombreCompleto varchar(50) Nombre descriptivo de esta actividad. Obligatorio.

Las siguientes actividades se definen en este momento:


1. Administra autores y nombres
2. Administra tipos de autor y nombre
3. Administra cdigos de estado de copia
4. Administra tipos de medios
5. Administra series
6. Administra grupos de seguridad
7. Administra materiales de biblioteca
8. Administra clientes
9. Administra editores
10. Administra valores del sistema
11. Administra usuarios administrativos
12. Procesa y acepta cuotas
13. Administra ubicaciones
14. Da salida a artculos de la biblioteca

110 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 110 17/2/10 15:20:41


15. Da entrada a artculos de la biblioteca
16. Accede a caractersticas administrativas
17. Realiza procesamiento diario
18. Ejecuta informes del sistema
19. Los clientes acceden sin contrasea de cliente
20. Administra cdigos de barras
21. Administra das festivos
22. Administra grupos de clientes
23. Ve mensajes de clientes administrativos

NombreGrupo. Cada registro en esta tabla define un solo grupo de seguridad. Los bibliote-
carios y otros administradores pertenecen a un grupo de seguridad separado.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de este grupo. Obligatorio.

ActividadGrupo. Esta tabla conecta registros de la tabla Actividad con registros de la tabla
NombreGrupo (una relacin varias a varias) para establecer las actividades que puede realizar
un grupo de seguridad.

Campo Tipo Descripcin


IDGrupo bigint Clave principal. El grupo de seguridad asociado. Referencia externa a Nom-
breGrupo.ID. Obligatorio.
IDActividad bigint Clave principal. La actividad que pueden realizar miembros del grupo de
seguridad asociado. Referencia externa a Actividad.ID. Obligatorio.

NombreUsuario. Esta tabla contiene los registros reales para cada bibliotecario o administrador.
Cada registro incluye la contrasea del usuario y los parmetros del grupo de seguridad.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de este usuario, administrador o bibliotecario. Obligatorio.
IDInicio varchar(20) ID del usuario que le da acceso al sistema. Se ingresa en el formulario inicio
del programa Biblioteca, junto con la contrasea, para obtener acceso a las
caractersticas mejoradas. Obligatorio.
Clave varchar(20) La contrasea de este usuario, en un formato cifrado. Opcional.
Activo bit Este usuario tiene permitido el acceso al sistema? 0 para False, 1 para True.
Obligatorio.

Proyecto | 111

04_PATRICK-CHAPTER_04.indd 111 17/2/10 15:20:42


Campo Tipo Descripcin
IDGrupo bigint A qu grupo de seguridad pertenece este usuario? Referencia externa a
NombreGrupo.ID. Obligatorio.

Tablas de cdigo de soporte


Existen varias tablas simplemente para proporcionar una lista de valores de otras tablas. En una
aplicacin, estas tablas de lista a menudo aparecen como opciones en un control desplegable
(cuadro combinado).
TipoAutorCodigo. En el programa Biblioteca, la palabra autor es un trmino genrico usado
para autores, ilustradores, editores y cualquier otro colaborador similar a un elemento en el
inventario de la biblioteca. Esta tabla le permite definir esas funciones.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de este tipo de autor o colaborador. Obligatorio.

EstatusCopiaCodigo. La copia de cdigo de estatus incluye cosas como circulando, en re-


paracin y cualquier otro estatus primario que la biblioteca desea establecer. El estatus de
salida y entrada se maneja mediante otras caractersticas, como la marca que indica si un
artculo es de referencia.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de esta entrada de estatus. Obligatorio.

LugarCodigo. Ubicaciones fsicas donde estn almacenados los artculos de la biblioteca.


Podra tratarse de sitios, salas o reas dentro de una ubicacin comn.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de esta entrada de estatus. Obligatorio.
Ultimo- datetime La fecha en que el procesamiento diario se hizo para esta ubicacin. Si NULL,
Procesamiento el procesamiento an no se ha hecho. Opcional.

TipoMedioCodigo. Tipos de medios, como libros, revistas, videos, CD, etctera.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.

112 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 112 17/2/10 15:20:42


Campo Tipo Descripcin
NombreCompleto varchar(50) Nombre de este tipo de medio. Obligatorio.
DiasPrestado smallint Nmero de das durante los cuales los artculos de este tipo pueden prestar-
se, antes de la renovacin. Obligatorio.
DiasRenovado smallint Nmero de das que se agregar al periodo original de salida para una
renovacin de artculos dentro de este tipo. Obligatorio.
VecesRenovado smallint Nmero mximo de veces que un cliente puede renovar el artculo antes de
que deba devolverse. Obligatorio.
MultaDiaria money Monto cobrado por da por un artculo de este tipo cuya entrega se venci.
Obligatorio.

GrupoClienteCodigo. Categoras de grupos en que se colocan clientes. No son grupos de se-


guridad, sino generales para fines de creacin de informes. Esto se agreg para dar soporte
a agrupacin de clientes por unidades dentro de una compaa o por clase/grado dentro de
un ambiente de biblioteca escolar.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de este grupo de clientes. Obligatorio.

SerieCodigo. Algunos artculos aparecen como parte de una serie o coleccin ms grandes.
Esta tabla define los nombres de coleccin y serie.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de esta serie o coleccin. Obligatorio.

Artculos de la biblioteca
Las tablas de esta seccin administran el inventario real de artculos. Debido a que la biblioteca
podra poseer ms de una copia de un solo artculo, estas tablas administran el artculo con
nombre y sus copias individuales por separado.
ArticuloConNombre. Un artculo de la biblioteca, como un libro, CD o revista. Esta tabla
representa un artculo general y no la copia real del artculo.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
Titulo varchar(150) Ttulo de este artculo. Obligatorio.
Subtitulo varchar(150) Subttulo de este artculo. Opcional.

Proyecto | 113

04_PATRICK-CHAPTER_04.indd 113 17/2/10 15:20:42


Campo Tipo Descripcin
Descripcion varchar(max) Descripcin completa de este artculo. Opcional.
Edicion varchar(10) Nmero de edicin de este artculo. Opcional.
Editor bigint Editor de este artculo. Referencia externa a Editor.ID. Opcional.
Dewey varchar(20) Nmero decimal de Dewey. Use / para saltos de lnea. Opcional.
LC varchar(25) Nmero de la Biblioteca del Congreso. Use / para saltos de lnea. Opcional.
ISxN varchar(20) ISBN, ISSN u otro nmero estandarizado de este artculo. Opcional.
LCCN varchar(12) Nmero de control de la Biblioteca del Congreso. Opcional.
Copyright smallint Ao de copyright original, real o supuesto. Opcional.
Serie bigint La serie o coleccin en que aparece este artculo. Referencia externa a
SerieCodigo.ID. Opcional.
TipoMedio bigint La clasificacin de medios de este artculo. Referencia externa a
TipoMedioCodigo.ID. Obligatorio.
Descontinuado bit Este ttulo est descontinuado? 0 para False, 1 para True. Obligatorio.

CopiaArticulo. Una sola copia de un artculo con nombre. Copias separadas del mismo art-
culo aparecern como registros separados en esta tabla.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
IDArticulo bigint El registro de artculos con nombre relacionados. Referencia externa a Ar-
ticuloConNombre.ID. Obligatorio.
NumeroCopias smallint Posicin numerada de este artculo dentro del conjunto de copias para un
artculo con nombre. Obligatorio, y nico entre artculos con el mismo valor
de campo IDArticulo.
Descripcion varchar(max) Comentarios especficos para esta copia del artculo. Opcional.
Disponible bit La copia est disponible para prstamo o circulacin? 0 para False, 1 para
True. Obligatorio.
Faltante bit Se ha reportado la copia como faltante? 0 para False, 1 para True. Obligatorio.
Referencia bit Es una copia de referencia? 0 para False, 1 para True. Obligatorio.
Condicion varchar(30) Cualquier comentario relevante para la condicin de esta copia. Opcional.
Adquirido datetime Fecha en que esta copia fue adquirida por la biblioteca. Opcional.
Costo money Valor de este artculo, sea el original o el de reemplazo. Opcional.
Estatus bigint El estatus general de esta copia. Referencia externa a
EstatusCopiaCodigo.ID. Obligatorio.
CodigoBarras varchar(20) Cdigo de barras encontrado en la copia. Por el momento, slo se da soporte a
cdigos de barras numricos. Opcional.
Lugar bigint El sitio o lugar en que se encuentra este artculo. Referencia externa a
LugarCodigo.ID. Opcional.

Editor. Una organizacin que publica libros o algn otro tipo de medio.

114 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 114 17/2/10 15:20:42


Campo Tipo Descripcin
ID bigint Clave principal; asignado automticamente. Obligatorio.
NombreCompleto varchar(100) Nombre del editor. Obligatorio.
SitioWeb varchar(255) URL del sitio Web del editor. Opcional.

Autor. Alguien que escribe, edita, ilustra o colabora de alguna otra manera un libro o ar-
tculo de medios. En todos los casos, cuando aparece el trmino autor en esta tabla, hace
referencia a alguien que colabor con el artculo.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
Apellido varchar(50) Apellido de este autor. Obligatorio.
Nombre varchar(30) Nombre de este autor. Opcional.
Inicial varchar(30) Inicial intermedia de este autor. Opcional.
Sufijo varchar(10) Sufijo del nombre, como Jr. Opcional.
FechaNacimiento smallint Ao de nacimiento. Use nmeros negativos para antes de Cristo. Opcional.
FechaMuerte smallint Ao de muerte. Use nmeros negativos para antes de Cristo. Opcional.
Comentarios varchar(250) Comentarios diversos sobre este autor. Opcional.

AutorArticulo. Un autor, editor, etc., de un artculo con nombre especfico. Esta tabla esta-
blece una relacin varias a varias entre las tablas ArticuloConNombre y Autor.

Campo Tipo Descripcin


IDArticulo bigint Clave principal. El artculo con nombre asociado. Referencia externa a
ArticuloConNombre.ID. Obligatorio.
IDAutor bigint Clave principal. El autor asociado con el artculo con nombre. Referencia externa
a Autor.ID. Obligatorio.
Secuencia smallint Orden relativo de este autor entre los autores por su artculo con nombre. Los
autores con nmeros ms pequeos aparecen primero. Obligatorio.
TipoAutor bigint El tipo especfico de contribucin hecha por este autor a este artculo con
nombre. Referencia externa a TipoAutorCodigo.ID. Obligatorio.

Clave. Palabras personalizadas que pueden aplicarse a artculos con nombre para facilitar
la bsqueda.

Campo Tipo Descripcin


ID bigint Clave principal; asignada automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de esta palabra clave. Obligatorio.

Proyecto | 115

04_PATRICK-CHAPTER_04.indd 115 17/2/10 15:20:42


ClaveArticulo. Conecta una palabra clave con un artculo con nombre mediante una rela-
cin varias a varias entre las tablas ArticuloConNombre y Clave.

Campo Tipo Descripcin


IDArticulo bigint Clave principal. El artculo con nombre asociado. Referencia externa a
ArticuloConNombre.ID. Obligatorio.
IDClave bigint Clave principal. La palabra clave que se asocia con el artculo con nombre.
Referencia externa a Clave.ID. Obligatorio.

Tema. Encabezados de tema utilizados para clasificar artculos con nombre.

Campo Tipo Descripcin


ID bigint Clave principal; asignada automticamente. Obligatorio.
NombreCompleto varchar(150) Nombre de este tema. Obligatorio.

TemaArticulo. Conecta un tema con un artculo con nombre mediante una relacin varias a
varias entre las tablas ArticuloConNombre y Tema.

Campo Tipo Descripcin


IDArticulo bigint Clave principal. El artculo con nombre asociado. Referencia externa a Arti-
culoConNombre.ID. Obligatorio.
IDTema bigint Clave principal. El tema que se asocia con el artculo con nombre. Referencia
externa a Tema.ID. Obligatorio.

Tablas relacionadas con el cliente


Las tablas de esta seccin definen los registros reales del cliente y su relacin con las copias de
artculos (cuando el cliente pide prestadas esas copias).
Cliente. Un usuario identificado de la biblioteca. Los clientes suelen tener privilegios de
prstamo.

Campo Tipo Descripcin


ID bigint Clave principal; asignado automticamente. Obligatorio.
Apellido varchar(30) Apellido de este cliente. Obligatorio.
Nombre varchar(30) Nombre de este cliente. Obligatorio.
UltimaActividad datetime Fecha del ltimo prstamo, renovacin o devolucin. Opcional.
Activo bit Est activo el cliente? 0 para False, 1 para True. Obligatorio.
Comentarios varchar(max) Cualquier comentario relacionado con este cliente. Opcional.
MensajeAdmin varchar(500) Comentarios que se despliegan para los usuarios administrativos cuando se
accede al registro del cliente. Opcional.

116 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 116 17/2/10 15:20:42


Campo Tipo Descripcin
CodigoBarras varchar(20) Cdigo de barras encontrado en la tarjeta de la biblioteca del cliente. En
este momento, slo se da soporte a cdigos de barras numricos. Opcional.
Clave varchar(20) Contrasea del cliente, en formato cifrado. Obligatorio.
Email varchar(100) Direccin de correo electrnico del cliente. Opcional.
NumTel varchar(20) Nmero telefnico del cliente. Opcional.
Domicilio varchar(50) Direccin del cliente. Opcional.
Ciudad varchar(20) Ciudad del cliente. Opcional.
Estado varchar(2) Abreviatura del estado del cliente. Opcional.
CP varchar(10) Cdigo postal del cliente. Opcional.
GrupoClientes bigint Grupo en que aparece el patrn. Referencia externa a
GrupoClienteCodigo.ID. Opcional.

CopiaCliente. Esta tabla administra las copias de los artculos que se han prestado a un clien-
te, o las copias de artculos que se prestaron antes y ya se regresaron.

Campo Tipo Descripcin


ID bigint Clave principal; asignada automticamente. Obligatorio.
Cliente bigint El cliente asociado. Referencia externa a Cliente.ID. Obligatorio.
CopiaArticulo bigint La copia del artculo prestada actualmente o antes al cliente. Referencia
externa a CopiaArticulo.ID. Obligatorio.
Prestado datetime La fecha en que se prest inicialmente este artculo. Obligatorio.
Renovado smallint El nmero de veces que se ha renovado la copia de este artculo. Se asigna 0
cuando la copia del artculo se presta por primera vez. Obligatorio.
FechaVencimiento datetime Fecha de vencimiento actual para la copia de este artculo. Obligatorio.
Regresado datetime La fecha en que la copia de este artculo se regres. Opcional.
Devuelto bit Se ha devuelto la copia del artculo? 0 para False, 1 para True. Obligatorio.
Faltante bit Falta la copia del artculo y se considera perdida? 0 para False, 1 para True.
Obligatorio.
Multa money Multa total acumulada para la copia de este artculo. La opcin predeterminada
es 0.00. Un administrador puede reducir una multa acumulada. Obligatorio.
Pagado money Cantidad pagada total (en cuotas) por la copia de este artculo. Obligatorio.
FechaProceso datetime Cuando la copia de un artculo se procesa para multas vencidas, este campo
contiene la ltima fecha en que se hizo el procesamiento. Opcional.

PagosCliente. Multas, pagos y rechazos en el registro de copias de un cliente. Las multas


vencidas no se registran en esta tabla, pero las iniciadas por el administrador debido a cargos
por artculos faltantes se registran aqu.

Proyecto | 117

04_PATRICK-CHAPTER_04.indd 117 17/2/10 15:20:43


Campo Tipo Descripcin
ID bigint Clave principal; asignada automticamente. Obligatorio.
CopiaCliente bigint El artculo asociado prestado al cliente. Referencia externa a
CopiaCliente.ID. Obligatorio.
FechaEntrada datetime Fecha y hora en que se registr esta entrada. Obligatorio.
TipoEntrada varchar(1) El tipo de entrada de pago. Obligatorio. Los valores posibles son:
C = El cliente hizo un pago.
M = Una multa (diferente de las multas estndar por
vencimieto) fue impuesta por un administrador.
P = Una parte de la multa (o toda) fue perdonada.
R = Se hizo un reembolso al cliente debido a pago excesivo.
Monto money El monto asociado con esta entrada. El valor siempre es positivo. Obligatorio.
Comentario varchar(50) Un comentario corto acerca de esta entrada. Opcional.
IDUsuario bigint El usuario que agrega este evento de pago. Referencia externa a
NombreUsuario.ID. Opcional.

Tablas relacionadas con cdigo de barras


Hay tres niveles de definicin para crear un cdigo de barras: 1) la hoja en que se imprime una
cuadrcula de etiquetas; 2) una sola etiqueta en la hoja, y 3) los elementos individuales que apa-
recen en cada etiqueta. Las tres tablas de esta seccin definen esos tres niveles.
HojaCodigoBarras. Describe la plantilla para una sola pgina de etiquetas de cdigos de
barras.

Campo Tipo Descripcin


ID bigint Clave principal; asignada automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de esta plantilla de hoja. Obligatorio.
TipoUnidad varchar(1) Unidades usadas en las diversas medidas encontradas en casi todos los
campos de este registro. Obligatorio.
I = Pulgadas
C = Centmetros
P = Puntos
T = Twips
AnchoPagina decimal(10,4) Ancho de toda la pgina. Obligatorio.
AnchoPagina decimal(10,4) Altura de toda la pgina. Obligatorio.
MargenIzquierdo decimal(10,4) Borde izquierdo, hasta la orilla del rea imprimible de la etiqueta. Obligatorio.
MargenDerecho decimal(10,4) Borde derecho, hasta la orilla del rea imprimible de la etiqueta. Obligatorio.
MargenSuperior decimal(10,4) Borde superior, hasta la orilla del rea imprimible de la etiqueta. Obligatorio.
MargenInferior decimal(10,4) Borde inferior, hasta la orilla del rea imprimible de la etiqueta. Obligatorio.
EntreColumnas decimal(10,4) El ancho del rea en blanco entre las columnas de la etiqueta. Obligatorio.
EntreFilas decimal(10,4) La altura del rea en blanco entre las columnas de la etiqueta. Obligatorio.

118 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 118 17/2/10 15:20:43


Campo Tipo Descripcin
CuentaColumnas smallint El nmero de columnas de etiquetas en esta plantilla. Obligatorio.
CuentaFilas smallint El nmero de filas de etiquetas en esta plantilla. Obligatorio.

EtiquetaCodigoBarras. Describe la plantilla para una sola etiqueta en una hoja de clculo de
cdigo de barras. En una hoja puede haber cualquier nmero de etiquetas, pero todas tienen
la misma forma y el mismo formato.

Campo Tipo Descripcin


ID bigint Clave principal; asignada automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de esta plantilla de etiquetas. Obligatorio.
HojaCodigoBarras bigint La plantilla de hojas en que aparece esta plantilla. Referencia externa a
HojaCodigoBarras.ID. Obligatorio.
TipoUnidad varchar(1) Unidades usadas en las varias medidas encontradas en la mayor parte de
los campos de este registro. Obligatorio.
I = Pulgadas
C = Centmetros
P = Puntos
T = Twips

ArtEtiquetaCodBarras. Describe un solo artculo, como se encuentra en la etiqueta de cdigo


de barras. Entre los artculos se incluyen texto esttico y generado, lneas, rectngulos y
cdigos de barras generados.

Campo Tipo Descripcin


ID bigint Clave principal; asignada automticamente. Obligatorio.
Prioridad smallint Identifica el orden en que se imprimen los artculos de la etiqueta. Los
nmeros inferiores se imprimen primero. Obligatorio.
Etiqueta-Codi- bigint La plantilla de etiquetas en que aparece el artculo. Referencia externa a Eti-
goBarras quetaCodigoBarras.ID. Obligatorio.
TipoElemento varchar(1) Qu tipo de elemento representa este registro? Obligatorio.
T = Texto esttico
B = Cdigo de barras
N = Nmero de cdigo de barras
L = Lnea
R = Rectngulo
PosIzq decimal(10,4) Orilla izquierda del elemento en relacin con la orilla izquierda de la etiqueta.
Medida de acuerdo con el campo EtiquetaCodigoBarras.
TipoUnidad relacionado. Obligatorio.
PosSup decimal(10,4) Orilla superior del elemento en relacin con la orilla superior de la etiqueta.
Medida de acuerdo con el campo EtiquetaCodigoBarras.
TipoUnidad relacionado. Obligatorio.

Proyecto | 119

04_PATRICK-CHAPTER_04.indd 119 17/2/10 15:20:43


Campo Tipo Descripcin
PosAncho decimal(10,4) Ancho del elemento o del cuadro en que se dibuja el elemento. Para lneas, es la
coordenada x del extremo. Medida de acuerdo con el campo
EtiquetaCodigoBarras.TipoUnidad relacionado. Obligatorio.
PosAltura decimal(10,4) Altura del elemento o del cuadro en que se dibuja el elemento. Para lneas, es la
coordenada y del extremo. Medida de acuerdo con el campo
EtiquetaCodigoBarras.TipoUnidad relacionado. Obligatorio.
Giro smallint ngulo de giro, en grados, del cuadro en que se dibuja el elemento. Cero (0) es
igual a carencia de ngulo y los aumentos de ngulo avanzan en el sentido de
las manecillas del reloj. Rangos de 0 a 359. Slo se usa cuando
TipoElemento es T, B, N, o R. Opcional.
NombreFuente varchar(50) El nombre de la fuente para escribir el texto. Vlido slo cuando
TipoElemento es T o N. Opcional.
PuntosFuente decimal(10,4) El tamao de la fuente usada para escribir el texto. Vlido slo cuando
TipoElemento es T, B o N. Opcional.
TextoEstatico varchar(100) El texto esttico que se despliega en la etiqueta. Vlido slo cuando
TipoElemento es T. Opcional.
EstiloFuente varchar(4) El estilo del texto de la fuente. Puede ser cualquier combinacin de los siguien-
tes cuatro cdigos:
N = Negritas
I = Itlicas
S = Subrayado
T = Tachado
Deje este campo NULL para usar el estilo normal. Vlido slo cuando
TipoElemento es T o N. Opcional.
Color1 bigint El color principal del texto, cdigo de barras o lnea. Cuando se imprime un
rectngulo, es el color del borde. Si NULL, se usa negro. Un valor de color RGB
estndar de 32 bits de Windows. Opcional.
Color2 bigint El color de relleno cuando se imprime un rectngulo. Si es NULL, se usa blanco.
Un valor de color RGB estndar de 32 bits de Windows. Opcional.
Alineacion smallint La alineacin del texto dentro del cuadro que lo rodea. Vlido slo cuando
TipoElemento es T, B o N.
1 = Se alinea en la esquina superior izquierda del cuadro
2 = Se alinea en el rea central superior del cuadro
4 = Se alinea en la esquina superior derecha del cuadro
16 = Se alinea en el rea central izquierda del cuadro
32 = Se alinea en el rea central media del cuadro
64 = Se alinea en el rea media derecha del cuadro
256 = Se alinea en la esquina inferior izquierda del cuadro
512 = Se alinea en el rea inferior central del cuadro
1024 = Se alinea en la esquina inferior derecha del cuadro
DigitosRelleno smallint El nmero de dgitos en que se rellenar el nmero del cdigo de barras. Asigne
cero (0) para ignorar el relleno. Rango de 0 a 20. Si la longitud del cdigo de
barras es menor del nmero de dgitos especificados, se rellena a la izquierda
con ceros. Slo se aplica si TipoElemento es B y N.

120 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 120 17/2/10 15:20:43


Otras tablas
Dos tablas adicionales proporcionan soporte a caractersticas no manejadas mediante otras tablas.
Festivos. Cuando se presta un artculo a un cliente, la fecha de devolucin no debe caer en un
da festivo (o cualquier da que la biblioteca est cerrada), porque el cliente no tendra manera
de regresar el libro el da de vencimiento. Esta tabla define das festivos recurrentes y nicos.

Campo Tipo Descripcin


ID bigint Clave principal, asignada automticamente. Obligatorio.
NombreCompleto varchar(50) Nombre de este da festivo. No necesariamente nico. Obligatorio.
TipoEntrada varchar(1) El tipo de entrada. Obligatorio. De la siguiente lista:
A = Anual (como en cada 25 de diciembre)
S = Semanal (como en todos los domingos)
U = Una vez (como en 1/12/2006 toma de posesin del presidente)
DetalleEntrada varchar(10) Detalle especfico del tipo de entrada. Obligatorio. Difiere para cada tipo de
entrada.
Tipo de entrada Valor de detalle
A Mes y da en formato mm/dd
S Un solo dgito: 1 = Domingo hasta 7 = Sbado
U Fecha en formato aaaa/mm/dd

ValorSistema. Esta tabla almacena configuraciones diversas de toda la empresa que se aplican
a cada estacin de trabajo. Las configuraciones especficas de estaciones locales se almacenan
en cada equipo, no en la base de datos.

Campo Tipo Descripcin


ID bigint Clave principal; asignada automticamente. Obligatorio.
NombreValor varchar(50) Nombre de este valor. Obligatorio.
DatosValor varchar(100) Informacin asociada con esta entrada. Opcional.

Los siguientes valores del sistema se definen en este momento. El nombre del cdigo aparece
en el campo NombreValor. El valor correspondiente aparece en el campo DatosValor.
CodCodigoBarras39
El cdigo de barras especificado est en formato de cdigo 39 o cdigo 3 de 9?
En este caso, se colocar un asterisco antes y despus del nmero de cdigo de barras
antes de que se imprima en la etiqueta. Use un valor de 0 para False o cualquier valor
distinto de cero para True (1 es el preferido). Si se omite o es NULL, se supone False.
FuenteCodigoBarras
El nombre de la fuente usada para imprimir cdigos de barras. Esta fuente debe insta-
larse en cualquier estacin de trabajo que despliegue o imprima cdigos de barras. No
es necesario para escanear cdigos de barras.

Proyecto | 121

04_PATRICK-CHAPTER_04.indd 121 17/2/10 15:20:43


VersionBaseDatos
Cul versin estructural de la base de datos est en uso? Justo ahora, es la 1, y est
reservada para mejoras futuras.
LugarPredeterminado
Valor de LugarCodigo.ID para el lugar en que se establece como opcin predeterminada.
PeriodoGraciaMulta
Nmero de das que puede tenerse un artculo vencido sin incurrir en una multa.
SiguienteElementoCodBarras
El siguiente valor de inicio que se utilizar cuando se impriman cdigos de barras.
SiguienteVariosCodBarras
El siguiente valor de inicio que se utilizar cuando se impriman cdigos de barras di-
versos.
SiguienteClienteCodBarras
El siguiente valor de inicio que se utilizar cuando se impriman cdigos de barras de
cliente.
SalidaCliente
Indica si los clientes pueden sacar artculos sin iniciar sesin como usuarios administrati-
vos. Use un valor de 0 (cero) para indicar que no hay privilegios de prstamo, o cualquier
valor diferente de cero para permitir prstamos a clientes (1 es el preferido). Si se omite
este valor o est vaco, los clientes no podrn sacar los artculos sin ayuda administrativa.
LimiteBusqueda
Indica el nmero mximo de resultados devueltos en cada bsqueda. Si este valor se
omite o no es vlido, se usa un valor predeterminado de 250. El rango permitido est
entre 25 y 5 000, inclusive.
EncabezadoBoleta
Despliega el texto que se imprimir en la parte superior de la boleta de prstamos. To-
das las lneas estn centradas en la boleta. Incluye el carcter de barra vertical (|) para
dividir el texto en varias lneas.
PieBoleta
Despliega el texto que se imprimir en la parte inferior de las boletas de salida. Todas las
lneas estn centradas en la boleta. Incluye el carcter de barra vertical (|) para dividir
el texto en varias lneas.
UseLC
Indica si los libros estn ordenados por los nmeros de Dewey o la Biblioteca del Con-
greso (LC). Use un valor de 0 (cero) para indicar Dewey, o cualquier valor distinto de
cero para LC (1 es el preferido). Si este valor falta o est vaco, se supone Dewey.

Creacin de la base de datos


La adicin de la base de datos a SQL Server es casi tan fcil como documentarla; en reali-
dad, requiere menos escritura. Las instrucciones CREATE TABLE son sencillas y muy parecidas.

122 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 122 17/2/10 15:20:43


Mostrar aqu slo unas cuantas. El archivo Script de creacin de base de datos.sql en el directorio
de instalacin de este libro incluye el contenido completo de la secuencia de comandos.
Las instrucciones que aparecen aqu son para SQL Server 2005 Management Studio Express.
Puede realizar todas estas tareas empleando SQL Server 2005 Management Studio, o aun las he-
rramientas de lnea de comandos proporcionadas con SQL Server, pero los detalles de cada paso va-
ran. Las mismas instrucciones CREATE TABLE funcionan con cualquier herramienta que elija.
Si an no lo ha hecho, instale SQL Server 2005 Express Edition (o cualquier versin de la base
de datos que habr de usar). SQL Server 2005 Management Studio Express es un producto
separado del propio SQL Server, de modo que tambin debe instalarlo.
Casi todas las tablas del Proyecto Biblioteca son simples tablas de datos con una sola clave prin-
cipal. Su cdigo es simple. La tabla Autor es un buen ejemplo.
CREATE TABLE Autor
(
ID bigint IDENTITY PRIMARY KEY,
Apellido varchar(50) NOT NULL,
Nombre varchar(30) NULL,
Inicial varchar(30) NULL,
Sufijo varchar(10) NULL,
FechaNacimiento smallint NULL,
FechaMuerte smallint NULL,
Comentarios varchar(250) NULL
);

Los campos incluidos en cada instruccin CREATE TABLE aparecen como listas delimitadas por
comas, todo entre parntesis. Cada campo incluye una opcin NULL o NOT NULL que indica si
pueden usarse valores NULL en ese campo. La opcin PRIMARY KEY especifica automticamente
NOT NULL.
Algunas instrucciones crean tablas que vinculan otras dos tablas en una relacin varias a varias.
Un ejemplo es la tabla ActividadGrupo, que conecta la tabla NombreGrupo con Actividad.
CREATE TABLE ActividadGrupo
(
IDGrupo bigint NOT NULL,
IDActividad bigint NOT NULL,
PRIMARY KEY (IDGrupo, IDActividad)
);

La tabla Autor tiene una sola clave principal, de modo que la opcin PRIMARY KEY podra
unirse directamente a su campo ID. Debido a que la tabla ActividadGrupo tiene una clave
principal de dos campos (lo que es comn en las bases de datos relacionales), la opcin PRIMARY
KEY est especificada como una entrada propia, con los campos de clave especificados como listas
delimitadas por comas encerradas entre parntesis.
En pginas anteriores de este captulo mostr cmo podra establecerse una referencia a un cap-
tulo en otra tabla empleando las restricciones REFERENCES como parte de la instruccin CREATE
TABLE. Tambin puede establecerlas despus de que ya se han creado las tablas, como hago en
la secuencia de comandos. He aqu la instruccin que establece el vnculo entre las tablas Acti-
vidadGrupo y NombreGrupo:

Proyecto | 123

04_PATRICK-CHAPTER_04.indd 123 17/2/10 15:20:43


ALTER TABLE ActividadGrupo
ADD FOREIGN KEY (IDGrupo)
REFERENCES NombreGrupo (ID);

Como ya he escrito toda la secuencia de comandos de SQL, slo tendr que procesarla directa-
mente empleando Microsoft SQL Server 2005 Management Studio Express. (Si estar usando
la versin completa de SQL Server o alguna otra herramienta de administracin, la secuencia de
comandos proporcionada an funcionar, aunque las instrucciones paso a paso diferirn.) Antes
de agregar las tablas, necesitamos crear una base de datos especfica del Proyecto Biblioteca. Ini-
cie Microsoft SQL Server 2005 Management Studio Express (vase la figura 4-4).
Para agregar una nueva base de datos al Proyecto Biblioteca, haga clic con el botn derecho en
la carpeta Base de datos del Explorador de objetos y seleccione Nueva base de datos del men
contextual. En el formulario Nueva base de datos que aparece, ingrese Biblioteca en el campo
Nombre de la base de datos y luego haga clic en Aceptar.
La base de datos Biblioteca es una envoltura de una base de datos; no contiene tabla ni datos
an. Usaremos el archivo Script de creacin de base de datos.sql del directorio de instalacin del
libro para generar las tablas y los datos iniciales. En Management Studio Express, seleccione el
comando de men Archivo Abrir Archivo, y localice el archivo Script de creacin de base
de datos.sql. (Tal vez se le pida que vuelva a iniciar sesin en SQL Server.) Al abrir este archivo,
se coloca su contenido en un nuevo panel dentro de Management Studio Express.

Figura 4-4. El formulario principal del SQL Server 2005 Management Studio Express.

124 | Captulo 4: Diseo de la base de datos

04_PATRICK-CHAPTER_04.indd 124 17/2/10 15:20:44


Todo lo que queda es procesar la secuencia de comandos. En el rea de la barra de herramientas,
asegrese de que Biblioteca sea la base de datos seleccionada (vase la figura 4-5). Luego haga
clic en el botn Ejecutar de la barra de herramientas u oprima la tecla F5. Es una pequea se-
cuencia de comandos sin demasiado en su interior (por lo menos desde el punto de vista de SQL
Server), de modo que debe terminar en unos cuantos segundos.

Figura 4-5. Si no selecciona Biblioteca, sus tablas irn a cualquier otro lado.

Eso es todo! Cierre el panel de secuencia de comandos. Luego regrese al Explorador de objetos,
haga clic con el botn derecho en la carpeta de la base de datos Biblioteca y seleccione Actualizar
del men. Si luego expande la rama de la base de datos Biblioteca y su subrama Tablas, ver todas
las tablas creadas por la secuencias de comandos (vase la figura 4-6).
Con la base de datos hecha, es hora de empezar a programar.

Figura 4-6. Lista parcial de tablas de la base de datos.

Proyecto | 125

04_PATRICK-CHAPTER_04.indd 125 17/2/10 15:20:45


Captulo 5
Ensamblados de .NET

La mera mencin de la palabra ensamblado me transporta a los das en que entr a la prepara-
toria. El ensamblado se tena en realidad en el gimnasio de la escuela, con 2 000 adolescentes
gritones llenando las bancas alrededor de la cancha de basquetbol. Como era una funcin de
la escuela, naturalmente pensaba en una experiencia rica en frescas oportunidades educativas.
Escuela, educacin (las palabras parecen ir juntas). Pero luego vino la banda de msica y los
jugadores de futbol, y las porristas, y la mascota de la escuela (un caballo). Por los siguientes 30
minutos, el director aporre a los estudiantes en un frenes controlado, tratando de probar el
lugar de la institucin como la escuela nmero uno de la ciudad. An no s en qu rea era la
nmero uno, pero resultaba muy estimulante.
Los ensamblados de .NET no son tan estimulantes. En realidad, slo son archivos, EXE y DLL,
y sin que los active, slo estn all sentados, ocupando espacio en disco. Y mientras no estn
haciendo algo ms, tomemos un momento para examinar lo que son y lo que contienen.

Qu es un ensamblado?
Como ya lo mencion en el captulo 1, un ensamblado es una unidad de implementacin,
que en la mayora de los casos es slo un archivo. Un ensamblado es un depsito de cdigo
de aplicacin .NET compilado; cualquier cdigo que escriba con el tiempo se almacenar en
algn archivo EXE (si es una aplicacin) o DLL (para bibliotecas o extensiones de cdigo de
una aplicacin). Todo lo que .NET necesita para cargar y ejecutar su aplicacin se almacena en
el ensamblado.
Los ensamblados son privados o pblicos. Los ensamblados privados estn diseados para usarse
en una sola aplicacin. Si hay algn DLL, un ensamblado EXE es la aplicacin. Los ensamblados
privados aparecen en su propio directorio, el directorio de instalacin de la aplicacin o biblio-
teca. Puede ejecutar dos diferentes ensamblados privados al mismo tiempo y no se molestarn
entre s. Esto es verdadero, aunque cada ensamblado usa la misma combinacin de espacio de
nombre y nombres de clase para sus elementos codificados. Si dos ensamblados de aplicacin
implementan una clase denominada WindowsAplicacin1.Class1, no interferirn entre s
cuando se ejecuten; son privados, y privado significa privado.

126

05_PATRICK-CHAPTER_05.indd 126 17/2/10 15:21:17


Los ensamblados pblicos estn diseados para compartir entre varias aplicaciones .NET. Los
ensamblados pblicos difieren de los privados de dos maneras importantes:
Los ensamblados pblicos siempre tienen un nombre fuerte, una firma digital cifrada que
est adjunta a un ensamblado para garantizar que proviene de su vendedor o fuente con
nombre. (Los ensamblados privados tambin pueden incluir un nombre fuerte, pero no
lo tienen.) El nombre fuerte est construido a partir del nombre del ensamblado, el n-
mero de versin, la informacin de cultura, una clave pblica y una firma digital genera-
da a partir del archivo de ensamblado que contiene el manifiesto (descrito ms adelante).
.NET Framework incluye una herramienta de generacin de nombre fuerte (sn.exe) que
ayuda en este proceso, y Visual Studio incluye opciones que le permiten agregar una firma
digital durante el proceso de compilacin. (Est en la ficha Firma, de las propiedades del
proyecto.)
El nombre fuerte de un ensamblado debe ser nico (y mejor que lo sea); si dos ensamblados
comparten un nombre fuerte comn, son copias del mismo ensamblado.
Los ensamblados pblicos estn almacenados en la cach global de ensamblados (GAC,
Global Assembly Cache). Aunque puede poner una copia de su componente compartido
en el directorio de instalacin de su aplicacin, slo ser realmente compartido una vez que
alcanza el directorio GAC. La GAC vive en un directorio llamado assembly dentro del direc-
torio Windows de la computadora. (En mi sistema, est en c:\windows\assembly.) Una vez
que un ensamblado de .NET tiene aplicado un nombre fuerte, puede agregarlo a la GAC al
arrastrar el archivo al directorio assembly o empleando la herramienta de la cach global de
ensamblado (gacutil.exe). No se preocupe de que su archivo est solo si no se est comuni-
cando con sus otros archivos instalados. En mi recin instalada copia de .NET encontr casi
400 en el directorio GAC, incluidos todos los DLL de las bibliotecas de clases del marco
conceptual (FCL, Framework Class Libraries).
.NET le permite instalar varias versiones de un ensamblado en un sistema y usarlos al mismo
tiempo (un proceso llamado uso de versin). Esto se emplea en aplicaciones (EXE) y bibliotecas
(DLL), y para ensamblados privados y compartidos en la GAC. No me cree? Abra la carpeta
assembly de la GAC, establezca la carpeta del Explorador en la vista Detalles y luego ordene por
Nombre de ensamblado. Si se desplaza hacia abajo, ver que un mismo archivo se muestra varias
veces. En la figura 5-1 se muestra una parte de la cach. Dos copias de Microsoft.VisualStudio.
Windows.Forms aparecen en la lista (del archivo Microsoft.VisualStudio.Windows.Forms.dll),
uno con un nmero de versin 2.0 y otro con la versin 9.0.
Aunque suele haber una relacin una a una entre archivos y ensamblados, puede haber casos
en que un ensamblado est integrado por varios archivos. Por ejemplo, una aplicacin podra
incluir archivos grficos externos en su vista del ensamblado. .NET mantiene una vigilancia
estrecha de esos archivos. Si cualquiera de los archivos se modifica, elimina o de alguna otra
manera se mutila, lo sabr. Para los fines del anlisis, en el resto del captulo slo se consideran
ensamblados de un solo archivo.

Qu es un ensamblado? | 127

05_PATRICK-CHAPTER_05.indd 127 17/2/10 15:21:17


Figura 5-1. La GAC tiene sus duplicaciones bajo control.

Qu hay dentro de un ensamblado?


El archivo EXE o DLL de un ensamblado es un archivo de ejecucin porttil (PE, Portable Exe-
cution), el mismo formato de archivo usado para ejecutables que no son de .NET y para biblio-
tecas de cdigo (muy parecido a cualquier archivo EXE o DLL de Windows). Lo que diferencia a
los archivos PE de .NET son todos los elementos adicionales que se encuentran en su interior. Por
regla general, la palabra ensamblado indica una reunin de varias partes en una sola unidad. En un
ensamblado .NET, estas varias partes estn diseadas especficamente para uso con .NET.
Un archivo PE de .NET contiene tres partes principales:
Un encabezado PE
Obligatorio para todos los archivos PE files, en esta seccin se identifican las ubicaciones de
las dems secciones del archivo.
La seccin del cdigo MSIL
El cdigo real asociado con el ensamblado se almacena en cdigo de lenguaje intermedio de
Microsoft (MSIL, Microsoft Intermediate Lenguaje) semicompilado. Por desgracia, el chip
Intel o AMD de su equipo est, al parecer, demasiado descerebrado como para procesar
directamente el cdigo MSIL (qu estaban pensando?), de modo que .NET Framework in-
cluye un compilador justo a tiempo (JIT, Just-In-Time) que puede convertir MSIL a cdigo
nativo x86 en cuestin de momentos.
La seccin de metadatos
Todo el detalle extra en que .NET necesita hurgar para saber si su ensamblado aparece en
esta seccin esencial. Algunos de estos elementos, cuando se toman en conjunto, integran el
manifiesto del ensamblado, un tipo de documento que describe por completo el ensambla-
do al mundo. En la siguiente lista de elementos de metadatos he indicado cules elementos
aparecen en el manifiesto:

128 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 128 17/2/10 15:21:18


El nombre del ensamblado
(Parte del manifiesto.) Esto se define en la ficha Aplicacin de las propiedades del pro-
yecto.
El nmero de versin del ensamblado
(Parte del manifiesto.) Es el nmero de versin de cuatro partes, como en 1.2.3.4. Proba-
blemente se ha preguntado todo el da cmo podra establecer este nmero en sus propios
proyectos. Su paciencia se ver recompensada en la seccin Proyecto de este captulo,
donde demostrar no slo una, sino dos maneras de establecer el nmero de versin del
ensamblado.
Contenido de nombre fuerte
(Parte del manifiesto.) Esto incluye la clave pblica del editor.
Parmetros de cultura y lenguaje
(Parte del manifiesto.) Esto es especialmente til cuando necesita crear archivos de recursos
especficos del lenguaje.
Listado de archivos del ensamblado
(Parte del manifiesto.) Los ensamblados de un solo archivo nicamente mostrarn el nom-
bre del archivo EXE o DLL, pero algunos ensamblados pueden incluir varios archivos
en esta seccin. Todos los archivos de un ensamblado deben aparecer dentro del mismo
directorio, o en un directorio subordinado al archivo de ensamblado que contiene el ma-
nifiesto.
Informacin exportada de tipo
(Parte del manifiesto.) Algunos ensamblados exportan algunos de sus tipos para uso fuera
de la aplicacin. Aqu aparecen los detalles de esos tipos.
Referencias
(Parte del manifiesto, pero en ensamblados de varios archivos, cada uno contendr su propia
lista de referencias.) Los metadatos incluyen un listado de todos los ensamblados externos a
los que hace referencia su aplicacin, sean privados o aparezcan en la GAC. Esta lista indica
cul destino especfico de la versin, cultura y plataforma del ensamblado externo espera su
ensamblado.
Informacin interna de tipo
(No es parte del manifiesto.) Todos los tipos creados en su ensamblado estn descritos por
completo dentro de los metadatos. Adems, cualquier metadato adicional que agregue a sus
tipos mediante la consulta de atributos de Visual Basic aparece aqu.
En ensamblados de varios archivos, el manifiesto de elementos especficos slo aparece en el
archivo principal del ensamble.
El manifiesto es un subconjunto de los metadatos dentro de su ensamblado. Odio decir que es
la parte ms importante de los metadatos, pero lo es. El manifiesto es la expresin pblica de
su ensamblado y la nica manera en que .NET sabe si es legtimo. Es una especie de etiqueta
de Caractersticas nutricionales colocadas en los paquetes de comida (vase la figura 5-2).

Qu hay dentro de un ensamblado? | 129

05_PATRICK-CHAPTER_05.indd 129 17/2/10 15:21:18


Cantidad por
ensamblado
Tamao de la porcin 1 ensamblado
Archivos por ensamblado 1
Cantidad por ensamblado
Tipos exportados 12
% de valor diario*
Referencias 5 50%
Culturas 3 300%
Versin 1.0.0.4

Vitamina VB 100%
Vitamina C# 0%
* Los valores de porcentaje diarios estn basados
en una Pentium 4 con una memoria de 1 GB.
Sus necesidades diarias pueden ser menores,
pero lo dudo.

Figura 5-2. Realmente es bueno para m?

Cuando revisa la etiqueta del alimento, sabe lo que contiene el paquete de comida (aunque nadie
sabe en realidad lo que es la riboflavina). Cuando revisa el manifiesto de un ensamblado, sabe de
un vistazo lo que contiene el ensamblado y cules requisitos incluye antes de que pueda cargarse
y ejecutarse.
Aun antes de que .NET entre en escena, los ejecutables y las bibliotecas ya contenan algunos
metadatos, como el nmero de versin del archivo. Pero estos datos no se usaban para admi-
nistrar acceso entre componentes de software, ni estaban organizados de una manera genrica y
extensible. Los metadatos en .NET encarnan todos estos atributos.
La presencia de MSIL y metadatos en cada ensamblado hace que estos archivos sean muy legibles
y comprensibles. Con las herramientas correctas, incluso yo las puedo entender. Y si yo puedo,
cualquiera puede, lo que lleva a un gran problema. Las compaas invierten gran cantidad de
tiempo y dinero en sus esfuerzos de desarrollo de software, y no quieren que cualquier persona
con un poco de ingenio use ingeniera inversa en su cdigo y obtenga todos sus algoritmos se-
cretos. Para evitar esta lectura casual de cualquier aplicacin .NET, Microsoft y otros incluyen
obfuscadores, programas de software que revuelven el contenido de un ensamblado slo suficiente
para que sea difcil de comprender para los seres humanos, pero no para .NET Framework. Ha-
blar ms sobre la obfuscacin en el captulo 22.

130 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 130 17/2/10 15:21:18


Reflejo
Tal vez sea algo malo que las personas accedan a un ensamblado, pero es estupendo cuando el
cdigo de un ensamblado puede acceder al mismo. .NET incluye una caracterstica llamada
reflejo que le permite examinar el contenido de un ensamblado. Por lo general, usted utiliza esta
caracterstica para acceder a los metadatos en su propio ensamblado, pero tambin funciona con
cualquier ensamblado disponible. La mayor parte de las caractersticas relacionadas con el reflejo
aparecen en el espacio de nombres System.Reflection.
Mediante el reflejo, puede extraer casi cualquier cosa almacenada en los metadatos de un ensam-
blado, incluidos detalles de todos los tipos, sus miembros e incluso los parmetros incluidos con
miembros de funciones. Por esto la obfuscacin es tan importante para los vendedores; entre el
MSIL compilado y los metadatos, puede regenerar casi todo el cdigo fuente de una aplicacin
a partir de su ejecutable. El cdigo fuente estara en MSIL, pero sera difcil que alguien regrese
gran parte de l a Visual Basic o C#.

Ensamblados y aplicaciones
Las aplicaciones de .NET (archivos EXE) son una instancia de un ensamblado. Pero una sola
aplicacin puede incluir varios ensamblados; en realidad, casi siempre lo hace. Escrib un pe-
queo programa que usa reflejo para presentar todos los ensamblados que est usando el propio
programa. Le di al programa el nombre predeterminado WindowsAplicacin1. Cuando ejecuto
el programa contra s mismo, gener la siguiente lista:
mscorlib
Microsoft.VisualStudio.HostingProcess.Utilities
System.Windows.Forms
System
System.Drawing
Microsoft.VisualStudio.HostingProcess.Utilities.Sync
Microsoft.VisualStudio.Debugger.Runtime
vshost
System.Data
System.Deployment
System.Xml
System.Core
System.Xml.Linq
System.Datos.DataSetExtensions
Microsoft.VisualBasic
WindowsAplicacin1
System.Runtime.Remoting

Guau! Diecisiete ensamblados, incluido WindowsAplicacin1, el programa principal. La mayor


parte de los ensamblados son DLL proporcionados por .NET Framework. Para Microsoft.
VisualBasic, es el ensamblado Microsoft.VisualBasic.dll; para System, es el ensamblado System.
dll. Todos los ensamblados (excepto el ensamblado principal del programa) son bibliotecas com-
partidas de la GAC. La aplicacin tambin puede dar soporte a ensamblados privados cargados
de archivos DLL locales.

Ensamblados y aplicaciones | 131

05_PATRICK-CHAPTER_05.indd 131 17/2/10 15:21:18


.NET Framework carg automticamente estos ensamblados cuando se inici WindowsAplica-
cin1; supuso cules son los necesarios al revisar el manifiesto de WindowsAplicacin1. Cuando
el marco conceptual carg cada ensamblado, revis si esos ensamblados, a su vez, necesitaban
cargar ensamblados adicionales, etctera. Muy pronto, su aplicacin una vez simple se vuelve un
terreno frtil para volcar ensamblados de toda la GAC. Pero eso est correcto, porque el prop-
sito de .NET consiste en administrarlos todos.

El espacio de nombres My y los ensamblados


.NET Framework, con sus miles de clases, contiene gran cantidad de lgica empaquetada que
puedo usar en mis propios programas. Pero no tengo memorizados todos los ensamblados y sus
clases (an) y toma tiempo recorrer la documentacin de la FCL. Con tantas clases disponibles,
en ocasiones sufro cuando pienso en el esfuerzo que har para encontrar la clase o caracterstica
que necesito para realizar alguna tarea de desarrollo.
Por fortuna, no soy el nico que piensa de esa manera; Microsoft est de acuerdo conmigo.
Histricamente, los programadores de Visual Basic fueron protegidos de las complejidades del
desarrollo de aplicaciones de Windows. No que fuera necesario; todos sabemos que los desarro-
lladores de Visual Basic estn, por lo general, un poco arriba del resto. Pero haba que contender
con el lema de Visual Basic: Facilitar y acelerar el desarrollo de Windows. Y no es rpido ni fcil
llamar a algn mtodo esotrico en las profundas entraas del espacio de nombres System slo
para obtener una pieza menor de datos.
Para conseguir algn parecido con la placentera experiencia previamente disponible en el desa-
rrollo de Visual Basic, Microsoft introdujo el espacio de nombres pretendido My en su versin
2005 del lenguaje. El espacio de nombres pretendido My recolecta gran cantidad de caractersti-
cas tiles de toda la FCL y las organiza en una jerarqua mucho ms pequea para acceso simple
y directo. Mencion brevemente My en el captulo 1, pero ahora es un buen momento para echar
un vistazo de cerca a lo que hace.
El espacio de nombres pretendido My tiene un aspecto muy parecido a otros espacios de nombres,
como System, System.Reflection y System.Windows.Forms. Pero no es, en realidad,
un espacio de nombres (es pretendido!). Por algo no pude usar la palabra clave Imports para
crear accesos directos a ramas dentro de su jerarqua. Adems, algunas secciones de la jerarqua
son dinmicas; cambian a medida que su proyecto se transfigura. En la tabla 5-1 se presentan los
principales nodos de la jerarqua.

132 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 132 17/2/10 15:21:18


Tabla 5-1. Nodos principales en la jerarqua del espacio de nombres My.

Rama Caractersticas disponibles


My.Aplication Proporciona informacin acerca de la aplicacin actual, incluidos parmetros de cultura y el
mtodo de implementacin.
My.Aplication.Info Da detalles adicionales acerca de la aplicacin y su ensamblado, incluidos el nombre y la
versin.
My.Aplication.Log Le permite generar salida de traza y registro para destinos registrados. Slo se usa con aplica-
ciones cliente.
My.Computer Proporciona acceso a recursos generales localizados en la computadora local.
My.Computer.Audio Reproduce sonidos con nombre y del sistema a travs de las bocinas de la computadora.
My.Computer.Clipboard Recupera datos del portapapeles del sistema y le permite agregar sus propios datos al portapa-
peles en diversos formatos predefinidos y personalizados.
My.Computer.Clock Obtiene la fecha y la hora actuales del sistema dispuestos en diversas maneras.
My.Computer.FileSystem Proporciona herramientas para examinar y manipular archivos y directorios en sistemas de
archivos locales o en red.
My.
Computer.FileSystem. Hace referencia a carpetas de Windows como Documentos, Escritorio y Temp.
SpecialDirectories
My.Computer.Info Proporciona informacin acerca del sistema operativo instalado y otros recursos locales del
sistema.
My.Computer.Keyboard Expone el estado actual del teclado y sus claves.
My.Computer.Mouse Hace disponibles unas cuantas propiedades del ratn de la computadora local.
My.Computer.Network Informa acerca de la disponibilidad de la red y proporciona caractersticas para interactuar con
esa red.
My.Computer.Ports Le permite interactuar con los puertos seriales del sistema.
My.Computer.Registry Lee y escribe claves y valores del registro.
My.Forms Presenta una coleccin dinmica de todos los formularios definidos en la aplicacin. Este nodo
slo est disponible para aplicaciones de Windows Forms.
My.Log Le permite generar salida de traza y registro para destinos registrados. Slo se usa con aplica-
ciones de ASP.NET.
My.Request Este objeto es similar al antiguo objeto Request de pginas activas de servidor (ASP, Active
Server Pages). Slo est disponible en aplicaciones de ASP.NET.
My.Resources Proporciona acceso dinmico a recursos especficos de la aplicacin o de los datos locales de
configuracin incluidos con la aplicacin.
My.Response Este objeto es similar al antiguo objeto Response de las pginas activas de servidor. Slo
est disponible en aplicaciones de ASP.NET.
My.Settings Proporciona acceso dinmico al sistema de configuracin de la aplicacin.
My.User Identifica al usuario actual de Windows, incluida informacin de autentificacin.
My.WebServices Presenta una coleccin de servicios Web disponibles para usar en la aplicacin. Este nodo no
est disponible en aplicaciones de ASP.NET.

El espacio de nombres My y los ensamblados | 133

05_PATRICK-CHAPTER_05.indd 133 17/2/10 15:21:19


El espacio de nombres My incluye gran cantidad de caractersticas que usar de manera regular,
incluido el acceso al nmero de versin de la aplicacin. En lugar de escribir System.Reflection.lo-
quesea para obtener el componente principal del nmero de versin, ahora basta con escribir:
My.Aplication.Info.Version.Major

Necesita una lista de ensamblados, pero le da pereza escribir la palabra Reflection? Pruebe:
My.Aplication.Info.LoadedAssemblies

Necesita saber la hora correcta en Inglaterra?


My.Computer.Clock.GmtTime

Puede comunicarse en la red de rea local?


My.Computer.Network.IsAvailable

Quin est ejecutando esta computadora?


My.User.Name

No hay demasiado en el espacio de nombres My que no pueda hacer con las FCL estndar. In-
cluso hay algunas partes de My que son repeticiones de caractersticas ya incluidas en el lenguaje
Visual Basic, aunque con algunas mejoras. Por ejemplo, Visual Basic incluye un comando Kill
que le permite eliminar archivos. El mtodo My.Computer.FileSystem.DeleteFile tambin
elimina archivos, pero ofrece opciones adicionales, incluida una que le permite enviar el archivo
a la Papelera de reciclaje en lugar de slo perderlo para siempre.

Directivas y ensamblados
Las directivas son como instrucciones de Visual Basic (pero una vez ms, no lo son). Las dos
directivas clave (#Const e #If) proporcionan instrucciones al compilador sobre la manera de
manejar un bloque de cdigo fuente de Visual Basic. (Una tercera directiva, #Region, ayuda
a presentar visualmente el cdigo fuente dentro de Visual Studio, pero no tiene impacto en
el compilador o la aplicacin compilada final.) Mediante el uso de directivas, puede indicar al
compilador que incluya o excluya fragmentos especficos de cdigo fuente del proyecto final. De
modo que en realidad no se trata de instrucciones de cdigo fuente de Visual Basic, pero estn
disponibles en ste.
Por qu querra incluir o excluir cdigo de una aplicacin? Bueno, puedo pensar en varias razo-
nes, algunas de las cuales incluyen a la CIA y al ex director de la Reserva Federal de Estados Uni-
dos, Alan Greenspan. Pero el uso ms comn es cuando quiere producir dos versiones diferentes
de su aplicacin, con base en alguna condicin. Por ejemplo, puede vender una versin exprs
y una profesional de un producto. Gran parte del cdigo es idntico para las dos versiones,
pero la profesional incluira caractersticas no disponibles en la versin exprs. Adems, esta
ltima podra incluir una presentacin simplificada de una caracterstica que tiene un uso ms
complejo en la edicin profesional.

134 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 134 17/2/10 15:21:19


Algunos productos de software satisfacen esta necesidad al usar condiciones estndar de Visual
Basic.
If (VersionProfesional = True) Then
CaracteristasDelShowBis()
Else
CaracteristicasRisibles()
End If

Esto, por supuesto, funciona bien. Pero la aplicacin exprs an contendr todas las caracters-
ticas mejoradas. Como no puede acceder a ninguna parte de ese cdigo, por qu incluirla en la
instalacin del CD? Si usa directivas, puede marcar ese problema como resuelto. Las directivas
usan expresiones condicionales, de manera parecida a la condicin versionProfesional =
True del bloque de cdigo anterior. Pero estn definidos con la instruccin #Const y se les
denomina constantes de compilador.
#Const versionCompleta = True

Esta instruccin define una constante de compilador booleano. La constante slo puede usarse
con directivas; si trata de usar versionCompleta en una instruccin estndar de Visual Basic,
el compilador se quejar. Pero funcionar bien en la directiva #If.
#If (versinCompleta = True) Then
CaracteristasDelShowBis()
#Else
CaracteristicasRisibles()
#End If

Este cdigo se parece mucho al bloque de cdigo anterior, pero con el signo # agregado. Tiene
el mismo aspecto, pero no lo es. Con la instruccin If simple, el siguiente cdigo se compila en
la aplicacin final:
If (versionProfesional = True) Then
CaracteristasDelShowBis()
Else
CaracteristicasRisibles()
End If

Vaya, el bloque completo de cdigo. Pero lo que se incluye con las directivas en la aplicacin
compilada depende del valor de versionCompleta. Si versionCompleta is True, esto se com-
pila en la siguiente aplicacin compilada:
CaracteristasDelShowBis()

Las otras cuatro lneas han desaparecido; se esfumaron en el aire, como si nunca hubieran
existido. Pero en este caso, es algo bueno. El objetivo era tener una versin del ensamblado com-
pletamente dedicada al cdigo no deseado, y es lo que sucedi.
Para establecer la constante de compilador versionCompleta para generar la versin completa,
se incluye esta lnea en la parte superior de cada archivo de cdigo fuente que incluya bloques
de cdigo condicionales #If:

Directivas y ensamblados | 135

05_PATRICK-CHAPTER_05.indd 135 17/2/10 15:21:19


#Const versionCompleta = True

Cuando est listo para generar la versin exprs, slo cambie cada una de estas lneas a su
contraparte False:
#Const versionCompleta = False

De alguna manera, cambiar esta lnea en cada archivo de cdigo fuente que lo necesite parece mucho
trabajo. Y qu pasa si olvido definir en una de ellas la versin correcta? Nada bueno, se lo aseguro.
Para evitar que los desarrolladores en Visual Basic recorran los pasillos gritando ms de lo nor-
mal, Visual Studio proporciona unas cuantas maneras diferentes de establecer constantes de
compilador y hacer que se usen en cada parte de la aplicacin. La manera ms comn de hacerlo
es mediante el panel Compilar, de las propiedades del proyecto (vase la figura 5-3). Haga clic
en el botn Opciones de compilacin avanzadas y luego agregue sus constantes de compilador
global al campo Constantes personalizadas.

Figura 5-3. Esto es ms fcil que escribirlo todo.

Ahora, al agregar versionCompleta = True o versionCompleta = False a este campo,


puede construir diferentes versiones de la aplicacin. El compilador de Visual Basic tambin
proporciona caractersticas que le permiten establecer diferentes secuencias de comandos de
compilacin para su proyecto. No hablar de esto en el libro, pero puede leer acerca de la herra-
mienta MSBuild en la documentacin Visual Studio, si necesita este nivel de control.
Adems de booleanas, las constantes de compilador pueden ser nmeros y cadenas. El entorno de
Visual Studio tambin define algunas constantes de compilador. Las constantes DEBUG y TRACE
son True o False con base en las casillas de verificacin Definir constante DEBUG y Definir
constante TRACE que aparecen en la figura 5-3. La constante VBC_VER identifica la versin del
compilador de Visual Basic que se est usando; est establecida en 9.0 en Visual Basic 2008.

Resumen
Los ensamblados no slo son archivos EXE o DLL bien lavados; contienen muchos metadatos,
incluido el manifiesto, que permiten que las aplicaciones de .NET se describan por s solas. El
compilador usa esta informacin para configurar correctamente y procesar el cdigo MSIL ad-
ministrado en cada ensamblado.

136 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 136 17/2/10 15:21:19


Aunque en realidad no son partes de un ensamblado, en este captulo tambin se analiz el es-
pacio de nombres My y las directivas, dos caractersticas de Visual Basic que tienen impacto en lo
que se incluye en su ensamblado.

Proyecto
En este captulo se da la patada oficial de inicio del proyecto Biblioteca (aplauso). Empezaremos
con algo simple: construir el formulario AcercaDe que proporciona informacin bsica respecto
a la aplicacin, incluido su nmero de versin.

ACCESO AL PROYECTO
Cargue el proyecto Cap05 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap05 (Final) cdigo.

Nuestro objetivo es un formulario placentero que comunique informacin bsica acerca del
programa, un formulario que se parezca al de la figura 5-4.

Figura 5-4. Todo lo que quera saber acerca del programa.

Como cualquier aplicacin de Visual Basic para Windows, la creacin de este formulario incluye
dos pasos: 1) adicin de controles al formulario, y 2) escritura del cdigo relacionado.

Proyecto | 137

05_PATRICK-CHAPTER_05.indd 137 17/2/10 15:21:20


Adicin de controles
Si en algn rea Visual Basic resulta excelente, es en la creacin de formularios. Es posible crear
programas con slo arrastrar y colocar los controles preconstruidos en la superficie de un formulario
preconstruido. Se hace dentro de la comodidad y la conveniencia del entorno integrado de desarrollo
(IDE, Integrated Development Environment) de Visual Studio, como se muestra en la figura 5-5.

A C

Figura 5-5. El entorno de Visual Studio.

El entorno desplegado incluye cuatro reas clave, que estn etiquetadas con letras en la figura 5-5:
A. El Cuadro de herramientas
Esta lista de controles incluye no slo controles de despliegue, sino tambin controles que
no exponen una interfaz de usuario especfica, como el Timer. (Si no ve el Cuadro de he-
rramientas, seleccione el comando de men Ver Cuadro de herramientas.) Para agregar
un control a un formulario, haga doble clic en el control en el Cuadro de herramientas,
arrstrelo del Cuadro de herramientas al formulario, o dibuje el control en el formulario
despus de seleccionarlo en el Cuadro de herramientas.
B. La superficie del formulario
Coloque aqu cualquier control que exponga una interfaz de usuario. El formulario es WY-
SIWYG, de modo que puede ver el resultado final mientras disea el formulario.

138 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 138 17/2/10 15:21:21


C. El Explorador de soluciones
Aqu aparecen todos los archivos relacionados con su proyecto. En el caso del proyecto
actual, slo ver la entrada My Proyect y una entrada para el formulario, Form1.vb. En
realidad hay ms archivos. Si hace clic en el segundo botn de la izquierda, en la parte
superior del Explorador de soluciones, se mostrarn archivos adicionales, casi todos ellos
administrados por Visual Studio.
D. El panel Propiedades
Cuando selecciona un control en la superficie de su formulario, o la propia superficie del
formulario, o un elemento del Explorador de soluciones, las propiedades del elemento se-
leccionado aparecen en esta rea. Puede modificar los parmetros de muchas propiedades al
escribir los nuevos parmetros. Algunas propiedades incluyen herramientas especiales para
ayudarle a establecer el valor de propiedad.
Si an no lo ha hecho, abra el formulario Form1.vb en la vista diseo al hacer clic en el Explorador
de soluciones. Agregaremos ocho etiquetas de texto, tres elementos de forma y lnea, dos hipervn-
culos estilo Web, un botn de comandos y una imagen de la superficie del formulario. Ya he agre-
gado la imagen al formulario, con una ilustracin de algunos libros, llamada ImagenLateral.
Configure el formulario al ajustar las siguientes propiedades a partir de sus opciones predetermi-
nadas. Haga clic en la superficie del formulario y luego modifique estos valores de propiedades
utilizando el panel Propiedades.

Propiedad Configuracin
(Name) ProgramaAcercaDe
ControlBox False
FormBorderStyle FixedDialog
Size 440, 311
StartPosition CenterScreen
Text Acerca del Proyecto Biblioteca

A continuacin, agregue las ocho etiquetas de texto bsicas a la superficie del formulario, em-
pleando el control Label. Encontrar este control en el Cuadro de herramientas. A medida que
agregue cada control Label, use la lista siguiente de parmetros para establecer las propiedades
de cada etiqueta. El texto incluido coincide con mi situacin, pero sintase con la libertad de
modificar el contenido, como sea necesario.

Nombre de la etiqueta Valores de la propiedad


NombrePrograma (Name): NombrePrograma
AutoSize: True
Font/Bold: True
Location: 136, 16
Text: El Proyecto Biblioteca

Proyecto | 139

05_PATRICK-CHAPTER_05.indd 139 17/2/10 15:21:21


Nombre de la etiqueta Valores de la propiedad
VersionPrograma (Name): VersionPrograma
AutoSize: True
Location: 136, 32
Text: Versin X.Y Revisin Z
InfoLicencia (Name): InfoLicencia
AutoSize: False
Location: 136, 48
Size: 280, 32
Text: Sin licencia
DesarrolladoPor (Name): DesarrolladoPor
AutoSize: True
Location: 136, 88
Text: Desarrollado por
NombreDesarrollador (Name): NombreDesarrollador
AutoSize: True
Location: 160, 112
Text: Tim Patrick
LibroDesarrollador (Name): LibroDesarrollador
AutoSize: True
Location: 160, 128
Text: Programacin en Visual Basic 2008
ProyectoDesarrollador (Name): ProyectoDesarrollador
AutoSize: True
Location: 160, 144
Text: Proyecto en el libro
CopyrightEmpresa (Name): CopyrightEmpresa
AutoSize: True
Location: 136, 208
Text: Copyright (c) 2008 por Tim Patrick.

Agreguemos algunas lneas y secciones coloridas al formulario. Visual Basic 6.0 incluye distintos
controles de forma para lneas, rectngulos y elipses que se podan aplicar directamente a la su-
perficie del formulario. .NET ya no incluye estos elementos; tiene que agregarlos manualmente
empleando comandos de dibujo especificados por cdigo fuente.* Pero podemos simular lneas
y rectngulos usando el control Label estndar, sin el texto.

* Microsoft ofrece controles de lnea y forma como parte de sus Power Packs para Visual Basic 2005. Los encontrar en el rea
de descarga del Microsofts Visual Basic Development Center, localizado en http://msdn.microsoft.com/vbasic. Al momento
de escribir esto, las ediciones 2008 de los Power Packs an no estaban disponibles, pero las versiones 2005 probablemente
funcionarn bien con Visual Basic 2008.

140 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 140 17/2/10 15:21:21


Nombre de etiqueta Valores de propiedades
Divisorversion (Name): Divisorversion
AutoSize: False
BackColor: Black
Location: 136, 80
Size: 280,1
Text: [No agregar ningn texto]
FondoLateral (Name): FondoLateral
AutoSize: False
BackColor: White
Location: 0, 0
Size: 120, 296
Text: [No agregar ningn texto]
DivisorFondo (Name): DivisorFondo
AutoSize: False
BackColor: Black
Location: 120, 0
Size: 1, 296
Text: [No agregar ningn texto]

Si la etiqueta FondoLateral oculta la imagen, haga clic con el botn derecho en la etiqueta y
seleccione Enviar al fondo, del men contextual que aparece.
El control LinkLabel es similar al control Label ms bsico, pero puede incluir vnculos en
el texto, secciones en que es posible hacer clic que son similares a los vnculos de una pgina
Web. Los usaremos para desplegar la direccin del sitio Web y de correo electrnico. Agregue
dos controles LinkLabel al formulario y use los siguientes valores para configurar las propiedades
de cada control.

Nombre del LinkLabel Valores de la propiedad


WebEmpresa (Name): WebEmpresa
AutoSize: True
LinkBehavior: HoverUnderline
Location: 160, 160
Text: http://www.timaki.com
EmailEmpresa (Name): EmailEmpresaz
AutoSize: True
LinkBehavior: HoverUnderline
Location: 160, 176
Text: tim@timaki.com

El control final que se agregar es un botn que le permite al usuario cerrar el formulario. Agre-
gue un control Button al formulario con las siguientes propiedades.

Proyecto | 141

05_PATRICK-CHAPTER_05.indd 141 17/2/10 15:21:21


Nombre de Button Valor de la propiedad
AccCerrar (Name): AccCerrar
DialogResult: Cancel
Location: 344, 240
Size: 80, 24
Text: Cerrar

Es posible configurar los formularios para que al oprimir la tecla Esc se dispare un control
Button en el formulario, como si el usuario estuviera haciendo clic en el botn en lugar de
oprimir la tecla Esc. Para esto, haga clic en la superficie del formulario y luego establezca la
propiedad CancelButton en AccCerrar. Tenemos que demorar este paso hasta que el botn
se agregue realmente al formulario; la propiedad CancelButton no permitir un valor para un
botn no existente.
Bueno, el formulario debe verse bien por ahora. Lo ltimo que me gusta hacer es configurar el orden
de tabulacin, el orden en que el usuario accede a cada componente del formulario cuando se presio-
na la tecla Tab en el teclado. Para editar el orden de tabulacin, seleccione la superficie del formulario
y luego seleccione el comando de men Ver Orden de tabulacin. Cada control del formulario al
que puede darse un orden de tabulacin de pronto tendr un nmero de orden a un lado. Haga clic
en cada nmero o control en orden hasta que tenga el orden que desea. (Vase la figura 5-6 para co-
nocer cmo orden los controles.) Por ltimo, seleccione de nuevo el comando de men Ver Or-
den de tabulacin una vez ms, o presione la tecla Esc para dejar el proceso de orden de tabulacin.

Figura 5-6. Agradable y ordenado.

Tambin puede establecer el orden de tabulacin para cada control al modificar su propiedad
TabIndex, empleando el sistema de nmero basado en cero. Sin embargo, suele ser ms rpido
establecer estos valores al hacer clic en cada control en orden.

142 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 142 17/2/10 15:21:22


Adicin del cdigo al formulario
Ahora es momento de agregar algn cdigo real de Visual Basic. Esto no significa que no haya-
mos agregado ninguno hasta ahora. Todo lo que hicimos en el formulario, aunque no vimos que
sucediera, se convirti en cdigo fuente de Visual Basic. Echemos un vistazo. En el Explorador
de soluciones, haga clic en el botn Mostrar todos los archivos, el segundo botn de la izquier-
da. Cuando aparezcan todos los archivos, haga clic en el signo ms que se encuentra junto a
Form1.vb y por ltimo haga doble clic en Form1.Designer.vb (vase la figura 5-7).
Como es un placer de ms de 200 lneas de cdigo fuente, no lo imprimir aqu. Pero revselo;
es muy interesante. Mientras arrastraba y colocaba controles en el formulario y modificaba sus
propiedades, Visual Studio editaba este archivo. Es parte de su clase de formulario (todos los
formularios son clases que derivan de System.Windows.Forms.Form). Puede saberlo por la
palabra clave Partial en la parte superior.
Partial Public Class ProgramaAcercaDe
Inherits System.Windows.Forms.Form

Click here

Then here
Double-click here

Figura 5-7. Acceso al cdigo oculto, secreto, prohibido, s, ah est!

Casi toda la accin se da en el procedimiento InitializeComponent. Cuando haya terminado


de revisarlo, cierre el cdigo del diseador y regrese a la superficie del formulario. Para que nues-
tro formulario sea real e interesante, necesitamos hacer tres cosas:
Mostrar la versin real del nmero de la aplicacin. Esto debe determinarse y desplegarse
justo cuando aparece el primer formulario.
Saltar al sitio Web apropiado y al destinatario de correo electrnico cuando se hace clic en las
etiquetas de vnculo. Estos eventos se procesan como respuesta a una accin del usuario.
Cerrar el formulario cuando el usuario haga clic en el botn Cerrar. ste tambin es un
evento orientado al usuario.

Proyecto | 143

05_PATRICK-CHAPTER_05.indd 143 17/2/10 15:21:22


Empecemos con lo ms fcil: cerrar el formulario. Estoy seguro de que recuerda lo relacionado
con los eventos que se vieron en el captulo 1. Los eventos son bloques de cdigo que se procesan
como respuesta a algo que sucede, con ms frecuencia una accin del usuario como un clic del
ratn. Todas las acciones que queremos realizar en este formulario sern como respuesta a un
evento disparado (qu afortunados somos). La manera ms fcil de obtener el evento predeter-
minado de un control es hacer doble clic en ste. Prubelo ahora; haga doble clic en el botn
Cerrar. Cuando lo haga, el IDE abrir la vista de cdigo fuente asociado con el formulario y
agregar un manejador de eventos vaco (la subrutina AccCerrar_Click).
Public Class AboutPrograma
Private Sub AccCerrar_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles AccCerrar.Click

End Sub
End Class

Cada evento basado en formulario (y, en realidad, casi todos los dems tipos de eventos) en
.NET tienen muchos de los mismos argumentos: (1) un argumento sender que indica cul
objeto dispar este evento, y (2) el argumento e, que permite al sender proporcionar infor-
macin adicional que puede ser til en el evento. En este caso, el argumento sender ser una
referencia al botn AccCerrar, porque es el objeto que generar el evento Click. Un evento
Click del botn no tiene ms informacin til disponible, de modo que e es el tipo de objeto
predeterminado, System.EventArgs, que es muy parecido a un marcador de posicin, y el
objeto del que derivan todos los ms interesantes tipos de argumento de e.
El nombre de este manejador de eventos es AccCerrar_Click, pero si quiere cambiarlo a FerY-
Martha, es correcto; no cambiar nada. Pero debe mantener intacta la clusula Handles Acc-
Cerrar.Click. sta es la parte que vincula al manejador de eventos con el evento real.
El cdigo para cerrar el formulario es extremadamente simple. Ingrselo ahora, ya sea usando el
primer fragmento de cdigo de este captulo o escribindolo directamente.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap05, Elemento 1.

' ----- Cerrar el formulario.


Me.Close()

Esta instruccin dice: Soy el formulario/objeto ProgramaAcercaDe y me ordeno cerrarme.


Si ejecuta el programa ahora (oprima la tecla F5), cerrar el formulario al hacer clic en el botn
Cerrar. Debido a que el formulario ProgramaAcercaDe era el nico formulario de la aplicacin,
al cerrarlo se termina toda la aplicacin, sin mayores preguntas.
Muy bien, regresemos al segundo elemento: los vnculos de estilo Web. Puede regresar a la su-
perficie del formulario y hacer doble clic en cada etiqueta de vnculo para crear un manejador de
eventos para cada evento predeterminado de la etiqueta (en este caso, el evento LinkClicked).

144 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 144 17/2/10 15:21:22


Pero puede agregar las subrutinas del manejador de eventos en el editor, ya sea al escribir usted
mismo el cdigo (lo que es divertido) o usando las listas desplegables que se encuentran justo
arriba de la ventana del editor (vase la figura 5-8).

Figura 5-8. Los campos Nombre de clase y Nombre del mtodo.

La lista Nombre de clase aparece a la izquierda. Al seleccionar una entrada de esta lista, se ac-
tualiza la lista de la derecha, Nombre del mtodo. Para agregar una plantilla de manejador de
eventos para el evento LinkClicked de WebEmpresa, primero seleccione WebEmpresa de la
lista Nombre de clase y luego seleccione LinkClicked de la lista Nombre del mtodo. Aparece el
siguiente bloque de cdigo en la ventana de cdigo:
Private Sub WebEmpresa_LinkClicked(ByVal sender As Object, _
ByVal e As System.Windows.Forms. _
LinkLabelLinkClickedEventArgs) _
Handles WebEmpresa.LinkClicked

End Sub

Esta lista de argumentos de plantilla es un poco ms interesante, porque el argumento e es


un objeto de tipo System.Windows.Forms.LinkLabelLinkClickedEventArgs. El conrol
LinkLabel le permite tener varios vnculos con estilo Web en un solo control, entremezcln-
dolos con el texto regular. El argumento e tiene una propiedad Link que le indica en cules
vnculos del control ha hecho clic el usuario. Debido a que nuestras etiquetas slo tienen un
vnculo, no nos preocuparemos de revisarlo. Slo mostraremos la pgina Web de inmediato cada
vez que se haga clic en el vnculo.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap05, Elemento 2.

' ----- Muestra la pagina Web de la empresa.


Process.Start("http://www.timaki.com")

El objeto Process es parte del espacio de nombres System.Diagnostics y Start es uno de


sus miembros compartidos que le permiten iniciar aplicaciones y recursos externos. Usted le pasa
cualquier URL vlido y se ejecutar usando el explorador predeterminado o la aplicacin para
ese URL. Probmoslo de nuevo con el evento LinkClicked de EMailEmpresa. Agrguelo en
la plantilla de la manera que decida y luego escriba o inserte el cdigo que empieza un nuevo
mensaje a una direccin de correo electrnico.

Proyecto | 145

05_PATRICK-CHAPTER_05.indd 145 17/2/10 15:21:23


INSERCIN DE FRAGMENTO DE CDIGO
Inserte el fragmento de cdigo Cap05, Elemento 3.

' ----- Mandar email a la empresa.


Process.Start("mailto:tim@timaki.com")

El ltimo evento que se disear es uno de los primeros eventos llamados en el tiempo de vida del
formulario: el evento Load. Se le llama justo antes de que aparezca el formulario en pantalla. Al hacer
doble clic en la superficie del formulario se crea una plantilla de manejador de eventos para el evento
Load. Si prefiere usar, en cambio, las listas Nombre de clase y Nombre del mtodo, seleccione (Pro-
gramaAcercaDe eventos) de la lista Nombre de clase antes de usar la lista Nombre del mtodo.
Private Sub ProgramaAcercaDe_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load

End Sub
Agreguemos cdigo a este manejador de eventos que despliegue el nmero de versin correcta,
empleando la informacin de versin encontrada en My.Aplication.Info.Version, una ins-
tancia de la clase System.Version.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap05, Elemento 4.

' ----- Actualiza el numero de version.


With My.Aplication.Info.Version
VersionPrograma.Text = "Version " & .Major & "." & _
.Minor & " Revision " & .Revision
End With

Este cdigo usa una instruccin With para reducir la cantidad de escritura necesaria en la ins-
truccin principal de asignacin. Dentro de la instruccin With...End With, no es obligatorio
que vuelva a escribir el nombre del objeto que aparece justo antes de la palabra clave With (en
este caso, My.Aplication.Info.Version). Puede hacer simplemente referencia a los miem-
bros del objeto al escribir un punto (.) seguido por el nombre del miembro. Puede omitir la
instruccin With y escribir el nombre completo del objeto cada vez que quiera usar los valores de
versin, pero de esta manera mantiene su cdigo ms limpio y menos sobrecargado.

Establecimiento del nmero de versin


Si ejecuta el programa, desplegar el nmero de versin actualmente definido, 1.0 Revision 0,
como se muestra en la figura 5-9.

Figura 5-9. El nmero de versin del formulario ProgramaAcercaDe.

146 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 146 17/2/10 15:21:23


Mi pregunta es (y espero que pueda responderla antes de que termine el prrafo): Dnde est
definido ese nmero de versin y cmo puede cambiarse? Resulta que conozco la respuesta: los
valores de versin se almacenan como metadatos dentro del ensamblado. Visual Studio incluye
un formulario que le permite modificar metadatos de informacin bsicos almacenados en el
ensamblado. Para acceder al formulario, despliegue las propiedades del proyecto (haga doble clic
en My Proyect, en el Explorador de soluciones), seleccione la ficha Aplicacin y luego haga clic en
el botn Informacin de ensamblado (vase la figura 5-10).
Nuestro formulario ProgramaAcercaDe despliega el nmero de versin del ensamblado, que se
establece usando los cuatro campos que se encuentran junto a la etiqueta Versin del ensamblado.
Estos cuatro campos representan los nmeros Mayor, Menor, Construccin y Revisin del ensam-
blado. Siga adelante, incluya otros valores, haga clic en Aceptar y ejecute de nuevo el programa.

Figura 5-10. El formulario Informacin del ensamblado, rellenado con algunos valores relevantes.

Aunque este formulario es conveniente, slo es otro ejemplo de Visual Studio escribiendo el c-
digo de su proyecto por cuenta propia. Cada campo de este formulario se guarda en un archivo
de cdigo fuente incluido en su proyecto. Para verlo, asegrese de que an tiene seleccionado
el botn Mostrar todos los archivos en el Explorador de soluciones. Expanda el elemento My
Proyect usando el signo ms y luego haga doble clic en el elemento AssemblyInfo.vb. Este ar-
chivo define varios asistentes especficos del ensamblado (lo que exploraremos en el captulo 18),
incluidas las siguientes entradas informativas:
<Assembly: AssemblyTitle("El Proyecto Biblioteca")>
<Assembly: AssemblyDescription( _
"ACME Library Base de datos System")>

Proyecto | 147

05_PATRICK-CHAPTER_05.indd 147 17/2/10 15:21:24


<Assembly: AssemblyCompany("ACME")>
<Assembly: AssemblyProduct("Library")>
<Assembly: AssemblyCopiaright( _
"Copyright 2008 por Tim Patrick")>
<Assembly: AssemblyTrademark("")>
<Assembly: AssemblyVersion("1.0.0.0")>

Como ver, este archivo se ha actualizado con los valores que escrib en el formulario Informa-
cin de ensamblado. Gracias, Visual Studio! Ver el atributo AssemblyVersion definido aqu.
Si modifica estos valores, los cambios se reflejarn en el formulario Informacin de ensamblado,
y tambin en su aplicacin en ejecucin y en el ensamblado compilado final.
Lo ltimo que haremos por ahora al formulario ProgramaAcercaDe es darle un nombre de
archivo con un significado. Actualmente se llama Form1.vb, pero ProgramaAcercaDe.vb sera
mucho ms descriptivo. Para cambiar el nombre, seleccione Form1.vb en el Explorador de so-
luciones, y modifique la propiedad Nombre de archivo a ProgramaAcercaDe.vb en el panel
Propiedades. Si an tiene mostrados todos los archivos, ver que Visual Studio tambin actualiza
los nombres de los dos archivos subordinados del archivo, el archivo del diseador (ProgramaA-
cercaDe.Designer.vb) y el de recursos (ProgramaAcercaDe.resx).
Ahora sera un estupendo momento para que guarde su trabajo (Archivo Guardar todo).

Adicin del formulario principal


Aunque el formulario ProgramaAcercaDe es til y est lleno de caractersticas, estos formularios ape-
nas son el eje de una aplicacin. En el Proyecto Biblioteca, este formulario slo se desplegar cuando
se dispare desde el formulario Principal, de modo que agreguemos un formulario principal simple
ahora. En Visual Studio, seleccione el comando de men Proyecto Agregar Windows Form. Cuan-
do aparezca el formulario Agregar nuevo elemento, seleccione Windows Form de la lista de elementos
disponibles, y asgnele el nombre FormularioPrincipal.vb antes de hacer clic en el botn Agregar.
Cuando aparezca el nuevo formulario, ajuste las siguientes propiedades, como se indica.

Propiedad Valor
(Name) FormularioPrincipal
FormBorderStyle FixedSingle
MaximizeBox False
Size 576, 459
Text El Proyecto Biblioteca

Del Cuadro de herramientas, agregue un control Button al formulario con las siguientes pro-
piedades:

Propiedad Valor
(Name) AccAyudaAcercaDe
Size 80, 24
Text &Acerca de...

148 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 148 17/2/10 15:21:24


Si est familiarizado con el desarrollo en Visual Basic desde sus das anteriores a .NET, reconoce-
r el carcter & en el texto del botn. Este carcter especial define el mtodo abreviado para
el botn. Cuando oprime la tecla Alt y la letra que sigue a & (en este caso, A), el programa
acta como si hubiera hecho clic con el botn del ratn.
Haga doble clic en el botn y agregue el siguiente cdigo al procedimiento del evento de clic.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap05, Elemento 5.

' ----- Mostrar el formulario AcercaDe.


ProgramaAcercaDe.ShowDialog()

Aqu especificamos una referencia directa al formulario ProgramaAcercaDe. Antes de la versin


2005 de Visual Basic, para mostrar un nuevo formulario se necesitaba que creara una instancia
de la clase del formulario antes de mostrarlo.
(New ProgramaAcercaDe).ShowDialog()

Esa sintaxis an funciona y es la manera que habr de seguir si necesita desplegar varias copias del
mismo formulario en pantalla al mismo tiempo. Sin embargo, la sintaxis ProgramaAcercaDe.
ShowDialog( ) es mucho ms limpia para formularios de un solo uso, y refleja ms de cerca la
manera en que la presentacin del formulario se hizo en Visual Basic desde su versin inicial. En
realidad, esta instruccin est usando el esc My. La instruccin completa tiene este aspecto:
My.Forms.ProgramaAcercaDe.ShowDialog(
)

La coleccin My.Forms le permite hacer referencia a cualquier formato dentro de l sin tener que
decir primero My.Forms. El miembro de la coleccin My.Forms representa instancias predeter-
minadas de cada formulario en el proyecto.
ste es todo el cdigo que necesitamos por ahora, pero si ejecuta el programa, an mostrar
slo el ProgramaAcercaDe. Eso se debe a que este formulario est establecido como formulario
de inicio. Para modificar esto, abra la ventana de propiedades del proyecto, seleccione la ficha
Aplicacin y establezca el campo Formulario de inicio en FormularioPrincipal.
Debido a que el formulario ProgramaAcercaDe se est mostrando ahora como formulario de cua-
dro de dilogo (mediante una llamada a su mtodo ShowDialog), su comportamiento es en cierto
modo diferente. Cada formulario incluye una propiedad DialogResult, cuyo valor es devuelto
por el mtodo ShowDialog cuando se cierra el formulario. Cada botn de su formulario puede
configurarse automticamente para establecer esta propiedad y cerrar el formulario. El botn
Cerrar del formulario ProgramaAcercaDe hace eso; su propiedad DialogResult se establece
en Cancel, que est asignada a la propiedad DialogResult del formulario, cuando el usuario
hace clic en el botn Cerrar. Como efecto lateral, en cualquier momento en que se asigna un
valor (diferente de None) a la propiedad DialogResult del formulario, ste se cierra.
El remate de este prrafo es que ahora puede eliminar el manejador de eventos del evento Click
del botn Cerrar, y el botn an cerrar el formulario. Elimine el procedimiento AccCerrar_

Proyecto | 149

05_PATRICK-CHAPTER_05.indd 149 17/2/10 15:21:24


Click del cdigo fuente de ProgramaAcercaDe, ejecute el programa y vea lo que sucede. El
botn Cerrar an cierra el formulario, aun sin el manejador de eventos.
Tambin podra dejar el procedimiento, limpiar la propiedad DialogResult del botn Cerrar
y agregar la siguiente instruccin al manejador de eventos del botn:
Me.DialogResult = Windows.Forms.DialogResult.Cancel

Esto aumenta a tres el nmero de maneras diferentes en que puede cerrar el formulario Progra-
maAcercaDe. Es la flexibilidad de .NET en funcionamiento; hay muchas maneras diferentes de
realizar la misma tarea. Sea creativo!

Crdito extra: adicin de un icono


Si an le queda un poco de energa, podemos hacer un cambio ms antes de quedarnos sin papel
en este captulo: agregar un icono personalizado al formulario principal. Slo siga estas instruc-
ciones paso a paso:
1. Despliegue el formulario principal al hacer doble clic en el elemento FormularioPrincipal.vb, en
el Explorador de soluciones.
2. Seleccione la superficie del formulario.
3. Seleccione la propiedad Icon del formulario, en el panel Propiedades.
4. Haga clic en el botn ... de esta propiedad, y busque el archivo Libro.ico en el subdirectorio
Cap05 Antes del directorio de instalacin del libro. Tambin puede usar cualquier otro archivo
.ico.

Guarde su trabajo
Asegrese de que siempre guarda los cambios. Como opcin predeterminada, Visual Studio est
configurado para guardar sus cambios cada vez que se ejecuta su programa, pero prefiero guar-
darlo a menudo slo por si acaso.
En este captulo se incluyeron gran cantidad de instrucciones manuales, porque hay demasiadas
caractersticas estupendas de Visual Studio para jugar con ellas; no pude evitarlo. Probablemente
mantendremos este paso de alguna manera por algunos captulos, pero con el tiempo habr
tanto cdigo que gran parte de l vendr de fragmentos de cdigo.

150 | Captulo 5: Ensamblados de .NET

05_PATRICK-CHAPTER_05.indd 150 17/2/10 15:21:24


Captulo 6
Datos y tipos de datos

Datos es una palabra divertida, aunque no tan divertida como datum. Nuestra mente est llena
de datos: las trivialidades tiles e intiles que nublan las ideas; los millones de recuerdos que evi-
tan que las conversaciones superficiales se hagan ms fuertes. Pero la palabra datos rara vez surge
en las conversaciones. A menos que sea un fantico de las computadoras o que se pase todas las
horas del da o la noche en la oficina esperando informes de nmeros procesados, nunca ha te-
nido oportunidad de usar el trmino. Nunca se me ha pedido que le preste a alguien una taza de
datos. Mis amigos nunca tratan de juzgar mi salud al preguntar: Cmo estn tus datos? Y casi
nunca la ha odo usada como el nombre de un personaje en programas populares de televisin
de ciencia ficcin.
A pesar de su falta de uso en la conversacin cotidiana, los datos son extremadamente impor-
tantes. En el mundo de la programacin, lo es todo. En este captulo, analizaremos la manera
en que Visual Basic usa y manipula datos dentro de sus aplicaciones, y la manera en que puede
dominar las herramientas que hacen posible esta manipulacin.

La naturaleza de los datos en computacin


En el captulo 2 mencion la manera en que los datos se dividen en una computadora en bits
individuales, impulsos elctricos que representan 1 o 0, encendido o apagado, verdadero o fal-
so. Debido a que nuestro sistema numrico decimal requiere ms que slo esos dos valores, las
computadoras trabajan en el mundo binario: un sistema numrico limitado slo a los nmeros
0 y 1. Por fortuna, es muy fcil representar los nmeros enteros decimales bsicos empleando
notacin binaria. Tal vez recuerde al maestro Peralta de segundo ao indicndole los diferentes
valores que toman los nmeros de varios dgitos debido a su posicin, como se muestra en la
figura 6-1.
El mismo tipo de diagrama puede usarse con los nmeros binarios; slo cambian los nombres de
la posicin y los valores. Por conveniencia, llamamos a estas posiciones por sus nombres decima-
les, o usamos las potencias relacionadas de dos. Todo esto se muestra en la figura 6-2.

151

06_PATRICK-CHAPTER_06.indd 151 17/2/10 15:22:01


Miles
Cientos
Decenas
Unidades

2,135
Figura 6-1. Los frutos del trabajo del maestro Peralta.

Diecisis (16 = 2) Ocho (8 = 2)


Treinta y dos (32 = 2) Cuatro (4 = 2)
Sesenta y cuatro (64 = 2) Dos (2 = 2)
Ciento veintiocho (128 = 2) Uno (1 = 2)

01001100
Figura 6-2. Las posiciones de un nmero binario de 8 bits (8 dgitos).

Para encontrar el valor de este nmero en el sistema decimal, simplemente sume las columnas. Vea-
mos, hay uno de cada uno de los siguientes valores: cuatro, ocho, sesenta y cuatro, y ninguno del
resto; 4 + 8 + 64, es decir, 76. Debido a que ningn dgito binario puede valer nunca ms de 1, la
cuenta es muy simple. Aqu le mostr un ejemplo binario de 8 bits (8 dgitos), que puede manejar
nmeros del 0 al 255, pero puede representar nmeros decimales ms grandes al aadir ms dgitos.
Eso est correcto para valores enteros, pero cmo representa nmeros decimales y fraccionarios?
Qu hay de los nmeros negativos, donde caben en el sistema binario? Y no se trata slo de n-
meros. Mi computadora puede procesar datos de texto, matrices de nmeros, imgenes grficas
y registros de clientes. Cmo se almacenan en forma binaria?
Para manejar miradas de formas de datos, cada computadora incluye una pequea comunidad
de liliputienses que son buenos en matemticas, lenguas y artes. No, espere, creo que eso provie-
ne de una historia que estoy leyendo a mi hijo cuando va a la cama. Oh, s, ahora recuerdo. Las
computadoras implementan tipos de datos para manejar todas las formas de datos diferentes que
deben administrarse. Cada tipo de datos acta como un intrprete entre una coleccin de bits y
una pieza de informacin que un usuario de computadora puede utilizar y comprender mejor.
Todos los tipos de datos almacenan, al final de cuentas, su contenido como bits individuales
de datos, pero difieren en la manera en que se interpretan esos bits. Imagine un tipo de datos
llamado Vitaminas que indica cules vitaminas se incluyeron en un producto alimenticio. En la
figura 6-3 se muestra la manera en que esos 8 bits usados antes podan asignarse e interpretarse
como vitaminas.
Con este tipo de datos, podra asignar valores de vitaminas a alimentos a los que se da segui-
miento en su aplicacin. (sta slo es una muestra de vitaminas; requerira ms bits para manejar

152 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 152 17/2/10 15:22:01


Vitamina B1 Vitamina E
Vitamina B2 Vitamina D
Vitamina B6 Vitamina C
Vitamina B12 Vitamina A

01001100
Figura 6-3. Cargado con vitaminas B6, D y E.

todas. Este ejemplo no debe usarse como un ofrecimiento de servicios de salud. Consulte a su
mdico.)
Para conocer un ejemplo que est ms a tono con Visual Basic, tome ese nmero 76 que est-
bamos analizando antes. Es lo bastante fcil convertirlo en una representacin binaria, como
01001100. .NET Framework incluye unos cuantos tipos de datos que hacen automticamente
esta conversin, variando slo en el nmero de dgitos binarios (bits) que pueden manejar. En
el mundo de la computacin, 76 tambin representa una letra del alfabeto (la letra L mayscu-
la). Eso se debe a que hay tipos de datos que establece un diccionario entre valores binarios y
caracteres alfabticos (y de otros tipos). Los programas de Windows han usado desde hace mu-
cho ASCII (cdigo estadounidense estndar para intercambio internacional, American Standard
Code for Information Interchange) como diccionario de nmeros a caracteres. Este sistema de 8
bits documenta la manera de convertir los nmeros del 0 al 255 en todos los diversos caracteres
usados en el ingls, incluidos los signos de puntuacin y otros caracteres varios. Otro dicciona-
rio, Unicode, usa 16 bits de datos para manejar alrededor de 65000 caracteres diferentes. .NET
usa Unicode para sus tipos de datos de carcter y de cadena.
Otro tipo de datos que sigue la regla es el booleano, que usa un solo bit para representar True (un
valor de bit de 1) o False (0). Los enteros negativos, los valores decimales de punto flotante y las
fechas y horas completan los tipos de datos bsicos que se usan con ms frecuencia en los equipos
de cmputo y sus aplicaciones. Las estructuras de datos ms complejas pueden construirse a partir de
estos tipos bsicos.

Datos en .NET
Todos los tipos de datos en .NET se implementan como clases dentro del espacio de nombres
System. Uno de esos tipos de datos es System.Byte, que implementa un valor entero de 8 bits,
tal como lo analizamos antes. Contiene valores enteros de 0 a 255. Estos valores se almacenan
siempre empleando datos binarios de 8 bits, pero aparecen mgicamente en forma decimal cada
vez que pida que se presenten.
.NET Framework incluye 15 tipos de datos centrales para interpretacin: 8 para enteros, 3 para
nmeros decimales, 2 para datos de carcter, un tipo de datos combinados para fechas y horas,
y un tipo de datos booleano.

Datos en .NET | 153

06_PATRICK-CHAPTER_06.indd 153 17/2/10 15:22:02


Tipos de datos enteros
Con base en el nmero de tipos de datos disponibles (8 de los 15 tipos centrales), pensara que
la mayor parte de los programas funcionan con enteros todo el da, y tendra razn. Si se trata de
datos de usuario reales, contadores de bucles, cdigos de estado o el mtodo de almacenamiento
para tipos de datos enumerados, los enteros se muestran en todos lados del cdigo .NET.
El rango de valores para un tipo de datos entero depende directamente del nmero de dgitos
binarios administrados por ese tipo de datos; cuanto mayor sea el nmero de dgitos, mayor
ser el rango. Adems, la mitad de los tipos de datos enteros almacenan valores positivos y ne-
gativos (llamados enteros con signo), mientras que la otra mitad slo da soporte a nmeros
positivos (sin signo). En la tabla 6-1 se presenta una lista de cada uno de los ocho tipos de
datos enteros incluidos con .NET, y sus rangos asociados.

Tabla 6-1. Tipos de datos enteros en .NET.

Tipo de datos de .NET Bits Estilo Rango de valores


System.Byte 8 Sin signo 0 a 255
System.SByte 8 Con signo 128 a 127
System.Int16 16 Con signo 32,768 a 32,767
System.UInt16 16 Sin signo 0 a 65,535
System.Int32 32 Con signo 2,147,483,648 a 2,147,483,647
System.UInt32 32 Sin signo 0 a 4,294,967,295
System.Int64 64 Con signo 9,223,372,036,854,775,808 a
9,223,372,036,854,775,807
System.UInt64 64 Sin signo 0 a 18,446,744,073,709,551,615

Al revisar estos tipos de otra manera, en la tabla 6-2 se muestra la relacin entre los tipos y su
nmero de bits y estilo rango.

Tabla 6-2. Bits y estado de signo para tipos de datos enteros de .NET.

8 bits 16 bits 32 bits 64 bits


Con signo SByte Int16 Int32 Int64
Sin signo Byte UInt16 UInt32 UInt64

Tipos de datos decimales


Haba una vez en que la vida era feliz. Los extraos decan hola cuando se cruzaban en la ca-
lle. Frutas suculentas caan de los rboles. En resumen, Dios estaba en Su paraso, y todo era
correcto en el mundo, y luego llegaron las fracciones. Al principio, no parecan malas, porque

154 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 154 17/2/10 15:22:02


muchas de ellas podan convertirse fcilmente en una forma numrica simple al insertar un
punto decimal en el nmero: se volva 0.5; se volva el ms largo pero an corto 0.25;
1/3 se volva 0.333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333
333333333333333333333333333333333333333 hey, qu pasa aqu? No puedo escribir
todos esos 3. El libro tendra 2000 pginas o ms. Con el tiempo, las personas descubrieron
eso en muchos casos, simplemente no vala la pena escribir todos esos 3, de modo que dejaban
de escribirlos en algn punto, como en 0.33333333. No era perfectamente exacto, pero era lo
bastante bueno.
sta es la vida para los valores decimales computacionales. Puede tener exactitud perfecta (hasta
cierto punto). Despus de eso, tiene que aceptar algunas cosas. .NET Framework incluye tres
tipos de datos decimales. Dos de ellos aceptan exactitud limitada a cambio de un amplio rango
de valores. El tercero tiene exactitud perfecta, pero su rango es ms limitado. En la tabla 6-3 se
documentan estos tres tipos.

Tabla 6-3. Una lista exacta de los tipos de datos decimales inexactos.

Tipo de datos de .NET Exactitud Rango Descripcin


System.Decimal Perfecta Limitado El tipo de datos Decimal proporciona alrededor de 28 dgitos
combinados a ambos lados del punto decimal. Y aunque puede
truncarse despus de la posicin del ltimo dgito disponible,
es exacta dentro de esos dgitos. Debido a esto, es perfecto para
trabajar con dinero.
Cuantos ms dgitos tenga a la izquierda del punto decimal,
menos tendr disponibles a la derecha, y viceversa. En el caso de
nmeros sin parte decimal, el rango va de 79,228,162,514,
264,337,593,543,950,335 a 79,228,162,514,264,337,593,543,
950,335. (Es decir, 29 dgitos, pero quin los est contando?)
En el caso de nmeros con slo ceros (0) a la izquierda del punto
decimal, el rango es -0.0000000000000000000000000001 a
0.0000000000000000000000000001.
System.Single Imperfecta Grande El tipo de datos Single ofrece un rango mucho ms grande
que Decimal, pero tiene algunos problemas de exactitud. En
ocasiones, cuando hace un clculo complejo que sabe que debe
resultar cero, el resultado real podra ser 0.0000000000023. Est
cercano al cero, pero no es exactamente cero. Sin embargo, puede
usar nmeros muy grandes o muy pequeos. En el caso de nme-
ros negativos, el rango es de -3.402823E+38 a -1.401298E-45; en el
caso de nmeros positivos, va de 1.401298E-45 a 3.402823E+38.
System.Double Imperfecta Enorme El tipo de datos Double es como Single, pero con
una mayor actitud, quiero decir, rango. En el caso de valo-
res negativos, el rango es de 1.79769313486231E+308 a
4.94065645841247E-324; en el caso de valores positivos, el
rango es de 4.94065645841247E-324 a 1.79769313486232E+308.

Datos en .NET | 155

06_PATRICK-CHAPTER_06.indd 155 17/2/10 15:22:02


Tipos de datos de carcter
Hey, revise esto. ktuefghbiokh. Excelente, no? Es el poder de una computadora en accin
administrando datos de texto. Tan eficiente, tan agradable: igual que lskjdfljsdfjl. Aunque las
computadoras son en realidad mquinas para procesar nmeros, tambin manejan texto. Por
supuesto, slo que usted tiene que hacer todo el trabajo de forjador de palabras. En realidad, la
computadora ni siquiera es tan inteligente como para saber la diferencia entre nmeros y letras;
todos son bits para la CPU. Poca inteligencia, si me pregunta. Quiero decir, cul es la utilidad
de tener toda esa capacidad de cmputo si ni siquiera puede pensar?
A pesar de toda su velocidad y tecnologa, las computadoras son slo montones de silicio en-
vuelto en un bonito paquete. La computadora en que estoy escribiendo ni siquiera sabe que la
estoy insultando; puede escribir estas cosas una y otra vez, y esta komputadrora non puedre haser
nata sobre elyo.
El marco conceptual incluye dos tipos de datos relacionados con el texto: System.Char y Sys-
tem.String. El tipo de datos Char contiene un solo carcter, ni ms ni menos. A 16 bits, con-
tiene cualquiera de los miles de caracteres de Unicode.
El tipo de datos String permite que hasta dos mil millones de caracteres Unicode se encadenen
en un bloque largo de texto. Las cadenas de .NET son inmutables; una vez que crea una cadena, ya
no puede cambiarse de manera alguna. Si quiere agregar texto a una cadena existente, .NET crear
una cadena completamente nueva construida a partir de las dos cadenas inmutables originales.
Aunque Char y String son tipos de datos diferentes, puede mover fcilmente datos entre ellos,
porque ambos estn basados en los caracteres bsicos de Unicode.

Tipo de datos de fecha y hora


El tipo de datos System.DateTime permite almacenar valores de fecha u hora (o ambos) como
datos. Internamente, DateTime es slo un simple contador de enteros que despliega un formato
convertido de fecha u hora cuando se necesita. Como nmero, cuenta la cantidad de tics desde
las 12:00 a.m. del 1 de enero del ao 1 de nuestra era. Cadatic es exactamente 100 nanosegun-
dos, de modo que es muy preciso. La fecha mxima permitida es el 31 de diciembre de 9999, en
el calendario gregoriano.

Tipo de datos booleano


El tipo de datos System.Boolean representa la verdadera esencia de los datos de compu
tadora: el bit. Contiene uno de dos valores posibles: True o False. Lo sorprendente es que el
tipo de datos en realidad requiere entre 2 y 4 bytes de espacio para llevar registro de ese nico
bit de datos.
Resulta que esos valores booleanos son muy importantes en programas. Como desarrollador,
siempre est probando si se cumplen varias condiciones antes de procesar un bloque de cdigo.
Con el tiempo, todas esas condiciones se reducen a valores y operaciones booleanos. Incluso,

156 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 156 17/2/10 15:22:02


.NET tiene maneras de migrar fcilmente datos entre valores enteros y los tipos de datos boolea-
nos. En esas conversiones, 0 se vuelve False y el mundo de todos los dems valores posibles se
vuelve True. Cuando se mueve de booleano a un equivalente entero, False se vuelve 0 y True,
1. (Si alguna vez usa el lenguaje C#, encontrar que convierte True en 1, no 1. Internamente
en .NET, True s se convierte en 1, pero por razones histricas, Visual Basic usa 1. Esta diferen-
cia no suele ser un problemas, a menos que almacene valores booleanos como enteros en un archi-
vo de disco y espere que programas de Visual Basic y C# interpreten los datos correctamente.)

La clase System.Object
Ya saba que .NET es un entorno de desarrollo orientado a objetos. Lo que probablemente no sabe
es que algunos bromistas de Microsoft hicieron una apuesta para ver si podan hacer que todo el
sistema .NET fuera una sola y enorme clase derivada. Bueno, el grupo que dijo que se poda gan
la apuesta. Todo en .NET (todo el cdigo y todos los datos) se derivan de una sola clase de base:
System.Object. Por s sola, esta clase no tiene muchas caractersticas. Puede decir su nombre, su
tipo y si dos instancias de un objeto son en realidad el mismo objeto. Aparte de eso, no es til para
muchas cosas, excepto para usarse como punto de partida para todas las dems clases y tipos.
Debido a que todas las clases en .NET (incluidos todos los tipos de datos) derivan de System.
Object, puede tratar una instancia de cualquier clase (o tipo de datos) como Object. Los datos
recordarn de qu tipo realmente es, de modo que si tiene System.Int32 pasando como Sys-
tem.Object, puede regresarlo despus a System.Int32.

Tipos de valor y de referencia


De regreso al captulo 1, ley acerca de la diferencia entre tipos de valor y tipos de referencia: los
tipos de valor son contenedores que contienen datos reales y los de referencia contienen ins-
trucciones sobre el lugar en que puede encontrar los datos reales. En general, los tipos de valor
contienen valores de datos simples y pequeos, mientras que los tipos de referencia sealan a
bloques de datos grandes y complejos. Esto no siempre es cierto, pero s lo ser con la mayor
parte de los datos con los que trabajar.
System.Object es un tipo de referencia del que derivan otros tipos y clases. Esto incluye todos
los tipos de datos centrales, de modo que pensara que tambin son tipos de referencia. Pero hay
otra clase entre System.Object y casi todos los tipos de datos de Visual Basic. Esta clase, Sys-
tem.ValueType, implementa la definicin bsica y el uso de un tipo de valor. En la tabla 6-4 se
presenta una lista de algunas de las diferencias entre los tipos de valor y de referencia.

Tabla 6-4. Uso de los tipos de valor y de referencia.

Tipos de valor Tipos de referencia


Deriva, en ltima instancia, de System.ValueType, Deriva, en ltima instancia, de System.Object.
que a su vez deriva de System.Object.

Datos en .NET | 157

06_PATRICK-CHAPTER_06.indd 157 17/2/10 15:22:02


Tabla 6-4. Uso de los tipos de valor y de referencia (continuacin).

Tipos de valor Tipos de referencia


Tipos de datos centrales derivados: booleano, Tipos de datos centrales derivados: String.
Byte, Char, DateTime, Decimal,
Double, Int16, Int32, Int64, SByte,
Single, UInt16, UInt32, UInt64.
Proporciona soporte a estructuras de Visual Basic. Proporciona soporte a clases de Visual Basic.
Las enumeraciones se derivan de la siguiente manera: Delegados, usados como referencias a mtodos de clases, se derivan
System.Object System.ValueType como sigue: System.Object System.
System.Enum. Delegate. Un tipo de delegado, el delegado de multidifusin,
deriva an ms mediante System.MulticastDelegate.
Los tipos de valor no pueden derivar de otras clases o Los tipos de referencia pueden derivar de otras clases y no pueden
estructuras, ni estructuras posteriores pueden derivar de ellos. usarse como clases de base.
Las instancias no pueden establecerse en Nothing. Las instancias pueden establecerse en Nothing.
(El uso de un tipo que permite valores nulos permite superar
esta limitacin.)
Las instancias slo pueden contener datos del tipo especifi- Las instancias suelen hacer referencia a datos de su tipo definido, pero
cado. Por ejemplo, las instancias de System.Int32 slo una instancia tambin puede sealar un tipo derivado. Por ejemplo, una
pueden contener datos enteros con signo de 32 bits. instancia de System.String podra hacer referencia a cualquier
dato que haya usado System.String como clase de base.
No recorre el proceso de recoleccin de basura completo de .NET. Se destruyen mediante la recoleccin de basura.

(Adems de clases y estructuras, Visual Basic tambin define mdulos. La documentacin de


.NET identifica a los mdulos como tipos de referencia, pero no puede crear instancias de ellos.)
Un tipo de valor slo puede contener datos de su propio tipo, pero los tipos de referencia pueden
sealar instancias derivadas. Esto es importante en .NET, porque est diseado para permitir
que una instancia de System.Object haga referencia a cualquier dato de una aplicacin. Las
instancias de System.Object pueden hacer referencia a cualquier dato de tipo de valor o de
referencia. En el caso de los tipos de referencia, esto es fcil de comprender porque esas instan-
cias slo sealarn algunas instancias derivadas de s mismas. Pero si asigna un tipo de valor a
una referencia a System.Object, .NET tiene que marcar esa instancia de una manera especial
para indicar que un tipo de referencia contiene un tipo de valor. A este proceso se le denomina
encuadre y al proceso inverso desencuadre. Aunque el encuadre es til y en ocasiones esencial,
viene con una afectacin importante en el rendimiento.

Tipos de datos de Visual Basic


Todos los tipos de datos implementados en el lenguaje de Visual Basic son envolturas de los
tipos de datos centrales de .NET. Slo se han cambiado algunos de los nombres para proteger
a los inocentes. En la tabla 6-5 se presenta una lista de los tipos de datos de Visual Basic y sus
equivalentes de .NET.

158 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 158 17/2/10 15:22:03


Tabla 6-5. Tipos de datos de Visual Basic y tipos de .NET relacionados.

Tipo de Visual Basic Tipo de .NET


Boolean System.Boolean
Byte System.Byte
Char System.Char
Date System.DateTime
Decimal System.Decimal
Double System.Double
Integer System.Int32
Long System.Int64
Object System.Object
SByte System.SByte
Short System.Int16
Single System.Single
String System.String
UInteger System.UInt32
ULong System.UInt64
UShort System.UInt16

Todos los tipos de datos de Visual Basic son plenamente intercambiables con sus equivalentes
de .NET. Cualquier instancia de System.Int32 puede tratarse como si fuera una instancia de
Integer, y viceversa.

Literales
La manera ms rpida de incluir valores de un tipo de datos en particular en su cdigo de Visual
Basic es mediante el uso de una literal. Ya ha visto las literales en accin en este libro. En el cap-
tulo 1 se incluy una literal en su proyecto de ejemplo.
MsgBox("Hola, mundo!")

Esta llamada a la funcin MsgBox incluye una literal de cadena. Estas literales siempre aparecen
dentro de un conjunto de comillas. Casi todas las literales numricas aparecen con un carcter
que define un tipo de datos al final de la literal, pero hay otras variantes. En la tabla 6-6 se pre-
senta una lista de los diferentes valores de literales que puede incluir en su cdigo.

Tabla 6-6. Literales soportadas por Visual Basic.

Tipo de literal Ejemplo Descripcin


Boolean True El tipo de datos Boolean da soporte a dos valores de literal: True y False.
Char "Q"c Las literales de un solo carcter aparecen con una c al final. Una literal de tipo Char
no es lo mismo que una literal de un solo carcter de tipo String.

Literales | 159

06_PATRICK-CHAPTER_06.indd 159 17/2/10 15:22:03


Tabla 6-6. Literales soportadas por Visual Basic (continuacin).

Tipo de literal Ejemplo Descripcin


Date #11/7/2005# Las literales de fecha y hora aparecen entre un carcter de signos de nmero. Puede
incluir fechas, horas o una combinacin de ambas. Los valores de fecha u hora pueden
estar en cualquier formato reconocido por Windows, aunque Visual Studio puede modifi-
car el formato de su literal de fecha para adecuarse a sus propios estndares.
Decimal 123.45D Los valores de punto flotante de tipo Decimal son seguidos por una D
123.45@ mayscula o el carcter @.
Double 123.45R Los valores de punto flotante de tipo Double son seguidos por una R mayscula o
123.45# el carcter #. Adems, si usa una literal numrica con una parte decimal, pero sin un
carcter de tipo de datos al final, esa literal se escribir como un Double.
Hexadecimal &HABCD Puede incluir literales hexadecimales en su cdigo al iniciar el valor con la secuencia
de caracteres &H, seguida por los dgitos hexadecimales.
Integer 123.45I Los valores de entero de tipo Integer son seguidos por una I mayscula o el carcter
123.45% %. Adems, si usa una literal numrica que falla en el rango de un Integer, pero sin
carcter de tipo de datos al final, a esa literal se le asignar un tipo Integer.
Long 123.45L Los valores enteros de tipo Long son seguidos por una L mayscula o el carcter &.
123.45& Adems, si usa una literal numrica que cae en el rango de un Long y fuera del rango de
un Integer, pero sin carcter final de tipo de datos, esa literal tendr el tipo Long.
Octal &O7654 Puede incluir literales octales en su cdigo al iniciar el valor con la secuencia de
caracteres &O, seguida por los dgitos octales.
Short 123.45S Los valores enteros de tipo Short son seguidos por una S mayscula.
Single 123.45F Los valores de punto flotante de tipo Single son seguidos por una F mayscula o
123.45! el carcter !
String "A
""B""
C" Las literales de cadena aparecen entre comillas, sin carcter especial despus de las
comillas finales. Use las comillas dentro de la literal de cadena para incrustar un solo
signo de interrogacin.

Constantes
Las literales son agradables, pero no siempre queda claro lo que significan. Encontrar el nmero
12 en una frmula, por ejemplo, podra causar que sta generara resultados correctos, pero an
sera til saber lo que significa 12. Es el nmero de meses en un ao, el nmero de horas en un
da, el nmero mnimo de dientes en la boca para comer un bistec, o algo an ms siniestro?
Las constantes proporcionan una manera de asignar nombres con sentido a valores de literal. Se
les trata en gran medida como a stos, pero una vez definidos pueden usarse una y otra vez en su
cdigo. Cada uso de un valor de literal, aunque sea el mismo valor, representa una definicin y
una instancia distintas de ese valor.
En Visual Basic, las constantes se definen usando la palabra clave Const.
Const MesesAnuales As Short = 12
Esta definicin de constante tiene las siguientes partes:

160 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 160 17/2/10 15:22:03


Un nombre
En este caso, el nombre es MesesAnuales.
Un tipo de datos
En este ejemplo se define una constante Short. El tipo de datos siempre sigue a la palabra
clave As. Si deja fuera esta clusula As, el tipo de datos de la constante ser cualquier
cosa que la literal asignada tendra por su cuenta. Slo los siguientes tipos de datos pueden
usarse para las constantes: Boolean, Byte, Char, Date, Decimal, Double, Integer, Long,
Object, SByte, Short, Single, String, UInteger, ULong, UShort, o el nombre de una
enumeracin (lo que se analiza en la siguiente seccin).
Un inicializador
El inicializador asignado aqu es 12. Una vez asignado, este valor no puede modificarse mien-
tras su cdigo se est ejecutando. Las constantes son siempre tipos de valor, no de referencia.
Los inicializadores suelen ser literales simples, pero tambin pueden incluir clculos simples:
Const Siete As Integer = 3 + 4

Un nivel de acceso
La definicin de MesesAnuales presentada aqu representa el formato tpico de una defini-
cin de constante incluida dentro de un procedimiento de cdigo. Tambin puede definir las
constantes fuera de los procedimientos, pero an dentro de una clase u otro tipo. Cuando hace
esto, por lo general agrega una palabra clave de modificador de acceso justo antes de la palabra
clave Const. Esta palabra clave indica cunto cdigo podr usar la constante. Describir los
modificadores de acceso un poco ms adelante, en la seccin sobre variables. Las constantes
definidas dentro de un procedimiento slo pueden usarse dentro de ese procedimiento.
Una vez que define una constante, puede usarla de cualquier manera en que usara un equiva-
lente literal.
Const GranSaludo As String = "Hola, mundo."
...Adelante...
MsgBox(GranSaludo)

Enumeraciones
Las enumeraciones, uno de los tipos centrales de .NET, le permiten agrupar como un conjunto va-
lores enteros, con nombre y relacionados. Una vez unidos, la enumeracin puede usar como cual-
quier otro tipo de datos; puede crear variables que son instancias especficas de una enumeracin.
Las enumeraciones son una construccin de varias lneas; la primera define el nombre y el tipo
de datos de la enumeracin. Cada miembro de la enumeracin aparece en una lnea separada,
terminando con una lnea End Enum final de cierre.
01 Enum TipoAuto As Integer
02 Sedan = 1
03 Vagoneta = 2
04 Camioneta = 3
05 SUV = 4

Enumeraciones | 161

06_PATRICK-CHAPTER_06.indd 161 17/2/10 15:22:03


06 Otro = 5
07 End Enum

La lnea de declaracin (lnea 01) incluye la palabra clave Enum, el nombre de la enumeracin
(TipoAuto) y los tipos de datos subyacentes (Integer). La clusula de tipo As es opcional; si
la deja fuera, la enumeracin tiene Integer como opcin predeterminada. Si proporciona un
tipo de datos, debe ser uno de los siguientes: Byte, Integer, Long, SByte, Short, UInteger,
ULong o UShort.
Cada miembro de la enumeracin (lneas 02 a 06) debe incluir por lo menos un nombre de
miembro (como Sedan). Tiene la opcin de asignar un valor numrico a alguno o a todos los
miembros, como he hecho en el ejemplo. Si un miembro carece de asignacin, se establece en
uno ms de los miembros anteriores. Si ninguno de los miembros tiene un valor asignado, al
primero se asigna 0, al siguiente 1, etctera.
Una vez definidos, los miembros de la enumeracin actan como constantes enteras. Cuando
haga referencia a los miembros de una enumeracin en su cdigo, incluya el nombre de la enu-
meracin y del miembro.
TipoAuto.Sedan
No puede usarse la instruccin Enum dentro de un mtodo o procedimiento. En cambio, debe
definir una enumeracin como un miembro de un tipo (clase, estructura o mdulo), o como
su propio tipo independiente, como en una clase. .NET Framework incluye muchas enume-
raciones predefinidas tiles, que estn orientadas para usarse con caractersticas de .NET. Por
ejemplo, la enumeracin System.DayOfWeek incluye miembros de cada da de la semana.

Variables
Las literales son agradables y las constantes y las enumeraciones an ms, pero ninguna de ellas
puede modificarse una vez que inicia su programa. Esto tiende a hacer que sus aplicaciones
sean rgidas e inflexibles. Si todos sus clientes se llaman Fernando y slo colocan pedidos de
$342.34, tal vez no sea una gran limitacin. Pero casi todos los usuarios quieren ms variedad en
su software. Las variables son contenedores con nombre para datos, como las constantes, pero su
contenido puede modificarse mientras se ejecuta una aplicacin. Adems, pueden contener tipos
de valor y de referencia. He aqu la sintaxis bsica para definir una nueva variable:
Dim nombreCliente As String
La palabra clave Dim (que proviene de la palabra dimensin) define una nueva variable; en este
caso, una llamada nombreCliente con un tipo de datos String. Este contenedor con nom-
bre est listo para contener cualquier valor String; asgnele literales de cadena, otras variables
de cadena o el valor de devolucin de funciones que generan cadenas. Debido a que es un tipo de
referencia, tambin puede asignarle Nothing, un valor y una palabra clave especiales de Visual
Basic que significa este tipo de referencia est vaco, realmente vaco.
nombreCliente = Nothing ' Nothing
nombreCliente = "Fernando" ' Literal
nombreCliente = ObtenerNombreCliente(IDCliente) ' Resultado de la funcion

162 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 162 17/2/10 15:22:03


Todas las variables contienen su valor predeterminado hasta que se cambia por otro. En el caso de
tipos de referencia y los que pueden ser nulos, el valor predeterminado es Nothing; en el caso
de valores numricos, el valor predeterminado es 0. Los valores booleanos son False, como
opcin predeterminada. Puede incluir una asignacin inicial como parte de la instruccin Dim
para sobrescribir la asignacin predeterminada.
Dim cuentaRegresivaSegundos As Short = 60
Dim procesansoFecha As Date = Hoy
Dim nombreCliente As String = ObtenerNombreCliente(IDCliente)

La ltima lnea en ese bloque de cdigo muestra un tipo de referencia (String) asignado al
resultado String de una funcin. Tambin puede asignar una instancia completamente nueva
de una variable de tipo de referencia. Y ser nueva. Es decir, usar la palabra clave New, que dice
Estoy creando una nueva instancia del tipo de datos especfico. Hay unas cuantas variaciones,
pero todas producen los mismos resultados.
' ----- Variacin de una lnea.
Dim unEmpleado As New Empleado

' ----- Otra variacin de una lnea.
Dim unEmpleado As Empleado = New Empleado

' ----- Variacin de dos lneas.


Dim unEmpleado As Empleado
unEmpleado = New Empleado

Recuerde que esos tipos de referencia son contenedores que incluyen instrucciones para localizar
los datos reales. Cuando surge a la vida por primera vez una variable de referencia, contiene No-
thing. Es decir, el contenedor no incluye instrucciones porque no hay datos relacionados que
se hayan almacenado en algn lugar. Cuando asigna una nueva instancia a una variable de tipo
de referencia, esa instancia se almacena en algn lugar de la memoria y las instrucciones para
localizar esos datos se vuelcan en el contenedor. En el bloque de cdigo anterior, cada uso de
la palabra clave New crea una nueva instancia de datos en algn lugar de la memoria. Luego, la
ubicacin de estos datos se asigna a la variable unEmpleado.
Muchas clases incluyen uno o ms constructores, rutinas de inicializacin que configuran los valores
iniciales de la instancia. Puede llamar a un constructor especfico mediante la clusula New. El tipo
de String incluye constructores que le permiten construir una cadena inicial. Uno de esos construc-
tores especiales le permite crear una nueva cadena que contiene varias copias de un carcter especfico.
La siguiente instruccin asigna una cadena de 25 asteriscos a la variable muchasEstrellas:
Dim muchasEstrellas As New String("*"c, 25)

Los constructores se exponen de manera detallada en el captulo 8.


Las instrucciones Dim pueden aparecer en cualquier lugar de un procedimiento, pero por tradi-
cin aparecen al principio, antes de cualquier otra instruccin lgica.
Sub MiProcedimiento()
Dim miVariable As Integer
' ----- Aqu va cdigo adicional...
End Sub

Variables | 163

06_PATRICK-CHAPTER_06.indd 163 17/2/10 15:22:03


Al igual que con las constantes, las variables pueden definirse dentro de un procedimiento,
o fuera de l pero dentro de un tipo. (A las variables y las constantes declaradas fuera de un
procedimiento se les conoce como campos. A las variables y las constantes declaradas dentro de
un procedimiento se les conoce como variables locales y constantes locales, respectivamente.) La
palabra clave Dim se usa siempre con declaraciones de variables en el procedimiento. En el nivel
de tipo, la palabra clave Dim es reemplazada por uno de los siguientes modificadores de acceso:
Private
Cualquier miembro o procedimiento dentro del tipo, pero en ningn otro lado, puede usar
las variables Private. Si deriva una nueva clase a partir de una clase de base que incluye
una variable de tipo privado, el cdigo de esa clase derivada no tendr acceso a esa variable
Private; ni siquiera sabr que existe.
Friend
Las variables Friend son privadas de un ensamblado. Cualquier cdigo puede usarlas en
su tipo relacionado, pero tambin las puede usar cualquier cdigo en otro lugar del mismo
ensamblado. Eso es ser amigable.
Public
Las variables Public estn disponibles en cualquier lugar. Es posible escribir una aplicacin
o un componente que exponga su tipo para codificar ms all de s mismo. Cualquier cosa
marcada como Public puede exponerse de esta manera.
Protected
Las variables Protected son como las variables de tipo Private, pero el cdigo de clases
derivadas tambin puede acceder a ellas. Tiene la opcin usar la palabra clave Protected
slo en una definicin de clase; no funciona en una estructura o mdulo.
Protected Friend
Las variables Protected Friend combinan todas las caractersticas de Friend y Protec-
ted. Slo pueden usarse en clases.
Una sola clase o tipo puede contener campos y variables y constantes locales.
Class MiClase
' ----- Aqu va un campo.
Private SoloParaUsoInterno As Boolean

Sub MiProcedimiento()
' ----- Aqu va una variable local.
Dim miVariable As Integer
End Sub
End Class

Hay otras variaciones de sintaxis de la instruccin Dim, algunas de las cuales analizar ms ade-
lante en ste y otros captulos.

mbito y tiempo de vida


Cuando define una variable dentro de un procedimiento, tiene un mbito en el nivel del proce-
dimiento. Esto significa que puede usarla en cualquier lugar de ese procedimiento. Es probable

164 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 164 17/2/10 15:22:03


que ste tenga instrucciones de bloque (instrucciones, como For...Next e If...Then, que
requieren ms de una lnea de cdigo fuente para completarse). Si agrega una instruccin Dim
entre las lneas de inicio y final de una de esas instrucciones, esa variable declarada slo tendr un
mbito en el nivel del bloque. Slo estar disponible dentro de ese bloque del procedimiento.
For contador = 1 To 10
Dim procesarResultado As Integer
' ----- Ms cdigo aqu.
Next contador
MsgBox(procesarResultado) ' esta lnea fallar

Este cdigo declara procesarResultado dentro del bloque For...Next. De modo que slo
estar disponible para usarse dentro de ese bloque; cualquier intento de usar procesarResul-
tado fuera del bloque For genera un error inmediato.
El tiempo de vida de una variable en el nivel del procedimiento empieza cuando el cdigo ingresa
por primera vez en ese procedimiento, y termina cuando el cdigo lo deja. Esto es verdad para
las variables en el nivel del procedimiento y del bloque. Esto significa que si asigna a una variable
en el nivel del bloque algn valor antes de salir de ste, an tendr ese valor si vuelve a ingresar
en ese bloque durante la llamada al mismo procedimiento.
En el caso de campos (variables en el nivel de clase), el mbito depende del nivel de acceso usado
cuando se declara la variable. El tiempo de vida de un campo empieza cuando se crea la instancia
de la clase en el cdigo, y termina cuando se destruye la instancia o cuando deja de usarse.

Convenciones de asignacin de nombres


a variables y constantes
Los nombres que le d a sus variables no tendrn mucho impacto en la manera en que su aplica-
cin se ejecuta en la estacin de trabajo del usuario, pero s pueden afectar la claridad del cdigo
fuente. En los das anteriores a .NET, muchos lenguajes de programacin de Windows usaban
un sistema denominado notacin hngara para crear nombres de variables. Esos nombres ayuda-
ban a comunicar la informacin acerca de los tipos de datos y el uso de una variable a cualquier
persona que leyera el cdigo. Por desgracia, las reglas usadas para definir los nombres de variables
hngaros eran complejas y variaban no slo entre lenguajes de programa, sino tambin entre
programadores que usaban el mismo lenguaje.
Cuando Microsoft lanz .NET en 2002, su documentacin inclua varias recomendaciones de pro-
gramacin. Una de ellas era Dejar de usar el lenguaje de programacin Java. Otra animaba a los
programadores a que dejaran de usar la notacin hngara y, en cambio, aplicaran un nuevo sistema
que usaba reglas de maysculas y minsculas para diferenciar a las variables. Las reglas establecen que
todos los nombres de variable deben emplear una combinacin de maysculas y minsculas (donde
cada palabra lgica del nombre de la variable empieza con una mayscula y sigue con minsculas).
La nica diferenciacin proviene del uso de maysculas y minsculas en la letra inicial:
Establezca la primera letra de todas las variables locales y todos los parmetros de mtodos
en minsculas. A esto se le denomina Uso de maysculas y minsculas Camel.

Convenciones de asignacin de nombres a variables y constantes | 165

06_PATRICK-CHAPTER_06.indd 165 17/2/10 15:22:03


Establezca la primera letra de todos los campos, mtodos, miembros de tipo (incluidos
controles) y tipos en maysculas. A esto se le conoce como Uso de maysculas y minsculas
de Pascal.
Para ser honesto, debo decir que modifiqu ligeramente las recomendaciones originales de la
documentacin proporcionada con Visual Studio. Las reglas originales eran un poco ms com-
plejas cuando se trataba de nombres de campos y de parmetros de mtodos. En lo personal, me
parece que las dos reglas de esta lista son adecuadas para mis necesidades.
Podra darle a un variable local un nombre como revisarEstaVariable, que pone en mays-
culas la primera letra de cada palabra, pero no la letra inicial. Si define esta variable como un
campo, en cambio, cambiara su nombre a RevisarEstaVariable, poniendo en maysculas
la primera letra.

Inferencia de tipo local


Visual Basic es un lenguaje con un uso fuerte de los tipos. Esto significa que todos los valores de
datos son Integer, Short, String o algn otro tipo de datos especfico. Aun el tipo de datos
predeterminado Object se considera fuerte. La creacin de una variable sin un tipo de datos se
considerara dbil, y los programadores en Visual Basic son cualquier cosa menos dbiles.
Por lo general, le indica especficamente a Visual Basic qu tipo de datos se usa para una variable.
Pero una nueva caracterstica de Visual Basic 2008 llamada inferencia de tipo local permite al
compilador de Visual Basic unirse a la diversin de asignar tipos a variables. Qu divertido!
En la declaracin estndar de variables, se incluye el tipo de datos con una clusula As.
Dim queSoy As String
queSoy = "Eres una cadena, y solamente una cadena."

Pero con la inferencia de tipo local, Visual Basic adivinar el tipo de datos por su cuenta cuando
deje fuera la clusula As.
Dim cosa1
Dim cosa2
cosa1 = "Esto es una cadena."
cosa2 = 25
MsgBox(cosa1.GetType.ToString)
MsgBox(cosa2.GetType.ToString)

Cuando ejecute este cdigo, aparecern dos mensajes para indicarle el nombre del tipo fuerte de
cada cosa: System.String y System.Int32, respectivamente. (No se preocupe por GetType,
por ahora. Slo identifica el tipo verdadero de las cosas.) Visual Basic acta como si las primeras
dos lneas tuvieran este aspecto:
Dim cosa1 As String
Dim cosa2 As Integer

Una vez que Visual Basic identifica el tipo de datos para una de sus variables an sin tipo, esa
variable se pega a ese tipo. El siguiente cdigo fallar:

166 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 166 17/2/10 15:22:03


Dim cosa1
cosa1 = "Esto es una cadena."
cosa1 = 25 ' Esto falla, porque cosa1 es una cadena.

Como el nombre lo implica, la inferencia de tipo local slo funciona con variables locales. Los
campos de clase deben declararse con un tipo de datos especfico. Tambin se aplican otras res-
tricciones. Consulte al proveedor para conocer ms detalles.
Puede activar y desactivar el sistema de inferencia de tipos empleando la instruccin Option
Infer en la parte superior de cada archivo de cdigo fuente.
Option Infer On

Tambin puede establecer esto en todo un proyecto mediante la ficha Compilar de las propie-
dades del proyecto.
La inferencia de tipo existe para dar soporte a las nuevas caractersticas de LINQ analizadas en el
captulo 17. Aunque puede dejar que Visual Basic infiera la mayor parte de las variables o todas,
no es buena idea hacerlo en la prctica. Aunque el compilador es inteligente, no piensa en la
lgica general de su aplicacin y puede tomar diferentes decisiones de asignacin de tipos de las
que tomara usted. Por ejemplo, Visual Basic puede inferir una variable como Integer, mien-
tras que usted planea incluir en ella valores Long grandes ms adelante. Si tiene la oportunidad
de incluir clusulas As que signifiquen algo y sean exactas con sus instrucciones Dim, hgalo.
Porque yo lo digo. Y porque es la manera correcta de hacer las cosas.

Operadores
Visual Basic incluye diversos operadores que le permiten manipular los valores de sus variables.
Ya ha visto el operador de asignacin (=), que le facilita asignar un valor directamente a una
variable. La mayor parte de los dems operadores le permiten construir expresiones que com-
binan diversos valores originales a la manera de frmulas para su posterior asignacin a una
variable. Considere la siguiente instruccin:
areaCuadrado = largo * ancho

Esta instruccin incluye dos operadores: asignacin y multiplicacin. El operador de multipli-


cacin combina dos valores (largo y ancho) usando una multiplicacin, y el operador de asig-
nacin almacena el producto en la variable areaCuadrado. Sin operadores, sera difcil calcular
un rea y cualquier frmula compleja.
Hay dos tipos de operadores de no asignacin: unario y binario. Los operadores unarios funcio-
nan con un solo valor u operando. Los operadores binarios requieren dos operandos, pero dan
como resultado un solo valor procesado. Entre los operandos se incluyen literales, constantes,
variables y valores de devolucin de funciones. En la tabla 6-7 se presenta una lista de diferentes
operadores con detalles de uso.

Operadores | 167

06_PATRICK-CHAPTER_06.indd 167 17/2/10 15:22:04


Tabla 6-7. Operadores de no asignacin de Visual Basic.

Operador Descripcin
+ Suma. Suma dos operandos, produciendo un total. Algunos programadores tambin usan este operador para rea-
lizar unin de cadenas, pero es mejor unir cadenas con otro operador (&) especficamente diseado para ese fin.
Sintaxis: operand1 + operand2
Ejemplo: 2 + 3
+ Suma unaria. Asegura que un operando retenga su signo actual, sea positivo o negativo. Debido a que todos
los operandos retienen automticamente su signo, este operador suele ser redundante. Ser tocado de
nuevo cuando analicemos la sobrecarga de operador en el captulo 12.
Sintaxis: +operando
Ejemplo: +5
- Resta. Resta un operando (el segundo) de otro (el primero), y devuelve la diferencia.
Sintaxis: operando1 operando2
Ejemplo: 10 4
- Negacin unaria. Invierte el signo de su operando. Cuando se usa con un nmero de literal, da como resultado un
valor negativo. Cuando se usa con una variable que contiene un valor negativo, produce un resultado positivo.
Sintaxis: operando2
Ejemplo: 34
* Multiplicacin. Multiplica dos operandos y devuelve el producto.
Sintaxis: operando1 * operando2
Ejemplo: 8 * 3
/ Divisin. Divide un operando (el primero) entre otro (el segundo) y devuelve el cociente. Si el segundo operan-
do contiene cero, ocurre un error de divisin entre cero. (Cuando se trabaja con valores Single y Double,
la divisin entre cero en realidad devuelve indicadores especiales de infinito o no es un nmero.)
Sintaxis: operando1 / operando2
Ejemplo: 9 / 3
\ Divisin de entero. Divide un operando (el primero) entre otro (el segundo) y devuelve el cociente, truncan-
do primero cualquier parte decimal de ese resultado. Si el segundo operando contiene cero, ocurre un error
de divisin entre cero. (Revise el comentario presentado en el operador /.)
Sintaxis: operando1 \ operando2
Ejemplo: 9 \ 4
Mod Mdulo. Divide un operando (el primero) entre otro (el segundo) y devuelve el sobrante como un valor
entero. Si el segundo operando contiene cero, ocurre un error de divisin entre cero. (Revise el comentario
presentado en el operador /.)
Sintaxis: operando1 Mod operando2
Ejemplo: 10 Mod 3
^ Exponenciacin. Eleva un operando (el primero) a la potencia de otro (el segundo).
Sintaxis: operando1 ^ operando2
Ejemplo: 2 ^ 8
& Unin de cadenas. Une dos operandos y devuelve un resultado con la cadena combinada. Ambos operandos
se convierten a su equivalente String antes de unirse.
Sintaxis: operando1 & operando2
Ejemplo: "O" & "K"

168 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 168 17/2/10 15:22:04


Tabla 6-7. Operadores de no asignacin de Visual Basic (continuacin).

Operador Descripcin
Y Conjuncin. Realiza una conjuncin lgica o en el nivel de bits sobre dos operandos y devuelve el resultado.
En el caso de operaciones lgicas (booleanas), el resultado ser True slo si ambos operadores se evalan
como True. Para operaciones en el nivel de bits (enteros) cada bit especfico del resultado ser 1 slo si
los bits correspondientes en ambos operandos son 1.
Sintaxis: operando1 Y operando2
Ejemplo: esOficinista Y esCaballero
O Disyuncin. Realiza una conjuncin lgica o en el nivel de bits sobre dos operandos y devuelve el resultado.
En el caso de operaciones lgicas (booleanas), el resultado ser True si cualquier operando se evala como
True. Para operaciones en el nivel de bits (enteros) cada bit especfico del resultado ser 1 slo si el bit
correspondiente en cada operando es 1.
Sintaxis: operando1 O operando2
Ejemplo: disfrutaLasMontanas O enjoySea
AndAlso Conjuncin de corto circuito. Este operador es equivalente a la versin lgica del operador Y, pero si el pri-
mer operando se evala como False, el segundo no se evaluar en absoluto. Este operador no da soporte
a operaciones en el nivel de bits.
Sintaxis: operando1 AndAlso operando2
Ejemplo: esOficinista AndAlso esCaballero
OrElse Disyuncin de corto circuito. Este operador es equivalente a la versin lgica del operador O, pero si el pri-
mer operando se evala como True, el segundo no se evaluar en absoluto. Este operador no da soporte a
operaciones en el nivel de bits.
Sintaxis: operando1 OrElse operando2
Ejemplo: disfrutaLasMontanas OrElse disfrutaElMar
Not Negacin. Realiza una negacin lgica o en el nivel de bits en un solo operando. En el caso de operaciones
lgicas (booleanas) el resultado ser True si el operando se evala como False, y False si el operando
se evala como True. En el caso de operaciones en el nivel de bits (enteros), cada bit especfico del resulta-
do ser 1 si el bit del operando correspondiente es 0, y ser 0 si el bit del operando es 1.
Sintaxis: Not operando1
Ejemplo: Not listoParaEnviar
Xor Exclusin. Realiza un operacin lgica o en el nivel de bit excluyente o sobre dos operandos y devuelve the
result. En el caso de operaciones lgicas (booleanas) el resultado ser True slo si los operandos tienen
diferentes valores lgicos (True o False). En el caso de operaciones en el nivel de bits (enteros), cada bit
especfico del resultado ser 1 slo si los bits correspondientes en los operandos son diferentes.
Sintaxis: operando1 Xor operando2
Ejemplo: platilloDePollo Xor platilloDeRes
<< Desplazamiento a la izquierda. El operador de desplazamiento a la izquierda desplaza los
bits del primer operando a la izquierda en el nmero de posiciones especificado en el segundo operando y
devuelve el resultado. Los bits empujados a la izquierda del resultado se pierden; los bits
agregados en el extremo derecho son siempre 0. Este operador funciona mejor si el primer operando es un
valor entero sin signo.
Sintaxis: operando1 << operando2
Ejemplo: &H25 << 3

Operadores | 169

06_PATRICK-CHAPTER_06.indd 169 17/2/10 15:22:04


Tabla 6-7. Operadores de no asignacin de Visual Basic (continuacin).

Operador Descripcin
>> Desplazamiento a la derecha. El operador de desplazamiento a la derecha desplaza los bits
del primer operando a la derecha en el nmero de posiciones especificado en el segundo operando y de-
vuelve el resultado. Los bits empujados a la derecha del resultado se pierden; los bits
agregados a la izquierda son siempre los mismos que el bit que se encontraba originalmente en el extremo
izquierdo. Este operador funciona mejor si el primer operando es un valor entero sin signo.
Sintaxis: operando1 >> operando2
Ejemplo: &H25 >> 2
= Igual a (comparacin). Compara dos operandos y devuelve True si tienen el mismo valor.
Sintaxis: operando1 = operando2
Ejemplo: montoEsperado = montoReal
<> No es igual a. Compara dos operandos y devuelve True si no tienen el mismo valor.
Sintaxis: operando1 <> operando2
Ejemplo: valorInicial <> valorFinal
< Menor que. Compara dos operandos y devuelve True si el primero tiene un valor menor que el segundo.
Cuando se comparan valores de cadenas, el resultado es True si el primer operando aparece primero
cuando se ordenan las cadenas.
Sintaxis: operando1 < operando2
Ejemplo: tasaAumento < tasaInflacion
> Mayor que. Compara dos operandos y devuelve True si el primero tiene un valor mayor que el segundo.
Cuando se comparan valores de cadenas, el resultado es True si el primer operando aparece despus
cuando se ordenan las cadenas.
Sintaxis: operando1 > operando2
Ejemplo: tasaAumento > tasaInflacion
<= Menor que o igual a. Compara dos operandos y devuelve True si el primero es menor o igual al valor del
segundo.
Sintaxis: operando1 <= operando2
Ejemplo: tasaAumento <= tasaInflacion
>= Mayor que o igual a. Compara dos operandos y devuelve True si el primero es mayor o igual al valor del
segundo.
Sintaxis: operando1 >= operando2
Ejemplo: tasaAumento >= tasaInflacion
Like Comparacin de patrones. Compara el primer operando con el patrn especificado en el segundo operando
y devuelve True si hay una coincidencia. El operando del patrn da soporte a algunas opciones bsicas de
comodn y seleccin, y se describe por completo en la documentacin proporcionada con Visual Studio. .NET
tambin incluye una caracterstica llamada expresiones regulares que proporciona una solucin de
comparacin de patrones ms amplia.
Sintaxis: operando1 Like operando2
Ejemplo: idGobierno Like patrnSSN

170 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 170 17/2/10 15:22:04


Tabla 6-7. Operadores de no asignacin de Visual Basic (continuacin).

Operador Descripcin
Is Comparacin de tipos. Compara el primer operando con otro objeto, un tipo de datos, o Nothing y
devuelve True si hay una coincidencia. Documentar este operador de manera ms detallada en pginas
posteriores y en el captulo 8.
Sintaxis: operando1 Is operando2
Ejemplo: unaVariable Is Nothing
IsNot Comparacin de tipo negada. Este operador es un mtodo abreviado para el uso de los operadores Is y
Not juntos. Las siguientes dos expresiones son equivalentes:
primero IsNot segundo
Not (primero Is segundo)
Sintaxis: operando1 IsNot operando2
Ejemplo: algo IsNot algoAdicional
TypeOf Comparacin de instancia. Devuelve el tipo de datos de un valor o variable. El tipo de cada clase o tipo de
datos en .NET se implementa como un objeto, basado en System.Type. El operador TypeOf slo
puede usarse con el operador Is:
Sintaxis: TypeOf operando1 Is typeOperand
Ejemplo: TypeOf unaVariable Is Integer
AddressOf Delega la recuperacin. Devuelve un delegado (descrito en el captulo 8) que representa una instancia
especfica de un procedimiento o mtodo.
Sintaxis: AddressOf metodo1
Ejemplo: AddressOf uno.unMetodo
GetType Recuperacin de tipo. Devuelve el tipo de datos de un valor o variable, de manera parecida al operador
TypeOf. Sin embargo, GetType trabaja como una funcin y no es necesario que se utilice con el
operador Is.
Sintaxis: GetType(operando1)
Ejemplo: GetType(one)

Los operadores de no asignacin usan sus operandos para producir un resultado, pero no ha-
cen que los operandos se modifiquen de alguna manera. El operador de asignacin actualiza el
operando que aparece a su izquierda. Adems del operador de asignacin estndar, Visual Basic
incluye varios operadores que combinan el operador de asignacin con alguno de los otros ope-
radores binarios. En la tabla 6-8 se presenta una lista de estos operadores de asignacin.

Tabla 6-8. Operadores de asignacin de Visual Basic.

Operador Basado en
= Operador de asignacin estndar
+= + (suma)

= (resta)
*= * (multiplicacin)

Operadores | 171

06_PATRICK-CHAPTER_06.indd 171 17/2/10 15:22:04


Tabla 6-8. Operadores de asignacin de Visual Basic (continuacin).

Operador Basado en
/= / (divisin)
\= \ (divisin entera)
^= ^ (exponenciacin)
&= & (unin)
<<= << (desplazamiento a la izquierda)
>>= >> (desplazamiento a la derecha)

Estos operadores de asignacin son mtodos abreviados de los operadores completos. Por ejem-
plo, para sumar 1 a una variable numrica, puede usar cualquiera de estas dos instrucciones:
' ----- Incrementa totalProvisional en 1.
totalProvisional = totalProvisional + 1

' ----- Otra manera de aumentar totalProvisional en 1.


totalProvisional += 1

Variables estticas
Por lo general, el tiempo de vida de una variable en el nivel del procedimiento local termina
junto con el procedimiento. Pero en ocasiones tal vez quiera que una variable retenga su valor
entre cada llamada al procedimiento. En ocasiones tal vez quiera un milln de dlares, pero no
siempre puede tenerlos. Pero s puede hacer que las variables conserven sus valores si lo desea.
Se les llaman variables estticas. Para declarar una variable esttica, use la palabra clave Static
en lugar de Dim.
Static llevaSeguimiento As Integer = 0

La asignacin de 0 a llevaSeguimiento slo se hace una vez, cuando se crea la instancia del tipo
que contiene esta instruccin. Despus de eso, mantiene cualquier valor asignado a l hasta que la
instancia se destruye. Las variables estticas tambin pueden crearse dentro de procedimientos.

Matrices
Las aplicaciones de software a menudo funcionan con conjuntos de datos relacionados, no slo valo-
res de datos aislados. Visual Basic incluye dos maneras principales de trabajar con esos conjuntos de
datos: colecciones (analizadas en el captulo 16) y matrices. Una matriz asigna una posicin numrica
a cada elemento incluido en el conjunto, empezando con 0 y terminando con uno menos el nmero
de elementos incluido. Una matriz de cinco elementos tiene elementos numerados de 0 a 4.
Como ejemplo, imagine que est desarrollando una aplicacin de simulacin de zoolgico. Po-
dra incluir una matriz llamada animales que incluya cada nombre de animal en su zoolgico:

172 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 172 17/2/10 15:22:04


Animal #0: Armadillo
Animal #1: Buitre
Animal #2: Chimpanc
Animal #3: Delfn
...etctera ...
Visual Basic identifica elementos de matriz por el nmero entre parntesis despus del nombre
de la matriz. En el caso de nuestros animales, una simple asignacin pone el nombre String de
cada animal en un elemento de matriz.
animal(0) = "Armadillo"
animal(1) = "Buitre"
animal(2) = "Chimpance"
animal(3) = "Delfin"

El uso de cada elemento de la matriz es igual de fcil.


MsgBox("El primer animal es: " & animal(0))

Cada elemento de una matriz no es tan diferente de una variable independiente. En realidad, po-
dra considerar slo el conjunto de animales en el cdigo de ejemplo que sean variables distintas:
una variable llamada animal(0), otra animal(1), etctera. Pero son mejores que las variables
ordinarias porque puede procesarlas como un conjunto. Por ejemplo, puede rastrear cada ele-
mento empleando un bucle For...Next. Considere una matriz Integer llamada cadaEle-
mento con elementos numerados del 0 al 2. El siguiente bloque de cdigo agrega los elementos
de la matriz como si fueran variables distintas:
Dim montoTotal As Integer
montoTotal = cadaElemento(0) + cadaElemento(1) + cadaElemento(2)

Pero como los elementos estn en una matriz numerada, puede usar un bucle For...Next para
rastrear cada elemento, de uno en uno.
Dim montoTotal As Integer = 0
For contador As Integer = 0 to 2
' ----- Mantener un total actual de los elementos.
montoTotal += cadaElemento(contador)
Next contador

Antes de que asigne valores a elementos de las matrices o que recupere esos elementos, debe decla-
rar y cambiar el tamao de la matriz para sus necesidades. La instruccin Dim crea una matriz como
lo hacen las variables comunes; la instruccin ReDim cambia el tamao de una matriz despus de
que ya existe.
Dim animal(0 To 25) As String ' Matriz de 26 elementos
Dim animalesAdicionales() As String ' Una matriz String indefinida
ReDim animalesAdicionales(0 To 25) ' Ahora tiene elementos

Por lo general, la instruccin ReDim eliminara cualquier dato existente almacenado en cada ele-
mento de la matriz. La adicin de la palabra clave Preserve retiene todos los datos existentes.

Matrices | 173

06_PATRICK-CHAPTER_06.indd 173 17/2/10 15:22:04


ReDim Preserve animalesAdicionales(0 to 30) ' Conserva elementos de 0 a 25

Cada elemento de la matriz es un objeto independiente al que pueden asignarse datos conforme
se necesite. En este ejemplo, cada elemento es una String, pero puede usar cualquier tipo de
valor o de referencia que desee en la declaracin de la matriz. Si crea una matriz de elementos
Objeto, puede combinar y comparar los datos de la matriz; no es necesario que el elemento 0
contenga el mismo tipo de datos que el 1.
La propia matriz tambin es un objeto independiente (una instancia de clase que administra su con-
junto de elementos contenidos). Si necesita especificar toda la matriz, y no slo uno de sus elemen-
tos (y hay ocasiones en que necesita hacerlo), use su nombre sin parntesis o valores de posicin.

Matrices de varias dimensiones


Las matrices de Visual Basic dan soporte a ms de una dimensin (o rango). Las dimensiones
indican el nmero de rangos independientes a los que da soporte la matriz. Una matriz de una
dimensin, como la matriz animal que vimos antes, incluye un solo rango. Una matriz de dos
dimensiones incluye dos rangos delimitados por comas, formando una organizacin de cuadr-
cula de elementos, con rangos separados para filas y columnas.
Dim tableroGato(0 To 2, 0 To 2) As Char ' tablero de 3 x 3

Una matriz puede tener hasta 60 dimensiones diferentes, aunque suele haber mejores maneras
de organizar datos que dividirlos en sus muchas dimensiones.

Lmites de matriz
El lmite inferior de cualquier dimensin de matriz suele ser 0, como lo indica la clusula 0 To x
cuando se define o redimensiona la matriz. En realidad puede dejar fuera la parte 0 To de la
instruccin, y slo incluir el lmite superior.
' ----- Estas dos lineas son equivalentes.
Dim animal(0 To 25) As String
Dim animal(25) As String

Cada una de estas dos instrucciones crea una matriz con 26 elementos, numeradas del 0 al 25.
Hay unos cuantos casos especiales donde se permiten lmites menores a cero, como cuando se
trabaja con matrices generadas en el COM ms antiguo. Pero la sintaxis estndar de declaracio-
nes de Visual Basic no le permite crear matrices con lmites inferiores a cero.
Para determinar los lmites inferior y superior actuales de una dimensin de matriz, use las fun-
ciones LBound y UBound.
MsgBox("El tablero es " & (UBound(tableroGato, 1) + 1) & _
" by " & (UBound(tableroGato, 2) + 1))

Si su matriz incluye una sola dimensin, no tiene que indicar a LBound o UBound cul dimen-
sin quiere revisar.
MsgBox("El elemento superior se ha numerado " & UBound(animal))

174 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 174 17/2/10 15:22:04


Cada matriz tambin incluye mtodos GetLowerBound y GetUpperBound que devuelven el
mismo resultado que LBound y UBound. (Analizo los mtodos con detalle en el captulo 8.) Sin
embargo, el nmero de dimensin que pase a los mtodos GetLowerBound y GetUpperBound
empiezan en 0, mientras que los valores de dimensin LBound y UBound empiezan a contar en 1.
MsgBox("El tablero es " & _
(tableroGato.GetUpperBound(0) + 1) & _
" por " & (tableroGato.GetUpperBound(1) + 1))

Inicializacin de matrices
Una vez que ha declarado los elementos de su matriz, puede almacenar y recuperar elementos
cuando lo necesite. Tambin es posible almacenar elementos en su matriz en el momento de la
declaracin. La lista de nuevos elementos de la matriz aparece en un conjunto de llaves.
Dim cuadrados( ) As Integer = {0, 1, 4, 9, 16, 25}
Debe dejar fuera las especificaciones de lmites superior e inferior cuando crea una matriz de esta
manera. La matriz cuadrados mostrada aqu tendr elementos numerados del 0 al 5.

Tipos que pueden ser nulos


Los tipos de valor son variables que trabajan mucho y mantienen sus valores de datos durante toda
su vida. Los tipos de referencia tambin trabajan duro, pero pueden llenarse con Nothing y ob-
tener un poco de descanso. Esta diferencia ha sido una espinita clavada en el costado de los tipos
de valor. Es mucho pedir que se d un poco de descanso a estas variables de la clase trabajadora?
Bueno, Microsoft ha escuchado esta plegaria y, a partir de Visual Basic 2008, ahora se puede
asignar Nothing a los tipos de valor. Estos nuevos tipos que pueden tener valores nulos son esen-
ciales cuando quiere tener un estado indefinido para un tipo de valor estndar (especialmente
til cuando se trabaja con campos de base de datos). Considere esta clase que administra infor-
macin del empleado:
Public Class Empleado
Public Nombre As String
Public FechaContrato As Date
Public FechaDespido As Date

Public Sub New(ByVal nombreEmpleado As String, _


ByVal fechaContrato As Date)
Me.Nombre = nombreEmpleado
Me.FechaContrato = fechaContrato
End Sub
End Class

Esta clase funciona bien, excepto que FechaDespido en realidad no es correcta. Como opcin
predeterminada, se establecer en 1 de enero del ao 1, a la medianoche, y puede usar esa fecha
como su fecha de nunca se despide. Pero qu pasa si su compaa realmente quiere despedir
a alguien en ese momento, hace dos mil aos?

Tipos que pueden ser nulos | 175

06_PATRICK-CHAPTER_06.indd 175 17/2/10 15:22:04


Para resolver este problema, los tipos a los que se pueden asignar valores nulos le permiten
asignar y recuperar Nothing de variables de tipo de valor. Estos tipos de valor enriquecidos con
vitaminas se declaran usando una sintaxis especial con un signo de interrogacin.
' ----- Cualquiera de estas dos instrucciones funciona.
Public FechaDespido As Date?
Public FechaDespido2? As Date

Prefiero la primera sintaxis, con el signo de interrogacin agregado al tipo de datos. Pero cual-
quier instruccin funcionar. Una vez que est declarada, un tipo de valor puede tomar datos
estndar o Nothing.
FechaDespido = Nothing
FechaDespido = #7/18/2008#
If (FechaDespido Is Nothing) Then...

Hay una sintaxis especial cuando define sus propios tipos de valor como posibles nulos, pero
como usa la caracterstica genricos de Visual Basic, esperar a presentarla hasta el captulo 16.

Funciones comunes de Visual Basic


En esta seccin final se incluye una breve lista de las funciones integradas en el lenguaje Visual
Basic, muchas de las cuales usar de manera regular en sus aplicaciones. Adems, aqu se inclu-
yen algunos miembros de la biblioteca de clases del marco conceptual (FCL, Framework Class
Library) que replican caractersticas que eran parte del lenguaje Visual Basic antes de .NET, pero
se pasaron al marco conceptual para acceso ms general. Para conocer la sintaxis exacta necesaria
para usar estas funciones, acceda a la ayuda en lnea de Visual Studio.

Funciones de conversin
Las funciones de conversin le permiten convertir datos de un tipo de datos de Visual Basic a
otro. No es aplicable a todo, de modo que no puede convertir la cadena hola en un entero y
esperar que funcione. Pero convertir nmeros de un tipo numrico a otro, o convertir nmeros
entre tipos de cadena y numricos, por lo general funciona bien.
Todas estas instrucciones (excepto CType) tienen la misma sintaxis bsica:
dest = CXxxx(origen)

donde origen es el valor que habr de convertirse con CXxxx. No tiene que asignar el resultado
a una variable; puede usarlo en cualquier lugar en que usara un valor de literal o variable similar.
En la tabla 6-9 se presenta una lista de funciones de conversin integradas.

Tabla 6-9. Funciones de conversin de Visual Basic.

Funcin Descripcin
CBool Convierte un valor a Boolean.
CByte Convierte un valor a Byte.

176 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 176 17/2/10 15:22:05


Tabla 6-9. Funciones de conversin de Visual Basic (continuacin).

Funcin Descripcin
CChar Convierte un valor a Char. Si el valor de origen es una cadena, slo el primer carcter se convierte.
CDate Convierte un valor a Date. Si el valor de origen es una cadena, debe estar en un formato vlido de hora o
fecha.
CDbl Convierte un valor a Double.
CDec Convierte un valor a Decimal.
CInt Convierte un valor a Integer.
CLng Convierte un valor a Long.
CObj Convierte un valor a Object. Es til cuando quiere almacenar un tipo de valor como una instancia de
Object.
CSByte Convierte un valor a SByte.
CShort Convierte un valor a Short.
CSng Convierte un valor a Single.
CType Convierte un valor a cualquier tipo, clase o interfaz definido, ya sea en su aplicacin o en FCL. La sintaxis es:
CType(datosOrigen, nuevoTipo)
donde nuevoTipo es un tipo de datos. Por ejemplo:
CType(5, String)
Convierte el 5 Integer en un String. Al igual que con otras funciones de conversin, no puede conver-
tir datos de un tipo a otro, si los tipos son incompatibles, o si no hay conversin disponible que sepa cmo
generar el tipo de destino a partir del tipo de origen. La sobrecarga de operadores, analizada en el captulo
12, proporciona una manera de hacer que la funcin CType convierta entre tipos que de otra manera
seran incompatibles
CUInt Convierte un valor a UInteger.
CULng Convierte un valor a ULong.
CUShort Convierte un valor a UShort.

Funciones relacionadas con fechas


Visual Basic incluye varias funciones diseadas para administrar valores de fecha y hora. En la
tabla 6-10 se presenta una lista de esas funciones. La mayor parte de esas funciones aceptan uno
o ms argumentos y devuelven Date, String o un resultado numrico.

Tabla 6-10. Funciones y propiedades relacionadas con fechas de Visual Basic.

Funcin Descripcin
DateAdd Suma o resta un valor de fecha u hora a una fecha de inicio. Por ejemplo, puede sumar 12 minutos, o restar
tres aos, de una fecha determinada.

Funciones comunes de Visual Basic | 177

06_PATRICK-CHAPTER_06.indd 177 17/2/10 15:22:05


Tabla 6-10. Funciones y propiedades relacionadas con fechas de Visual Basic (continuacin).

Funcin Descripcin
DateDiff Devuelve la diferencia entre dos valores de fecha u hora. Puede especificar el intervalo, como meses o segundos.
DatePart Devuelve un componente de una fecha u hora, como la hora o el ao.
DateSerial Devuelve una Date integrada a partir de valores especficos de mes, da y ao.
DateString Devuelve la fecha actual como una cadena. Tambin puede establecer la fecha de la computadora local
utilizando esta palabra clave.
DateValue Devuelve la parte de la fecha de un valor combinado de fecha y hora; la parte de la hora se descarta.
Day Devuelve el da a partir de un valor de fecha determinado.
FormatDateTime Forma una fecha u hora determinada como una cadena, empleando un pequeo conjunto de formatos
predefinidos. Esta funcin se incluye para compatibilidad con cdigo antiguo de VBScript.
Hour Devuelve la hora de un valor de hora determinado.
IsDate Indica si los datos proporcionados a esta funcin son una fecha vlida.
Minute Devuelve el minuto de una valor de hora determinado.
Month Devuelve el mes de un valor de fecha determinado.
MonthName Devuelve el nombre de un mes a partir un valor de mes numrico, de 1 a 12.
Now Devuelve la fecha y hora actuales. Equivalente a TimeOfDay.
Second Devuelve los segundos a partir de un valor de hora determinado.
TimeOfDay Devuelve la fecha y hora actuales. Equivalente a Now.
Timer Devuelve el nmero de segundos que han transcurrido desde la medianoche del da actual. Esta funcin se
restablece a 0 cada medianoche.
TimeSerial Devuelve una Date integrada, a partir de valores especficos de hora, minuto y segundo.
TimeString Devuelve la hora actual como una cadena. Tambin puede establecer la hora en la computadora local
empleando esta palabra clave.
TimeValue Devuelve la parte de la hora de un valor combinado de fecha y hora; se descarta la parte de la fecha.
Today Devuelve la fecha actual.
Weekday Devuelve un entero que indica el da de la semana.
WeekdayName Devuelve el nombre de un da de la semana para un da entero de la semana.
Year Devuelve el ao de un valor de fecha determinado.

Las variables creadas como System.DateTime (o Date de Visual Basic) incluyen varias propie-
dades y mtodos que proporcionan caractersticas similares a las funciones que aparecen en la
lista de la tabla 6-10. Por ejemplo, la propiedad Second devuelve el nmero de segundos.
Dim horaJunta As Date
horaJunta = #11/7/2005 8:00:03am#
MsgBox(horaJunta.Second) ' Despliega '3'
MsgBox(Second(horaJunta)) ' Igual despliega '3'
Puede usar funciones intrnsecas de Visual Basic o los mtodos y las propiedades equivalentes de
System.DateTime en su cdigo. Cada tcnica proporciona el mismo resultado.

178 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 178 17/2/10 15:22:05


Funciones numricas
Los programadores en Visual Basic adoran el trabajo con nmeros; lo llevan en la sangre. Por
fortuna, Visual Basic incluye muchas caractersticas para realizar maravillas con nmeros. Ade-
ms de los operadores estndar de manipulacin de datos, en la tabla 6-11 se presenta una lista
de varias funciones relacionadas con nmeros.

Tabla 6-11. Funciones relacionadas con nmeros de Visual Basic.

Funcin Descripcin
Fix Trunca la parte decimal de un nmero, devolviendo slo la parte entera. Similar a la funcin Int.
FormatCurrency Forma un nmero determinado como un valor de moneda, empleando un conjunto pequeo de formatos
predefinidos. Esta funcin se incluye para compatibilidad con cdigo antiguo de VBScript.
FormatNumber Forma un nmero determinado como un nmero general, empleando un conjunto pequeo de formatos
predefinidos. Esta funcin se incluye para compatibilidad con cdigo antiguo de VBScript.
FormatPercent Forma un nmero determinado como un porcentaje, empleando un conjunto pequeo de formatos predefi-
nidos. Esta funcin se incluye para compatibilidad con cdigo antiguo de VBScript.
Hex Forma un nmero como hexadecimal y devuelve su representacin de cadena.
Int Devuelve el nmero entero que es menor o igual al valor proporcionado. Similar a la funcin Fix.
IsNumeric Indica si los datos proporcionados a esta funcin son un nmero vlido.
Oct Forma un nmero como octal y devuelve su representacin de cadena.
Val Extrae el primer nmero vlido de una cadena y lo devuelve.

.NET Framework incluye la clase System.Math, que contiene varios miembros de funcin
relacionados con clculos matemticos. Algunos de stos, como Round, Sin y Log, se imple-
mentaron como funciones intrnsecas en Visual Basic 6.0, pero se han movido del lenguaje a la
clase Math en .NET.
Visual Basic tambin incluye varias funciones usadas para clculos financieros y de contabilidad.
Estas funciones se incluyeron en Visual Basic 6.0. Como no son relevantes para el proyecto
analizado en este libro, slo presentar aqu sus nombres: DDB, FV, IPmt, IRR, MIRR, NPer, NPV,
Pmt, PPmt, PV, Rate, SLN y SYD.

Funciones de cadena
La manipulacin de cadenas es una parte esencial de la programacin en Windows. Las nuevas
caractersticas XML incluidas con .NET son en realidad slo bonitas rutinas de manipulacin de
cadenas, aunque con las complejidades ocultas. Visual Basic incluye muchas funciones diseadas
para manipular cadenas y caracteres. Aparecen en la tabla 6-12.

Funciones comunes de Visual Basic | 179

06_PATRICK-CHAPTER_06.indd 179 17/2/10 15:22:05


Tabla 6-12. Funciones relacionadas con cadena de Visual Basic.

Funcin Descripcin
Asc, AscW Devuelve el valor ASCII o Unicode numrico de un carcter.
Chr, ChrW Dado un nmero, estas funciones devuelven el carcter ASCII o Unicode correspondiente.
Filter Devuelve una matriz que es un subconjunto de una matriz de origen, pero incluyendo slo los elementos
que coinciden con un patrn.
Format Forma valores de nmero, fecha y hora que usa cdigos de formato predefinidos o personalizados.
GetChar Extrae un solo carcter de una cadena ms larga.
InStr Devuelve la posicin de una subcadena dentro de una cadena ms larga.
InStrRev Devuelve la posicin de una subcadena dentro de una cadena ms larga, buscando del final de la cadena
hacia el principio.
Join Devuelve una cadena construida a partir de una unin de una matriz de cadenas.
LCase Convierte una cadena a su equivalente en minsculas.
Left Devuelve la parte del extremo izquierdo de una cadena.
Len Devuelve la longitud de una cadena.
LSet Alinea a la izquierda una cadena dentro de una cadena de espacios ms grande.
LTrim Elimina espacios a partir del inicio de una cadena.
Mid Extrae una subcadena a partir de la parte media de una cadena ms larga.
Instruccin Mid Modifica un rango de caracteres en una cadena existente con nuevo contenido. sta no es una funcin, sino
una instruccin especial de Visual Basic. Su sintaxis vara considerablemente de la de casi todas las dems
caractersticas de Visual Basic.
Replace Reemplaza ocurrencias de una subcadena con otra subcadena, todo dentro de una cadena ms larga.
Right Devuelve la parte del extremo derecho de una cadena.
RSet Alinea a la derecha una cadena dentro de una cadena de espacios ms larga.
RTrim Elimina espacio del final de una cadena.
Space Genera una cadena que contiene un nmero especificado de caracteres de espacio. Similar a la funcin
StrDup.
Split Divide una cadena en una matriz de subcadenas con base en un delimitador.
Str Convierte un nmero a su representacin de cadena.
StrComp Compara dos cadenas y devuelve un entero que indica su orden.
StrConv Convierte una cadena a un nuevo formato con base en un cdigo de conversin. Algunas de las conversiones
incluyen el cambio de maysculas y minsculas del contenido.
StrDup Genera una cadena que contiene un nmero especificado de un carcter dado. Similar a la funcin Space,
pero funcin con cualquier carcter.
StrReverse Invierte los caracteres de una cadena.
Trim Elimina espacio del principio y el final de una cadena.
UCase Convierte una cadena a su equivalente en maysculas.

180 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 180 17/2/10 15:22:05


Al igual que con la mayor parte de las funciones, stas devuelven una nueva cadena o valor,
dejando intactos los valores originales de cadena u origen. La nica excepcin es la instruccin
Mid, que modifica el valor de la variable de origen.
Cada una de las variables creadas como System.String (o String de Visual Basic) incluye va-
rias propiedades y mtodos que proporcionan caractersticas similares a las funciones de la tabla
6-12. Por ejemplo, la propiedad Length devuelve el nmero de caracteres en la cadena.
Dim cadenaSimple As String = "abcde"
MsgBox(cadenaSimple.Length) ' Despliega '5'
MsgBox(Len(cadenaSimple)) ' Tambien despliega '5'

Puede usar las funciones intrnsecas de Visual Basic o los mtodos y propiedades equivalentes de
System.String en su cdigo. Cada tcnica proporciona el mismo resultado, aunque los detalles
y las opciones de sintaxis pueden variar.

Otras funciones
Visual Basic incluye varias funciones que se niegan a insertarse en cualquier de las otras catego-
ras. En la tabla 6-13 se documentan esas funciones.

Tabla 6-13. Funciones varias de Visual Basic.

Funcin Descripcin
DirectCast Convierte un valor de un tipo a otro, aunque los tipos de datos de inicio y final deben estar relacionados.
Similar a las funciones TryCast y CType.
ErrorToString Devuelve la representacin de cadena de un cdigo de error. Esto funciona con los cdigos de error del
sistema previamente disponibles en Visual Basic 6.0, aunque estos cdigos an estn disponibles en .NET.
IsArray Indica si los datos proporcionados a esta funcin son una matriz vlida.
IsDBNull Indica si los datos proporcionados a esta funcin son un valor de base de datos NULL.
IsError Indica si los datos proporcionados a esta funcin son una condicin de error.
IsNothing Indica si los datos proporcionados a esta funcin son indefinidos o tienen el valor Nothing.
IsReference Indica si los datos proporcionados a esta funcin son un tipo de referencia o de valor.
QBColor Devuelve un cdigo de color a partir de un conjunto pequeo de colores predefinidos.
RGB Devuelve un cdigo de color integrado a partir de componentes individuales rojo, verde y azul.
SystemTypeName Dado un nombre de tipo de datos de Visual Basic, esta funcin devuelve el nombre de tipo de datos equiva-
lente de .NET.
TryCast Convierte un valor de un tipo de datos a otro, aunque los tipos de datos de inicio y final deben estar relacio-
nados. Similar a las funciones DirectCast y CType.
TypeName Devuelve un nombre de tipo de datos que resume el tipo del contenido proporcionado. La cadena devuelta
es un resumen generalizado, y no necesariamente el nombre del tipo de datos verdadero.
VarType Devuelve un cdigo que indica el tipo de datos general del contenido proporcionado.

Funciones comunes de Visual Basic | 181

06_PATRICK-CHAPTER_06.indd 181 17/2/10 15:22:05


Resumen
Cuando est trabajando con Visual Basic, lo est haciendo con datos. Los tipos de datos in-
cluidos con Visual Basic son simples envolturas para los tipos de datos centrales en .NET, pero
Visual Basic tambin agrega muchas funciones y caractersticas que mejoran su capacidad de
administrar y organizar datos.

Proyecto
Se ve cansado. Por qu no se toma un descanso de cinco minutos y luego se echa un clavado en
el cdigo del proyecto?
Bienvenido una vez ms! En este captulo usaremos las caractersticas de tipo de datos y funcin
sobre las que ya lemos para disear algunas rutinas de soporte generales que se usarn en todo
el programa. Todo este cdigo aparecer en un mdulo de Visual Basic llamado General, alma-
cenado en un archivo de proyecto llamado General.vb.

ACCESO AL PROYECTO
Cargue el proyecto Cap06 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap06 (Final) cdigo.

Ya he agregado el archivo General.vb con sus bloques de inicio y final.


Friend Module General

End Module

Todo el cdigo que agregaremos en este captulo aparecer entre estas dos lneas. Recuerde que
los mdulos son como clases y estructuras, pero no puede crear instancias de ellos; todos sus
miembros son compartidos con todas las partes de su cdigo fuente. Esto les permite usarlos en
cualquier lugar de la aplicacin. No necesitamos hacer nada especial para que estn disponibles
para todo el programa, aparte de establecer el nivel de acceso de cada miembro, de acuerdo con
lo necesario.
En primer lugar, agregaremos algunas de las constantes generales usadas en todo el programa
de regreso a Visual Basic 6.0, llamar a stas constantes globales. Pero ahora simplemente son
miembros compartidos del mdulo General. Agregue el siguiente cdigo justo debajo de la
instruccin Module General.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap06, Elemento 1.

182 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 182 17/2/10 15:22:05


' ----- Constantes publicas.
Public Const TituloPrograma As String = "Proyecto Biblioteca"
Public Const MensajeNoAutorizado As String = _
"No tiene autoridad para realizar esta tarea."
Public Const UsarVersionDBV As Integer = 1

' ----- Constantes para la lista de imagenes ImagenesCoincidentes image list.


Public Const CoincidenciaPresente As Integer = 0
Public Const NingunaCoincidencia As Integer = 1

Public Enum MetodosBusqueda As Integer


PorTitulo = 1
PorAutor = 2
...excluidos elementos restantes para brevedad...
End Enum

Public Enum SeguridadBiblioteca As Integer


AdministrarAutores = 1
...excluidos elementos restantes para brevedad...
VerMensajesAdminCliente = 23
End Enum
Public Const MaxSeguridadBiblioteca As SeguridadBiblioteca = _
SeguridadBiblioteca.VerMensajesAdminCliente

Estas constantes y las enumeraciones se explican por s mismas con base en sus nombres con uso
de maysculas y minsculas de Pascal. UsarVersionDBV se emplear para asegurar que la apli-
cacin coincida con la base de datos que se est usando cuando hay disponibles varias versiones.
Las constantes CoincidenciaPresente y NingunaCoincidencia se utilizarn para bsquedas
de elementos de la biblioteca.
Las dos enumeraciones definen cdigos que especifican el tipo de bsqueda de artculo de la
biblioteca que se realizar (MetodosBusqueda), y los cdigos de seguridad usados para limitar
las caractersticas que un administrador especfico podr realizar en la aplicacin (Seguridad-
Biblioteca).
Es hora de agregar algunos mtodos. El primer mtodo, CentrarTexto, centra una lnea de
texto dentro de un ancho especfico. Por ejemplo, si tuviera la cadena Hola, mundo (12
caracteres de largo) y quisiera centrarla en una lnea con hasta 40 caracteres de largo, necesitara
agregar 14 espacios al principio de la lnea (determinada al restar 12 de 40 y luego dividir el
resultado entre 2). La rutina usa un par de las funciones especficas de cadena de Visual Basic
(como Trim, Left y Len) para manipular y probar los datos, y el operador de divisin de entero
\ para ayudar a calcular el nmero de espacios que se insertar.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap06, Elemento 2.

Public Funcin CentrarTexto(ByVal textoOriginal As String, _


ByVal anchoTexto As Integer) As String

Proyecto | 183

06_PATRICK-CHAPTER_06.indd 183 17/2/10 15:22:05


' ----- Centrar una pieza de texto en un ancho de campo. Si el
' texto es demasiado ancho, truncarlo.
Dim textoResultado As String

textoResultado = Trim(textoOriginal)
If (Len(textoResultado) >= anchoTexto) Then
' ----- Truncar lo necesario.
Return Trim(Left(textoOriginal, anchoTexto))
Else
' ----- Empezar con espacios adicionales.
Return Space((anchoTexto - Len(textoOriginal)) \ 2) & _
textoResultado
End If
End Funcin

La funcin empieza por hacer una copia de la cadena original (textoOriginal), eliminando
cualquier espacio adicional con la funcin Trim. Luego prueba ese resultado para saber si cabr
en la lnea. Si no, recorta los caracteres finales que no cabrn y devuelve el resultado. En el caso
de cadenas que s caben en el ancho de caracteres anchoTexto de una lnea, la funcin agrega el
nmero apropiado de espacios para iniciar la cadena y devuelve el resultado.
En el fragmento de cdigo #2 tambin se agreg una funcin llamada TextoIzquierdaYDerecha.
Funciona de manera muy parecida a CentrarTexto, pero coloca dos cadenas de texto distintas en los
extremos izquierdo y derecho de una lnea de texto. Alguna pregunta? Estupendo. Sigamos adelante.
El fragmento de cdigo #3 agrega una rutina llamada SoloDigitos. Construye una nueva
cadena hecha con los dgitos encontrado en una cadena de origen, textoOriginal. Hace esto
al llamar a la funcin IsNumeric para cada carcter de textoOriginal, de uno en uno. Cada
dgito encontrado se une entonces al final de textoDestino.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap06, Elemento 3.

Public Function SoloDigitos(ByVal textoOriginal As String) As String


' ----- Devuelve solo los digitos encontrados en una cadena.
Dim textoDestino As String
Dim contador As Integer

' ----- Examina cada caracter.


textoDestino = ""
For contador = 1 To Len(textoOriginal)
If (IsNumeric(Mid(textoOriginal, contador, 1))) Then _
textoDestino &= Mid(textoOriginal, contador, 1)
Next contador
Return textoDestino
End Function

Las dos ltimas funciones, ContarSubCadena y ObtenerSubCadena, cuentan y extraen sub-


cadenas de cadenas ms largas, con base en un delimitador. Visual Basic incluye dos funciones,

184 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 184 17/2/10 15:22:05


Mid y GetChar, que tambin extraen subcadenas de cadenas ms largas, pero estn basadas en
la posicin de la subcadena. Las funciones ContarSubCadena y ObtenerSubCadena examinan
subcadenas al usar primero un delimitador para dividir la cadena ms larga en fragmentos.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap06, Elemento 4.

La funcin ContarSubCadena cuenta cuntas veces aparece una subcadena determinada en


una cadena ms larga. Usa la funcin InStr de Visual Basic para encontrar la ubicacin de una
subcadena (textoSub) en una cadena ms larga (textoPrincipal). Sigue haciendo esto hasta
que alcanza el final de textoPrincipal, manteniendo una cuenta constante (vecesTotales)
del nmero de coincidencias.
Public Function ContarSubCadena(ByVal textoPrincipal As String, _
ByVal textoSub As String) As Integer
' ----- Devuelve una cuenta de la cantidad de veces que
' ocurre textoSub en una cadena (textoPrincipal).
Dim vecesTotales As Integer
Dim posInicio As Integer
Dim posEncontrado As Integer

vecesTotales = 0
posInicio = 1

' ----- Seguir buscando hasta que ya no se encuentra.


Do
' ----- Buscar textoSub.
posEncontrado = InStr(posInicio, textoPrincipal, textoSub)
If (posEncontrado = 0) Then Exit Do
vecesTotales += 1

' ----- Mover justo tras la ocurrencia.


posInicio = posEncontrado + Len(textoSub)
Loop

' ----- Devolver la cuenta.


Return vecesTotales
End Function

Slo para hacerlo ms interesante, us un mtodo diferente para implementar la funcin Obte-
nerSubCadena. Esta funcin devuelve una seccin delimitada de una cadena. Por ejemplo, la
siguiente instruccin obtiene la tercera parte delimitada por comas de cadenaGrande:
cadenaGrande = "abc,def,ghi,jkl,mno"
MsgBox(ObtenerSubCadena(cadenaGrande, ",", 3)) ' Despliega: ghi

Us la funcin Split de Visual Basic para dividir la cadena original (cadenaOriginal) en una
matriz de cadenas ms pequeas (partesCadena), empleando delim como punto de interrup-
cin. Luego regreso un nmero de elemento cualCampo del resultado. Debido a que cualCam-

Proyecto | 185

06_PATRICK-CHAPTER_06.indd 185 17/2/10 15:22:06


po empieza con 1 y la matriz empieza en 0, debo ajustar la posicin para devolver el elemento
correcto.
Public Function ObtenerSubCadena(ByVal cadenaOriginal As String, _
ByVal delim As String, ByVal cualCampo As Integer) _
As String
' ----- Extraer una cadena delimitada de otra
' cadena mayor.
Dim partesCadena( ) As String

' ----- Manejar algunos errores.


If (cualCampo < 0) Then Return ""
If (Len(cadenaOriginal) < 1) Then Return ""
If (Len(delim) = 0) Then Return ""

' ----- Dividir la cadena en partes delimitadas.


partesCadena = Split(cadenaOriginal, delim)
' ----- Ver si existe la parte que queremos y devolverla.
If (cualCampo > UBound(partesCadena) + 1) Then Return "" _
Else Return partesCadena(cualCampo - 1)
End Function

Si estas funciones le parecen simples, estupendo! Casi todo el cdigo de Visual Basic es ms
difcil que estos ejemplos. Seguro, podra usar partes no familiares de la FCL, o interactuar con
cosas ms complicadas que cadenas y nmeros. Pero la estructura general ser similar. La mayor
parte del cdigo fuente est integrado por instrucciones de asignacin, pruebas usando la ins-
truccin If, bucles a travs de datos que usan una instruccin For...Next o similar, y llamadas
a funcin. Y eso es lo que hicimos en estos mtodos cortos.

186 | Captulo 6: Datos y tipos de datos

06_PATRICK-CHAPTER_06.indd 186 17/2/10 15:22:06


Captulo 7
Windows Forms

William Shakespeare escribi: Todo en el mundo es un formulario, todos los controles y las eti-
quetas son meros jugadores: marcan la entrada a los eventos y la salida a los eventos; y un control
en su hora expone muchas propiedades (de Mientras lo codifica, acto 2.7.0). Aunque .NET
an estaba en versin beta cuando acu estas palabras, se aplican perfectamente a cualquier
aplicacin de Windows Forms que escriba, aun en nuestros das.
La tecnologa de .NET conocida como Windows Forms incluye todas las clases y caractersticas
necesarias para desarrollar aplicaciones estndar de escritorio para Microsoft Windows. En los
primeros das de Windows, ste era el nico tipo de programa que poda escribir para la plata-
forma. Pero ahora slo es uno de muchos tipos de aplicacin, junto con aplicaciones de consola,
aplicaciones Web (Web Forms) aplicaciones y servicios.

Dentro de una aplicacin de Windows


Si usted es nuevo en el desarrollo del sistema Windows, la escritura de aplicaciones en .NET
puede evitar que aprecie por completo lo que en realidad sucede dentro de una aplicacin de
Windows, y de ser confinado involuntariamente a un asilo. Eso es porque los elementos internos
de las aplicaciones de Windows no son divertidos.
Windows fue desarrollado originalmente como una aplicacin que se ejecutaba dentro de
MS-DOS, y esto ha tenido un impacto importante en el diseo de Windows y de las aplica-
ciones que se ejecutan dentro de su entorno de sistema de pseudooperacin. Las versiones ms
recientes de Windows son verdaderos sistemas operativos, ya no dependientes de MS-DOS.
Pero la metodologa de programacin se dej sin cambio para compatibilidad con versiones
anteriores. Las aplicaciones escritas en Visual Basic para .NET an usan internamente esta
tecnologa de Windows 1.0, pero est oculta en su mayor parte por muchas clases bien dise-
adas del paquete Windows Forms.

187

07_PATRICK-CHAPTER_07.indd 187 17/2/10 15:22:48


Todo est en una ventana
Abundan rumores acerca de la razn por la que Microsoft adjunt el nombre Windows a su
producto insignia. Algunos dicen que representa las ventanas de utilidad y oportunidad que
los usuarios ganaran al usar la interfaz grfica de usuario mejorada. Algunos creen que repre-
senta la cavidad del edificio a travs de la cual los ejecutivos de Microsoft prometieron lanzar a
varios desarrolladores y administradores si el producto explotaba. Pero el nombre en realidad se
refiere a los diferentes elementos que aparecen en la pantalla cuando usa Windows y sus aplica-
ciones incluidas: ventanas. En resumen, todo lo que ve en la pantalla es una ventana o aparecen
dentro de una ventana: todos los formularios, los controles, las barras de desplazamiento y todos
los elementos de despliegue. En la figura 7-1 se seala una de las ventanas dentro de una pantalla
tpica de Microsoft Windows.

Figura 7-1. Algunas de las muchas ventanas de Windows 2.0.

Toda ventana de aplicacin era claramente una ventana, como todos los botones, los campos
de entrada de texto, las casillas de verificacin y los botones de opcin, los cuadros de lista y
cuadros combinados (con una ventana separada para la parte desplegable). El texto esttico
y las imgenes grficas se dibujan en una superficie de la ventana, y no incorporan las propias
ventanas. Pero ciertamente cientos de ventanas pueden desplegarse a un mismo tiempo.

188 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 188 17/2/10 15:22:48


Aunque los desarrolladores originales del equipo del proyecto de Windows sufrieron de una falta
deplorable de originalidad en l rea de asignacin de nombre a las caractersticas, Microsoft com-
pens esto de alguna manera con su lanzamiento de Visual Basic. Aunque todo era an una ven-
tana internamente, Microsoft dividi el mundo pblico de las ventanas en sus dos hemisferios:
formularios y controles. Haba siempre algunas diferencias internas entre estos dos tipos de venta-
nas, y los nuevos nombres hicieron mucho para llevar normalidad a la situacin de desarrollo de
aplicaciones de Windows. Microsoft eligi conservar estos tiles motes hasta que se implement
el paquete de .NET de Windows Forms.

Mensajes y la bomba de mensajes


Cuando interacta con Windows es muy fcil para usted (como ser humano) detectar los dife-
rentes formularios y controles en la pantalla. La imagen de Windows 2.0 que mostr en la figura
7-1 parece una pantalla tpica de Windows, con su capacidad para interactuar con el teclado y
el ratn, pero no lo es. Siga adelante, trate de manipular la figura con su dedo. Puede tratar de
hacerlo todo el da, pero fuera de hacer un hoyo en la pgina y no lograr que le devuelvan el
dinero que pag por su libro, nada ms suceder. Pero mientras la maneja, podra gritar: Slo
estoy oponiendo el botn OK o Slo estoy oprimiendo los cuatro botones de la ventana Cal-
culator.
Esto es lo que Microsoft Windows hace por usted. Windows mantiene una lista de todas las
ventanas desplegadas en la pantalla, la manera en que se superponen y estorban entre s, y a cul
aplicacin pertenece cada ventana. (Algunas aplicaciones estn divididas en varios subprocesos
que se ejecutan al mismo tiempo. En estos programas, Windows lleva registro de todas las ven-
tanas por subproceso, no slo por aplicacin.) El controlador del dispositivo relacionado coloca
cada accin de entrada del usuario (como clics del ratn y opresiones de teclas) en la cola de
mensajes del sistema. Mientras hace clic en la pantalla con su ratn, Windows extrae el mensaje
de sistema de esta cola, determina dnde hizo clic, trata de determinar en cul ventana ocurri el
clic del ratn y luego informa a la aplicacin de la ventana acerca del clic del ratn, al agregar un
mensaje a la cola de mensajes de la aplicacin. Hace lo mismo para la entrada del teclado y otras
acciones sobre las que tal vez debera saber acerca de esto.
Para funcionar dentro del entorno de Windows, su aplicacin (o un subproceso especfico
de su aplicacin) incluye una bomba de mensajes, un bloque de cdigo que monitorea la cola de
mensajes. Cada mensaje entrante incluye el nmero de ID de la ventana de destino. El cdigo
extrae el mensaje de la cola y lo enruta al procedimiento de ventana (tambin llamado WndProc,
de Window Procedure) de la ventana apropiada para el procesamiento final. En el lenguaje C,
esta bomba de mensaje tiene un aspecto como ste:
while (!done)
{
/* ----- Extraer y examinar el siguiente mensaje. */
MSG msj;
if (GetMessage(&msj, NULL, 0, 0))

Dentro de una aplicacin de Windows | 189

07_PATRICK-CHAPTER_07.indd 189 17/2/10 15:22:49


{
/* ----- WM_QUIT significa que es hora de salir del programa. */
if (msg.message == WM_QUIT)
done = true;

/* ----- Enviar el mensaje a la ventana correcta. */


TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

Lo s, lo s. Le hace feliz escribir en Visual Basic.


As, cada aplicacin (en realidad, cada subproceso dentro de una aplicacin) tiene una bomba
de mensajes, pero varios procedimientos de ventana. La bomba de mensajes existe para enlutar
los mensajes entrantes al procedimiento de ventana correcto.

Procedimientos de ventanas
As como la bomba de mensajes despacha mensajes a distintos procedimientos de ventana, la
rutina WndProc dirige el procesamiento a bloques de cdigo individuales o procedimientos
basados en el tipo de mensaje entrante. He aqu un esquema lgico general (pseudocdigo) que
muestra la estructura de un procedimiento de ventana tpico:
If (el tipo de mensaje es un clic del ratn)
Do cdigo relacionado con el clic del ratn
Else If (el tipo de mensaje es la opresin de una tecla)
Do cdigo relacionado con la opresin de una tecla
Else If (el tipo de mensaje es el cambio de tamao de una ventana)
Do cdigo relacionado con el cambio de tamao de una ventana
Else...

(El pseudocdigo usa sucesivas instrucciones If, pero un procedimiento de ventana real usa con
ms frecuencia un tipo de instruccin Select Case para procesar el mensaje entrante.) As,
el procedimiento de ventana es como una mquina expendedora. Si el cliente oprime el botn
de los refrescos de cola, hace el procesamiento que regresa una lata de refresco de cola. Si el clien-
te oprime el botn de goma de mascar, hace el procesamiento que regresa goma de mascar. Si el
cliente oprime el botn para regresar el dinero, conserva su dinero.
Para cada tipo de mensaje (por lo menos los que el programa quiere manejar) se procesa algn
cdigo relacionado cuando llega un mensaje. Muchacho, eso realmente suena familiar, pero
parece que recuerda lo que son eventos! Esto suena como a los eventos en Visual Basic. Y as
es. An en Visual Basic 1.0, todas las aplicaciones generadas incluan una bomba de mensajes
y procedimientos WndProc para cada ventana, todas ocultas a la vista. La principal tarea de di-
chos procedimientos WndProc era llamar al cdigo de su manejador de eventos de Visual Basic.

190 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 190 17/2/10 15:22:49


Ventanas en .NET
Tmelo de alguien que sola escribir aplicaciones de Windows en el lenguaje C: escribir bombas
de mensajes y procedimientos de ventana no es muy divertido. Microsoft trat de enmascarar
parte del tedio con diversas tecnologas, incluidos los Rompedores de mensajes y MFC.
Fue Visual Basic el que finalmente tuvo xito en enterrar la complejidad bajo un sistema lgico
amigable para el programador.
.NET Framework usa un sistema que es muy similar al de antiguas implementaciones de Visual
Basic, haciendo que el WndProc llame a un manejador de eventos personalizado escrito por
usted. Empaqueta todo su poder y simplicidad en una tecnologa llamada Windows Forms.
Todas sus clases aparecen en el espacio de nombres System.Windows.Forms. Muchas de estas
clases implementan tipos especficos de ventanas, como ventanas principales ordinarias, botones,
cuadros de texto, listas desplegables de cuadros combinados, etctera.
Si realmente lo quiere, an puede acceder a la bomba de mensajes y las diversas rutinas de Wnd
Proc. Cada clase especfica de ventana incluye un mtodo WndProc que puede sobrescribir y
crear usted mismo. La bomba de mensajes se encuentra en el mtodo System.Windows.Forms.
Application.Run. Podra apropiarse de cualquiera de estos componentes y controlar la bola
ensalivada, pero pronto encontrar que el desarrollo de Windows Forms es tan placentero que le
costar mucho olvidar lo que en realidad significa bomba de mensajes.

Formularios y controles
En .NET, como en versiones ms antiguas de Visual Basic, las ventanas estn agrupadas en
formularios y controles. Pero an son ventanas, construidas con los mismos componentes
centrales. Si no me cree, revise las clases de los diversos formularios y controles de .NET. Tanto
formularios como controles derivan de la clase comn System.Windows.Forms.Control, que
abstrae la funcionalidad central de ventana de Windows.
Algunos de los controles proporcionados con .NET (y tambin con la versin antigua de Visual
Basic) en realidad no implementan elementos de ventana en pantalla. Estos controles (como
Timer) no incluyen la experiencia de interfaz de usuario, pero s proporcionan una experiencia
de programacin que es similar a la de los controles visibles. Presentar una lista de los controles
especficos un poco ms adelante, en este captulo, e indicar cules no son controles de interfaz
de usuario.

Diseo de aplicaciones de Windows Forms


La creacin de una aplicacin de Windows Forms en Visual Basic es fcil. Probmoslo. Inicie
Visual Studio y seleccione Nuevo Proyecto del men Archivo. Aparece el formulario Nuevo
proyecto, como se muestra en la figura 7-2.

Ventanas en .NET | 191

07_PATRICK-CHAPTER_07.indd 191 17/2/10 15:22:49


Figura 7-2. Formulario Nuevo proyecto de Visual Studio.

Seleccione el tipo de proyecto Windows y luego la plantilla Aplicacin de Windows Forms. Asig-
ne al proyecto cualquier nombre que quiera en el campo Nombre, y luego haga clic en Aceptar.
El nuevo proyecto ya tiene un solo formulario (Form1) listo para usarse. En este punto, Visual
Studio ya ha agregado alrededor de 250 lneas de cdigo fuente a su aplicacin. Si hace clic en
el botn Mostrar todos los archivos, en el panel Explorador de soluciones (descrito en la figura
1-13, del captulo 1) y abre los varios archivos del proyecto, puede ver el cdigo. La parte ms
interesante est en el archivo Form1.Designer.vb file, editado ligeramente aqu:
Partial Class Form1
Inherits System.Windows.Forms.Form

'Form reemplaza a Dispose para limpiar la lista de componentes.


<System.Diagnostics.DebuggerNonUserCode(
)> _
Protected Overrides Sub Dispose(ByVal disposing As booleano)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub

'Requerido por el Diseador de Windows Forms


Private components As System.ComponentModel.IContainer

'NOTA: el Diseador de Windows Forms


'necesita el siguiente procedimiento
'Se puede modificar usando el Diseador de Windows Forms.
'No lo modifique con el editor de cdigo.

192 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 192 17/2/10 15:22:49


<System.Diagnostics.DebuggerStepThrough(
)> _
Private Sub InitializeComponent()
components = New System.ComponentModel.Container(
)
Me.AutoScaleMode = _
System.Windows.Forms.AutoScaleMode.Font
Me.Text = "Form1"
End Sub
End Class

Todo el cdigo que implementa un comportamiento del formulario aparece en la clase Form del
espacio de nombres System.Windows.Forms. El formulario inicial de este proyecto, Form1,
hereda de ese formulario de base, recibiendo toda la funcionalidad y los parmetros predetermi-
nados de Form. Cualquier cambio personalizado en el momento del diseo hecho a la interfaz
de usuario Form1, como la adicin de controles secundarios, se agrega automticamente al
procedimiento InitializeComponent mientras usa Visual Studio. Revise peridicamente la
rutina para ver cmo cambia.
La mayor parte de los programas tendrn varios formularios. Supongo que .NET podra selec-
cionar al azar uno de los formularios para desplegarlo cuando se ejecuta por primera vez un pro-
grama. Esto sera divertido e impredecible. Pero no funciona de esa manera. En cambio, usted
indica el formulario de inicio mediante las propiedades del proyecto, en el campo Formulario
de inicio, de la ficha Aplicacin (vase la figura 7.3). (La ventana de propiedades del proyecto
aparece cuando selecciona el comando de mens Proyecto Propiedades, en Visual Studio,
o cuando hace doble clic en el elemento My Project, en el Explorador de soluciones.)

Figura 7-3. Las opciones de inicio para una aplicacin de Windows Forms.

Cuando una aplicacin de .NET empieza, el marco conceptual llama a un mtodo denominado
Main en algn lugar de su cdigo. Usted indica cul rutina Main de cul formulario se utiliza
mediante el campo Formulario de inicio. Incluye una lista de todos los formularios; slo elija
el que desee. Pero espere, an no ha agregado el mtodo Main a cualquiera de sus formularios?
No hay problema. Visual Basic escribir una rutina Main simple que desplegar el formulario
indicado. Esta rutina Main ad hoc, agregada en tiempo de compilacin, realiza slo el procesa-
miento mnimo para desplegar el formulario.
Si quiere agregar a su formulario una rutina Main personalizada, o alguna otra clase que no sea
de Form en su aplicacin, no hay problema. Si quita la marca del campo Habilitar marco de
trabajo de la aplicacin en el mismo formulario de propiedades, la lista Formulario de inicio
cambia para incluir cualquier clase de su aplicacin con una rutina Main compatible. Pero el

Ventanas en .NET | 193

07_PATRICK-CHAPTER_07.indd 193 17/2/10 15:22:50


marco conceptual de la aplicacin habilita una gran cantidad de funcionalidad estupenda, y todo
sin que tenga que hacer trabajo alguno. Deshabiltelo slo cuando necesita control preciso sobre
el tiempo de vida inicial de la aplicacin.

Uso de mtodos Main personalizados


Si decide escribir su propia rutina Main en una clase que no es de Form, con el tiempo querr
desplegar el formulario principal de su aplicacin. De regreso a Visual Basic 6.0, cada vez que
quiere desplegar un formulario, debe llamar a su mtodo Show:
Form1.Show
Esta sintaxis desapareci cuando surgi la primera versin de .NET de Visual Basic en 2002, pero
regres con la versin de 2005. Digamos que quiere empezar su aplicacin a partir de un
procedimiento Sub Main en un mdulo separado a partir de su formulario principal. En
primer lugar, necesita agregar un nuevo mdulo al proyecto. Seleccione el comando de men
Proyecto Agregar mdulo. Modifique el nuevo mdulo de cdigo Module1 para que tenga
el siguiente bloque de cdigo:
Module Module1
Public Sub Main( )
Form1.Show( )
End Sub
End Module
En las propiedades del proyecto, desmarque el campo Habilitar el marco de trabajo de la aplica-
cin y seleccione Module1 o Sub Main de la lista Formulario de inicio. Es muy simple: llame
al mtodo Main de Module1, muestre el formulario Form1, y habr terminado. Y en verdad, si
ejecuta este programa, habr terminado muy rpido. En realidad, Form1 aparecer por un mo-
mento muy breve antes de salir del programa. Por qu no apegarse a Form1?
El programa sali de inmediato debido a esa molesta bomba de mensajes, o ms correctamente, la
falta de una bomba de mensajes. Cada ventana (o formulario o control) tiene un procedimiento
WndProc, pero hay slo una bomba de mensajes para cada aplicacin o subproceso. En este
programa simple, Form1 tiene su propio procedimiento WndProc, pero no controla la bomba de
mensajes por s mismo. Tiene que indicarle especficamente al programa que empiece a ejecutar
la bomba de mensajes. Debido a que la bomba de mensajes estndar para las aplicaciones de
Windows Forms aparece en el mtodo System.Windows.Forms.Application.Run, al modifi-
car el cdigo Sub Main para incluirlo se habilitar la bomba y mantendr Form1 desplegado hasta
que el usuario cierra el formulario o patea por accidente el cable de energa elctrica de la pared.
Module Module1
Public Sub Main( )
System.Windows.Forms.Application.Run(Form1)
End Sub
End Module
Puede agregar todo tipo de cdigo de inicializacin a su procedimiento Sub Main, y mostrar el
formulario principal slo cuando su cdigo est listo para interactuar con el usuario.

Si necesita agregar un nuevo formulario a su aplicacin, use el comando de men Proyecto


Agregar Windows.

194 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 194 17/2/10 15:22:50


Trabajo con formularios
En .NET, todos los formularios son simplemente clases, variaciones de la clase System.Windows.
Forms.Form. Cada vez que crea un nuevo formulario, est creando una clase derivada que se basa
en la clase Form comn. Y su nueva clase est cargada con funcionalidad; incluye todos los cam-
pos, mtodos, errores, propiedades y eventos que integran la clase Form. Visual Studio toma estos
elementos y los presenta de una manera que facilita la programacin de un formulario, mediante
cdigo fuente y la interfaz de arrastrar y colocar del diseador de formularios de Visual Studio.
Cuando agrega por primera vez un formulario a su aplicacin, es ms bien simple y aburrido.
Use el panel Propiedades (vase la figura 7-4) para ajustar el formulario a su gusto. En este panel
se muestran las principales propiedades del elemento seleccionado dentro del entorno de Visual
Studio. Incluye una entrada separada para cada configuracin de propiedad, la mayor parte de
las cuales puede actualizarse mediante la simple entrada de texto. Por ejemplo, puede modificar
la leyenda desplegada en la parte superior del formulario al cambiar el contenido de la propiedad
Text de Form1 por Estupendo formulario.

Figura 7-4. Las propiedades de su formulario.

En la tabla 7-1 se presenta una lista de algunas de las propiedades ms interesantes y sus usos.

Tabla 7-1. Propiedades de formulario.

Propiedad Descripcin
(Name) Es el nombre del formulario, o ms correctamente de la clase que es el formulario. Como opcin
predeterminada, se llama Formx, donde x es algn nmero. Necesita cambiar por algo informativo.
AcceptButton Indica cul control Button ya colocado en el formulario debe dispararse cuando el usuario oprime la tecla Enter.
AutoScroll Si establece este campo en True, el formulario agrega automticamente barras de desplazamiento que
mueven el contenido del formulario si ste es demasiado pequeo para mostrar todo.
BackColor El color de fondo. Usa un color de sistema especfico o general.

Ventanas en .NET | 195

07_PATRICK-CHAPTER_07.indd 195 17/2/10 15:22:51


Tabla 7-1. Propiedades de formulario (continuacin).
Propiedad Descripcin
BackgroundImage Use esta propiedad, junto con BackgroundImageLayout, para colocar una imagen en el fondo del
formulario.
CancelButton Es como la propiedad AcceptButton, pero el botn asignado se dispara con la tecla Esc, no Enter.
ContextMenuS- Esta propiedad le permite crear un mtodo abreviado personalizado que aparece cuando el usuario hace clic
trip con el botn derecho en el fondo del formulario. ContextMenuStrip alude a un control separado
que agrega al formulario.
ControlBox Usted oculta o muestra el cuadro de control en la esquina superior izquierda del formulario mediante este
valor de propiedad.
Cursor Indica el estilo del cursor del ratn que aparece cuando ste se encuentra sobre el formulario. Esta
propiedad demuestra uno de los muchos editores que aparecen dentro de la ventana de propiedades. Si
hace clic en la flecha hacia abajo, a la derecha de la configuracin de la propiedad, se despliega una lista
grfica de todos los cursores de ratn incluidos. Haga clic en una imagen para obtener la que quiera. (Otras
propiedades incluyen editores personalizados, diseados para su tipo de contenido.) Esta lista incluye slo
los cursores integrados. Tambin puede modificar esta propiedad en el cdigo fuente del formulario si
necesita establecer el cursor en una imagen personalizada.
FormBorderStyle Esta propiedad indica el tipo de formulario que habr de desplegarse. La opcin predeterminada es
Sizable, que permite al usuario cambiar el tamao del formulario al arrastrar la esquina inferior dere-
cha. Si establece esta propiedad en None, desaparecen la barra de ttulo y los bordes del formulario. Podra
usar este valor para el formulario de bienvenida de la aplicacin, que no suele tener borde.
Icon Establece la imagen desplegada en la esquina superior izquierda del borde del formulario.
IsMdiContainer Habilita la interfaz de mltiples documentos en este formulario. Esto permite que un formulario maestro
contenga varios formularios de documento secundarios. El propio Visual Studio puede desplegar ventanas
de formularios y de cdigo fuente en el estilo MDI.
KeyPreview Si establece esta propiedad en True, los eventos KeyDown y KeyPress del formulario
procesarn cualquier tecla oprimida por el usuario, aunque esas teclas estn destinadas a un control conte-
nido en el formulario. Esto es til cuando necesita capturar teclas que se aplican a todo el formulario, como
F1 para disparar la ayuda en lnea.
Location Establece las posiciones superior e izquierda del formulario en la pantalla. La propiedad
StartPosition tambin tiene impacto en la ubicacin del formulario.
MainMenuStrip Identifica el control MenuStrip para usar el men principal del formulario. El control
MenuStrip de referencia se agrega por separado al formulario.
MaximizeBox Indica si aparece el recuadro para maximizar en la esquina superior derecha del formulario. Este botn le
permite al usuario mostrar un formulario en su modo de pantalla completa.
MinimizeBox Indica si aparece el recuadro para minimizar en la esquina superior derecha del formulario. Este botn le
permite al usuario enviar el formulario a la barra de tareas del sistema.
MinimumSize En formularios cuyo tamao puede cambiarse, esta propiedad indica el tamao mnimo permitido para
el formulario. El usuario no podr hacer el formulario ms pequeo que el tamao indicado. sta, como
algunas de las dems propiedades, es compuesta, integrada por la combinacin de dos o ms propiedades.
En este caso, est construida de las subpropiedades independientes Width y Height.
Opacity Le permite especificar el nivel de transparencia para un color distinto que aparece en el formulario (establecida
mediante el campo TransparencyKey). Si asigna a este campo un valor de 100% ese color se des-
plegar sin transparencia alguna; si asigna un valor de 0%, el color ser completamente transparente. Puede
establecer esta propiedad en cualquier valor, entre 0 y 100%. Cualquier cosa que aparece tras el formulario ser
visible parcial o completamente mediante las porciones transparentes de este formulario.

196 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 196 17/2/10 15:22:51


Tabla 7-1. Propiedades de formulario (continuacin).

Propiedad Descripcin
ShowInTaskbar Especifica si este formulario debe aparecer como un elemento en la barra de tareas del sistema.
Size Indica el tamao actual del formulario mediante las subpropiedades Width y Height.
StartPosition Especifica la manera en que el formulario debe colocarse en la pantalla cuando aparece por primera vez. Se
establece mediante una lista de valores predefinidos, que en realidad se vinculan con una enumeracin.
Tag Puede colocar cualquier tipo de datos que quiera en esta propiedad; est all para su uso.
Text La leyenda que despliega el formulario se define con este campo.
TopMost Si se establece en True, este formulario aparece arriba de los dems, aunque no sea el formulario activo.
TransparencyKey Indica el color que se usar para transparencia cuando el campo Opacity es diferente de 100%.
WindowState Identifica el estado actual de la ventana: normal, maximizado o minimizado.

Slo inclu la mitad de las propiedades disponibles; evidentemente se tiene una gran cantidad de con-
trol sobre el formulario y la manera en que se presenta al usuario. Lo que es realmente interesante es
que muchas de estas propiedades no estn limitadas slo a los formularios. Algunas de ellas provienen
de la clase mutua System.Windows.Forms.Control y tambin aparecen en todos los controles
que usan la misma clase de base. Esto incluye propiedades como Location, BackColor y Text.
Aunque la presentacin del texto desplegado en la leyenda de un formulario y el texto desplegado en
un botn de comando difieren de manera importante, el uso mediante cdigo es idntico.
Form1.Text = "Esto es la leyenda del formulario."
Button1.Text = "Esto es la leyenda del boton."

Aunque puede establecer todas las propiedades de la tabla 7-1 mediante el panel Propiedades,
tambin puede actualizarlas y verlas mediante cdigo. En realidad, si modific cualquiera de
las propiedades en el panel Propiedades, ya las actualiz mediante cdigo fuente, porque Visual
Studio actualiza su cdigo. Prubelo! Establezca las propiedad TopMost del formulario en True,
y luego vea la rutina InitializeComponent del archivo Form1.Designer.vb file. Encontrar las
siguientes nuevas instrucciones cerca de la parte inferior del mtodo:
Me.TopMost = True

S lo que est pensando: Soy un programador, pero mi editor de texto es el que se est divirtiendo
con la programacin. Cundo tendr una oportunidad de modificar las propiedades mediante c-
digo? sta es una pregunta justa. Es muy fcil modificar las propiedades. Slo mencione el objeto
que se modificar, junto con el nombre de la propiedad y su nuevo valor, como hizo Visual Studio
con la propiedad TopMost.
Me.Text = "El Proyecto Biblioteca"

Tambin puede recuperar los valores de propiedad al mencionarlos.


MsgBox("La leyenda del formulario es: " & Me.Text)

Se accede a los diversos mtodos del formulario de una manera muy parecida. Por ejemplo, el
mtodo Close cierra el formulario:
Me.Close()

Ventanas en .NET | 197

07_PATRICK-CHAPTER_07.indd 197 17/2/10 15:22:51


Por supuesto, es necesario que estas instrucciones aparezcan dentro de algn procedimiento v-
lido, como un manejador de eventos. Agreguemos algn cdigo al evento Click del formulario
para que cuando el usuario haga clic en el formulario, el nuevo cdigo modifique la leyenda del
formulario, nos recuerde lo que es una leyenda y cierre el formulario, causando que el programa
termine. Qu gran programa! Acceda al cdigo fuente del formulario al seleccionar Form1.vb
en el Explorador de soluciones, y luego haga clic en el botn Ver cdigo en la parte superior del
Explorador de soluciones. Aparece el bloque de cdigo predeterminado del formulario.
Public Class Form1

End Class

Como recordar de las primeras pginas de este captulo, sta es la parte para el turista de la clase
Form1, la parte que Visual Studio muestra al pblico (usted), y no las partes ocultas ms interesan-
tes (la parte de Form1.Designer.vb). Pero podremos hacer que esta seccin sea interesante de inme-
diato. Agregue un evento Click a la superficie del formulario al seleccionar (Form1 eventos) de la
lista Nombre de clase (arriba y a la izquierda del editor de texto del cdigo), y luego seleccione Click
de la lista desplegable Nombre del mtodo a su derecha, como se muestra en la figura 7-5.

Figura 7-5. Adicin de un evento Click al formulario.

Modifique el manejador de eventos para que despliegue este cdigo:


Private Sub Form1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Click
Me.Text = "El Proyecto Biblioteca"
MsgBox("La leyenda del formulario es: " & Me.Text)
Me.Close()
End Sub

Si ejecuta este cdigo y hace clic en la superficie del formulario, aparece un cuadro de mensaje
con la leyenda del formulario justo antes de que salga de la aplicacin (vase la figura 7-6).

Adicin de controles
Los nuevos formularios son como lienzos en blanco, y como los grandes pintores antes de no-
sotros, tenemos a nuestra disposicin una gran paleta de herramientas de color a nuestra dispo-
sicin. En Visual Studio, esas herramientas estn en la forma de controles, clases de .NET dise-
adas especficamente para usarlas en superficies del formulario. Visual Basic y .NET incluyen
docenas de controles de Windows Forms, y hay an ms disponibles de terceros. Incluso puede
construir sus propios controles, ya sea al derivarlos a partir de clases de control existentes o al
implementarlos por completo desde cero.

198 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 198 17/2/10 15:22:52


Figura 7-6. Un programa que comunica algo cuando se hace clic.

El Cuadro de herramientas de Visual Studio incluye todos los controles bsicos que necesita
para construir aplicaciones de software de alta calidad, o incluso de una pattica baja calidad.
Acceda al Cuadro de herramientas, parte del cual aparece en la figura 7-5, mediante el comando
de men Ver Cuadro de herramientas.

Figura 7-7. Cuadro de herramientas de Visual Studio con controles de Windows Forms.

Hay cinco maneras de agregar un control a un formulario:


Haga doble clic en un control en el Cuadro de herramientas. Una instancia del control
aparece en formulario en su ubicacin predeterminada con todos sus parmetros predeter-
minados.
Arrastre y coloque un control del Cuadro de herramientas al formulario.

Ventanas en .NET | 199

07_PATRICK-CHAPTER_07.indd 199 17/2/10 15:22:53


Haga clic en un control del Cuadro de herramientas, y luego use el ratn para dibujar el
rea del rectngulo en el formulario donde aparecer el control. Algunos controles, como
ComboBox, tienen lmites en su ancho o alto; no necesariamente tendrn el tamao que se
pretende.
Pida a alguien ms que agregue el control al formulario. Esta opcin es para los dbiles de
corazn. Si est leyendo este libro, esa opcin no es para usted.
Agregue el control al formulario usando cdigo fuente de Visual Basic. Mientras agrega
controles al formulario, Visual Studio est escribiendo cdigo fuente. No hay razn para
que no pueda agregar usted mismo ese cdigo. Aunque hay advertencias en el archivo
Form1.Designer.vb que le indican que no edite el archivo, puede modificar a mano la rutina
InitializeComponents si se amolda de manera apropiada al estilo de cdigo generado por
Visual Studio. Tambin puede agregar controles en otras reas de su cdigo, como en el evento
Load del formulario. La adicin dinmica de controles est ms all del alcance de este libro,
pero siga adelante, experimente.
Algunos controles no tienen una verdadera presencia de interfaz de usuario en una aplicacin
en ejecucin. Estos controles, cuando se agregan a su formulario, aparecen en un panel justo
debajo de la superficie del formulario. An puede interactuar con ellas como lo hara con los
controles de formularios.
Una vez que aparece un control en el formulario, use el ratn para mover el control, o cambie
su tamao usando las anclas de cambio de tamao que aparecen cuando se selecciona el control.
Unos cuantos controles tiene opciones de cambio de tamao limitadas. Por ejemplo, slo puede
cambiarse de tamao del control ComboBox horizontalmente; su tamao vertical est determina-
do por cosas como la fuente usada en el control. Otros controles le permiten cambiar su tamao,
pero slo en ocasiones. El control Label puede cambiarse de tamao manualmente cuando su
propiedad AutoSize se asigna en False.
Algunos controles incluyen un pequeo botn de flecha, a menudo cerca de la esquina supe-
rior derecha. Son las etiquetas inteligentes, similares a la caracterstica de etiquetas inteligentes
incluidas en Microsoft Office. Al hacer clic en la etiqueta inteligente se proporciona acceso a
caractersticas tiles asociadas con el control, como se muestra en la figura 7-8.

Figura 7-8. La etiqueta inteligente del control ComboBox.


En la tabla 7-2 se presentan algunos de los controles de uso ms comn, todos incluidos en el
Cuadro de herramientas, como opcin predeterminada, con una nueva aplicacin de Windows
Forms. Si crea una aplicacin de Web Forms en Visual Studio (usado para disear aplicaciones
Web con ASP.NET) los controles disponibles diferirn de esta lista. Consulte el captulo 23 para
conocer un anlisis de las aplicaciones de ASP.NET.

200 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 200 17/2/10 15:22:53


Tabla 7-2. Controles de Windows Form disponibles en Visual Studio.

cono Control Descripcin


BackgroundWorker .NET incluye soporte para aplicaciones de multisubprocesamiento. El control
BackgroundWorker le permite iniciar una tarea en segundo plano desde la comodi-
dad de su propio formulario. Es til, en especial, cuando desea actualizar interactivamente
elementos de despliegue de formularios con otro subproceso de trabajador. Usted lanza
la nueva tarea de trabajo mediante el mtodo RunWorkerAsync de este control, y
realiza el trabajo real en su evento DoWork.
Button Un botn estndar. El evento Click de un botn es su caracterstica programtica ms
comn, aunque tambin puede usar su propiedad DialogResult para desplegar una
accin especfica de un cuadro de dilogo.
CheckBox Este control implementa un campo de seleccin marcado de dos vas (encendido, apaga-
do) o tres vas (encendido, apagado, otra). La propiedad ThreeState indica el nmero
total de opciones. Use la propiedad booleana Checked para casillas de verificacin de
dos vas, o la propiedad CheckState para casillas de verificacin de tres vas.
CheckedListBox El control CheckedListBox combina lo mejor de los mundos de ListBox y
CheckBox, dndole una lista donde cada elemento puede marcarse de una manera de
dos o tres vas. Los mtodos GetItemChecked y GetItemCheckState (y sus
contrapartes Set) proporcionan una de las muchas maneras para examinar el estatus de
elementos de la lista. Est al tanto de que existe un control similar llamado
CheckBoxList; es slo para uso con aplicaciones de ASP.NET.
ColorDialog Despliega el formulario estndar de Windows usado para seleccin de color por parte del
usuario. Despliega el cuadro de dilogo de color empleando el mtodo ShowDialog del
control, obteniendo el resultado mediante la propiedad Color.
ComboBox Implementa el control desplegable ComboBox estndar de Windows, en todos sus diver-
sos estilos. La lista de elementos puede incluir cualquier objeto que desee; no est limitado
a cadenas. Tambin puede proporcionar cdigo dibujado por el propietario que le permite
dibujar usted mismo cada elemento de la lista.
ContextMenuStrip Este control le permite disear un men contextual, que habr de desplegarse cuando el
usuario hace clic con el botn derecho en el formulario o el control de su eleccin. Est dise-
ado y se usa de la misma manera, en gran medida, que el control estndar MenuStrip.
DataGridView El control DataGridView implementa una cuadrcula tipo tabla empleada para
desplegar o editar datos en celdas individuales. Est cargado con ms opciones de desplie-
gue de las que puede necesitar. Los datos desplegados pueden unirse a algn origen de
datos externo, o puede incluirlos al vuelo. Un modo de datos virtuales tambin le permite
cargar slo los datos cuando sea necesario.
DateTimePicker El control DateTimePicker permite al usuario ingresar una fecha, una hora, o ambas,
mediante su entrada bsica de texto o controles basados en el ratn. Aunque no permite la
misma libertad de un campo de texto simple, impone la seleccin de una fecha u hora. Puede
establecer lmites mximo y mnimos en la seleccin de usuario. El control
MonthCalendar proporciona una interfaz alterna para la seleccin especfica de fechas.
DomainUpDown Mediante este control, el usuario selecciona una entre una lista de opciones que usted
define, opciones que tienen un orden inherente especfico. Use este control como alternati-
va a un control ComboBox o TrackBar, cuando sea posible.

Ventanas en .NET | 201

07_PATRICK-CHAPTER_07.indd 201 17/2/10 15:22:56


Tabla 7-2. Controles de Windows Form disponibles en Visual Studio (continuacin).

cono Control Descripcin


FolderBrowserDialog Despliega el formulario estndar de Windows usado para seleccin de directorios o carpetas por
parte del usuario. Despliega el cuadro de dilogo de seleccin empleando el mtodo Show-
Dialog del control, obteniendo el resultado mediante la propiedad SelectedPath.
FontDialog Despliega el formulario estndar de Windows usado para seleccin de fuentes por parte del
usuario. Despliega el cuadro de dilogo de seleccin usando el mtodo ShowDialog del
control, y obteniendo el resultado va la propiedad Font. Otras propiedades proporcionan
acceso a los componentes de la fuente seleccionada.
GroupBox El control GroupBox proporciona una manera simple de agrupar los controles de un
formulario de manera visible. Los controles subordinados se dibujan o pegan de manera
directa en el control GroupBox. Para acceder a una funcionalidad similar sin el borde
visible o la leyenda, use el control Panel.
HelpProvider El control HelpProvider le permite indicar detalles de ayuda en lnea para otros contro-
les del formulario. Cuando se usa, agrega otras propiedades adicionales de ayuda a cada uno
de los dems controles, mediante los cuales puede proporcionar los detalles del contexto de
ayuda. Cuando se implementa apropiadamente, el contenido de la ayuda en lnea indicado se
desplegar cuando el usuario oprima la tecla F1 en el contexto del control activo.
HScrollBar Este control implementa una barra de desplazamiento horizontal, permitiendo al usuario
desplazarse entre una regin de despliegue o una lista de opciones. Para una implemen-
tacin vertical de este control, use VScrollBar. Otros diversos controles incluyen su
propia copia de estas barras de desplazamiento.
ImageList El control ImageList encapsula un conjunto de pequeas imgenes o conos para uso
por parte de otros controles que dan soporte a listas de imgenes. Las listas se usan de
manera comn con los controles ListView, Toolbar y TreeView.
Label Este control despliega texto esttico en un formulario. Al usar las diversas propiedades
de borde y fondo, puede desplegar lneas simples y rectngulos en un formulario. Visual
Basic 6.0 inclua controles especficos de dibujo de lneas y rectngulos, pero no estn
disponibles en.NET. Debe simularlos usando un control Label, o dibujarlo mediante los
comandos de dibujo (lo que no es tan difcil; consulte el captulo 18).
LinkLabel El control LinkLabel implementa una etiqueta esttica que incluye uno o ms vnculos
dentro del contenido del texto. Estos vnculos son similares a los de texto estndares que
aparecen en el contenido de exploradores Web. El control llama a su manejador de eventos
LinkClicked cuando el usuario hace clic en cualquiera de los vnculos incrustados.
ListBox Este control implementa el control de cuadro de lista estndar de Windows, desplegando
una lista de los elementos entre los que el usuario puede seleccionar cero o ms. La lista de
elementos puede incluir cualquier objeto que desee; no est limitado a cadenas. Tambin
puede proporcionar cdigo dibujado por propietario, que le permite dibujar a usted
mismo cada elemento de la lista.
ListView El control ListView presenta un conjunto de elementos con propiedades de despliegue
opcionales. Es muy similar al Explorador de archivos de Windows (previo a Vista), con todos
sus diversos modos de despliegue. Tambin puede agregar datos especficos de columna
para la vista de detalles. Los elementos del control aparecen como un conjunto de objetos
de la clase ListViewItem.

202 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 202 17/2/10 15:22:59


Tabla 7-2. Controles de Windows Form disponibles en Visual Studio (continuacin).

cono Control Descripcin


MaskedTextBox Esta variacin del campo de texto estndar ayuda al usuario a ingresar datos formados
numricos o de texto, al desplegar una plantilla o mscara de entrada. Por ejemplo, puede
obligar al usuario a ingresar un nmero de telfono en formato xxx-xxx-xxxx al usar una
mscara numrica con caracteres de guin incrustados.
MenuStrip Este control le permite disear mens de formulario estndar, que se despliegan en la parte superior
del rea del usuario del formulario. Los mens de esta tira estn implementados mediante instan-
cias de la clase ToolStripMenuItem. La tira de mens es una implementacin tipo barras
de herramientas de un men estndar de Windows. Puede agregar otros tipos de controles al men,
incluidos controles ComboBox especficos de una barra de herramientas. Los mens sensibles
a maysculas y minsculas, desplegados cuando el usuario hace clic con el botn derecho en el
formulario o un control, estn implementados mediante el control ContextMenuStrip.
MonthCalendar El control MonthCalendar despliega un subconjunto de un calendario, concen-
trado en una vista especfica de un mes. Es posible desplegar ms de un mes al mismo
tiempo, en una configuracin vertical, horizontal o de cuadrcula. El control DateTi-
mePicker proporciona una interfaz alterna para la seleccin de una fecha especfica.
NotifyIcon El control NotifyIcon le permite colocar un cono en el rea de la charola del sistema
de la barra de tareas de Windows, y comunicar mensajes importantes al usuario mediante
esta interfaz. Debido a que este control no tiene una interfaz de usuario especfica del
formulario, es posible usarlo sin tener desplegado un formulario estndar.
NumericUpDown Permite al usuario seleccionar un valor numrico empelando el mtodo de seccin
desplegable hacia arriba o hacia abajo. Use este control como una opcin a los controles
HScrollBar, TextBox, TrackBar o VScrollBar, cuando se permita.
OpenFileDialog Despliega el formulario estndar de Windows usado para la seleccin de archivos que
habr de abrir el usuario. El usuario puede seleccionar uno o ms archivos existentes
del sistema de archivos local p uno remoto. Despliega el cuadro de dilogo de seleccin
empleando el mtodo ShowDialog de este control, y obteniendo el resultado va la
propiedad FileName o FileNames. El mtodo OpenFile proporciona una manera
rpida de abrir un archivo seleccionado.
PageSetupDialog Despliega el formulario estndar de Windows usado para la configuracin de la pgina
impresa por parte del usuario. Despliega el cuadro de dilogo de seleccin empleando el
mtodo ShowDialog de este control, y obteniendo el resultado mediante las propieda-
des PageSettings y PrinterSettings.
Panel El control Panel agrupa controles de manera lgica en un formulario. Los controles subordina-
dos se dibujan o pegan directamente en el control Panel. Para acceder a funcionalidad similar
con un borde visible y una leyenda desplegada por el usuario, utilice el control GroupBox.
PictureBox Este control despliega una imagen en diversos formatos. No debe confundirse con el control Pic-
tureBox de Visual Basic 6.0, que est ms relacionado con el control Panel de Windows Forms.
PrintDialog Despliega el formulario estndar de Windows para impresin de documentos y seleccin
de propiedades de impresin. Despliega el cuadro de dilogo de seleccin empleando el
mtodo ShowDialog de este control. Este control se usa junto con una instancia de la
clase System.Drawing.Printing.PrintDocument, que se crea mediante
cdigo o va el control PrintDocument.

Ventanas en .NET | 203

07_PATRICK-CHAPTER_07.indd 203 17/2/10 15:23:03


Tabla 7-2. Controles de Windows Form disponibles en Visual Studio (continuacin).

cono Control Descripcin


PrintDocument Este control se usa como parte de un proceso de impresin y de vista previa de impresin.
Agrega una envoltura alrededor de su implementacin de impresin predeterminada, pro-
porcionando un mtodo consistente de seleccin e impresin de pginas de documentos.
PrintPreviewDialog Este control proporciona una interfaz estandarizada para vista previa de impresin, im-
plementando todos los elementos de un cuadro de dilogo completo de vista previa de
impresin. Cuando se usa con una clase o un control PrintDocument, despliega en
pantalla de manera precisa lo que aparecer en la pgina impresa final. En realidad, su
cdigo de impresin no sabe necesariamente si est imprimiendo en la impresora o en la
pantalla de vista previa de impresin.
ProgressBar ProgressBar proporciona retroalimentacin grfica al usuario para un rango de terminacin
de tarea. Por lo general, el rango va de 0 a 100%, pero puede proporcionar un rango personalizado.
La propiedad Valor indica el valor actual entre los lmites de rango Minimum y Maximum.
PropertyGrid El control PropertyGrid permite al usuario editar de manera grfica miembros especficos
de una instancia de clase adjunta. El panel Propiedades del entorno de Visual Studio es una ins-
tancia de este control. Hace un uso continuo de atributos de clase para controlar las propiedades
de despliegue y edicin de las propiedades. En el captulo 18 se usa este control para dar soporte
a la administracin de etiquetas de cdigo de barras en el Proyecto Biblioteca.
RadioButton Este control implementa el botn de seleccin de opciones estndar de Windows. Aunque el
despliegue del punto circular es el ms comn, el control puede aparecer como un botn
interruptor, al establecer la propiedad Appearance de manera apropiada. La propiedad
Checked indica el valor actual de un control. Todos los controles RadioButton que
aparecen dentro del mismo contexto de grupo actan de manera mutuamente excluyente.
Use los controles Panel y GroupBox para crear contextos de grupo especficos.
ReportViewer El control ReportViewer le permite disear y desplegar informes en bandas personali-
zadas unidos a colecciones u orgenes de datos de ADO.NET. Tambin funciona con informes
generados por SQL Server Reporting Services. El uso de este control para disear un infor-
me agregar un archivo .rdlc a su proyecto que contiene el diseo del informe real.
SaveFileDialog Despliega el formulario estndar de Windows usado para seleccionar un archivo que habr de
guardar el usuario. ste puede seleccionar un nuevo archivo o uno existente del sistema de
archivos local o remoto. El control pregunta al usuario, de manera opcional, si debe sobres-
cribir archivos existentes. Despliega el cuadro de dilogo de seleccin empleando el mtodo
ShowDialog del control, y obteniendo el resultado va la propiedad FileName. El
mtodo OpenFile proporciona una manera rpida de abrir el archivo seleccionado.
SplitContainer Este control agrega una barra de divisin mediante la cual puede dividir su formulario en
varias regiones a las que puede cambiar el tamao, y cada una de las cuales contiene un
control Panel. Use la propiedad Orientation para modificar la direccin de la divi-
sin. El orden en que agregue los controles SplitContainer a un formulario tendr
impacto en la utilidad de las divisiones; se recomienda experimentar con ellas.
StatusStrip Este control despliega una barra de estado, por lo general en la parte inferior de un formulario;
en ella, se puede desplegar informacin de estatus y sensible al contexto. La tira puede contener
varios controles ProgressBar, StatusStripPanel y ToolStripLabel.

204 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 204 17/2/10 15:23:06


Tabla 7-2. Controles de Windows Form disponibles en Visual Studio (continuacin).

cono Control Descripcin


TabControl El control TabControl le permite dividir los controles de su formulario en varias
regiones con fichas, cada ficha con nombre tiene un control TabPage asociado, que
funciona en gran parte como el control Panel. Agregue o pegue controles subordinados
directamente en cada control TabPage.
TextBox Este control implementa el cuadro de texto estndar de Windows, en sus estilos de una y
varias lneas. El contenido del cuerpo principal se establece mediante la propiedad Text.
Las propiedades PasswordChar y UseSystemPasswordChar le permiten
enmascarar la entrada cuando acepta una contrasea proporcionada por el usuario.
Timer Este control dispara un evento cronometrado en un intervalo que usted especifica. El tamao
del intervalo, en milisegundos, se establece mediante la propiedad Interval. Si la pro-
piedad Enabled est establecida en True, se llamar al manejador de eventos Tick
cada vez que se cumpla el intervalo. Aunque puede establecer el intervalo hasta en un milise-
gundo, es improbable que logre esta frecuencia con el hardware que existe hoy en da.
ToolStrip El control ToolStrip implementa una barra de herramientas en que aparecen otros
controles. Viene con un conjunto de controles y clases asociados que proporcionan genera-
cin avanzada y caractersticas de interaccin con el usuario.
ToolStripContainer El control ToolStripContainer proporciona una manera conveniente de agregar con-
troles MenuStrip, StatusStrip y ToolStrip a los extremos de un formulario.
ToolTip El control ToolTip le permite indicar informacin sobre herramientas para otros
controles del formulario. Cuando se usa, agrega una pseudopropiedad ToolTip a cada
uno de los dems controles, mediante los cuales puede proporcionar el texto asociado
de informacin sobre herramientas. Cuando el ratn se coloca sobre un control con un
texto de informacin sobre herramientas asignado, aparece temporalmente una pequea
ventana de texto sobre el control para proporcionar informacin til para el usuario.
TrackBar El control TrackBar permite al usuario hacer una seleccin entre un pequeo nmero
de valores relacionados y ordenados. Su contraparte real es el control de volumen de una
radio. Use este control como una opcin a un control HScrollBar, NumericUpDown
o VScrollBar, cuando se permite.
TreeView El control TreeView presenta un conjunto de elementos en una organizacin jerrquica. Es
muy similar a la parte rbol de directorios del Explorador de archivos (previo a Vista) de Win-
dows. Cada elemento del rbol es un nodo que puede tener cero o ms nodos secundarios.
VScrollBar Este control implementa una barra de desplazamiento vertical, permitiendo al usuario
desplazarse entre una regin de despliegue o una lista de opciones. Para una
implementacin horizontal de este control, use HScrollBar. Otros diversos controles
incluyen su propia copia de estas barras de desplazamiento.
WebBrowser Implementa un explorador Web dentro de su aplicacin. Puede usar las caractersticas de navega-
cin estndares disponibles dentro de Internet Explorer para acceso mediante URL, o proporcio-
nar su propio contenido HTML mediante la propiedad DocumentText u otras relacionadas.

Aunque no hay un lmite razonable para el nmero de controles que puede agregar a un formu-
lario, hay uno sobre la cantidad de informacin que el usuario puede experimentar en un solo
formulario sin una conexin directa al cerebro. No rebase los lmites.

Ventanas en .NET | 205

07_PATRICK-CHAPTER_07.indd 205 17/2/10 15:23:09


Eventos y delegados
Cada formulario y control de una aplicacin.NET contiene su propio procedimiento de ventana
WndProc, y a medida que procesa cada mensaje entrante de la bomba de mensajes, traduce esos
mensajes en eventos. Los eventos son la tcnica estndar de .NET que los controles (y todas las dems
clases) usan para decir: Hey, algo est sucediendo y tal vez quiera hacer algo sobre eso. Cuando in-
cluye un formulario o un control en su aplicacin, puede monitorear uno, alguno o todos esos even-
tos, y escribir cdigo personalizado que responda de manera apropiada. Todo el cdigo personalizado
que escribe para cada evento aparece en un manejador de eventos. Pero qu sucede en realidad entre el
dedo del usuario en el ratn y la lgica en su manejador de eventos personalizados? En la figura 7-9
se le muestra grficamente lo que en realidad sucede entre la accin y la lgica personalizada.

1. El usuario hace clic 2. Surge la magia 3. Se ejecuta el manejador


en el botn de eventos
Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
' ---- Aqu va el codigo
End Sub

Figura 7-9. Lo que en realidad sucede cuando el usuario hace clic en un botn.

Evidentemente, an hay algn misterio alrededor del procesamiento de eventos.


Los controles (y todas las clases) determinan cules eventos estarn disponibles. En el caso
de controles, muchos de los eventos son paralelos a acciones iniciadas por el usuario: Click,
MouseDown, KeyPress y SizeChanged. Pero tambin hay muchos eventos que podran dispa-
rarse slo mediante modificaciones al control en su cdigo fuente: TabIndexChanged (cuando
cambia el orden de tabulacin de los controles), BackgroundImageChanged y CursorChan-
ged son slo tres de los principales eventos que el usuario no puede afectar de manera directa.
Unos cuantos eventos finales se unen a los cambios en el nivel del sistema, como el evento
SystemColorsChanged, que se dispara cuando el usuario modifica el esquema de color median-
te el panel de control.
Cada evento no slo tiene un nombre (como Click), sino que tambin tiene un conjunto de
parmetros que el manejador de eventos recibir cuando se le llamad. He aqu un tpico mane-
jador de eventos para un control Button:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click

End Sub

Este manejador de eventos recibe dos argumentos de disparo de un evento: una instancia Sys-
tem.Object (sender) y una System.EventArgs (e). Otros manejadores de eventos pue-
den usar un conjunto de argumentos ligeramente diferente, as que cmo sabe cul usar? Cual-
quier evento definido dentro de una clase de control tambin debe indicar el nmero y el tipo

206 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 206 17/2/10 15:23:09


de argumentos que enviar al manejador de eventos. Visual Basic incluye una instruccin Event
que define eventos. Aunque el control Button haya sido escrito en C#, he aqu la manera en que
la definicin del evento Click de Button se vera en Visual Basic:
Public Event Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs)

Seguramente, esta definicin se parece mucho al manejador de eventos, y debe parecerlo. La ins-
truccin Event establece un contrato de paso de parmetros entre el control y cualquier cdigo
que quiera que reciba notificaciones de evento. En este caso, el evento Click promete enviar dos
argumentos al manejador de eventos. El primero, sender, es una referencia que hace el evento
a un objeto. En el caso de controles Button, este parmetro recibe una referencia a la propia
instancia Button. El segundo argumento, e, proporciona un mtodo para pasar un objeto com-
pleto de informacin adicional. La clase System.EventArgs no tiene mucha informacin, pero
algunos eventos usan una variacin del segundo argumento, que emplea System.EventArgs
como su clase de base.
Resulta que los argumentos usados por el evento Click son muy comunes entre los diferentes
controles y eventos. En lugar de volver a escribir la lista de argumentos en cada instruccin
Event, el diseador de un control puede definir un delegado, un tipo .NET que define una lista
de argumentos y, para el caso de funciones, un valor de devolucin.
Public Delegate Sub StandardEventDelegate( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs)

Entonces las instrucciones Event pueden usar el delegado definido como un mtodo abreviado
para no escribir la lista completa de parmetros.
Public Event Click As StandardEventDelegate

Si la instruccin Event usa un delegado a una lista completa de argumentos, tiene una concep-
cin firme de cules datos necesita enviar a cualquier manejador de eventos que escuche. Y enva
esos argumentos usando la instruccin RaiseEvent de Visual Basic. Sigamos este proceso para
el control Button. Cuando el usuario hace clic en el botn, la bomba de mensajes encuentra una
manera de obtener un mensaje al procedimiento WndProc para el control Button. Ese control
examina el mensaje, lo ve como un clic del ratn y decide hablar a los manejadores de eventos
sobre l. Luego, desde el interior del cdigo de WndProc, eleva el evento.
RaiseEvent Click(Me, New System.EventArgs)

La palabra clave de Visual Basic Me alude a la propia instancia del control Button. El argumento
e de un control Button no contiene informacin ms all de los campos predeterminados in-
cluidos en una instancia System.EventArgs, as que WndProc slo enva una nueva instancia
vaca. Los controles con otros argumentos de evento hubieran creado primero una instancia, la
hubieran rellenado con los datos relevantes y pasado esa instancia al manejador de eventos.
Si un evento se dispara en una aplicacin, y no hay un manejador de eventos que lo escuche,
hace un sonido? Tal vez no. No es obligatorio que un evento tenga controladores activos escu-
chndolo. Pero cuando queremos escuchar un evento, cmo lo hacemos? La manera estndar

Ventanas en .NET | 207

07_PATRICK-CHAPTER_07.indd 207 17/2/10 15:23:09


en una aplicacin de Windows Forms es un proceso de dos pasos. En primer lugar, el usuario del
control (su clase de formulario) necesita anunciar al control: Quiero monitorear tus eventos.
Luego se adjuntan manejadores de eventos a eventos especficos.
En pginas anteriores de este captulo, vimos que la adicin de un control a la interfaz de usuario de
Form1 en realidad dispara a Visual Studio para que escriba cdigo fuente en el archivo Form1.designer.
vb. He aqu el cdigo agregado para un control Button llamado Button1 (con nmeros de lnea):
01 Partial Class Form1
02 Inherits System.Windows.Forms.Form
03
04 Friend WithEvents Button1 As System.Windows.Forms.Button
05
06 Private Sub InitializeComponent()
07 Me.Button1 = New System.Windows.Forms.Button
08
09 Me.Button1.Location = New System.Drawing.Point(48, 16)
10 Me.Button1.Name = "Button1"
11 Me.Button1.Size = New System.Drawing.Size(75, 23)
12 Me.Button1.TabIndex = 0
13 Me.Button1.Text = "Button1"
14 Me.Button1.UseVisualStyleBackColor = True
15
16 Me.Controls.Add(Me.Button1)
17 End Sub
18 End Class

El cdigo del mtodo InitializeComponent crea la instancia del control Button (lnea 07),
modifica sus propiedades para obtener lo que queremos (lneas 09 a 14) y lo adjunta al formu-
lario (lnea 16). Pero hay una lnea adicional que define la variable de tipo de referencia real
Button1 (lnea 04):
Friend WithEvents Button1 As System.Windows.Forms.Button

Habl acerca de los campos en el nivel de la clase en el captulo 6, y Button1 es slo un cam-
po tpico. Pero la palabra clave WithEvents incluida en la instruccin es lo que le hace saber
al control que alguien quiere monitorear las notificaciones de eventos. Ahora, cada vez que se
dispare un evento Button1, sabe que Form1 puede contener manejadores de eventos que estn
mirando y escuchando.
La segunda parte de nuestro proceso de conexin de evento con manejador de dos pasos incluye
la conexin real al manejador. Echemos un vistazo de nuevo a la definicin del manejador de
eventos Click para la instancia Button1:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click

End Sub

Es slo un mtodo de clase ordinario, pero con una clusula Handles colgando al final de la de-
finicin. Esta clusula es la que vincula al manejador de eventos con el propio evento Button1.
Click. Puede colocar varios nombres de evento despus de la palabra clave Handles.

208 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 208 17/2/10 15:23:09


Private Sub MuchosBotones_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click, _
Button2.Click, Button3.Click
End Sub

Ahora el manejador de eventos MuchosBotones_Click escuchar eventos Click desde tres


controles distintos. Incluso puede combinar los eventos monitoreados; un manejador de eventos
puede escuchar diferentes eventos con nombre.
Private Sub MuchosEventos(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.MouseDown, _
Button2.MouseUp

End Sub

Otra variacin consiste en hacer que varios manejadores de eventos monitoreen un solo evento,
aunque Visual Basic decida a cul manejador llama primero.
Private Sub PrimerManejador(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click

End Sub

Private Sub SegundoManejador(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles Button1.Click

End Sub

Hay otra manera de conectar eventos con manejadores de eventos que no incluyen las palabras
clave WithEvents o Handles, y que le permiten controlar el orden de procesamiento de varios
manejadores. Una vez que tenga una instancia de una clase que expone un evento, adjunta un ma-
nejador a uno de sus eventos usando la instruccin AddHandler. La siguiente instruccin vincula
el evento Click de Button1 con un manejador de eventos llamado MiManejador. El mtodo
MiManejador debe tener la lista de argumentos correctos para el evento definido.
AddHandler Button1.Click, AddressOf MiManejador

Una instruccin RemoveHandler separa un manejador de un evento.


Una buena cantidad de pasos complicados le llevan de un usuario inicial o una accin de sistema
al cdigo de un manejador de eventos. He dedicado una gran cantidad de espacio a analizar la
manera exacta en que funcionan los eventos, pero por una buena razn. Los eventos y el proce-
samiento de eventos son caractersticas centrales del desarrollo de aplicaciones de .NET. Al final
de cuentas, pasar mucho tiempo escribiendo manejadores de eventos que se volvern su segunda
naturaleza. Pero tambin expondr todos los detalles para que pueda aprovechar por completo
esta tecnologa. Visual Basic no slo le permite monitorear controles de eventos, tambin le per-
mite disear nuevos eventos en sus propias clases. Puede usar las palabras clave Delegate, Event,
RaiseEvent, WithEvents, Handles, AddHandler y RemoveHandler para sus propios even-
tos personalizados, disparados por cualquier condicin que elija. Si tiene una clase que representa
un empleado, puede hacer que dispare un evento Despedido cada vez que el empleado pierde su
trabajo. Al agregar eventos personalizados puede hacer posible que se adjunte cdigo personali-
zado a la lgica de su clase, aunque un programador no tenga acceso al cdigo fuente de su clase.

Ventanas en .NET | 209

07_PATRICK-CHAPTER_07.indd 209 17/2/10 15:23:10


Cmo hacer formularios tiles
Cualquier formulario identificado como objeto de inicio de su proyecto aparece automticamen-
te cuando empieza el programa. Todos los dems formularios deben desplegarse manualmente,
usando el mtodo Show o ShowDialog de ese formulario. Por ejemplo, si tiene un formulario
llamado Form2, puede usar su mtodo Show:
Form2.Show( )

El mtodo Show despliega un formulario sin modo. Los formularios sin modo pueden accederse in-
dependientemente de los dems formulario en la aplicacin que se ejecuta. Todos los formularios sin
modo pueden activarse en cualquier momento con slo hacer clic en ellos; el formulario en que haga
clic pasar al frente de los dems y recibir el enfoque de entrada. Un programa podra tener uno, dos o
docenas de formularios sin modo abiertos a la vez, y el usuario puede moverse libremente entre ellos.
Los formularios modales toman el control de toda la entrada de la aplicacin, siempre y cuando
aparezcan en la pantalla. A los formularios modales suele denominrseles cuadros de dilogo;
el usuario debe completar un formulario modal y cerrarlo antes de que se acceda a cualquier otro
formulario en la aplicacin. El cuadro de mensaje que aparece cuando usa la funcin MsgBox es
una ventana de dilogo modal comn. El mtodo ShowDialog despliega formularios modal-
mente, y le permite regresar un valor de ese formulario. Los valores devueltos son los miembros
de la enumeracin System.Windows.Forms.DialogResult.
Si considera que los formularios son obras literarias de Alejandro Dumas, los formatos sin modo
seran como Los tres mosqueteros: Todos para uno y uno para todos. Trabajan juntos para dar
soporte a toda la aplicacin. Los formularios modales son como El conde de Montecristo. S, hay
otros formularios/personajes en la aplicacin/ancdota, pero no son nada cuando el conde est
a la vista.
Para desplegar al conde (es decir, un formulario modal), use el mtodo ShowDialog del formu-
lario y, como opcin, capture su valor de devolucin.
Dim elResultado As DialogResult
elResultado = Form2.ShowDialog()

Los cuadros de dilogo modales son tiles para edicin de algunos registros que requieren que
haga clic en el botn Aceptar, cuando se hayan completado los cambios. Digamos que est es-
cribiendo una aplicacin que despliega una lista de libros de Alejandro Dumas. Podra incluir
dos formularios: 1) un formulario principal que despliega la lista de libros; y 2) un formulario
secundario que le permite escribir el nombre de un solo libro. No sera estupendo que pudiera
regresar el nombre del libro (o, tal vez, un nmero de ID de un registro para el libro, tal como
se almacena en una base de datos) en lugar de un valor de DialogResult?
Si el mtodo ShowDialog, un mtodo pblico de la clase Form, puede devolver un cdigo de
resultado, tal vez podemos agregar otro mtodo pblico para un formulario que devolver un c-
digo de resultado que tenga un significado real. Por supuesto, s podemos. Considere el formu-
lario secundario (llamado EntradaLibro) con un campo de entrada de datos (TituloLibro) y
botones Aceptar (AccAceptar) y Cancelar (AccCancelar), como se muestra en la figura 7-10.

210 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 210 17/2/10 15:23:10


Figura 7-10. Formulario de entrada de ttulo del libro.

Cuando se alimenta con el siguiente cdigo, este simple formulario devuelve cualquier cosa
escrita en el campo cuando el usuario hace clic en Aceptar (rechazando primero los valores en
blanco), o devuelve una cadena en blanco al hacer clic en Cancelar:
Public Class EntradaLibro
Public Funcin EditarLibro() As Cadena
' ----- Mostrar el formulario y devolver lo que ingresa el usuario.
If (Me.ShowDialog() = DialogResult.OK) Then
Return TituloLibro.Text.Trim
Else
Return ""
End If
End Funcin

Private Sub AccCancelar_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles AccCancelar.Click
' ----- Devolver un titulo en blanco para "Cancelar".
Me.DialogResult = DialogResult.Cancel
' ----- Continuar con EditarLibro( )
End Sub

Private Sub AccAceptar_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles AccAceptar.Click
' ----- Solo aceptar titulos validos.
If (Len(TituloLibro.Text.Trim) = 0) Then
MsgBox("Por favor proporcione un titulo valido.")
Else
Me.DialogResult = DialogResult.OK
' ----- Continuar con EditarLibro( )
End If
End Sub
End Class

Para usar este formulario, el formulario principal llama al mtodo EditarLibro, que devuelve
el ttulo del libro ingresado por el usuario.
Dim nuevoTitulo As Cadena = EntradaLibro.EditarLibro(
)

La rutina EditarLibro muestra el formulario modalmente con el mtodo ShowDialog, y


permanece all hasta que el usuario cierra el formulario. El cierre del formulario se hace median-
te el evento del botn Aceptar o Cancelar; el establecimiento de la propiedad DialogResult
tiene el efecto colateral de cerrar el formulario. Estupendo!

Cmo hacer formularios tiles | 211

07_PATRICK-CHAPTER_07.indd 211 17/2/10 15:23:10


Una vez que se cierra el formulario, la ejecucin regresa a EditarLibro, que hace una rpida
revisin del estatus antes de regresar el valor final. Y aqu lo tenemos: una nueva interfaz pblica
para el valor de regreso ms importante del formulario. Usaremos este mtodo en gran medida
en la aplicacin Proyecto Biblioteca.

Resumen
La programacin en Windows en realidad no ha cambiado mucho desde Windows 1.0. An
hace todo mediante mensajes, colas de mensajes y procedimientos de ventana. Lo que ha cam-
biado es la manera en que se abstrae el cdigo para beneficio del programador. El paquete de
.NET Framework para desarrollo en Windows, Windows Forms, facilita el desarrollo de aplica-
ciones de escritorio de Windows y (me atrevo a decirlo) lo hace divertido!

Proyecto
El cdigo del proyecto de este captulo implementa el formulario bsico Principal del Proyecto
Biblioteca, adems del formulario Bienvenido que aparece cuando inicia el proyecto. Micro-
soft, sabiendo que sta era una necesidad comn, incluy soporte para formularios principales y
de bienvenida en el sistema de marco conceptual de la aplicacin de Visual Basic. Como opcin
predeterminada, este sistema se habilita mediante el panel Aplicacin de la propiedades del pro-
yecto (vase la figura 7-11).

Figura 7-11. Campos de inicio y presentacin mediante las propiedades del proyecto.

212 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 212 17/2/10 15:23:11


Los campos Formulario de inicio y Formulario de presentacin indican los formularios prin-
cipal y de bienvenida, respectivamente. Es rpido, fcil y lo mejor para nosotros. As que pase-
mos al trabajo. Ahora es un buen momento para cargar el proyecto inicial para el captulo 7.

ACCESO AL PROYECTO
Cargue el proyecto Cap07 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap07 (Final) cdigo.

Configuracin de la pantalla de bienvenida


Ya he agregado un nuevo archivo de formulario al proyecto, llamado Bienvenida.vb (el propio
formulario se denomina Bienvenida), incluidos algunos elementos simples de despliegue, para
darle un poco de vida. Revise la imagen en el formulario. Se presenta mediante el control Pic-
tureBox, pero est almacenado en la aplicacin como un recurso, una coleccin de cadenas e
imgenes adjuntadas a su cdigo fuente. La carpeta Recursos del Explorador de soluciones inclu-
ye este archivo grfico. Est vinculado en el cuadro de imgenes mediante la propiedad Image
de ese control. Y es seguro que hace que el formulario tenga un buen aspecto. Su trabajo ser
adjuntar este formulario a la seccin de inicio de la aplicacin.
Acceda al panel Aplicacin de las propiedades del proyecto (que vio en la figura 7-11), y establez-
ca el campo Pantalla de presentacin en Bienvenida. Esto tiene el efecto colateral de establecer
My.Application.SplashScreen en el formulario Bienvenida. Ahora ejecute el programa.
Debe ver que la pantalla de bienvenida aparece por alrededor de 1/100 de segundo y es reempla-
zado rpidamente por el formulario principal. Hey, qu fue eso?
La modificacin del campo Pantalla de presentacin hace que la pantalla de bienvenida aparez-
ca brevemente, pero la aplicacin se quedar hasta que considere que el programa ha terminado
la preparacin del formulario principal. Como no hemos hecho ninguna preparacin, presenta
el formulario principal de inmediato.
Con el tiempo, agregaremos una gran cantidad de cdigo de inicio relacionado con bases de datos
que consumirn un poco ms de tiempo. Pero por ahora tendremos que simularlo. En el modelo
del marco conceptual de la aplicacin, cualquier cdigo que quiera procesar cuando el programa
empieza aparece en el evento Startup de la aplicacin. Este evento es uno de una pequea co-
leccin de eventos incluidos en la jerarqua My. El cdigo fuente para estos eventos aparece en el
archivo ApplicationEvents.vb, un archivo que Visual Studio agrega automticamente a su proyecto
cuando es necesario. Use el botn Ver eventos de aplicaciones, en el panel Aplicacin para abrir
el cdigo fuente de ese archivo.
Namespace My
Class MyApplication

End Class
End Namespace

Proyecto | 213

07_PATRICK-CHAPTER_07.indd 213 17/2/10 15:23:11


Imaginemos que la inicializacin requerida para el Proyecto Biblioteca toma alrededor de tres
segundos. .NET incluye un mtodo Sleep que demora el cdigo por un nmero especfico de
milisegundos. El fragmento de cdigo 1 agrega el manejador de eventos Startup para la aplica-
cin. Agrguelo entre las palabras clave Class y End Class de MyApplication.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap07, Elemento 1.

Private Sub MyApplication_Startup(ByVal sender As Object, _


ByVal e As Microsoft.VisualBasic.ApplicationServices. _
StartupEventArgs) Handles Me.Startup
' ----- Tomar una siesta de tres segundos.
System.Threading.Thread.Sleep(3000)
End Sub

Ahora ejecute el programa, y ver que la pantalla de bienvenida se queda alrededor de tres segundos
(3000 milisegundos). Aunque es gratificante verla por tanto tiempo, es posible que la base de datos
real y el cdigo de inicializacin de la aplicacin tome mucho menos de tres segundos. Quiero
decir, estamos hablando aqu de SQL Server. Se supone que es resplandecientemente rpido.
De modo que queda claro que an necesitamos demorar el retiro de la pantalla de bienvenida.
Y resulta que el objeto My.Application incluye la propiedad que necesitamos para imponer
una demora. La propiedad MinimumSplashScreenDisplayTime indica el nmero mnimo de
milisegundos que la pantalla de bienvenida debe desplegarse. Lo malo es que tiene que asignarla
en un lugar realmente extrao, por lo menos comparado con los que hemos aprendido de pro-
gramacin en Visual Basic hasta el momento.
Elimine todo el cdigo que agreg del fragmento de cdigo 1, que sera todo el mtodo My
Application_Startup. Luego, en ese espacio vaco, incluya el siguiente cdigo.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap07, Elemento 2.

Protected Overrides Funcin OnInitialize _


(ByVal commandLneaArgs As System.Collections. _
ObjectModel.ReadSloCollection(De Cadena)) As booleano
' ----- Desplegar el formulario de bienvenida por al menos 3 segundos.
My.Application.MinimumSplashScreenDisplayTime = 3000
Return MyBase.OnInitialize(commandLneaArgs)
End Funcin

Este bloque de cdigo contiene una gran cantidad de cosas sobre las que an no hemos hablado,
y no hablaremos por algunos captulos. Baste con decir que el mtodo OnInitialize es una de
las primeras cosas que suceden en la vida del programa, y que es el lugar donde debe asignarse
MinimumSplashScreenDisplayTime.

214 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 214 17/2/10 15:23:11


Lo ltimo que debemos hacer con la pantalla de bienvenida es incluir algn cdigo que des-
pliegue el nmero de versin. Ya hicimos esto en el formulario AcercaDe en el captulo 5, de
modo que slo agregaremos cdigo similar al evento Load del formulario Bienvenida. Tam-
bin actualizaremos el mensaje de copyright. Abra el cdigo fuente del formulario Bienvenida
y agregue el siguiente cdigo.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap07, Elemento 3.

Private Sub Bienvenida_Load(ByVal sender As Object, _


ByVal e As System.EventArgs) Handles Me.Load
' ----- Actualizar el numero de version.
With My.Application.Info.Version
VersionPrograma.Text = "Version " & .Major & "." & _
.Minor & " Revision " & .Revision
End With
ProgramaCopyright.Text = My.Application.Info.Copyright
End Sub

Ejecute el programa de nuevo y sintese con profundo respeto mientras atestigua una pantalla de
bienvenida completamente funcional.

Configuracin del formulario principal


Aunque diseamos un formulario principal en el captulo inicial, era muy parco, y slo inclua
un botn Acerca de. En el proyecto de este captulo se agregan todos los elementos de la interfaz
de usuario al formulario. En realidad, ya he agregado los controles del formulario a su superficie
(vase la figura 7-12). Pero puede agregar algunos de los manejadores de eventos que le darn
algo de espectacularidad a su despliegue.
Todo el cdigo de eventos en general para el formulario aparece en el fragmento de cdigo 4.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap07, Elemento 4.

Casi todo este cdigo existe para mover las cosas por el despliegue. Por ejemplo, el usuario puede
acceder a diferentes caractersticas del formulario al hacer clic en los conos o etiquetas de texto rela-
cionadas, a lo largo del lado izquierdo del formulario. Cada cono y etiqueta desencadena una de las
siete rutinas comunes que existen para reordenar los muebles. El cono de la parte superior izquierda,
ImgArtBiblioteca, llama a la rutina comn TareaArtBiblioteca cuando se hace clic en l.
Private Sub ImgArtBiblioteca_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles ImgArtBiblioteca.Click
' ----- Modo Articulo Biblioteca.
TareaArtBiblioteca()
End Sub

Proyecto | 215

07_PATRICK-CHAPTER_07.indd 215 17/2/10 15:23:11


Figura 7-12. El aspecto bsico del formulario principal.

El procedimiento TareaArtBiblioteca ajusta los diversos paneles y campos del despliegue


para que el usuario use los campos necesarios para revisar los artculos de la biblioteca.
Private Sub TareaArtBiblioteca()
' ----- Actualizar el despliegue.
TodosLosPanelesInvisibles()
PanelArtBiblioteca.Visible = True
AccArtBiblioteca.BackColor = SystemColors.Control
EtqSeleccionado.Location = New System.Drawing.Point( _
EtqSeleccionado.Left, ImgArtBiblioteca.Top)
Me.AcceptButton = AccBuscar
End Sub

La rutina TodosLosPanelesInvisibles tambin hace lo mismo.


Me gusta tener el texto existente en un campo TextBox seleccionado cuando se vuelve el control
activo. Cada control de texto incluye un mtodo SelectAll que realiza todo esto. Llamaremos
a ese mtodo durante el evento Enter de cada control TextBox, un evento que ocurre cuando
un control recibe el enfoque de entrada del teclado.
Private Sub TextoBusqueda_Enter(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles TextoBusqueda.Enter
' ----- Resaltar todo el texto.
TextoBusqueda.SelectAll()
End Sub

216 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 216 17/2/10 15:23:12


El empleo del ratn para acceder a las diferentes caractersticas del formulario es bueno, pero yo
soy una persona con preferencias por el teclado. Para tratar a los usuarios del teclado como yo, el
cdigo agrega soporte a caractersticas que hacen uso de las teclas F2 a F9.
Private Sub FormularioPrincipal_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles MyBase.KeyDown
' ----- Las teclas F2 a F9 dan acceso a las diferentes
' secciones del formulario.
Select Case (e.KeyCode)
Case Keys.F2
TareaArtBiblioteca()
e.Handled = True
Case Keys.F3
TareaRegistroClientes()
e.Handled = True
Case Keys.F4
' ----- Permitir que el formulario maneje Alt+F4.
If (e.Alt = True) Then
Me.Close()
Else
TareaAyuda()
End If
e.Handled = True
Case Keys.F5
TareaSalida()
e.Handled = True
Case Keys.F6
TareaEntrada()
e.Handled = True
Case Keys.F7
TareaAdmin()
e.Handled = True
Case Keys.F8
TareaProceso()
e.Handled = True
Case Keys.F9
TareaInformes()
e.Handled = True
End Select
End Sub

Mientras cada teclazo proviene del manejador de eventos KeyDown, la instruccin Select Case
lo examina. Cuando se encuentra una entrada Case coincidente, se ejecuta el cdigo dentro del
bloque Case. Al oprimir la tecla F2 se dispara el cdigo en el bloque Case Keys.F2. Keys es
una de las muchas enumeraciones integradas que puede usar en sus aplicaciones .NET. Observe el
cdigo especial para la tecla F4. Permite la combinacin de teclas Alt-F4 para salir de la aplicacin,
que es la combinacin de teclas estndar para salir de los programas existentes de Windows.
Por lo general, todos los teclazos van al control activo, no al formulario. Para habilitar el manejador
de eventos FormularioPrincipal.KeyDown, la propiedad KeyPreview del formulario debe
estar establecida en True. Establezca esta propiedad de regreso al diseador del formulario.

Proyecto | 217

07_PATRICK-CHAPTER_07.indd 217 17/2/10 15:23:12


Creacin de una sola instancia del programa
El Proyecto Biblioteca est diseado para usarse slo dentro de una pequea biblioteca, slo
se ejecutar en unas cuantas estaciones de trabajo a la vez, tal vez un mximo de 10. Y no hay
necesidad de ejecutar ms de una copia en una sola estacin de trabajo, porque cada copia in-
cluye todas las caractersticas disponibles de la aplicacin. Una de las estupendas caractersticas
incluidas con Visual Basic es la capacidad de crear una aplicacin de una sola instancia, que
imponga la directiva de ejecutarse slo una vez en cada estacin de trabajo. Aunque poda crear
antes ese tipo de aplicaciones, ahora se permite con un solo clic del ratn.
Para que el Proyecto Biblioteca sea de una sola instancia, despliegue el panel Aplicacin de las
propiedades del proyecto, y luego seleccione el campo Convertir aplicacin de instancia nica.
Cuando el usuario trate de iniciar una segunda instancia, .NET rechazar la solicitud. En cam-
bio, disparar el evento StartupNextInstance. Cualquier manejo especial que desee realizar
en el inicio de una segunda instancia se dirigir a este manejador. Como el manejador de eventos
Startup, el manejador StartupNextInstance aparece en el archivo ApplicationEvents.vb.
En el caso del Proyecto Biblioteca, lo nico que realmente necesita hacer cuando el usuario trata
de iniciar una segunda instancia es asegurarse de que la aplicacin se despliega al frente y el cen-
tro, donde el usuario pueda verla fcilmente. Abra el archivo ApplicationEvents.vb, y agregue el
manejador de eventos StartupNextInstance.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap07, Elemento 5.

Private Sub MyApplication_StartupNextInstance( _


ByVal sender As Object, _
ByVal e As Microsoft.VisualBasic.ApplicationServices. _
StartupNextInstanceEventArgs) _
Handles Me.StartupNextInstance
' ----- Forzar el formulario principal al frente.
My.Application.FormularioPrincipal.Activate( )
End Sub

stos son todos los desafos de este captulo. Lo veo en la siguiente pgina.

218 | Captulo 7: Windows Forms

07_PATRICK-CHAPTER_07.indd 218 17/2/10 15:23:12


Captulo 8
Clases y herencia

Cuntos programadores en .NET se necesitan para cambiar un bulbo? Ninguno; llaman a un


mtodo en el objeto bulbo, y se cambia solo. Ja, ja, ja! Es divertido, pero slo si comprende los
conceptos de la programacin orientada a objetos que son la base del sistema .NET. (En realidad,
ni siquiera es divertido si no comprende la programacin orientada a objetos.) Sin sta, sera
difcil dar soporte a caractersticas centrales de .NET, como el objeto System.Object, que es
la base del sistema .NET. Adems, la productividad caera entre desarrolladores de Windows,
quienes son la base del sistema .NET.
Aunque mencion brevemente los conceptos de desarrollo de programacin orientada a objetos
brevemente en los captulos 1 y 2, slo fue para proporcionar algn contexto para otros temas de
anlisis. Pero en este captulo, ya no me contendr. Despus de un vigoroso anlisis de conceptos
de programacin orientada a objetos, analizar la manera en que puede usarlos en su cdigo .NET.

Conceptos de programacin orientada a objetos


Si ha ledo este libro hasta ahora, probablemente sea aceptable dejarlo conocer el secreto de la
computacin orientada a objetos. El secreto es: todo resulta falso, es un engao, una cobertura.
Es correcto, su computadora en realidad no realiza ningn procesamiento con objetos, sin im-
portar su orientacin. La CPU de su equipo de cmputo procesa datos e instrucciones lgicas
a la vieja escuela: un paso a la vez, recorriendo reas especficas de la memoria como lo indica
la lgica, manipulando valores y bits individuales, de acuerdo con esas mismas instrucciones
lgicas. No ve los datos como objetos colectivos; los ve como bits y bytes.
Un momento, se me acaba de pasar este importante boletn noticioso. Dice: No seas un geek,
Tim. No se trata de que la computadora haga cosas orientadas a objetos, sino que las haga el
programador. Oh, perdn por eso. Pero lo que dije antes sigue siendo cierto: el cdigo final,
como lo ejecuta su CPU, ya no est ms orientada a objetos que el antiguo cdigo MS-DOS.
Pero los compiladores de lenguaje orientado a objetos proporcionan la ilusin de que la programa-
cin orientada a objetos est integrada en su computadora. Usted disea su cdigo y sus datos
en la forma de objetos, y el compilador los toma de all. Reorganiza su cdigo y sus datos, agrega

219

08_PATRICK-CHAPTER_08.indd 219 17/2/10 15:24:18


algo de cdigo adicional para que la programacin orientada a objetos simulada haga magia, y
se empaqueta todo en un archivo EXE. Podra escribir cualquier programa con programacin
orientada a objetos empleando lenguajes ordinarios procedurales, o aun lenguaje ensamblador.
Pero las aplicaciones que se concentran en datos a menudo pueden escribirse de manera mucho
ms eficiente empleando prcticas de desarrollo de programacin orientada a objetos.

El objeto
La esencia de la programacin orientada a objetos es, por supuesto, el objeto. Un objeto es una
persona, un lugar, una cosa. Espere un minuto, esos son nombres. Un objeto es como un nom-
bre. Los objetos son construcciones de datos y lgica de computadora que simbolizan entidades
reales, como personas, lugares o cosas. Puede tener objetos que representan personas, empleados,
perros, nutrias marinas, casa, archiveros, computadoras, dobles hlices de DNA, galaxias, imge-
nes, documentos de procesamiento de palabras, calculadoras, artculos de oficina, libros, perso-
najes de telenovela, invasores espaciales, rebanadas de pizza, canales majestuosos que se amorti-
zan a s mismos, plantaciones de t madurado, unas cuantas de mis cosas favoritas y arena.
Los objetos proporcionan un software conveniente con el objetivo de describir y administrar los
datos asociados con uno de esos objetos reales. Por ejemplo, si tuviera un conjunto de objeto
que representan DVD en su coleccin de videos caseros, el objeto podra administrar caracters-
ticas del DVD, como su ttulo, los actores que actan, la longitud del video en minutos, si los
DVD estaban daados o rayados, su costo, etc. Si conectara su aplicacin con el reproductor de
DVD-ROM en su sistema, su objeto incluso podra incluir una caracterstica reproducir que
(suponiendo que el DVD est en la unidad) empezaran a reproducir la pelcula, tal vez a partir
de una posicin de inicio o captulo del DVD.
Los objetos funcionan bien porque su capacidad para simular las caractersticas de sus contrapar-
tes reales a travs de medios de desarrollo de software. Hacen esto a travs de los cuatro atributos
clave de los objetos: abstraccin, encapsulamiento, herencia y polimorfismo.
En todo este captulo, el trmino objeto por lo general har referencia a una instancia de algo,
un uso especfico en memoria del elemento definido, una instancia con su propio conjunto de
datos, no slo su definicin o diseo. Clase alude al diseo y cdigo fuente del objeto, que com-
prende la implementacin.

Abstraccin
Una abstraccin indica la vista limitada de un objeto en relacin con un objeto real. Como una
pintura abstracta, un objeto abstracto muestra slo los elementos esenciales del equivalente real
(vase la figura 8-1).
Los objetos no pueden representar perfectamente contrapartes reales. En cambio, implementan
almacenamiento y procesos de datos en esos elementos de la contraparte real que son importantes
para la aplicacin. El software no es lo nico que requiere abstraccin. Su expediente mdico en
el consultorio del doctor es una abstraccin de su salud fsica total. Cuando compra una nueva

220 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 220 17/2/10 15:24:18


Original Abstracto
Figura 8-1. En realidad, la de la izquierda es tambin una especie de abstraccin.

casa, el informe del inspector de la casa es una abstraccin de la condicin real de la construccin.
Aunque el termmetro en su patio trasero es una abstraccin, no puede comunicar con exactitud
todas las variaciones menores de temperatura que existen alrededor de la barra de mercurio. En
lugar de eso, recupera toda la informacin que puede, y comunica un solo resultado numrico.
Todas estas herramientas abstractas registran, comunican o actan slo sobre la informacin
esencial que estaban diseadas para administrar. Un objeto de software, de una manera similar,
slo almacena, comunica o acta sobre informacin esencial acerca de su contraparte real. Por
ejemplo, si estuviera diseando un objeto que monitorea la condicin de una construccin,
podra registrar lo siguiente:
Ubicacin y direccin de la construccin.
Material principal de construccin (madera, concreta, vigas de acero, etc.)
Edad (en aos)
Condicin general (a partir de una lista de opciones)
Notas del inspector
Aunque una construccin tambin tendra color, varias puertas y ventanas, y una altura, estos
elementos tal vez no sean importantes para la aplicacin, y por tanto, no seran parte de la
abstraccin. A esos valores que estn contenidos dentro del objeto se les llama propiedades. A
cualquier regla de procesamiento o clculo contenido dentro del objeto que actan sobre las pro-
piedades (u otros datos proporcionados internos o externos) se le conoce como mtodo. Tomados
en conjunto, mtodos y propiedades integran los miembros del objeto.

Conceptos de programacin orientada a objetos | 221

08_PATRICK-CHAPTER_08.indd 221 17/2/10 15:24:19


Encapsulamiento
La mayor ventaja del software es que un usuario puede realizar rpida y fcilmente una gran
cantidad de trabajo complejo y que consume tiempo. En realidad, el software se ocupa de la
velocidad y la complejidad a nombre del usuario y, en muchos casos, el usuario ni siquiera se
preocupa de la manera en que se hace el trabajo. Estas computadoras slo estn haciendo lo que
deben; no s y no me preocupa cmo trabajan siempre y cuando me den los resultados que ne-
cesito es una afirmacin comn que suele escucharse en juntas con administradores. Y tambin
es una afirmacin realista, porque la computadora ha encapsulado los datos necesarios y la lgica
de procesamiento para realizar las tareas deseadas.
El encapsulamiento conlleva la idea de interfaces. Aunque una computadora puede contener
una gran cantidad de lgica y datos tiles, si no hubiera manera de interactuar con esa lgica o
esos datos, la computadora sera bsicamente un bulto intil de plstico y silicio. Las interfaces
proporcionan los medios para interactuar con los elementos internos de un objeto. Una interfaz pro-
porciona entradas muy controladas y existe en los datos y las rutinas de procesamiento contenidas
dentro del objeto. Como consumidor del objeto, es realmente irrelevante la manera en que el
objeto trabaja internamente, siempre y cuando produzca los resultado que espera mediante sus
interfaces pblicamente expuestas.
Con el uso de la computadora como ejemplo, las diversas interfaces incluyen (entre otras cosas)
el teclado, el monitor, el ratn, el cable de corriente, los puertos USB y 1394, las bocinas, el co-
nector del micrfono y el botn de encendido. A menudo, las cosas que conecto a esas interfaces
tambin son cajas negras, encapsuladas con interfaces pblicas bien definidas. La manera en que
el controlador de la impresora puede enviar comandos mediante el cable USB y, con el tiempo,
esparcir tinta en papel de 24 libras es simplemente inexplicable, pero no s y no me importa
cmo funciona, siempre y cuando funcione.

Herencia
La herencia en .NET no es como la herencia en la vida real; nadie tiene que morir antes de que
funcione. Pero como en la vida real, la herencia define una relacin entre dos objetos diferentes.
De manera especfica, define la manera en que un objeto desciende de otro.
A la clase original en la relacin del objeto se le denomina clase de base. Incluye varios y diversos
miembros de interfaz, adems de detalles internos de implementacin. Una clase derivada se define
empleando la clase de base como punto de partida. Las clases derivadas heredan las caractersticas de
sta. Como opcin predeterminada, cualquier miembro pblicamente expuesto de la clase de base
se vuelve, de manera automtica, un miembro pblicamente expuesto de la clase derivada, incluida
la implementacin. Una clase derivada puede elegir la sobrescritura de uno, alguno o todos esos
miembros, proporcionando sus propios detalles distintivos y suplementarios de implementacin.
A menudo, las clases derivadas proporcionan detalles especficos a un subconjunto de la clase de
base. Por ejemplo, una clase de base que define animales incluira interfaces para el nombre comn,
el nombre de la especie en latn, el nmero de patas y otras propiedades tpicas que pertenecen a

222 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 222 17/2/10 15:24:19


todos los animales. Las clases derivadas mejoraran an ms las caractersticas de la clase de
base, pero slo para un subconjunto de animales. Una clase mamfero podra definir el tiempo
de gestacin, mientras que una clase derivada de ave podra definir el dimetro de un hue-
vo. Tanto mamfero como ave an retendran el nombre, el nombre de la especie y la cuenta
de patas de la clase de base animal. Una instancia de ave sera un animal; una instancia de
mamfero sera un animal. Sin embargo, una instancia de ave no sera un mamfero. Adems, una
instancia de animal podra considerarse como un ave slo si se defini originalmente como ave.
Aunque una clase de base y una derivada tienen una relacin, los detalles de implementacin
son privados para la clase de base que no estn disponibles para la clase derivada. sta ni siquiera
sabe que existen esos miembros privados. Una clase de base puede incluir miembros protegidos
que, aunque ocultos para los usuarios de la clase, estn visibles para la clase derivada. Cualquier
miembro definido como pblico en la clase de base est disponible para la derivada, y tambin
para todos los usuarios de la clase de base. (Visual Basic define otro nivel llamado amigo. Los
miembros marcados como amigos estn disponibles para todo el cdigo del mismo ensamblado,
pero no para el cdigo fuera de ste. El cdigo fuera del ensamblado definido puede usar los
miembros pblicos.)
En la realidad s existen ejemplos de herencia. Un reloj es un objeto de base del que se deriva un
reloj con alarma. ste expone las interfaces pblicas de un reloj, y agrega sus propiedades y m-
todos propios especficos de la implementacin. Otros ejemplos incluyen un cuchillo, as como
navaja suiza derivada, una silla y su derivado la silla reclinable, y una tabla y su derivado la tabla
peridica de los elementos qumicos.

Polimorfismo
Los conceptos introducidos hasta ahora podran implementarse empleando lenguajes estndar
de programacin procedimental. Aunque no puede hacer herencia real en un lenguaje que no
sea de programacin orientada a objetos, como C, puede simularla empleando campos de mar-
ca: si un campo de marca denominado tipo en una estructura parecida a una clase que no es
de programacin orientada a objetos fue establecida en mamfero, podra habilitar el uso de
ciertos campos especficos de mamferos. Hay otras maneras de simular estas caractersticas, y no
sera demasiado difcil.
El polimorfismo es un ave completamente diferente. Su significado es muchas formas. Debido
a que una clase derivada puede tener su propia versin (sobrescrita) de un miembro de una clase
de base, si trata a un objeto mamfero como un animal genrico, podra haber cierta confusin
sobre cul versin de los miembros debe usarse, la versin de animal o la de mamfero. El poli-
morfismo se ocupa de determinar todo esto, en una base ad hoc, mientras su programa se est
ejecutando. El polimorfismo permite que cualquier cdigo de su programa trate una instancia
derivada como si fuera una instancia de base. Esto resulta estupendo para la codificacin. Si tiene
una rutina que trata a los objetos animal, puede pasarle objetos de tipo animal, mamfero o ave,
y funcionar bien. A este tipo de polimorfismo se le conoce como polimorfismo de asignacin de
subtipos, pero a quin le interesa su nombre.

Conceptos de programacin orientada a objetos | 223

08_PATRICK-CHAPTER_08.indd 223 17/2/10 15:24:19


Otra variacin de polimorfismo es la sobrecarga. Permite que un solo mtodo de clase (olvide por
ahora las clases derivadas) tenga varias formas, pero an se considerar como un solo mtodo.
Por ejemplo, si tiene un objeto casa con un mtodo pintura (que cambiara el color de la casa),
podra tener un mtodo pintura que acepte un solo color (pintar toda la casa de un color) y
otro mtodo pintura que aceptara dos colores (el color principal ms un color de adorno).
Cuando estos mtodos estn sobrecargados en una sola clase, el compilador determina a cul
versin llamar con base en los datos que incluya en la llamada al mtodo.

Interfaces e implementacin
El desarrollo de la programacin orientada a objetos diferencia entre la definicin de una clase,
el cdigo escrito para implementar esa clase y el uso resultante en memoria de esa clase como
objeto. Es similar a la manera en que, en un restaurante, diferencia entre un men, el cocinado
de su seleccin y el alimento real que aparece en su mesa:

La descripcin de un elemento en el men es (hasta cierto punto) su interfaz; describe lo que


expondr pblicamente el objeto real en cuanto a gusto, olor, etctera.
El mtodo usado por el personal de cocina para hacer la comida es la implementacin; es la
manera en que se preparan los alimentos. Puede haber diferentes implementaciones por par-
te diferentes restaurantes para el mismo elemento del men. En objetos, la implementacin
est oculta de la vista del pblico; en un restaurante, la preparacin de los alimentas est,
por suerte, oculta de la vista o nadie comera all.
La comida que recibe de la cocina es (ta ra r!) el objeto, la instancia real de lo que se descri-
be en el men. Muchos clientes hambrientos pueden ordenar el mismo platillo del men, y
recibira una instancia distinta de la comida.

Programacin orientada a objetos


en Visual Basic y .NET
En el aspecto conceptual, la programacin orientada a objetos en realidad no es as de compleja.
Debido a que seres humanos y programadores interactan todos los das con objetos reales e
instancias, es muy fcil que su mente gire alrededor de la idea de programar con objetos. Pero es
fcil comunicar esos conceptos de objeto a la computadora con el compilador de Visual Basic y
.NET Framework? Puede hacerse sin sesiones semanales en un cmodo sof? No me diga! Es
Visual Basic; por supuesto, es fcil.
Una razn es que los objetos son tan fciles en .NET como habran de serlo. Todo en su progra-
ma de .NET es parte de un objeto, y si todo acerca de .NET fuera difcil, estara leyendo un libro
sobre desarrollo en Macintosh ahora mismo. Pero no es demasiado difcil porque la implementa-
cin de Visual Basic de objetos es paralela a las ideas conceptuales de objetos.

224 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 224 17/2/10 15:24:19


Clases
Visual Basic usa clases y estructuras para definir objetos. Hablar acerca de las estructuras un poco
ms adelante en este captulo. La palabra clave Class empieza la definicin de una clase.
Class Superheroe
' ----- Aqui entra codigo relacionado con la clase.
End Class

Eso es casi todo: la palabra clave Class, y un nombre para la clase (Superheroe, en este caso).
Todas las clases residen en un espacio de nombres (analizados ya en el captulo 1). Como opcin
predeterminada, sus clases aparecen en un espacio de nombres que tiene el nombre de su proyec-
to. Puede modificar esto en las propiedades del proyecto (para establecer un espacio de nombres
en el nivel superior de su ensamblado) y con la instruccin Namespace (para indicar espacios de
nombres relativos a partir del espacio de nombres de nivel superior de su ensamblado).
Namespace ChicosBuenos
Class Superheroe
End Class
End Namespace

Si el espacio de nombres predeterminado de su aplicacin es WindowsAplicacion1, la clase en


este cdigo de ejemplo se identificara como WindowsAplicacion1.ChicosBuenos.Superhe-
roe. Puede agregar cualquier nmero de clases a un espacio de nombres. Las clases que usan el
mismo nombre, pero que aparecen en espacios de nombres diferentes, no estn relacionados.
Los miembros de una clase aparecen entre las clusulas Class y End Class. Tambin puede
dividir una definicin de clase en varios archivos de cdigo fuente. Si dividiera una clase como
sta, por lo menos una de las partes debe incluir la palabra clave Partial en esta definicin.
Partial Class Superheroe
Como en el caso de las definiciones de variables, las clases se definen usando una de las palabras
clave de modificador de acceso: Public, Private, Protected, Friend o Protected Friend.
Regrese al captulo 6, en la seccin Variable, si necesita refrescar sus nociones.
Las bibliotecas de clases de .NET Framework (FCL) estn simplemente cargados con clases y
objetos, y estn definidas en gran medida con la simple palabra clave: Class.

Miembros de clase
El hecho de llamar a su clase Superheroe no le otorgar poderes especiales si no agrega algn
miembro a la clase. Todos los miembros de clase deben aparecer entre los lmites Class y End
Class, aunque si usa la caracterstica Partial para dividir su clase, puede salpicar los miembros
entre las diferentes partes de la clase de cualquier manera que desee.
Puede incluir 11 tipos diferentes de miembros en sus clases de Visual Basic. Otros libros o do-
cumentos pueden darle una cifra diferente, pero estn equivocados, por lo menos si se organizan
las cosas de la manera como lo hago aqu:

Programacin orientada a objetos en Visual Basic y .NET | 225

08_PATRICK-CHAPTER_08.indd 225 17/2/10 15:24:19


Campos de variables
Las variables de tipo de valor y de referencia pueden agregarse de manera directa a su clase
como miembros de nivel superior. Como miembros de toda la clase, quedan accesibles para
cualquier cdigo definido en la misma clase, y tal vez para el cdigo que usa su clase. Las
variables se definen usando uno de los modificadores de acceso.
Class Superheroe
Public Nombre As Cadena
Protected VerdaderaIdentidad As Cadena
End Class

Los campos de variables son rpidos y convenientes para agregarlos a clases, pero en ocasiones
ofrecen poco control. Los campos pblicos pueden modificarse a voluntad, sin limitacin alguna,
aunque desee limitar el rango permitido de un campo. Adems, los campos no funcionan direc-
tamente con todas las caractersticas de Visual Basic, incluidas algunas caractersticas especficas
de LINQ. Cuando surgen problemas como ste, puede usar miembros de propiedad en lugar de
miembros de campos de variables. Presentar las propiedades unos prrafos ms adelante.
Campos de constantes
Las constantes se definen de la misma manera que los campos de variables, pero incluyen
la palabra clave Const. Al igual que con las constantes en el nivel del procedimiento, debe
asignar un valor a la constante de inmediato en el cdigo fuente, empleando literales o
clculos simples sin variables.
Private Const FactorBaseFuerza As Integer = 1

Enumeraciones
Las enumeraciones definen valores enteros relacionados. Una vez definidos puede usarlos en
su cdigo de la misma manera que otros valores enteros.
Private Enum SuperPoderGeneral
Vuelo
Velocidad
SuperVista
SuperOido
RelacionadoConAgua
RelacionadoConTemperatura
HerramientasYObjetos
Disfraces
End Enum

Las enumeraciones tambin pueden definirse en el nivel del espacio de nombres, fuera de
cualquier clase especfica.
Mtodos Sub
Las clases incluyen dos tipos de mtodos: subs y funciones. Todo el cdigo de la lgica de
su aplicacin aparece en uno estos tipos de mtodos o en propiedades, de modo que no se
moleste en buscar cdigo en una enumeracin. Los mtodos sub realizan alguna lgica de-
finida, trabajando de manera opcional en datos pasados como argumentos.

226 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 226 17/2/10 15:24:19


Public Sub DemostrarPoderPrincipal( _
ByVal factorFuerza As Integer)
' ----- Aqui aparece el codigo de la logica.
End Sub

El mtodo DemostrarPoderPrincipal, como miembro pblico de su clase, puede ser


llamado por cdigo dentro de la clase, o por cualquier cdigo que haga referencia a una
instancia de su clase. Este mtodo incluye un solo parmetro, factorFuerza, mediante el
cual se envan llamadas al mtodo en argumentos de datos.
Puede salir de un mtodo sub en cualquier momento empleando la instruccin Return, la
instruccin Exit Sub previa a .NET.
Mtodos de funcin
Los mtodos de funcin son como los sub, pero dan soporte a un valor devuelto. Los tipos
de datos definen el valor devuelto como una clusula As al final de la definicin de la fun-
cin. Puede asignar el valor de devolucin empleando la instruccin Return, o asignado el
nombre de la funcin directamente dentro del cdigo.
Public Function ObtenerIdentidadSecreta( _
ByVal ClaveSecreta As Cadena) As Cadena
If (ClaveSecreta = "Kriptonita") Then
' ----- Antes cree un campo de clase llamado
' VerdaderaIdentidad.
Return VerdaderaIdentidad
Else
ObtenerIdentidadSecreta = "OLVIDALO CHICO MALO"
End If
End Function

Si usa el estilo de asignacin a nombre de funcin para asignar un valor devuelto, use la
instruccin Exit Function para regresar al cdigo que llama en cualquier momento.
Propiedades
Las propiedades combinan las ideas de campos y mtodos. Puede crear propiedades de
lectura-escritura, slo lectura o slo escritura mediante los accesotes Get y Set. El siguiente
cdigo define una propiedad de slo escritura:
Public WriteOnly Property IdentidadSecreta(
) As Cadena
Set(ByVal valor As Cadena)
VerdaderaIdentidad = valor
End Set
End Property

Delegados
Los delegados definen argumentos y devuelven valores para un mtodo, y los encierran en
un solo objeto independiente. Suelen usarse para dar soporte al proceso del evento, a proce-
dimientos de devolucin de llamada y a llamadas indirectas a mtodos de clase.
Public Delegate Sub LlamadaGenericaAPoder( _
ByVal factorFuerza As Integer)

Como los delegados son muy genricos, suelen definirse en el nivel del espacio de nombres,
fuera de cualquier definicin de clase.

Programacin orientada a objetos en Visual Basic y .NET | 227

08_PATRICK-CHAPTER_08.indd 227 17/2/10 15:24:20


Eventos
La adicin de eventos a su clase permite a los consumidores de su clase reaccionar a cambios
y acciones que ocurren dentro de una instancia de la clase. La sintaxis usada para definir
eventos se parece un poco a la definicin de mtodos, pero una sintaxis alterna usa delegados
previamente definidos para indicar la firma del evento.
' ----- Definicin de no delegado.
Public Evento UsarPoder( _
ByVal factorFuerza) As Integer

' ----- Definicin delegado.


Public Evento UsarPoder As LlamadaGenericaAPoder

Declaraciones
La instruccin Declare le permite llamar a cdigo definido en archivos DLL externos,
aunque slo funciona con llamadas a DLL de Windows previas a .NET. La sintaxis para
declaraciones se parece mucho a la usada para definir mtodos.
Public Declare Function HablarAChicoMalo Lib "malvado.dll" ( _
ByVal mensaje As Cadena) As Cadena

Una vez definida, una sub o funcin declarada externamente puede usarse en su cdigo
como si fuera una definicin de sub o funcin integrada en .NET. .NET Framework hace
gran parte del trabajo tras bambalinas para intercambiar datos entre su programa y la DLL.
An as, debe tenerse cuidado cuando se interacta con este tipo de cdigo no administra-
do externo, sobre todo si la DLL se llama malvado.dll.
Interfaces
Las interfaces le permiten definir una clase abstracta y, en cierta manera, plantillas de clases.
En una seccin cerca del final de este captulo se analizarn las interfaces. Tambin pueden
definirse en el nivel del espacio de nombres, y suele hacerse.
Tipos anidados
Las clases pueden incluir otras clases (o estructuras) subordinadas para su propio uso interno
o pblico. Si hace pblica una clase secundaria puede devolver instancias de esa clase al
cdigo que usa la clase principal ms grande.
Class Superheroe
Class Superpoder
End Class
End Class

Puede anidar clase a cualquier profundidad, pero no exagere. La creacin de varias clases den-
tro del mismo espacio de nombres probablemente satisfar sus necesidades sin hacer que el c-
digo resulte excesivamente complejo. Pero esa es mi idea; haga lo que quiera. Despus de todo
es su cdigo. Si quiere tirar su vida en una carrera en el cine, no tengo problemas con ello.
La adicin de una estupenda variedad de miembros a una clase es muy divertido. Puede agregar
miembros de clase de cualquier variedad, en cualquier orden y en cualquier cantidad. Si agrega
demasiados miembros, incluso podra obtener un descuento por mayoreo en Visual Studio por
parte de Microsoft, pero no contenga el aliento.

228 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 228 17/2/10 15:24:20


Miembros de clase compartidos
Por lo general, los objetos (instancias de clases) suelen ser codiciosos y egostas; quieren todo para
s y no compartir con los dems. Por eso es por lo que cada instancia de una clase que cree tiene
su propia versin de los elementos de datos definidos como miembros de clase. Aun los mtodos
y propiedades de una clase dan la apariencia de ser distintos para cada instancia de clase. Es como
si cada objeto dijera: Tengo los mos, obtn los tuyos. Es esta actitud la que lleva a lo que suele
denominarse lucha de clases.
En un intento de promover la concordia entre los componentes de software y buscar clases ms
amables y gentiles, Microsoft incluy la palabra clave Shared en su diseo de clases. Esta
palabra clave puede aplicarse a un campo de variable, un mtodo sub, un mtodo de funcin y
a miembros de propiedad de su clase. Cuando se define, un miembro compartido puede usarse
sin necesidad de crear una instancia de esa clase. Se hace referencia a estos miembros compartidos
empleado slo el nombre de la clase y el del miembro.
Class ClaseConValorCompartido
Public Shared ElValorCompartido As Integer
End Class
...luego, en otro codigo...
ClaseConValorCompartido.ElValorCompartido = 10

Los miembros compartidos son compartidos literalmente por todas las instancias de su clase
y, si son pblicos, tambin por el cdigo fuera de su clase. Como no requieren una instancia
de un objeto, estn limitados slo a los recursos que no requieren una instancia de objeto. Esto
significa que un mtodo compartido no puede acceder a un campo de variable no compartido
de la misma clase. Cualquier miembro de clase que no est marcado como Shared se conoce
como miembro de instancia.

Miembros sobrecargados y argumentos opcionales


La sobrecarga de un mtodo ocurre al adjuntar la palabra clave Overloads a cada miembro
sobrecargado.
Class Casa
Public Overloads Sub PintarCasa()
' ----- Usar los mismos colores que antes.
End Sub
Public Overloads Sub PintarCasa(ByVal colorBase As Color)
' ----- Pintar la casa con un color plano.
End Sub
Public Overloads Sub PintarCasa(ByVal colorBase As Color, _
ByVal colorAdorno As Color)
' ----- Pintar usando un color principal y uno de adorno.
End Sub
Public Overloads Sub PintarCasa(ByVal colorBase As Color, _
ByVal capas As Integer)
' ----- Tal vez pintar con muchas capas, de pintura
' por supuesto, no para taparse.
End Sub
End Class

Programacin orientada a objetos en Visual Basic y .NET | 229

08_PATRICK-CHAPTER_08.indd 229 17/2/10 15:24:20


Cuando llama al mtodo PintarCasa debe pasar argumentos que coinciden con una de las ver-
siones sobrecargadas. Visual Basic determina cul versin habr de usarse en la firma del argumen-
to. Si pasa el tipo o el nmero de argumentos incorrecto, el programa se negar a compilar.
Dos de los miembros sobrecargados de esta clase tienen un aspecto parecido, excepto por el
segundo argumento capas.
Public Overloads Sub PintarCasa(ByVal cualColor As Color)

Public Overloads Sub PintarCasa(ByVal colorBase As Color, _


ByVal capas As Integer)

En lugar de definir dos mtodos distintos, puedo combinarlos en un solo mtodo, y definir un
argumento opcional para el parmetro capas.
Public Overloads Sub PintarCasa(ByVal colorBase As Color, _
Optional ByVal capas As Integer = 1)

La palabra clave Optional puede usarse con cualquier cantidad de parmetros, pero es posible que
los parmetros opcionales aparezcan despus de ellos; los argumentos opcionales siempre deben
ser los ltimos de la lista. Aunque el cdigo que llama no podra pasar un valor para capas, .NET
an requiere que cada parmetro reciba un argumento. Por tanto, cada argumento opcional incluye
un valor predeterminado empleando una asignacin simple dentro de la definicin del parmetro.
El argumento opcional capas usa un valor predeterminado de 1 mediante la clusula = 1.

Herencia
Visual Basic da soporte a la herencia, la unin de dos clases en una relacin ancestro-descendien-
te. Para implementar la herencia, se define la clase de base, y luego se agrega la clase derivada
usando la palabra clave Inherits. Vaya sorpresa!
Class Animal
' ----- Aqui van los miembros de la clase animal.
End Class

Class Mamifero
Inherits Animal

' ----- Todos los miembros de Animal son parte automaticamente


' de Mamifero. Agregar aqui las caractersticas
' adicionales de Mamifero.
End Class

La instruccin Inherits debe aparecer al principio de la definicin de clase, antes de la defini-


cin de cualquier miembro de la clase. Debe incluir el nombre exacto de otra clase, la clase de
base. Si divide su clase derivada usando la palabra clave Partial, necesita usar la instruccin
Inherits slo en una de las partes. Y como la clase derivada slo puede usar una clase de base,
est limitado a usar la instruccin Inherits una sola vez por clase. (La clase de base puede usar-
se en varias clases derivadas diferentes, y la clase derivada an puede usarse como clase de base
para otras clases derivadas.)

230 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 230 17/2/10 15:24:20


Las clases derivadas heredan automticamente todos los miembros definidos de la clase de base. Si
una clase derivada necesita proporcionar funcionalidad especial para un miembro definido en la
clase de base, sobrescribe ese miembro. Se trata de un proceso de dos pasos: 1) la clase de base debe
permitir que su miembro se sobrescriba con la palabra clave Overridable; y 2) la clase derivada
debe proporcionar el cdigo que sobrescribe empleando la palabra clave Overrides.
Class Animal
Public Overridable Sub Sonido()
MsgBox("Grrrr.")
End Sub
End Class

Class Can
Inherits Animal
Public Overrides Sub Sonido()
MsgBox("Guau.")
End Sub
End Class

Cualquier clase que derive de Animal puede proporcionar ahora su propio cdigo personalizado
para el mtodo Sonido. Pero lo mismo es cierto para la clase derivada de Can; la palabra clave
Overridable se pasa a cada generacin. Si necesita detener este atributo en una generacin
especfica, use la palabra clave NotOverridable. Esta palabra clave slo es vlida cuando se
usa en una clase derivada porque los miembros de la clase de base no permiten la sobreescritura,
como opcin predeterminada.
Class Can
Inherits Animal
Public NotOverridable Overrides Sub Sonido(
)
MsgBox(Guau.)
End Sub
End Class

Hay ocasiones en que no es posible escribir un mtodo verdaderamente general en la clase de


base, y tal vez quiera hacer que cada clase derivada imponga su propia versin del mtodo. El
uso de la palabra clave MustOverride en la definicin del miembro de base permite la imple-
mentacin de este requisito.
Class Animal
Public MustOverride Sub TacticaDeDefensa(
)
End Class

Los miembros marcados como MustOverride no incluyen cdigo de implementacin propio


porque no se usara. (Adems, observe que TacticaDeDefensa no tiene una instruccin End
Sub de cierre.) Como no hay cdigo asociado con este miembro, toda la clase Animal tiene una
deficiencia. Si creara una instancia de Animal y llamara a su mtodo TacticaDeDefensa, se
provocara el pnico dentro de la aplicacin. Por tanto, no es posible crear instancias de clases
que contienen miembros MustOverride. Para indicar esta limitacin, la clase tambin es deco-
rada con la palabra clave MustInherit.
MustInherit Class Animal
Public MustOverride Sub TacticaDeDefensa(
)
End Class

Programacin orientada a objetos en Visual Basic y .NET | 231

08_PATRICK-CHAPTER_08.indd 231 17/2/10 15:24:20


No ser posible crear directamente una instancia de Animal, aunque puede derivar clases de ella,
y crear instancias de esas clases. Adems, puede crear una variable Animal (un tipo de referencia)
y asignarle una instancia de una clase derivada de Animal.
Dim miembroZoo As Animal
Dim mono As New Simio ' Simio se deriva de Animal
miembroZoo = mono

Este cdigo en realidad no parece justo para la clase de base. Quiero decir, defini todos los
requisitos centrales para las clases derivadas, pero no merece crdito porque no puede crearse
directamente una instancia de l. Pero hay una manera para que una clase de base controle su
propio destino y que se lleve toda la gloria. Hace esto con la palabra clave NotInheritable.
NotInheritable Class Animal
End Class

La nica manera de usar una clase NotInheritable consiste en crear una instancia de ella; no
puede usarla como clase de base de otra clase derivada. (Si su clase no heredable contiene miem-
bros compartidos, pueden accederse sin la necesidad de crear una instancia.)
Inherits, MustInherit, NotInheritable, Overrides, Overridable, NotOverridable, ya
no se trata ms del Visual Basic de su abuelita, por cierto. Y an hay una ms de estas inimitables
palabras clave: Shadows. Cuando sobrescribe un miembro de una clase de base, el nuevo cdigo
debe usar una definicin que es idntica a la proporcionada en la clase de base. Es decir, si sobres-
cribe un mtodo de funcin con dos argumentos String y un cdigo de devolucin Integer,
el cdigo que sobrescribe debe usar la misma firma. Los miembros que usan Shadows no tienen
estos requisitos. Un miembro de este tipo coincide con un elemento de la clase de base slo en
el nombre; todo lo dems es distinto. Incluso puede cambiar el tipo del miembro. Si tiene un
mtodo sub llamado ManquillaCacahuate en una clase de base, puede echar sombra sobre ella
en la clase derivada con un campo de variable (o de constante, o una enumeracin o una clase
anidada) tambin llamada ManquillaCacahuate.
Class Alimento
Public Sub ManquillaCacahuate()
End Sub
End Class
Class Antojo
Inherits Alimento
Public Shadows ManquillaCacahuate As String
' Hey, esto ni siquiera es un "Sub"
End Class

Sin la palabra clave Shadows en la clase Antojo, ocurrira un error en tiempo de compilacin.

Creacin de instancias de clases


Paso uno: diseo de clases. Paso dos: derivacin de clases. Paso tres: creacin de instancias
de clase. Paso cuatro: cha-cha-ch. Visual Basic usa la palabra clave New para crear instancias de
sus clases personalizadas.

232 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 232 17/2/10 15:24:20


Dim miMascota As Animal = New Animal
' ----- O...
Dim miMascota As New Animal
' ----- O...
Dim miMascota As Animal
miMascota = New Animal

La instancia puede usar entonces como cualquier otra variable de instancia de .NET. El acceso a
miembros ocurre usando la notacin de punto.
miMascota.Nombre = "Fido"

Tambin puede pasar (dentro de lo razonable) variables de instancia entre sus variaciones de base
y derivadas.
Dim miMascota As Animal
Dim miPerro As Can
miPerro = New Can
miPerro.Nombre = "Fido"
miMascota = miPerro ' Como Can deriva de Animal
MsgBox(miMascota.Nombre) ' Despliega "Fido"

Si Option Strict tiene el valor On habr lmites en su capacidad para convertir entre tipos,
sobre todo en conversiones de estrechamiento (donde los datos de origen no siempre coinciden
con la variable de destino). En estos casos, debe usar la funcin CType (o una de unas cuantas
funciones similares proporcionadas por .NET y Visual Basic) para habilitar la conversin.
miPerro = CType(miMascota, Can)

Para hacer referencia a instancias de clase basta con hacer referencia a la variable u objeto que
contiene la instancia. Esto es cierto para el cdigo que usa una instancia de fuera de la propia
clase. En el caso del cdigo dentro de su clase (como en uno de sus mtodos) se hace referencia
a miembros de su instancia como si fueran variables locales (sin calificacin), o se usa la palabra
clave especial Me.
Class Animal
Public Nombre As String
Public Sub DisplayName()
----- Cualquiera de estas lineas funcionara.
MsgBox(Nombre)
MsgBox(Me.Nombre)
End Sub
End Class

Una palabra clave similar, MyClass, suele actuar como la palabra clave Me, pero tiene cierta
funcionalidad diferente cuando una instancia de clase se almacena en una variable de un tipo
de clase diferente (de base o derivada). Si crea una instancia de Can, pero la almacena en una
variable Animal, las referencia usando Me se concentrarn en el cdigo de Can, mientras que las
referencias a MyClass se concentrarn en el cdigo de Animal. No usar MyClass en el Proyecto
Biblioteca, y en el caso de los usos ms simples de las instancias de clase, nunca la necesitar.
Pero habr ocasiones en que es importante diferenciar entre cdigo de base y derivado, y sa es
la manera como se hace.

Programacin orientada a objetos en Visual Basic y .NET | 233

08_PATRICK-CHAPTER_08.indd 233 17/2/10 15:24:20


La palabra clave MyBase hace referencia a elementos de la clase de base de la que deriva la clase
actual. Slo hace referencia a la clase de base ms cercana; si tiene una clase llamada Clase5
que deriva de Clase4, que a su vez deriva de Clase3, que deriva de Clase2, que lo hace de
Clase1, que al final deriva de System.Object, las referencias a MyBase en el cdigo de Clase5
harn referencia a Clase4. Bueno, eso es casi cierto. Si trata de usar MyBase.NombreMiembro
y NombreMiembro no existe en Clase4, MyBase buscar a travs de la pila de clases hasta que
encuentre la definicin ms cercana de NombreMiembro.
Class Animal
Public Overridable Sub ObtenerLicencia(
)
' ----- Ejecutar codigo de licencia especifico de Animal.
End Sub
End Class

Class Can
Inherits Animal
Public Overrides Sub ObtenerLicencia(
)
' ----- Ejecutar codigo de licencia especifico de can, luego...
MyBase.ObtenerLicencia() ' Llama a codigo de la clase Animal
End Sub
End Class

Constructores y destructores
Las instancias de clase tienen un tiempo de vida: un inicio, un tiempo de actividad y, en algn
momento, por suerte, un final. El principio del tiempo de vida de un objeto ocurre mediante un
constructor; sus momentos finales son dictados por un destructor, antes de pasarlo al infinito en
el proceso de recoleccin de basura de .NET.
Cada clase incluye por lo menos un constructor, sea explcito o implcito. Si no proporciona
uno, .NET por lo menos realizar actividades mnimas en el nivel del constructor, como re-
servar espacio de memoria para cada campo de variable de instancia de su clase. Si quiere que
una clase tenga cualquier otra lgica de tiempo de inicio, debe proporcionarla mediante un
constructor explcito.
En Visual Basic los constructores son mtodos sub con el nombre New. Un constructor New sin
argumentos acta como el constructor predeterminado, llamado como opcin predeterminada
cada vez que se necesita una nueva instancia de una clase.
Class Animal
Public Nombre As String
Public Sub New()
' ----- Cada animal debe tener un nombre.
Nombre = "Fulano de tal de la Jungla"
End Sub
End Class

Sin este constructor, las nuevas instancias de Animal no tendran un nombre asignado en el
campo Nombre. Y como las variables String son tipos de referencia, Nombre tendra un valor
inicial de Nothing. No es algo muy amigable para el usuario. Un constructor predeterminado

234 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 234 17/2/10 15:24:20


le da una oportunidad de proporcionar por lo menos la lgica y los datos mnimos necesarios
para una nueva instancia.
Puede proporcionar constructores personalizados adicionales al agregar ms mtodos New, cada
uno con una firma de argumento diferente.
Class Animal
Public Nombre As String
Public Sub New()
' ----- Cada animal debe tener un nombre.
Nombre = "Fulano de tal de la Jungla"
End Sub
Public Sub New(ByVal nombreInicial As String)
' ----- Usar el nombre proporcionado por quien llama.
Nombre = nombreInicial
End Sub
Public Sub New(ByVal codigoInicial As Integer)
' ----- Construir un nombre a partir de un codigo numerico.
Nombre = "Animal numero " & CStr(codigoInicial)
End Sub
End Class

El siguiente cdigo demuestra cada constructor:


MsgBox((New Animal).Nombre)
' Despliega " Fulano de tal de la Jungla"

MsgBox((New Animal(Fido)).Nombre)
' Despliega "Fido"

MsgBox((New Animal(5)).Nombre)
' Despliega "Animal numero 5"

Puede obligar al consumidor de su clase a usar un constructor predeterminado al excluir un


constructor predeterminado de la definicin de clase. Adems, si est derivando su clase de algo
diferente a System.Object, suele ser una buena idea llamar al constructor de la clase de base
como la primera lnea de su constructor derivado, aunque el constructor predeterminado de la
clase de base ser llamado . . . como opcin predeterminada.
Class Can
Inherits Animal
Public Sub New()
MyBase.New() ' Llama a Animal.New(
)
' ----- Ahora agregar otro codigo.
End Sub
End Class

No es tan fcil destruir una instancia de una clase, como podra pensarse. Cuando crea instancias
de la clase local en sus mtodos, en realidad se destruyen cuando se sale del mtodo, si no ha asig-
nado la instancia a una variable fuera del mtodo. Si crea una instancia en un mtodo y la asigna a
un miembro de una clase, vivir en el miembro de la clase por el tiempo de vida de ste, aunque
se haya salido del mtodo que la cre.

Programacin orientada a objetos en Visual Basic y .NET | 235

08_PATRICK-CHAPTER_08.indd 235 17/2/10 15:24:20


Pero pensemos slo acerca de las instancias locales, por ahora. Una instancia se destruye cuando
se sale de la rutina. Tambin puede destruir una instancia de inmediato al asignar Nothing a la
variable.
miPerro = Nothing

El establecimiento de la variable en una nueva instancia destruir cualquier instancia anterior


almacenada en esa variable.
miPerro = New Can
miPerro.Nombre = "Fido"
miPerro = New Can ' Lo siento Fido, te has ido

Cuando se destruye un objeto, .NET llama a un mtodo especial denominado Finalize, si est
presente, para realizar cualquier limpieza antes de eliminar la instancia de la memoria. Finali-
ze est implementado como un mtodo Protected de la clase de base System.Object; debe
sobrescribir este mtodo en su clase para usarlo.
Class Animal
Protected Overrides Sub Finalize()
' ----- Aqui va el codigo de limpieza. Debe estar seguro
' de llamar al metodo Finalize de la clase de base.
MyBase.Finalize()
End Sub
End Class

Entonces, por qu resulta tan difcil terminar instancias? El problema es que .NET controla la
llamada del mtodo Finalize; es parte del proceso de recoleccin de basura. El marco concep-
tual no limpia continuamente su basura. Es como el servicio de limpia en su casa; la basura es
recogida por el camin slo de vez en cuando. Hasta entonces, se queda all, pudrindose, des-
componindose y sin llamar a su mtodo Finalize. En el caso de la mayor parte de los objetos,
esto no es mucho problema; a quin le importa si la memora para una cadena se libera ahora o
dentro de 30 segundos. Pero hay ocasiones en que es importante liberar los recursos adquiridos
lo ms rpidamente posible. Por ejemplo, si adquiere un candado para un recurso de hardware
externo y slo lo libera con el destructor, podra conservar ese candado mucho despus de que
se sali de la aplicacin. Hablemos de una muerte lenta.
Hay dos maneras de superar este problema. Una consiste en agregar un mtodo de limpieza se-
parado para su clase y esperar que cualquier cdigo que use su clase lo llame. Esto funcionar
hasta que algn cdigo olvide llamar al mtodo. (Por tanto, tambin debe llamar a esta rutina
desde el destructor Finalize). El segundo mtodo es similar, pero usa una interfaz proporcio-
nada por el marco conceptual llamada IDesechable. (Hablar acerca de las interfaces en un
minuto, de modo que no se preocupe por todo el cdigo mostrado aqu.)
Class Animal
Implements IDesechable

Protected Overrides Sub Finalize()


' ----- Aqui va el codigo de limpieza. Debe estar seguro
' de llamar al metodo Finalize de la clase de base.

236 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 236 17/2/10 15:24:21


MyBase.Finalize()
End Sub

Public Overloads Sub Dispose() _


Implements IDesechable.Dispose
' ----- Poner aqui codigo de limpieza. Y hacer estas llamadas.
MyBase.Dispose() ' Solo si la clase de base es desechable.
System.GC.SuppressFinalize(Me)
End Sub
End Class

El mtodo SuppressFinalize le indica al recolector de basura, No llames a Finalize; ya he


limpiado todo. Cualquier cdigo que use su clase necesitar llamar a su mtodo Dispose para
realizar la limpieza inmediata de recursos. De modo que no es tan diferente de la primera manera
de la que habl, pero estandariza un poco las cosas. Adems, permite el uso de la instruccin
Using de Visual Basic. Esta instruccin de bloque proporciona un mtodo estructurado de
limpieza de recursos:
Using miMascota As New Animal
' ----- Este codigo usa miMascota.
End Using
' ----- En este punto, se destruye miMascota, y la instruccin
' End Using llama de manera automatica a Disposes.

Interfaces
Las palabras clave MustOverride y MustInherit fuerzan a las clases derivadas a implementar
miembros especficos de la clase de base. Pero qu pasa si quiere que la clase derivada imple-
mente todos los miembros de la clase de base? Podra usar MustOverride junto a cada mtodo
y propiedad, pero una mejor manera consiste en usar una interfaz. Las interfaces definen cla-
ses abstractas, clases que slo constan de definiciones, sin implementacin. (Los puristas de la
programacin orientada a objetos sealarn que una clase con una sola marca MustOverride
tambin es una clase abstracta. Estupendo.) Las interfaces crean un contrato, un acuerdo que la
clase o estructura que implementa est dispuesta a cumplir.
La instruccin Interface empieza el proceso de definicin de la interfaz. Por convencin, to-
dos los nombres de interfaz empiezan con la I mayscula.
Interface IEdificio
Function AreaPiso() As Double
Sub ModificarExterior()
End Interface

Como se observa aqu, la sintaxis es una versin un poco simplificada de la sintaxis de definicin
de una clase. Todos los miembros de la interfaz se hacen pblicos automticamente, de modo
que no se incluyen modificadores de acceso. Slo se necesita la lnea de definicin de cada miem-
bro porque no hay implementacin. Adems de los mtodos de funcin y sub, los miembros de
la interfaz tambin incluyen propiedades, eventos, otras interfaces y estructuras. Las interfaces
tambin pueden derivar de otras (empleando la palabra clave Inherits), e incluyen automti-
camente todos los miembros de la interfaz de base.

Programacin orientada a objetos en Visual Basic y .NET | 237

08_PATRICK-CHAPTER_08.indd 237 17/2/10 15:24:21


Las interfaces se adjuntan a una clase empleando la palabra clave Implements. Esta misma palabra
clave se usa ms adelante para indicar cul miembro de clase define a cul miembro de la interfaz.
Class Casa
Implements IEdificio

Public Function AreaPiso() As Double _


Implements IEdificio.AreaPiso
' ----- Agregar aqui implementacion.
End Function

Public Sub PintarCasa() Implements IEdificio.ModificarExterior


' ----- Agregar aqui implementacion.
End Sub
End Class

No es necesario implementar los miembros de la interfaz en la clase, para mantener el nombre


del miembro de la interfaz original (aunque la firma del argumento debe coincidir con la de la
interfaz). En el cdigo de ejemplo, AreaPiso conserva el nombre del miembro equivalente de
la clase, pero el miembro ModificarExterior se implement usando el mtodo PintarCasa.
Esto hace posible algn cdigo interesante.
Dim unaCasa As New Casa
Dim unEdificio As IEdificio
unEdificio = unaCasa
unEdificio.ModificarExterior() ' Llama a unaCasa.PintarCasa(
)

Las clases slo puede heredar de una sola clase de base, pero no hay lmite en el nmero de in-
terfaces que una clase puede implementar.
Class Casa
Implements IEdificio, IDesechable

Adems, un solo miembro de una clase puede implementar varios miembros de una interfaz.
Public Sub PintarCasa() Implements _
IEdificio.ModificarExterior, IContratista.HacerTrabajo

Entonces, por qu usar interfaces? Proporcionan una manera genrica de acceder a fun-
cionalidad comn, incluso entre objetos que no tienen nada en comn. Las clases llamadas
Animal, Casa y Superheroe tal vez no tengan nada en comn en trminos de lgica, pero
podran necesitar una manera consistente de limpiar sus recursos. Si pueden implementar la
interfaz IDesechable, obtienen la capacidad sin la necesidad de derivar de alguna clase de
base.

Mdulos y estructuras
Adems de las clases, Visual Basic proporciona dos caractersticas de definicin de objetos rela-
cionadas: estructuras y mdulos. Aunque tienen nombres diferentes de clase, an actan de
manera parecida a stas, pero con diferentes caractersticas habilitadas e inhabilitadas.

238 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 238 17/2/10 15:24:21


Los mdulos proporcionan un lugar para incluir valores de cdigo y datos globales generales en
su aplicacin o ensamblado. Todos los miembros de un mdulo son compartidos. En realidad,
un mdulo acta como una clase con la palabra clave Shared agregada a cada miembro, pero
con una diferencia importante: no se permiten relaciones de herencia con los mdulos. No pue-
de crear un mdulo derivado de una clase de base o un mdulo, ni puede usar un mdulo como
base para cualquier otro tipo. Los mdulos son herencias de las versiones de Visual Basic previas
a .NET, que incluan Mdulos para todo el cdigo que no era Form.
Friend Module DatosYCodigoGenericos
' ----- Constante global de la aplicacion.
Public Const TodosLosDigitos As String = "0123456789"

' ----- Funcion global de la aplicacion.


Public Function ObtenerDigitosIncrustado( _
ByVal cadenaOrigen As String) As String
End Sub
End Module

No puede crear una instancia de un mdulo. Al igual que con las clases, los mdulos aparecen
en el contexto de un espacio de nombres. A diferencia de una clase con miembros comparti-
dos, no necesita especificar el nombre del mdulo para usar el miembro del mdulo. Todos los
miembros de mdulos actan como variables y mtodos globales, y pueden usarse de inmediato
en cualquier otro cdigo de su aplicacin sin calificacin adicional. (Puede restringir el uso del
miembro de un mdulo slo al mdulo al declarar el miembro como Private.)
Las estructuras son mucho ms parecidas a las clases que los mdulos. Las clases implementan
tipos de referencia, pero las estructuras implementan tipos de valor. Todas las estructuras derivan
de System.ValueType (que a su vez derivan de System.Object). Por tanto, actan de manera
similar a los tipos de datos centrales de Visual Basic, como Integer. Puede crear instancias de
una estructura usando la misma sintaxis empleada para crear instancias de clase. Sin embargo,
no puede usar una estructura como base para otra estructura derivada. Y aunque puede incluir
un constructor en su estructura, no se da soporte a los destructores.
Debido a la manera en que se almacenan y usan las estructuras en una aplicacin de .NET, son
adecuadas para tipos de datos simples. Puede incluir cualquier nmero de miembros en su es-
tructura, pero es mejor mantener las cosas simples.

Mtodos parciales
Al principio del captulo, escrib acerca de clases parciales, la capacidad de dividir una clase en
varios archivos. Las clases parciales son especialmente comunes en cdigo creado por genera-
dores de cdigo. Visual Studio es, en parte, un generador de cdigo; mientras arrastra y coloca
controles en su formulario, genera cdigo por usted en una clase parcial Form. En estos casos, las
clases parciales tienen dos autores: el generador automatizado y usted.
Los mtodos parciales, nuevos en Visual Basic 2008, tambin son usados por generadores de c-
digo, aunque tiene la libertad de emplearlos por s mismo. Son tiles en especial cuando alguna

Programacin orientada a objetos en Visual Basic y .NET | 239

08_PATRICK-CHAPTER_08.indd 239 17/2/10 15:24:21


clase generada automticamente quiere darle a su segundo autor (usted) la capacidad de propor-
cionar alguna lgica opcional que mejorar la lgica generada automticamente. Los mtodos
parciales podran llamarse con mayor exactitud mtodos opcionales, porque se tiene la opcin
de implementarlas o no.
Los mtodos parciales tienen dos partes: 1) una mitad no implementada, y 2) una mitad
implementada. Las dos mitades aparecen en partes diferentes de una clase parcial. Un m-
todo parcial nunca se divide entre una clase de base y una derivada; no se relacionan con la
herencia.
La mitad no implementada de un mtodo parcial parece una definicin de mtodo sub, pero con
la palabra clave Partial agregada.
Partial Private Sub ImplementarSiSeAtreve(
)
End Sub

Los mtodos parciales siempre deben ser mtodos sub, nunca funciones, y siempre deben de-
clararse como Private. Si proporciona cualquier parmetro, siempre deben decorarse con la
palabra clave ByVal, no ByRef. Hey, muchacho, sas son muchas restricciones.
La mitad implementada tiene un aspecto verdaderamente familiar, excepto por la falta de un
prefijo Partial. Pero es seguro que se ve bien con cdigo real entre las quijadas.
Private Sub ImplementarSiSeAtreve()
MsgBox("Lo hice, como se ve.")
End Sub

Entonces, qu es lo importante de estos mtodos parciales? Quiz no mucho, pero sera de


ayuda revisar un ejemplo. Regresemos a nuestra vida, usando la clase Animal, esta vez con un
mtodo parcial incluido. Empecemos con el lado autogenerado del mundo.
Partial Class Animal
Public Sub Mover()
' ----- Interesante codigo de movimiento, luego...
EfectosColateralesDeMover()
End Sub

Partial Private Sub EfectosColateralesDeMover(


)
End Sub
End Class

En ocasiones, cuando un animal se mueve, tiene efectos colaterales, como espantar a otros ani-
males. Como la segunda mitad del equipo de implementacin, podra programar estos efectos
colaterales al completar la otra mitad del mtodo parcial. Pero si no hubiera efectos colaterales
para esta implementacin en particular, podra simplemente dejar el mtodo parcial sin termi-
nar. Es opcional.
Basta de bla bl. Ve al punto, Tim, dir. El punto es que si nunca escribe la segunda mitad de
un mtodo parcial, el compilador de Visual Basic dejar fuera ambas mitades, generando cdigo
como si la mitad no implementada nunca fuera autogenerada, en primer lugar. As que esa pri-
mera clase Animal se vuelve:

240 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 240 17/2/10 15:24:21


Partial Class Animal
Public Sub Mover()
' ----- Interesante codigo de movimiento, luego...
End Sub
End Class

No slo hice que desapareciera la definicin del mtodo parcial, sino que tambin desapareci la
llamada a ese mtodo dentro de la rutina Mover.
Como un programador solitario que escribe cdigo a solas, probablemente nunca crear un
mtodo parcial; el sistema de eventos es una mejor manera de responder de manera genrica a
acciones dentro de una clase. Pero podra tener una posibilidad de escribir el lado de la imple-
mentacin de un mtodo parcial. Los mtodos parciales se usarn en algn cdigo especfico de
LINQ, sobre todo cuando se disea cdigo de LINQ que se comunica con SQL Server. Pero
conocer ms sobre esto en el captulo 17.

Problemas relacionados
Permtame tomar aqu unos cuantos momentos antes de entrar en el cdigo del proyecto para
analizar algunos temas que en realidad no caben en un anlisis particular de las computadoras,
pero que usted podra terminar usando demasiado en sus propias aplicaciones.

El mtodo MsgBox
Aunque lo he usado casi en cada pgina de este libro, hasta hora, nunca le he presentado for-
malmente el mtodo MsgBox. Parte del espacio de nombres Microsoft.VisualBasic, MsgBox
es una continuacin de la funcin MsgBox en la versin original de Visual Basic. Despliega una
ventana simple de mensaje, incluida una seleccin de botones de respuesta y un cono opcional.
Como funcin, devuelve un cdigo que indica en cul botn del formulario hizo clic el usuario,
uno de los valores de enumeracin de MsgBoxResult. La sintaxis es:
Public Function MsgBox(ByVal Prompt As Object, _
Optional ByVal Buttons As MsgBoxStyle = MsgBoxStyle.OKOnly, _
Optional ByVal Title As Object = Nothing) As MsgBoxResult

El parmetro Prompt acepta una cadena para despliegue en el cuerpo principal del cuadro de
dilogo; Buttons indica cules botones, conos y otros parmetros usar cuando se despliega el
cuadro de dilogo; y Title acepta un ttulo de ventana personalizado si quiere que aparezca algo
diferente del ttulo de la aplicacin. La siguiente instruccin despliega la ventana de la figura
8-2:
Dim resultado As MsgBoxResult = MsgBox( _
"Es seguro hacer clic; no va a explotar la computadora.", _
MsgBoxStyle.YesNoCancel O MsgBoxStyle.Question, _
"Haz clic en algo")

Problemas relacionados | 241

08_PATRICK-CHAPTER_08.indd 241 17/2/10 15:24:21


Figura 8-2. Comunicacin en un mensaje importante.

La funcin MsgBox se considera una parte intrnseca del lenguaje. Pero como miembro del es-
pacio de nombres Microsoft.VisualBasic, suele usarse dentro del lenguaje Visual Basic. Si
fuera a codificar algo de .NET en C#, normalmente optara por el mtodo MessageBox.Show.
Funciona de manera muy parecida a la funcin MsgBox, pero su segundo y tercer argumentos
estn invertidos. Algunos conformistas de .NET insisten en que MsgBox (y cualquier cosa que
aparezca en el espacio de nombres Microsoft.VisualBasic) debe desdearse en favor de al-
ternativas de biblioteca de clases. Encuentro que es una opcin preferida, pero puede encontrar
que esa persona insiste en que su cdigo es subestndar. Puede leer mis ideas sobre esas tcticas
en el captulo 26.
Si planea desarrollar cdigo de Visual Basic que tenga como destino la plataforma Silverlight de
Microsoft, evitar Microsoft.VisualBasic puede darle mejoras en el rendimiento cuando des-
cargue su ensamblado a la estacin de trabajo del cliente. Las aplicaciones de Silverlight obtienen
grandes beneficios de las reducciones en el tamao del cdigo compilado, al menos para fines de
descarga. Cualquier cosa que pueda hacer para eliminar dependencias de ensamblados externos
como Microsoft.VisualBasic le ayudar a hacer ms rpido su programa.

Uso de DoEvents
Los programas estn diseados para hacer una gran cantidad de cosas, y en ocasiones piensan de-
masiado, y bloquean la computadora. Esto resulta especialmente cierto para mtodos de Visual
Basic que realizan una gran cantidad de transacciones pesadas de base de datos, una tras otra.
El sistema difiere las actualizaciones de pantalla menos importantes de modo que pueda ocurrir
primero ese ms importante procesamiento de datos. Resulta estupendo, pero en ocasiones el
usuario piensa: Esta estpida computadora se muri de nuevo y desconecta el cable. Si tan slo
proporcionara mejorar actualizaciones, el usuario podra ser ms paciente.
Cada control de su formulario (y el propio formulario) incluye un mtodo Refresh, pero puede
ser una molestia actualizar todo de manera constante. Y actualizar la pantalla no hace mucho para
habilitar el botn Cancelar en que quiere que el usuario haga clic para abortar todo ese adora-
ble procesamiento de datos. Para facilitar la vida, Visual Basic incluye un mtodo DoEvents.

242 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 242 17/2/10 15:24:22


Cuando se llama a este mtodo, el cdigo del mtodo actual hace una pausa temporal, y se
procesan los mensajes en la cola de mensajes entrantes del subproceso, incluidos los mensajes de
pintura (actualizacin de la pantalla). DoEvents es parte del espacio de nombres My, y se usa
como una instruccin independiente:
My.Aplicacin.DoEvents()

Est prevenido de que el abuso de DoEvents puede hacer ms lenta su aplicacin, y puede llevar
a problemas relacionados con llamadas excesivas a un evento. En general, slo debe usarse en un
bloque de cdigo con procesamiento excesivo, y luego debe extenderse para que slo se le llame
unas veces por segundo, cuando mucho.

Argumentos ParamArray
Cualquier mtodo puede habilitar argumentos opcionales, y el cdigo que llama puede elegir
que se incluyan o excluyan esos argumentos. Pero qu pasa si quisiera agregar un nmero ilimi-
tado de argumentos opcionales a un mtodo? Cmo podra escribir, por ejemplo, una funcin
que devuelva el promedio de todos los argumentos proporcionados, sin lmites en el nmero
de argumentos? Aunque podra aceptar cualquier variable de matriz con los valores de datos de
origen, podra usar un argumento de matriz de parmetros, tambin denominado argumento
ParamArray.
Como con los argumentos opcionales, los argumentos ParamArray deben aparecer al final de
una lista de argumentos de mtodos, y slo puede haber una, porque uno es ms que suficiente
para cualquier mtodo. Los argumentos de matriz de parmetros usan la palabra clave Param
Array justo antes del nombre del argumento.

Public Function CalcularPomedio( _


ParamArray origenDatos() As Decimal) As Decimal
' ----- Calcular el promedio para un conjunto de numeros.
Dim unValor As Decimal
Dim totalConstante As Decimal = 0@

If (origenDatos.GetLength(0) = 0) Then
Return 0@
Else
For Each unValor En origenDatos
totalConstante += unValor
Next unValor
Return totalConstante / origenDatos.GetLength(0)
End If
End Function

Ahora la llamada a la funcin CalcularPomedio acepta cualquier cantidad de valores decima-


les.
MsgBox(CalcularPomedio(1, 2, 3, 4, 5)) ' Desplegar: 3

Problemas relacionados | 243

08_PATRICK-CHAPTER_08.indd 243 17/2/10 15:24:22


Resumen
La capacidad de extender clases mediante la herencia es, en verdad, la base sobre la que se
construyen programas completos pero manejables en .NET. Y no es demasiado compleja,
tampoco. Las clases son simples contenedores para sus miembros, y la variedad y complejidad
de todos los miembros disponibles no es tan grande. As que es realmente sorprendente que
pueda escribir casi cualquier tipo de programa, e implementar cualquier cantidad de carac-
tersticas, empleando estas herramientas simples. Oh, s, el lenguaje Visual Basic tambin es
de ayuda.
Mientras agregamos cdigo al Proyecto Biblioteca en este libro, se familiarizar cada vez
ms con las clases, estructuras, mdulos y sus miembros. Y aunque nunca recuerde si ByRef
o ByVal es el mecanismo de paso de parmetros predeterminado para mtodos, agregar
propiedades, mtodos, eventos, campos y otros tipos a clases como si hubiera nacido con esa
habilidad.

Proyecto
El cdigo de este captulo implementa dos caractersticas del Proyecto Biblioteca: 1) una simple
clase auxiliar usada con controles ListBox y ComboBox para administrar texto y datos, y 2) un
conjunto de formularios genricos para editar tablas que permiten la bsqueda en la Biblioteca,
como tablas de cdigos de estado.

Listas de soporte y cuadros combinados


En Visual Basic 6.0 y anteriores, los controles ListBox y ComboBox incluan dos colecciones
tipo matriz: List (usado para almacenar el texto desplegado para cada elemento) e ItemData
(usado para almacenar un valor numrico de 32 bits para cada elemento). El uso de la matriz
List era importante para el usuario porque presentaba el texto para cada elemento. Pero mu-
chos programadores dependan ms de la matriz ItemData, que permita que se adjuntara un
identificador nico a cada elemento de la lista.
cboMes.AddItem "Enero"
cboMes.ItemData(cboMes.NewIndex) = 1
cboMes.AddItem "Febrero"
cboMes.ItemData(cboMes.NewIndex) = 2
...
cboMes.AddItem "Diciembre"
cboMes.ItemData(cboMes.NewIndex) = 12

Ms adelante, despus de que el usuario seleccionaba un valor de la lista, el ID numrico podra


usarse para la bsqueda de bases de datos o cualquier otro propsito designado.
nMes = cboMes.ItemData(cboMes.ListIndex)

244 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 244 17/2/10 15:24:22


Las malas noticias son que ni List ni ItemData existen en la variacin .NET de los controles
ListBox o ComboBox. Las buenas noticias son que ambos son reemplazados con una coleccin
mucho ms flexible: Items. Esta coleccin almacena cualquier tipo de objeto que desee: ins-
tancias de Integer, String, Date, Animal o incluso Superheroe, y puede mezclarlos dentro
de un ListBox simple. Debido a que Items es slo una coleccin de instancias de System.
Object, puede poner cualquier tipo de objeto que desee en la coleccin. ListBox (o ComboBox)
usa esta coleccin para desplegar elementos en la lista.
Entonces, cmo sabe el control ListBox cmo desplegar texto para cualquier combinacin
de objetos? Como opcin predeterminada, el control llama al mtodo ToString del objeto.
ToString est definido en System.Object, y usted puede sobrescribirlo en su propia clase.
El control ListBox tambin incluye una propiedad DisplayMember que puede establecer en el
campo o la propiedad de su clase que genere el texto apropiado.
Veamos un ListBox en accin. Agregue un nuevo ListBox a un formulario y luego agregue el
siguiente cdigo al manejador de eventos Load.
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
ListBox1.Items.Add(1)
ListBox1.Items.Add("Simple")
ListBox1.Items.Add(#5/3/2006#)
End Sub
End Class

Al ejecutar el cdigo se despliega el formulario de la figura 8-3.

Figura 8-3. Una ListBox simple con tres elementos diferentes.

En el caso del valor ItemData ms antiguo, el control ListBox incluye una propiedad Value-
Member que identifica el campo o la propiedad del identificador para el objeto de la coleccin
Items. Pero no tiene que usar ValueMember. En cambio, puede simplemente extraer el objeto
en cuestin de la coleccin Items, y examinar sus miembros con su propio cdigo personali-
zado para determinar su identidad. En realidad, es un poco ms de trabajo que con el antiguo
mtodo de Visual Basic 6.0. Pero una vez ms, debido a que puede almacenar objetos de cual-
quier tamao en la coleccin Items, podra optar por almacenar registros de toda una base de
datos, algo que nunca antes poda hacer con .NET.

Proyecto | 245

08_PATRICK-CHAPTER_08.indd 245 17/2/10 15:24:22


Ms an, el almacenamiento de registros completos en un control ListBox o ComboBox es un des-
perdicio. Suele ser mejor almacenar slo un nmero de ID, y usarlo en bsquedas en una base de
datos. Es lo que haremos con el Proyecto Biblioteca. Para dar soporte a esto, necesitamos crear una
clase simple que expondr un texto y valores de datos. Primero, vayamos al cdigo en Biblioteca.

ACCESO AL PROYECTO
Cargue el proyecto Cap08 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap08 (Final) cdigo.

Pongamos la clase en un archivo propio de cdigo fuente. Agregue un nuevo archivo de clase
mediante el comando de men Proyecto Agregar clase. Asigne al archivo el nombre Da-
tosListaElementos.vb y haga clic en el botn Agregar. El siguiente cdigo aparece automtica-
mente:
Public Class DatosListaElementos

End Class

Esta clase ser muy simple. Slo incluir miembros para el despliegue del texto y el elemento, en
caso de que olvidemos conectar el campo de texto con la propiedad DisplayMember de List-
Box o ComboBox, tambin incluiremos una sobrescritura de la funcin ToString, adems de
un constructor personalizado que facilita la inicializacin de los miembros. Agregue el cdigo
siguiente al cuerpo de la clase.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap08, Elemento 1.

Public TextoElemento As String


Public DatosElemento As Integer

Public Sub New(ByVal desplegarTexto As String, _


idElemento As Integer)
' ----- Inicializar el registro.
TextoElemento = desplegarTexto
DatosElemento = idElemento
End Sub

Public Overrides Function ToString() As String


' ----- Desplegar el texto de elemento basico.
Return TextoElemento
End Function

Public Overrides Function Equals(ByVal obj As Object) _


As Boolean

246 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 246 17/2/10 15:24:22


' ----- Permitir busquedas de IndexOf(
) y Contains(
) para DatosElemento.
If (TypeOf obj Is Integer) Then
Return CBool(CInt(obj) = DatosElemento)
Else
Return MyBase.Equals(obj)
End If
End Function

Ms adelante, cuando sea hora de poblar un ListBox, podemos usar este objeto para agregar el
despliegue y los valores de identificacin.
ListBox1.Items.Add(New DatosListaElementos("Texto del elemento", 25))

La sobrescritura del mtodo Equals nos permite buscar rpidamente elementos ya agregados
a un control ListBox (o similar) usando caractersticas ya incluidas en el control. La colec-
cin Items del control ListBox incluye un mtodo IndexOf que devuelve la posicin de un
elemento coincidente. Por lo general, este mtodo slo coincidir con el propio objeto; si lo
pasa a una instancia de DatosListaElementos, informar si ese elemento ya se encuentra
en el ListBox. El cdigo actualizado de Equals tambin devolver True si pasamos un valor
Integer que coincide con un miembro de DatosListaElementos.DatosElemento para
un elemento que ya se encuentra en la lista.
Dim posicionElemento As Integer = UnListBox.Items.IndexOf(5)

Edicin de tablas de cdigo


De regreso al captulo 4, cuando creamos la base de datos para el Proyecto Biblioteca, varias de
las tablas se crearon para llenar listas simples de ComboBox en la aplicacin. Todas estas tablas
empiezan con el prefijo Codigo y contienen registros que en raras ocasiones, si acaso, cambian
en el tiempo de vida de la aplicacin. Una de estas tablas es CodigoCopiaStatus, que identifica
la condicin general actual de un elemento en las colecciones de biblioteca.

Archivo Tipo Descripcin


ID Long - Auto Clave principal; asignado automticamente. Obligatorio.
NombreCompleto Text(50) Nombre de esta entrada de estatus. Obligatorio.

Como todas estas tablas tienen bsicamente el mismo formato (un campo ID, y uno o ms cam-
pos de contenido), debe ser posible disear una plantilla genrica para usarla en edicin de estas
tablas. Un formulario de base (clase) proporcionar las caractersticas de edicin bsicas, que
habrn de desarrollarse por completo mediante versiones derivadas del formulario de base.
Para el proyecto, agregaremos dos formulario, uno de resumen (que despliega una lista de
todos los cdigos definidos actualmente) y uno de detalle (que permite la edicin de un solo
cdigo nuevo o existente). Para simplificar las cosas an ms, incluiremos slo la funcionalidad
ms bsica de administracin de registros en el formulario de resumen, la mayor parte del cdigo
necesario para editar, desplegar y eliminar cdigos aparecer en los formularios de detalle.

Proyecto | 247

08_PATRICK-CHAPTER_08.indd 247 17/2/10 15:24:22


El formulario de detalle genrico
Agregue un nuevo formulario al proyecto (Proyecto Agregar Windows Form), llamndolo
FormularioCodigoBase.vb. Modifique las siguientes propiedades, como se indica:

Propiedad Valor
(Nombre) FormularioCodigoBase
ControlBox False
FormBorderStyle FixedDialog
ShowInTaskbar False
Size 406, 173
StartPosition CenterScreen
Text Formulario de cdigo

Ahora acceda al cdigo fuente de esta clase (Ver Cdigo). El cdigo nunca crear instancias
de este formulario genrico de manera directa, de modo que deshabilitaremos toda la creacin
directa de instancias al incluir la palabra clave MustInherit.
Public MustInherit Class FormularioCodigoBase

End Class

Las caractersticas principales del formulario sern la adicin de nuevos registros de cdigo, la
edicin de registros de cdigo existentes y la eliminacin de registros existentes. Agregue tres es-
queletos de funcin que den soporte a estas caractersticas. Podramos hacerlas MustOverride,
pero como ver ms adelante, queremos la opcin de mantener la funcionalidad predeterminada
a partir del formulario de base genrico.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap08, Elemento 2.

Public Overridable Function AgregarRegistro() As Integer


' ----- Preguntar para agregar un nuevo registro.
' Devuelve el ID cuando se agrega, o 1 si se cancela.
Return 1
End Function

Public Overridable Function EliminarRegistro( _


ByVal idRegistro As Integer) As Boolean
' ----- Preguntar al usuario para eliminar un registro.
' Devuelve True al eliminarse.
Return False
End Function

Public Overridable Function EditarRegistro( _


ByVal idRegistro As Integer) As Integer

248 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 248 17/2/10 15:24:23


' ----- Preguntar al usuario para eliminar un registro.
' Devuelve el ID del registro si se guarda, o 1 al cancelar.
Return 1
End Function

El formulario de detalles tomar responsabilidad completa de llenar el control ListBox en el


formulario de resumen con sus elementos. Dos mtodos manejarn esto: uno que agrega todos
los elementos, y uno que actualiza un solo elemento. La clase derivada ser necesaria para pro-
porcionar estas caractersticas.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap08, Elemento 3.

' ----- Llenar un control ListBox con registros existentes.


Public MustOverride Sub RellenarListaConRegistros( _
ByRef listaDestino As ListBox, ByRef coincidenciasExcedidas As Boolean)

' ----- Devolver el nombre formado de un solo registro.


Public MustOverride Function FormarNombreRegistro( _
ByVal idRegistro As Integer) As String

El formulario de detalle tambin debe desplegar los ttulos apropiados y la informacin de uso
del formulario de resumen.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap08, Elemento 4.

' ----- Devolver una descripcion de este editor.


Public MustOverride Function ObtenerDescripcionEditor(
) As String

' ----- Devolver el texto de la barra de titulo de este editor.


Public MustOverride Function ObtenerTituloEditor(
) As String

Aunque la mayor parte de las tablas proporcionar una corta lista de cdigos alfabetizados, algu-
nas incluirn una gran cantidad (posiblemente miles de cdigos). El formulario de resumen dar
soporte a un mtodo de bsqueda, para localizar rpidamente un cdigo existente. Debido a que
slo ciertos formularios derivados usarn esta caracterstica, no incluiremos MustOverride.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap08, Elemento 5.

Public Overridable Sub BuscarRegistro( _


ByRef listaDestino As ListBox, _
ByRef coincidenciasExcedidas As Boolean)
' ----- Preguntar al usuario para buscar un registro.
Return
End Sub

Proyecto | 249

08_PATRICK-CHAPTER_08.indd 249 17/2/10 15:24:23


Por ltimo, el formulario de detalle indicar cules caractersticas disponibles pueden usarse a
partir del formulario de resumen. Este ltimo llamar a cada una de las siguientes funciones, y
luego habilitar o deshabilitar caractersticas, segn sea necesario.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap08, Elemento 6.

Public Overridable Function UsuarioPuedeAgregar(


) As Boolean
' ----- Revisar la seguridad del usuario actual para ver
' si se permite la adicion.
Return False
End Function

Public Overridable Function UsuarioPuedeEditar(


) As Boolean
' ----- Revisar la seguridad del usuario actual para ver
' si se permite la edicion.
Return False
End Function

Public Overridable Function UsuarioPuedeEliminar(


) As Boolean
' ----- Revisar la seguridad del usuario actual para ver
' si se permite la eliminacion.
Return False
End Function

Public Overridable Function UsaBusqueda(


) As Boolean
' ----- ?El editor soporta la busqueda?
Return False
End Function

Esto es todo para el formulario genrico. En pginas posteriores de este libro, crearemos versio-
nes derivadas de cada una de las tablas de cdigo.

El formulario de resumen genrico


El formulario de resumen es un poco ms sencillo, porque es un formulario simple. Cuando se
inicia, usa una instancia de uno de los formularios de detalle para controlar la experiencia pre-
sentada al usuario. Ya he agregado el formulario al proyecto; se llama ListaRegistrosEditados.vb, y
tiene el aspecto mostrado en la figura 8-4.
Un control ListBox llena la mayor parte del formulario, un control que contendr todos los
elementos existentes. Tambin hay botones para agregar, editar, eliminar y buscar elementos en
la lista. Hay una gran cantidad de cdigo para administrar estos elementos; ya lo he escrito en el
fragmento de cdigo.

250 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 250 17/2/10 15:24:23


Figura 8-4. El formulario de resumen genrico.

Vaya a la vista de cdigo fuente del formulario y agregue el fragmento de cdigo justo despus
de la lnea Public Class ListaRegistrosEditados.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap08, Elemento 7.

La primera lnea del cdigo agregado define una instancia privada del formulario de detalle
genrico que acabamos de disear.
Private EditorDetalle As Biblioteca.FormularioCodigoBase

Este campo contiene una instancia de una clase derivada de FormularioCodigoBase. Esa asig-
nacin aparece en el mtodo pblico AdministrarRegistros.
Public Sub AdministrarRegistros(ByRef UsarDetalle _
As Biblioteca.FormularioCodigoBase)
' ----- Configurar el formulario para uso con este conjunto de codigo.
Dim coincidenciasExcedidas As Boolean
EditorDetalle = UsarDetalle

Proyecto | 251

08_PATRICK-CHAPTER_08.indd 251 17/2/10 15:24:23


TituloRegistros.Text = EditorDetalle.ObtenerTituloEditor()
Inforegistros.Text = EditorDetalle.ObtenerDescripcionEditor(
)
Me.Text = EditorDetalle.ObtenerTituloEditor()
AccAgregar.Visible = EditorDetalle.UsuarioPuedeAgregar(
)
AccEditar.Visible = EditorDetalle.UsuarioPuedeEditar(
)
AccEliminar.Visible = EditorDetalle.UsuarioPuedeEliminar()
AccBuscar.Visible = EditorDetalle.UsaBusqueda(
)
EditorDetalle.RellenarListaConRegistros(ListaRegistros, _
coincidenciasExcedidas)
ActualizarCuentaElementos(coincidenciasExcedidas)
Me.ShowDialog()
End Sub

El cdigo que llama a AdministrarRegistros se pasa en una instancia del formulario, uno de
los formularios derivados de FormularioCodigoBase. Una vez asignado al campo interno Edi-
torDetalle, el cdigo usa las caractersticas pblicas de esa instancia para configurar los elemen-
tos del despliegue en el formulario de resumen. Por ejemplo, la funcin UsuarioPuedeAgregar
del formulario de detalle, que contiene un valor de devolucin Boolean, establece la propiedad
Visible del botn AccAgregar. La llamada al mtodo RellenarListaConRegistros puebla
el control ListBox de resumen con cualquier valor de cdigo existente. Despus de algunos ajus-
tes de despliegue, el mtodo Me.ShowDialog despliega el resumen para el usuario.
Aunque el usuario interacta con los controles en el formulario de resumen, casi todos estos
controles difieren su procesamiento al formulario de detalle, EditorDetalle. Por ejemplo, un
clic en el botn Agregar difiere la mayor parte de la lgica al mtodo AgregarRegistro del
formulario de detalle. El cdigo en el formulario de resumen no hace ms que actualizar sus
propios campos de despliegue.
Private Sub AccAgregar_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles AccAgregar.Click
' ----- Dejar que el usuario agregue un registro.
Dim nuevoID As Integer
Dim nuevaPosicion As Integer
' ----- Preguntar al usuario.
nuevoID = EditorDetalle.AgregarRegistro()
If (nuevoID = -1) Then Return
' ----- Agregar este registro a la lista.
nuevaPosicion = ListaRegistros.Items.Add( _
(New Biblioteca.DatosListaElementos( _
EditorDetalle.FormarNombreRegistro(nuevoID), nuevoID)))
ListaRegistros.SelectedIndex = nuevaPosicion
ActualizarBotones()
ActualizarCuentaElementos(False)
End Sub

Casi todo el resto del cdigo del formulario de resumen es como este (para caractersticas de edi-
cin, eliminacin y bsqueda) o se utiliza para actualizar el despliegue con base en la interaccin
del usuario con el formulario. Asegrese de examinar el cdigo para obtener una buena com-
prensin de la manera en que funciona el cdigo. En captulos posteriores, cuando agreguemos
formularios de detalle reales, veremos este cdigo en accin.

252 | Captulo 8: Clases y herencia

08_PATRICK-CHAPTER_08.indd 252 17/2/10 15:24:23


Captulo 9
Programacin funcional

En este captulo cubriremos dos temas importantes de programacin en Visual Basic: expresiones
lambda y manejo de errores. Ambos son misteriosos, porque uno usa una letra griega en su nombre
y el otro porque podra tambin estar en griego por todas las dificultades que los programadores
tienen con l. Las expresiones lambda en particular se relacionan con el concepto ms amplio de
la programacin funcional, la idea de que toda tarea de computacin puede expresarse como una
funcin y que las funciones pueden pasearse por el cdigo fuente. Visual Basic no es un lenguaje
de programacin verdaderamente funcional, pero la introduccin de las expresiones lambda en
Visual Basic 2008 trae algunas de esas maneras y medios funcionales al lenguaje.

Expresiones lambda
Las expresiones lambda se denominan clculos lambda (o clculos-), un sistema matemtico di-
seado en 1930 por Alonzo Church, ciertamente un nombre familiar entre las guerras. Aunque su
trabajo fue muy terico, llev a caractersticas y estructuras que beneficiaron a la mayor parte de
los lenguajes de programacin de hoy en da. De manera especfica, el clculo lambda proporciona
la racionalizacin de las funciones, argumentos y valores de retorno de Visual Basic sobre las que
ya hemos aprendido. As que, por qu agregar una nueva caracterstica a Visual Basic y llamarla
lambda cuando ya hay cosas lamba en el lenguaje? Estupenda pregunta. No hay respuesta.
Las expresiones lambda le permiten definir un objeto que contiene una funcin completa. Aun-
que esto es algo nuevo en Visual Basic, ha existido una caracterstica en el lenguaje BASIC por
largo tiempo. Encontr un antiguo manual del primer lenguaje de programacin que us,
BASIC PLUS en la computadora de tiempo compartido RSTS/E. Proporcionaba un ejemplo
de la instruccin DEF, que permite definir funciones simples. He aqu algn cdigo de ejem-
plo de ese lenguaje que imprime una lista de los primeros cinco cuadrados:
100 DEF SQR(X)=X*X
110 FOR I=1 TO 5
120 PRINT I, SQR(I)
130 NEXT I
140 END

253

09_PATRICK-CHAPTER_09.indd 253 17/2/10 15:25:08


La definicin de la funcin para SQR() aparece en la lnea 100, regresando el cuadrado de cual-
quier argumento pasado a ella. Se usa en la segunda mitad de la lnea 120, generando la siguiente
salida:
1 1
2 4
3 9
4 16
5 25

Las expresiones lambda en Visual Basic trabajan de manera parecida, dejndole definir una varia-
ble como una funcin simple. He aqu el equivalente de Visual Basic para el cdigo anterior:
Dim cuad As Func(Of Integer, Integer) = _
Function(x As Integer) x * x
For i As Integer = 1 To 5
Console.WriteLnea("{0}{1}{2}", i, vbTab, cuad(i))
Next i

La expresin lambda real est en la segunda lnea:


Function(x As Integer) x * x

Las expresiones lambda empiezan con la palabra clave Function, seguida por una lista de argu-
mentos pasados entre parntesis. Despus de eso viene la definicin de la propia funcin, una
expresin que usa los argumentos pasados para generar algn resultado final. En este caso, el
resultado es el valor de x multiplicado por s mismo.
Algo que no ve en una expresin lambda es la instruccin Return. En cambio, el valor devuelto
parece salir naturalmente de la expresin. Por eso necesita alguna especie de variable que conten-
ga la definicin y devuelva el resultado en una sintaxis parecida a la de la funcin.
Dim cuad As Func(Of Integer, Integer)

Las variables de la expresin lambda se definen usando la palabra clave Func (qu original). La
lista de argumentos de tipo de datos coincide con la lista de argumentos de la expresin lambda,
pero con un tipo de datos adicional lanzado al final que representa el tipo de datos del valor
devuelto. He aqu una expresin lambda que revisa si un argumento Integer es par o no, de-
volviendo un resultado booleano:
Public Sub ProbarNumero()
Dim EsPar As Func(Of Integer, Boolean) = _
Function(x As Integer) (x Mod 2) = 0
MsgBox("El 5 es par? " & EsPar(5))
End Sub

Este cdigo despliega un mensaje que dice, El 5 es par? False. Tras bambalinas, Visual Basic
est generando una funcin real, y vinculndolo a la variable empleando un delegado. (Un dele-
gado, como tal vez lo recuerde, es una manera de identificar un mtodo genricamente a travs
de una variable distintiva.) El siguiente cdigo est a lo largo de las lneas de lo que el compilador
est realmente generando para el ejemplo de cdigo anterior:

254 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 254 17/2/10 15:25:08


Private Function FuncionOculta1( _
ByVal x As Integer) As Boolean
Return (x Mod 2) = 0
End Function

Private Delegate Function DelegadoOculto1( _


ByVal x As Integer) As Boolean

Public Sub ProbarNumero()


Dim EsPar As DelegadoOculto1 = _
AddressOf FuncionOculta1
MsgBox("El 5 es par? " & EsPar(5))
End Sub

En este cdigo, la expresin lambda y la variable relacionada EsPar se han reemplazado con una
verdadera funcin (FuncionOculta1) y un delegado intermedio (DelegadoOculto1). Aunque
las lambdas son nuevas en Visual Basic 2008, este tipo de funcionalidad equivalente ha estado
disponible desde la primera versin de Visual Basic para .NET. Las expresiones lambda propor-
cionan una sintaxis ms simple cuando la funcin con referencia a delegados slo est regresando
un resultado de una expresin.
Las expresiones lambda se agregaron a Visual Basic 2008, sobre todo, para dar soporte a la nueva
funcionalidad LINQ (consulte el captulo 17). Son especialmente tiles cuando necesita pro-
porcionar una expresin como una regla de procesamiento para algn otro cdigo, sobre todo
cdigo escrito por un tercero. Y en sus propias aplicaciones, Microsoft es un tercero. Coinci-
dencia? No lo creo!

Inclusiones de lambdas
Las expresiones lambda son buenas y todo, pero resulta evidente que la funcionalidad equiva-
lente ya estaba disponible en el lenguaje. Y por s mismas, las expresiones lambda son slo una
simplificacin de alguna compleja sintaxis de funcin-delegado. Pero cuando combina expresio-
nes lambda con el tipo de caractersticas de inferencia de tipo analizadas en el captulo 6, tiene
algo an mejor: pizza!
Tal vez deba escribir este captulo despus del almuerzo. Lo que obtiene son expresiones lambda
con tipos inferidos. No es un nombre muy romntico, pero es una estupenda herramienta nueva.
Digamos que quera escribir una expresin lambda que multiplica dos nmeros.
Dim mult As Func(Of Integer, Integer, Integer) = _
Function(x As Integer, y As Integer) x * y

MsgBox(mult(5, 6)) ' Despliega 30

sta es la versin con extra queso del cdigo: le digo todo a Visual Basic, y me obedece sin aspa-
vientos. Pero hay una versin menos estricta del cdigo que trae al juego a la inferencia de tipos.
Dim mult = Function(x As Integer, y As Integer) x * y

Expresiones lambda | 255

09_PATRICK-CHAPTER_09.indd 255 17/2/10 15:25:08


Hey, eso es mucho menos cdigo. Ya me estaba cansando de escribir Integer una y otra vez. El
cdigo funciona porque Visual Basic revis lo asignado a mult e identific de manera correcta
su tipo de datos fuerte. En este caso, mult es de tipo Function(Integer, Integer) As In-
teger (vase la figura 9-1). Incluso adivin correctamente el tipo devuelto.

Figura 9-1. Visual Basic tambin es bueno para jugar a las 20 preguntas.

En este cdigo se supone que tiene Option Infer en On en su cdigo fuente, o que la ha habi-
litado mediante las propiedades del proyecto (es la opcin predeterminada). En el captulo 6 se
analiza esta opcin.
Podramos acortar an ms la definicin mult.
Dim mult = Function(x, y) x * y

En esta lnea, Visual Basic inferira la misma funcin, pero usara el tipo de datos Object en
todo, en lugar de Integer. Adems, si ha establecido Option Strict en On (lo que debera
hacerlo), esta lnea no se compilar hasta que agregue las clusulas As apropiadas.

rboles de expresiones
Internamente, el compilador de Visual Basic cambia una expresin lambda en un rbol de
expresiones, una estructura jerrquica que asocia operandos con sus operadores. Considere esta
expresin lambda semicompleja que eleva una expresin multiplicada a una potencia:
Dim calcularlo = Function(x, y, z) (x * y) ^ z

Visual Basic genera un rbol de expresiones para calcularlo que tiene el aspecto de la figura 9-2.

* z

x y

Figura 9-2. Los rboles de expresiones agrupan operandos por operador.

Cuando llega el momento de usar una expresin lambda, Visual Basic recorre el rbol, calculan-
do valores desde los niveles inferiores a los superiores. Estos rboles de expresiones estn alma-
cenados como objetos basados en clases del espacio de nombres System.Linq.Expressions.
Si no le gusta escribir expresiones lambda puede construir sus propios rboles de expresiones

256 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 256 17/2/10 15:25:09


empleando estos objetos. Sin embargo, mi estmago me grue an ms, de modo que voy a
dejar eso fuera del libro.

Lambdas complejos
Aunque las expresiones lambda no pueden contener instrucciones de Visual Basic, como bucles
For...Next, an puede integrar algunos clculos muy complejos empleando operadores estn-
dar. Las llamadas a otras funciones tambin pueden aparecer en lambdas. En este ejemplo de
cdigo, mult difiere su trabajo a la funcin Multiplicarlo:
Private Sub MultiplicarAlgo()
Dim mult = Function(x As Integer, y As Integer) _
Multiplicarlo(x, y) + 10

MsgBox(mult(5, 6)) ' Displays 40


End Sub

Public Function Multiplicarlo(ByVal x As Integer, _


ByVal y As Integer) As Integer
Return x * y
End Function

Eso es muy sencillo. Pero las cosas se ponen ms interesentes cuando tiene expresiones lambda
que devuelven otras expresiones lambda. El clculo lambda fue inventado parcialmente para
ver cmo podra dividirse cualquier funcin compleja en las funciones ms bsicas. Aunque
los valores literales pueden definirse como lambdas. He aqu la expresin lambda que siempre
devuelve el valor 3:
Dim tres = Function() 3

Ya ha visto expresiones lambda que aceptan ms de un argumento:


Dim mult1 = Function(x As Integer, y As Integer) x * y

En el clculo lambda, esto puede dividirse en funciones ms pequeas, donde cada una incluye
slo un argumento:
Dim mult2 = Function(x As Integer) Function(y As Integer) x * y

El tipo de datos de mult2 no es exactamente el de mult1, pero generan la misma respuesta a


partir de los mismos valores de x y y. Cuando usa mult1, calcula el producto de x y y; luego lo
devuelve. Cuando usa mult2, primero ejecuta la parte Function(x As Integer), que devuel-
ve otra lambda calculada al pasar el valor de x en su definicin. Si pasa 5 como valor de x, el
lambda devuelto es:
Function(y As Integer) 5 * y

Luego se calcula esta lambda, y se devuelve el producto de 5 y y. La llamada a mult2 en code


tambin es ligeramente diferente. No pasa ambos argumentos a la vez. En cambio, pasa el argu-
mento para x, y luego pasa y a la lambda inicial devuelta.
MsgBox(mult2(5)(6))

Expresiones lambda | 257

09_PATRICK-CHAPTER_09.indd 257 17/2/10 15:25:09


Cuando se ejecuta, la parte mult2(5) se reemplaza con la primera lambda devuelta. Luego esa
primera lambda se procesa usando (6) como argumento y. Es as de simple? Bueno, no, no lo
es. Y es correcto, porque el mult1 de dos argumentos funciona bien. La parte importante que
hay que recordar es que resulta posible construir expresiones lambda complejas a partir de ex-
presiones lambda ms bsicas. Visual Basic usar este hecho cuando genere el cdigo para sus
expresiones relacionadas con LINQ. Hablaremos ms acerca de ello en el captulo 17, pero an
entonces Visual Basic administrar una gran parte de las expresiones concentradas en LINQ
para usted tras bambalinas.

Levantamiento de variables
Aunque puede pasar argumentos en una expresin lambda, tambin puede usar otras variables
que estn dentro del alcance de la expresin.
Private Sub NombrarMiHijo()
Dim logicaNombre = ObtenerLogicaNomenclaturaHijos(
)
MsgBox(logicaNombre("John")) Despliega: Johnson
End Sub

Private Function ObtenerLogicaNomenclaturaHijos(


) As _
Func(Of String, String)
Dim sufijoNombre As String = "son"
Dim nuevaLogica = Function(nombreBase As String) _
nombreBase & sufijoNombre
Return nuevaLogica
End Function

La funcin ObtenerLogicaNomenclaturaHijos devuelve una expresin lambda. Esa expresin


se usa en el mtodo NombrarMiHijo, pasando John como argumento a la lambda. Y funciona.
La pregunta es cmo. El problema es que sufijoNombre, usado en la lgica de la expresin
lambda, es una variable local dentro del mtodo ObtenerLogicaNomenclaturaHijos. Todas
las variables locales se destruyen cada vez que existe un mtodo. Para el momento en que se llama
a la funcin MsgBox, sufijoNombre se habr ido. Pero el cdigo funciona como si sufijoNom-
bre siguiera vivo.
Para que este cdigo funcione, Visual Basic usa una nueva caracterstica llamada levantamiento
de variables. Al ver que se acceder a sufijoNombre desde fuera del mbito ObtenerLogi-
caNomenclaturaHijos, Visual Basic reescribe su cdigo fuente, cambiando la variable local
sufijoNombre por una que tiene un mbito ms amplio.
En la nueva versin del cdigo fuente, Visual Basic agrega una clase de cierre, una clase generada
dinmicamente que contiene la expresin lambda y las variables locales usadas por la expresin.
Cuando combina esto, cualquier cdigo que tiene acceso a la expresin lambda tambin tendr
acceso a la variable local.
Private Sub NombrarMiHijo()
Dim logicaNombre = ObtenerLogicaNomenclaturaHijos(
)

258 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 258 17/2/10 15:25:09


MsgBox(logicaNombre("John")) ' Displays: Johnson
End Sub
Public Class ClaseCierreGenerada
Public sufijoNombre As String = "son"
Public nuevaLogica As Func(Of String, String) = _
Function(nombreBase As String) nombreBase & Me.sufijoNombre
End Class

Private Function ObtenerLogicaNomenclaturaHijos(


) As _
Func(Of String, String)
Dim cierreLocal As New ClaseCierreGenerada
cierreLocal.sufijoNombre = "son"
Return cierreLocal.nuevaLogica
End Function

El cdigo real generado por Visual Basic es ms complejo que esto, e incluira todo el cdigo
convertido de delegado de funcin sobre el que se escribi antes. Pero sta es la idea bsica. Las
clases de cierre y el levantamiento de variables son caractersticas esenciales para expresiones
lambda, porque nunca sabe realmente donde estn sus expresiones lambda a todas horas de la
noche.

Inicializadores de objetos
Para inicializar propiedades de objetos no administradas por constructores, necesita asignar estas
propiedades por separado justo despus de que crea la instancia de clase.
Dim nuevaContratacion As New Empleado
nuevaContratacion.Nombre = "Fulano De Tal"
nuevaContratacion.FechaContratado = #2/27/2008#
nuevaContratacion.Sueldo = 50000@

La instruccin With...End With proporciona un poco ms de estructura.


Dim nuevaContratacion As New Empleado
With nuevaContratacion
.Nombre = Fulano De Tal
.FechaContratado = #2/27/2008#
.Sueldo = 50000@
End With

Una nueva sintaxis incluida en Visual Basic 2008 permite combinar la declaracin (con la pa-
labra clave New) y la asignacin de miembro. La sintaxis incluye una nueva variacin de la ins-
truccin With.
Dim nuevaContratacion As New Empleado With { _
.Nombre = "Fulano De Tal", _
.FechaContratado = #2/27/2008#, _
.Sueldo = 50000@}

Bueno, en cuanto a nuevas caractersticas, no es tan brillante como las expresiones lambda o el
levantamiento de variables. Pero hace el trabajo.

Inicializadores de objetos | 259

09_PATRICK-CHAPTER_09.indd 259 17/2/10 15:25:09


Manejo de errores en Visual Basic
La depuracin y el procesamiento de errores son dos de las actividades de programacin ms
esenciales que alguna vez desarrollar. Hay tres absolutos en la vida: la muerte, los impuestos y
los errores de software. Aun en una aplicacin relativamente libre de errores, hay muchas razo-
nes para creer que un usuario simplemente lo revolver todo. Como programador, su trabajo
consiste en ser el guardin de los datos del usuario, tal como los administra la aplicacin, y en
mantenerlos seguros, aun a costa de la propia negligencia (o mala conducta) del usuario, y tam-
bin de su propio cdigo fuente.
Recientemente habl con un desarrollador de una compaa de software grande con oficinas
centrales en Redmond, Washington; tal vez conozca a la compaa. Este desarrollador me dijo
que en cualquier aplicacin determinada desarrollada por esta empresa, ms del 50% del cdigo
est dedicado a tratar con los errores, datos malos, excepciones del sistema y fallas. Por cierto,
todo este cdigo adicional hace ms lenta cada aplicacin y agrega una gran carga de lo que se
llama bloatware. Pero en una era de hackers y errores en la introduccin de datos, esa admi-
nistracin de errores es obligatoria.
La prueba (aunque no sea un tema cubierto en este libro), va de la mano con el manejo de erro-
res. A menudo, el informe de un error llevar a un brote de pruebas, pero en realidad debera de
ser al revs: la prueba tendra que llevar al descubrimiento de errores. Hace unos aos, el Mars
Global Surveyor de la NASA, en rbita alrededor del planeta rojo, captur imgenes del Beagle
2, una nave de investigacin que se estrell en la superficie del planeta marciano en 2003. Una
evaluacin de las fallas del Beagle 2 detect muchas reas de preocupacin, y un problema im-
portante fue la prueba inadecuada:
Esto llev a un programa de pruebas atenuado para cumplir con las restricciones de costos
y calendario, con lo que inevitablemente aument el riesgo tcnico. (Del Beagle 2 ESA/UK
Commission of Inquiry Report, 5 de abril de 2004, pgina 4.)
Revise todas estas grandes palabras. Hombre, de seguro los europeos tienen algn problema con
el idioma. Tal vez una traduccin directa palabra por palabra a un idioma llano dejar en claro
que la comisin est tratando de comunicar:
No probaron lo suficiente, y tal vez arruinaron todo.

La naturaleza de los errores en Visual Basic


Tratar con tres categoras principales de errores en sus aplicaciones de Visual Basic:
Errores en tiempo de compilacin
Algunos errores son tan groseros que Visual Basic se negar a compilar su aplicacin. Por
lo general, esos errores se deben a simples problemas de sintaxis que pueden corregirse con
unos cuantos teclazos. Pero tambin puede habilitar en su programa caractersticas que
aumentarn el nmero de errores reconocido por el compilador. Por ejemplo, si establece
Option Strict en On en los archivos de su aplicacin o de cdigo fuente, las conversiones
implcitas de estrechamiento generarn errores en tiempo de compilacin.

260 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 260 17/2/10 15:25:09


' ----- Suponer: Option Strict On
Dim datosGrandes As Long = 5&
Dim datosPequenos As Integer
' ----- La siguiente linea no se compila.
datosPequenos = datosGrandes

Visual Studio 2008 incluye caractersticas que le ayudan a localizar y resolver errores en
tiempo de compilacin. Estos errores estn marcados con una lnea de subrayado azul de-
bajo de la sintaxis ofensora. Algunos errores tambin piden que Visual Studio despliegue
opciones mediante ventanas emergentes, como se muestra en la figura 9-3.

Figura 9-3. Opciones de correccin de error para una conversin de estrechamiento.

Errores en tiempo de ejecucin


Los errores en tiempo de ejecucin se presentan cuando una combinacin de datos y cdigo
causa una condicin no vlida en lo que, de otra manera, parecera cdigo vlido. Con fre-
cuencia, estos errores ocurren cuando un usuario ingresa datos incorrectos en la aplicacin,
pero su propio cdigo tambin puede generar errores en tiempo de ejecucin. La adecuada
verificacin de todos los datos entrantes reducir en gran medida esta clase de errores. Con-
sidere el siguiente bloque de cdigo:
Public Function ObtenerNumero() As Integer
' ----- Pedir al usuario un numero.
' Devolver cero si el usuario hace clic en Cancelar.
Dim usarCantidad As String

' ----- InputBox devuelve una String con


' cualquier cosa que escriba el usuario.
usarCantidad = InputBox("Ingrese una cantidad.")
If (EsNumerico(usarCantidad) = True) Then
' ----- Convertir en entero y regresarlo.
Return CInt(usarCantidad)
Else

La naturaleza de los errores en Visual Basic | 261

09_PATRICK-CHAPTER_09.indd 261 17/2/10 15:25:10


' ----- Datos no validos. Devolver cero.
Return 0
End If
End Function

Este cdigo se ve muy razonable, y en casi todos los casos, lo es. Le pide al usuario un n-
mero, convierte nmeros vlidos a formato de enteros y devuelve el resultado. La funcin
EsNumerico eliminar cualquier entrada no numrica que no sea vlida. Al llamar a esta
funcin se devolver cualquier entero vlido entre los valores numricos ingresados, y 0 para
entradas no vlidas.
Pero qu pasa cuando un dictador fascista trata de usar este cdigo? Como lo muestra la
historia, un dictador fascista ingresar un valor como 342304923940234. Debido a que
es un nmero vlido, pasara la pruba EsNumerico con colores vivos, pero como excede el
tamao del tipo de datos Integer, generar el error en tiempo de ejecucin atemorizante
que se muestra en la figura 9-4.

Figura 9-4. Un mensaje de error que slo un dictador fascista puede adorar.

Sin cdigo adicional de manejo de errores o revisiones de lmites vlidos, la rutina Obte-
nerNumero genera este error en tiempo de ejecucin, y luego causa que todo el programa
aborte. Entre cometer crmenes de guerra e ingresar valores numricos no vlidos, parece no
haber fin para el mal que los dictadores fascistas harn.
Errores de lgica
Los errores de lgica son el tercero y ms insidioso tipo de error. Son causados por usted, el
programador; no puede culpar al usuario de esto. Desde los problemas de flujo de procesos
hasta los clculos incorrectos, los errores de lgica son la maldicin del desarrollo de soft-
ware, y llevan a la necesidad de ms tiempo de depuracin que los otros dos tipos de errores
combinados.
Los errores de lgica son demasiado personales y variados para atenderse directamente en
este libro. Puede forzar muchos errores de lgica de su cdigo al agregar revisiones suficien-
tes en busca de datos no vlidos, y al probar adecuadamente su aplicacin bajo diferentes
condiciones y circunstancias.
No tendr muchas dificultades al tratar con errores en tiempo de compilacin. Una com-
prensin general de los conceptos de programacin de Visual Basic y .NET, y el uso regular
de las herramientas incluidas con Visual Studio 2008, ayudar rpidamente a localizarlas y
eliminarlas.

262 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 262 17/2/10 15:25:10


El problema ms grande es: qu hacer con los errores en tiempo de ejecucin? Aunque revise
todos los datos y las condiciones de recursos externos posibles, es imposible prevenir todos los
errores en tiempo de ejecucin. Nunca sabr cundo se caer de pronto una conexin de red, o el
usuario se tropezar con el cable de la impresora, o los rayones en un DVD generarn corrupcin
de los datos. Cada vez que trate con recursos que existen fuera de su cdigo fuente, est ante una
oportunidad de que ocurran errores en tiempo de ejecucin.
En la figura 9-4 se mostr lo que hace Visual Basic cuando encuentra un error en tiempo de
ejecucin: despliega al usuario un cuadro de dilogo de error genrico; y ofrece una oportunidad
de ignorar el error (posible corrupcin de datos no guardados) o salir del programa de inmediato
(prdida completa de cualquier dato que no se haya guardado).
Aunque estas dos acciones de usuario dejan mucho a la imaginacin, no contribuyen a que el
consumidor tenga confianza en sus habilidades de codificacin. Confe en esto: el usuario le cul-
par de cualquier error generado por su aplicacin, aunque el problema real se haya eliminado
de su cdigo.
Por fortuna, Visual Basic incluye tres herramientas que le ayudarn a tratar por completo con los
errores en tiempo de ejecucin, en caso de que se presenten. Estas tres caractersticas de Visual
Basic (manejo de errores no estructurado, manejo de errores estructurado y manejo de errores
no manejado) pueden usarse en cualquier aplicacin de Visual Basic para proteger los datos del
usuario (y al usuario) de los errores no deseados.

Manejo de errores no estructurado


El manejo de errores no estructurado ha sido parte de Visual Basic desde su debut a principios de
la dcada de 1990. Es simple de usar, captura todos los errores posibles en un bloque de cdi-
go, y puede habilitarse o deshabilitarse segn sea necesario. Como opcin predeterminada, los
mtodos y procedimientos de propiedades no incluyen manejo de errores, de modo que debe
agregar cdigo de manejo de errores (estructurado o no estructurado) para cada rutina donde
sienta que es necesario.
La idea tras el manejo de errores no estructurado es muy bsica. Simplemente se agrega una lnea
en su cdigo que dice: Si ocurre cualquier error, saltar temporalmente a esta otra seccin de mi
procedimiento donde tengo cdigo especial para tratar con l. A esta otra seccin se le llama
manejador de errores.
Public Sub RutinaPropensaAErrores()
' ----- Cualquier codigo incluido aqui antes de habilitar
' el manejador de errores debe ser muy resistente
' a errores en tiempo de ejecucin.

' ----- Habilitar el manejador de errores.


On Error GoTo ManejadorDeErrores

' ----- Codigo adicional aqui con el riesgo de errores en


' tiempo de ejecucion.
' Cuando toda la logica este completa, salir de la rutina.
Return

Manejo de errores no estructurado | 263

09_PATRICK-CHAPTER_09.indd 263 17/2/10 15:25:10


ManejadorDeErrores:
' ----- Cuando ocurra un error, el codigo salta temporalmente
' aqui, donde puede tratar con el. Cuando haya
' terminado, llamar a esta instruccion:
Resume
' ----- que regresara al codigo que causo el error.
' La instruccion "Resume" tiene unas cuantas
' variaciones disponibles. Si no quiere regresar al
' codigo principal, sino que solo quiere salir de esta
' rutina lo antes posible, llamar a:
Return
End Sub

La instruccin On Error habilita o deshabilita el manejo de errores en la rutina. Cuando ocurre


un error, Visual Basic coloca los detalles de ese error en un objeto Err global. Este objeto alma-
cena una descripcin de texto del error, el cdigo de error numrico de ste (si est disponible),
los detalles de ayuda en lnea relacionados y otros valores especficos de error. Presentar ms
adelante los detalles.
Puede incluir todas las instrucciones On Error que desee en su cdigo, y cada una puede dirigir
el cdigo errante a un nivel diferente. Puede tener un manejador para errores de red, uno para
errores de archivo, uno para errores de clculo, etc. O podra tener un manejador de errores
grande que use instrucciones If...Then...Else para examinar la condicin de error alma-
cenado en el objeto Err global.
ManejadorDeErrores:
If (Err.Number = 5) Then
' ----- Manejar problemas de cdigo de error 5 aqui.

Puede encontrar nmeros de error especficos para errores comunes en la documentacin en


lnea de Visual Studio, pero es esta dependencia de los nmeros codificados la que hace que el
manejo de errores no estructurado sea menos popular de lo que era antes de .NET. An ms, no
tiene obligacin de tratar de manera diferente los errores con base en el tipo de error. Siempre y
cuando pueda recuperarse de manera confiable de las condiciones de error, no siempre importa
cul fue la causa del error. Muchas veces, si he habilitado el manejo de errores donde no veremos
el final del mundo si el procedimiento llega al final en un asunto libre de errores, simplemente
reporto los detalles del error al usuario y omito la lnea errante.
Public Sub HacerAlgo()
On Error GoTo ManejadorDeErrores
' ----- Aqui va el codigo de logica.
Return

ManejadorDeErrores:
MsgBox("Ha ocurrido un error en 'HacerAlgo':" & _
Err.Description)
Resume Next
End Sub

264 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 264 17/2/10 15:25:10


Este bloque de cdigo informa el error, y luego usa la instruccin Resume Next (una variacin
de la instruccin Resume estndar) para regresar a la lnea de cdigo que sigue inmediatamente
a la que caus el error. Otra opcin usa Resume alguna_otra_etiqueta, que devuelve el
control a algn rea del cdigo con nombre especfico.

Deshabilitacin del manejo de errores


On Error GoTo habilita un manejador de errores especfico. Aunque puede usar una segunda
instruccin On Error GoTo para redirigir los errores a otro manejador de errores en su procedi-
miento, un solo manejador de error puede estar activo en cualquier momento. Una vez que haya
habilitado un manejador de errores, se mantiene activo hasta que termina el procedimiento,
redirige los errores a otro manejador o puede deshabilitar especficamente el manejo de errores
en la rutina. Para tomar esta ltima ruta use la siguiente instruccin:
On Error GoTo 0

Cmo ignorar errores


Su manejador de errores no tiene que hacer nada especial. Considere este bloque de manejo de
errores:
ManejadorDeErrores:
Resume Next

Cuando ocurre un error, este manejador devuelve de inmediato el control a la lnea que sigue a
la que gener el error. Visual Basic incluye a mtodo abreviado para esta accin.
On Error Resume Next

Al usar la instruccin On Error Resume Next, todos los errores poblarn el objeto Err (al igual
que con todos los errores, no importa cmo se manejen), y luego se omitir la lnea que gener
el error. El usuario no ser informado del error, y continuar usando la aplicacin en un estupor
que indica que la ignorancia es la dicha.

Manejo de errores estructurado


El manejo de errores no estructurado fue el nico mtodo de manejo de errores disponible en
Visual Basic antes de .NET. Aunque su uso era simple, no satisfaca la sensacin que rode al
anuncio de que la versin de 2002 de Visual Basic .NET sera un sistema de programacin
orientada a objetos. Por tanto, Microsoft tambin agreg manejo de errores estructurado al lengua-
je, un mtodo que usa objetos estndares para comunicar errores, y cdigo de manejo de errores
que est integrado ms firmemente con el cdigo que monitorea.

Manejo de errores estructurado | 265

09_PATRICK-CHAPTER_09.indd 265 17/2/10 15:25:10


Esta forma de procesar errores usa una instruccin de varias lneas Try...Catch...Finally
para capturar y manejar errores.
Try
' ----- Agregar aqui codigo propenso a errores.
Catch ex As Exception
' ----- Codigo de manejo de errores aqui.
Finally
' ----- Aqui va el codigo de limpieza.
End Try

La clusula Try
Las instrucciones Try estn diseadas para monitorear fragmentos de cdigo ms pequeos. Aun-
que podra poner todo el cdigo fuente para su procedimiento dentro del bloque Try, es ms
comn poner dentro de esa seccin slo las instrucciones que es probable que generen errores.
Try
My.Computer.FileSystem.CambiarNombreArchivo(archivoExistente, nuevoNombre)
Catch...

Las instrucciones seguras pueden permanecer fuera de la parte Try de la instruccin Try...
End Try. Se debate mucho sobre lo que constituye exactamente una instruccin de progra-
macin segura, pero dos tipos de instrucciones suelen ser inseguras: 1) las instrucciones que
interactan con sistemas externos, como archivos de disco, recursos de red o hardware, o incluso
bloques de memoria ms grandes, y 2) las instrucciones que pueden causar que una variable o
expresin exceda los lmites diseados para el tipo de datos de esa variable o expresin.

La clusula Catch
La clusula Catch define un manejador de errores. Al igual que con el manejo de errores no
estructurado, puede incluir un manejador de errores global en una instruccin Try, o puede
incluir varios manejadores para diferentes tipos de errores. Cada manejador incluye su propia
palabra clave Catch.
Catch ex As ClaseDeError

El identificador ex proporciona un nombre de variable para el objeto de error activo que puede
usar dentro de la seccin Catch. Puede darle cualquier nombre que desee; y puede variar entre
clusulas Catch, pero no es necesario.
ErrorClass identifica una clase de excepcin, una clase especial diseada especficamente para
proporcionar informacin de error. La clase de excepcin ms genrica es System.Exception;
otra clase de excepcin ms especfica deriva de System.Exception. Como Try...End Try
implementa procesamiento de errores orientado a objetos, todos los errores deben almacenarse
como objetos. .NET Framework incluye muchas clases de excepcin predefinidas ya derivadas
de System.Exception que puede usar en su aplicacin. Por ejemplo, System.DivideByZe-
roException captura cualquier error que surja (obviamente) de dividir un nmero entre cero.

266 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 266 17/2/10 15:25:10


Try
resultado = primerNumero / segundoNumero
Catch ex As System.DivideByZeroException
MsgBox("Error al dividir entre cero.")
Catch ex As System.OverflowException
MsgBox("Al dividir se causa un sobreflujo.")
Catch ex As System.Exception
MsgBox("Ocurrieron algunos otros errores.")
End Try

Cuando ocurre un error, su cdigo prueba la excepcin contra cada clusula Catch hasta que
encuentra una clase coincidente. Las clusulas Catch se examinan de arriba abajo, para ase-
gurarse de que pone al final la ms general; si coloca primero System.Exception, ninguna
otra clusula Catch en ese bloque Try se disparar porque todas las excepciones coinciden con
System.Exception. Depender de usted la cantidad de clusulas Catch que incluya, o cules
expresiones monitorea. Si deja fuera todas las clusulas Catch, actuarn de alguna manera como
una instruccin On Error Resume Next, aunque si ocurre un error, se omitirn todas las ins-
trucciones restantes en el bloque Try. La ejecucin contina en el bloque Finally, y luego en
el cdigo que sigue a toda la instruccin Try.

La clusula Finally
La clusula Finally representa la parte haz esto o muere de su bloque Try. Si ocurre un
error en su instruccin Try, el cdigo de la seccin Finally siempre se procesar despus
de que se completa la clusula Catch relevante. Si no ocurre un error, el bloque Finally
an se procesar antes de dejar la instruccin Try. Si usa una instruccin Return en algn
lugar de su instruccin Try, el bloque Finally an se procesar antes de dejar la rutina.
(Esto se est volviendo montono.) Si usa la instruccin Exit Try para salir del bloque Try
antes, an se ejecutar el bloque Finally. Si, mientras se est procesando su bloque Try, su
jefe anuncia que hay una degustacin de comida gratuita en la gran sala de juntas y todos
son bienvenidos, el cdigo Finally tambin se procesar, pero tal vez no est all para
verlo.
Las clusulas Finally son opcionales, de modo que slo debe incluir una cuando la necesite. La
nica ocasin en que las clusulas Finally son obligatorias es cuando omite todas las clusulas
Catch en una instruccin Try.

Errores no manejados
Le mostr antes en el captulo la manera en que los errores no manejados pueden llevar a corrup-
cin de datos, aplicaciones que dejan de funcionar y gastos del congreso fuera de control y en
espiral. Todos los buenos programadores comprenden lo importante que es el cdigo de manejo
de errores, y hacen el esfuerzo adicional de incluir cdigo de manejo de errores estructurado o
no estructurado.

Errores no manejados | 267

09_PATRICK-CHAPTER_09.indd 267 17/2/10 15:25:11


Pero hay ocasiones en que aun yo, como programador, pienso: Oh, este procedimiento no est
haciendo nada que pudiera generar errores. Slo dejar fuera el cdigo de manejo de errores y
ahorrar algn tiempo de escritura. Y luego llega, aparentemente sin previo aviso: un error no
manejado. Crash! Pum! Otro fragmento de datos de usuarios confinado a la cubeta de bits de
la vida.
Por lo general, todos los errores no manejados suben como la espuma por la pila de llamadas,
buscando un procedimiento que incluya cdigo de manejo de errores. Por ejemplo, piense en
este cdigo:
Private Sub Nivel1()
On Error GoTo ManejadorDeErrores
Nivel2()
Return

ManejadorDeErrores:
MsgBox("Error manejado.")
Resume Next
End Sub

Private Sub Nivel2()


Nivel3()
End Sub

Private Sub Nivel3()


' ----- El mtodo Err.Raise fuerza un
' error de estilo no estructurado.
Err.Raise(1)
End Sub

Cuando ocurre el error en Nivel3, la aplicacin busca un manejador de errores activo en ese
procedimiento, pero no encuentra nada. De inmediato sale de Nivel3 y regresa a Nivel2,
donde busca de nuevo un manejador de errores activo. Ese tipo de bsqueda ser, por tristeza,
infructfera. Con el corazn roto, el cdigo deja Nivel2 y regresa a Nivel1, continuando su
bsqueda de un manejador de errores razonable. Esta vez encuentra uno. El procesamiento salta
de inmediato al bloque ManejadorDeErrores y ejecuta el cdigo de esa seccin.
Si Nivel1 no tuviera un manejador de errores, y ningn cdigo fuera de la pila incluyera uno,
el usuario vera la Ventana de Manejo de Errores de la Miseria (revise la figura 9-4), seguido
por el Programa Muerto de la Desilusin.
Por fortuna, Visual Basic da soporte a un manejador de errores atrapa todo que captura esas
excepciones no manejadas y le permite hacer algo con ellas. Esta caracterstica slo funciona si
tiene el campo Habilitar marco de trabajo de la aplicacin seleccionado en la ficha Aplicacin,
de las propiedades del proyecto. Para acceder a la plantilla de cdigo del manejador de errores
global, haga clic en el botn Ver eventos de aplicacin, en la ficha de propiedades del mismo
proyecto. Seleccione (MiAplicacin eventos) de la lista desplegable Nombre de clase, arriba
de la ventana del cdigo fuente, y luego seleccione UnhandledException de la lista Nombre del
mtodo. El siguiente procedimiento aparece en la ventana de cdigo:

268 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 268 17/2/10 15:25:11


Private Sub MyAplicacin_UnhandledException( _
ByVal sender As Object, _
ByVal e As Microsoft.VisualBasic. _
ApplicationServices.UnhandledExceptionEventArgs) _
Handles Me.UnhandledException

End Sub

Agregue su cdigo de manejo de errores global a esta rutina. El argumento de evento e incluye
un miembro Exception que proporciona acceso a los detalles del error mediante un objeto
System.Exception. El miembro e.ExitApplication es una propiedad Boolean que puede
modificar para continuar o salir de la aplicacin. Como opcin predeterminada se establece en
True, de modo que puede modificarlo si quiere mantener el programa en ejecucin.
Aunque el programa siga ejecutndose, perder la ruta del evento activo que dispar el error. Si ste
surge de un clic en algn botn por parte del usuario, todo el evento Click, y todos sus mtodos
llamados, se abandonarn de inmediato, y el programa esperar una nueva entrada del usuario.

Administracin de errores
Adems de simplemente mirarlos y gritar Error! debe saber algunas otras cosas relacionadas
con la administracin de errores en programas de Visual Basic.

Generacin de errores
Aunque usted no lo crea, habr ocasiones en que tal vez quiera generar errores en tiempo de ejecu-
cin en su cdigo. En realidad, muchos de los errores en tiempo de ejecucin que encontrar en su
cdigo ocurrirn porque Microsoft escribi cdigo en las bibliotecas de clase del marco conceptual
(FCL, Framework Class Libraries) que genera errores de manera especfica. Esto es por diseo.
Digamos que tena una propiedad de clase que era para aceptar slo valores de porcentaje de 0 a
100, pero como tipo de datos Integer.
Private PorcentajeAlmacenado As Integer
Public Property PorcentajeAplicado() As Integer
Get
Return PorcentajeAlmacenado
End Get
Set(ByVal valor As Integer)
PorcentajeAlmacenado = valor
End Set
End Property

Nada es gramaticalmente incorrecto en este cdigo, pero no impedir que alguien establezca el
valor de porcentaje almacenado en 847 o 847, ambos fuera del rango deseado. Puede agregar
una instruccin If al accessor Set para rechazar datos no vlidos, pero las propiedades no pro-
porcionan una manera de regresar un cdigo de estado fallido. La nica manera de informar al
cdigo que llama de un problema consiste en generar una excepcin.

Administracin de errores | 269

09_PATRICK-CHAPTER_09.indd 269 17/2/10 15:25:11


Set(ByVal valor As Integer)
If (valor < 0) O (valor > 100) Then
Throw New ArgumentOutOfRangeException("valor", _
valor, "El rango permitido es de 0 a 100.")
Else
PorcentajeAlmacenado = valor
End If
End Set

Ahora, si trata de asignar a la propiedad PorcentajeAplicado un valor fuera del rango de 0


a 100 generar un error, que puede ser capturado por los manejadores de errores On Error o
Try...Catch. La instruccin Throw acepta un objeto System.Exception (o derivado) como
su argumento, y enva ese objeto de excepcin a la parte superior de la pila de llamadas en busca
de un manejador de errores.
El mtodo Err.Raise es similar a la instruccin Throw. Le permite generar errores usando un
sistema de errores numrico ms familiar para entornos de Visual Basic 6.0 y anteriores. Re-
comiendo que use la instruccin Throw, aunque emplee manejo de errores no estructurado en
cualquier lugar de su cdigo.

Mezcla de mtodos de manejo de errores


Tiene la libertad de mezclar mtodos de manejo de errores estructurados y no estructurados
en su aplicacin, pero un solo procedimiento o mtodo puede usar slo uno de estos mtodos.
Es decir, tal vez pueda usar On Error y Try...Catch...Finally en la misma rutina. Una
rutina que usa On Error puede llamar a otra rutina que usa Try...Catch...Finally sin
problemas.
Ahora tal vez est pensando: Hey, puedo ver ocasiones en que querra usar manejo de errores
no estructurado, y otras en que optara por el mtodo ms estructurado. Todo suena muy ra-
zonable, pero permtame prevenirle de que hay fanticos del manejo de errores que lo pondrn
en ridculo durante dcadas si se atreve siquiera a usar una instruccin On Error en su cdigo.
Para esos programadores, la pureza de la programacin orientada a objetos es esencial, y debe
destruirse cualquier cdigo que usa mtodos que no son objetos para lograr lo que podra hacerse
con uno orientado a objetos.

Estoy a punto de usar una palabra que prohib usar a mi hijo que va a la
primaria. Si tiene odos sensibles, cbraselos ahora, aunque no lo proteger
de ver la palabra en la pgina impresa.

Rechazar la instruccin On Error de esta manera es simplemente estpido. Como podra recor-
darlo de captulos anteriores, en su aplicacin .NET todo est orientado a objetos, porque todo
el cdigo aparece en el contexto de un objeto. Si est usando manejo de errores no estructurado,
an puede obtener el objeto de excepcin relevante mediante el mtodo Err.GetException(),
de modo que no es en realidad un problema relacionado con objetos.

270 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 270 17/2/10 15:25:11


La decisin de usar manejo de errores estructurado o no estructurado no es diferente de la de
usar C# o Visual Basic para escribir sus aplicaciones. Para casi todas las aplicaciones, la eleccin
es irrelevante. Un lenguaje puede tener algunas caractersticas esotricas que puede conducirlo
en esa direccin (como argumentos de mtodo opcionales en Visual Basic), pero el resto del
99.9% de las caractersticas son casi idnticas.
Lo mismo es cierto para los mtodos de manejo de errores. Habr ocasiones en que uno es mejor
que el otro. Por ejemplo, considere el cdigo siguiente que llama a tres mtodos, ninguno de los
cuales incluye su propio manejador de errores:
On Error Resume Next
ActualizarParte1()
ActualizarParte2()
ActualizarParte3()

Evidentemente, no me preocupa si ocurre un error en las rutinas o no. Si un error causa la salida
temprana de ActualizarParte1, an se llamar a la siguiente rutina, ActualizarParte2,
etc. A menudo necesito un cdigo ms diligente para comprobacin de errores, pero en cdigo
de bajo impacto, esto es suficiente. Sera un poco ms complejo realizar lo mismo empleando
manejo de errores estructurado.
Try
ActualizarParte1()
Catch
End Try
Try
ActualizarParte2()
Catch
End Try
Try
ActualizarParte3()
Catch
End Try

Es una gran cantidad de cdigo extra para la misma funcionalidad. Si odia la instruccin On
Error, use por todos los medios el segundo bloque de cdigo. Pero si es un programador ms
razonable, el tipo de programador que leera un bloque como ste, use cada mtodo adecuado
para su diseo de cdigo.

La clase System.Exception
System.Exception es la clase base de todas las excepciones estructuradas. Cuando ocurre un
error puede examinar sus miembros para determinar la naturaleza exacta del error. Tambin
puede usar esta clase (o una de sus clases derivadas) para construir su propia excepcin persona-
lizada antes de usar la instruccin Throw. En la tabla 9-1 se presenta una lista de los miembros
de este objeto.
Clases derivadas de System.Exception pueden incluir propiedades adicionales que proporcio-
nan detalle adicional de un tipo de error especfico.

Administracin de errores | 271

09_PATRICK-CHAPTER_09.indd 271 17/2/10 15:25:11


Tabla 9-1. Miembros de la clase System.Exception.

Miembro del objeto Descripcin


Propiedad Datos Proporciona acceso a una coleccin de pares clave-valor, cada una proporcionando
informacinadicional especfica de la excepcin.
Propiedad HelpLink Identifica la informacin de la ubicacin de la ayuda en lnea relevante para esta excepcin.
Propiedad InnerException Si una excepcin es un efecto colateral de otro error, aqu aparece el error original.
Propiedad Message Descripcin de texto del error.
Propiedad Source Identifica el nombre de la aplicacin o el objeto que caus el error.
Propiedad StackTrace Devuelve una cadena que documenta de manera completa el rastro de la pila actual, la lista
de todas las llamadas a procedimientos activos que llevan a la instruccin que caus el error.
Propiedad TargetSite Identifica el nombre del mtodo que desencaden el error.

El objeto Err
El objeto Err proporciona acceso al error ms reciente mediante sus diversos miembros. En
cualquier momento en que ocurre un error, Visual Basic documenta los detalles del error en
los miembros de este objeto. A menudo se accede a l dentro de un manejador de errores no
estructurado para hacer referencia a los detalles del error, o para desplegarlos. En la tabla 9-2 se
presenta una lista de los miembros de este objeto.

Tabla 9-2. Miembros del objeto Err.

Miembro del objeto Descripcin


Mtodo Clear Limpia todas las propiedades del objeto Err, regresndolas a sus valores predeterminados. Por
lo general, slo usar el objeto Err para determinar los detalles de un error desencadenado. Pero
tambin puede usarlo para iniciar un error con sus propios detalles de error. Consulte la descripcin
del mtodo Raise ms adelante en la tabla.
Propiedad Description Una descripcin de texto del error.
Propiedad Erl La etiqueta de nmero de lnea cerca de donde ocurri el error. En las aplicaciones modernas de
Visual Basic, las etiquetas de lnea numrica casi nunca se usa, de modo que este campo suele ser 0.
Propiedad HelpContext La ubicacin dentro de un archivo de ayuda en lnea relevante para el error. Si esta propiedad y Help-
File estn habilitadas, el usuario puede acceder a la informacin de ayuda en lnea relevante.
Propiedad HelpFile El archivo de ayuda en lnea relacionado con el error activo.
Propiedad LastDLLError El valor numrico de devolucin a partir de la llamada ms reciente al DLL anterior a .NET, sea un
error o no.
Propiedad Nmero El cdigo numrico del error activo.
Mtodo Raise Use este mtodo para generar un error en tiempo de ejecucin. Aunque incluye algunos argu-
mentos para establecer otras propiedades del objeto Err, tambin puede establecer las propie-
dades usted mismo antes de llamar al mtodo Raise. Cualquier propiedad que establezca ser
retenida en el objeto para que lo examine el cdigo manejador de errores que recibe el error.
Propiedad Source El nombre de la aplicacin, clase u objeto que gener el error activo.

272 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 272 17/2/10 15:25:11


El objeto Debug
Visual Basic 6.0 (y anteriores) inclua una herramienta prctica que daba rpidamente salida a
informacin de depuracin de su programa, desplegando esa salida en la ventana Inmediato del
entorno de desarrollo de Visual Basic.
Debug.Print "Alcanzado el punto G en el codigo"

La versin .NET de Visual Basic mejora el objeto Debug con ms caractersticas y un ligero cam-
bio de sintaxis. El mtodo Print se reemplaza con WriteLnea; un mtodo Write separado da
salida a texto sin un retorno de carro final.
Debug.WriteLnea("Reached point G en code")

Todo a lo que d salida usando el mtodo WriteLnea (o similar) va a una serie de escuchas ad-
juntos al objeto Debug. Puede agregar sus propios escuchas, incluida salida a un archivo de trabajo.
Pero en realidad el objeto Debug slo se usa cuando se depura su programa. Una vez que compila
una versin final, ninguna de las caractersticas relacionadas con Debug funciona, por diseo.
Si desea registrar los datos de estado de una aplicacin liberada, considere, en cambio, el uso
del objeto My.Application.Log (o My.Log en programas de ASP.NET). De manera similar
al objeto Debug, Log enva su salida a cualquier nmero de escuchas registrados. Como opcin
predeterminada, toda la salida va a la salida de depuracin estndar (como en el objeto Debug)
y a un archivo de registro creado especficamente para el ensamblado de su aplicacin. Consulte
la ayuda en lnea del objeto My.Application.Log para conocer informacin acerca de la con-
figuracin de este objeto para satisfacer sus necesidades.

Otras caractersticas de Visual Basic relacionadas con los errores


El lenguaje Visual Basic incluye unas cuantas instrucciones y caractersticas especficas del error
que tal vez le resultarn tiles:
Funcin ErrorToString
Este mtodo devuelve el mensaje de error relacionado con un cdigo numrico de error del
sistema. Por ejemplo, ErrorToString(10) devuelve esta matriz es fija o esta temporal-
mente bloqueada. Slo es til con cdigos de error no estructurados.
Funcin IsError
Cuando proporciona un argumento de objeto a esta funcin, devuelve True si el objeto es
System.Exception (o derivado).

Resumen
El mejor programa del mundo nunca generara errores, supongo. Pero vamos, eso no pasa en la
realidad. Si una sonda enviada a Marte y que cost millones de dlares se estrell en un planeta
a millones de kilmetros de distancia, aun despus de aos de ingeniera avanzada, mi aplicacin
para el seguimiento de clientes en una tienda de renta de videos local va a tener uno o dos errores.

Resumen | 273

09_PATRICK-CHAPTER_09.indd 273 17/2/10 15:25:11


Pero puede mitigar el impacto de estos errores usando las caractersticas de administracin de
errores incluidas con Visual Basic.

Proyecto
El cdigo del proyecto de este captulo ser un poco breve. El cdigo de manejo de errores
aparecer en toda la aplicacin, pero lo agregaremos poco a poco a medida que avanzamos en el
proyecto. Por ahora, slo nos concentraremos en las rutinas de manejo de errores que tomarn
alguna accin bsica cuando ocurra un error en cualquier lugar del programa. En cuanto a las
expresiones lambda retendremos ese tipo de cdigo hasta un captulo posterior.

Manejador de errores general


Tan importante y preciso como debe ser el manejo de errores, la aplicacin de trabajo tpica no
encontrar una gran variedad de tipos de error. Aplicaciones como el Proyecto Biblioteca son
principalmente vulnerables a tres tipos de errores: 1) errores de entrada de datos; 2) errores que
ocurren cuando se leen datos de una tabla de base de datos, o se escriben en ella, y 3) errores
relacionados con la impresin. Seguro, puede haber una gran cantidad de errores de sobreflujo
u otros errores relacionados con los datos en uso, pero lo que nos preocupa es, sobre todo, la
interaccin con recursos externos, como la base de datos.
Debido a los tipos limitados de errores que ocurren en la aplicacin, es posible escribir una ruti-
na genrica que informe al usuario del error de una manera consistente. Cada vez que ocurra un
error en tiempo de ejecucin, llamaremos a esta rutina central, slo para dejar que el usuario sepa
lo que est pasando. Luego el bloque de cdigo donde ocurri el error puede decidir si se toma
cualquier accin compensatoria especial, o se sigue como si no hubiera ocurrido ningn error.

ACCESO AL PROYECTO
Cargue el proyecto Cap09 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap09 (Final) cdigo.

En el proyecto, abra el archivo de clase General.vb, y agregue el cdigo siguiente como un nuevo
mtodo a Module General.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap09, Elemento 1.

Public Sub ErrorGeneral(ByVal nombreRutina As String, _


ByVal elError As System.Exception)
' ----- Informar un error al usuario.
MsgBox(Ha ocurrido el siguiente error en el lugar '" & _

274 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 274 17/2/10 15:25:11


nombreRutina & "':" & vbCrLf & vbCrLf & _
elError.Message, _
MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, _
TituloPrograma)
End Sub

No hay mucho en ese cdigo, verdad? De modo que he aqu cmo funciona. Cuando encuentra un
error en alguna rutina, el manejador de errores aplicado llama al mtodo central ErrorGeneral.
Public Sub AlgunaRutina()
On Error GoTo ManejadorDeErrores

' ----- Gran cantidad de codigo va aqui.


Return

ManejadorDeErrores:
ErrorGeneral("AlgunaRutina", Err.GetException(
))
Resume Next
End Sub

Puede usarlo tambin con errores estructurados.


Try
' ----- Aqui va el codigo problematico.
Catch ex As System.Exception
ErrorGeneral("AlgunaRutina", ex)
End Try

El objetivo del mtodo global ErrorGeneral es simple: comunicar al usuario que ha ocurrido
un error, y seguir adelante. Tiene el objetivo de ser simple, y es simple. Podra mejorar la rutina
con algunas caractersticas adicionales. Registrar el error en un archivo (o cualquier otro escu-
cha de registros activos) podra ayudarle despus sin necesita examinar errores generados por la
aplicacin. Agregue el siguiente cdigo a la rutina, justo despus del comando MsgBox, para
registrar la excepcin.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap09, Elemento 2.

My.Application.Log.WriteException(elError)

Por supuesto, si ocurre un error mientras est escribiendo en el registro, eso sera un gran proble-
ma, de modo que agregue una lnea ms al principio de la rutina ErrorGeneral.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap09, Elemento 3.

On Error Resume Next

Proyecto | 275

09_PATRICK-CHAPTER_09.indd 275 17/2/10 15:25:11


Captura de errores no manejados
Como ya lo mencion, es una buena idea incluir un manejador de errores global en su cdigo,
en caso de que algn error pase sus defensas. Para incluir este cdigo despliegue todos los archi-
vos en el Explorador de soluciones, usando el botn Mostrar todos los archivos, abra el archivo
ApplicationEvents.vb file, y agregue el siguiente cdigo a la clase MyApplication.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap09, Elemento 4.

Private Sub MyApplication_UnhandledException( _


ByVal sender As Object, ByVal e As Microsoft. _
VisualBasic.ApplicationServices. _
UnhandledExceptionEventArgs) Handles _
Me.UnhandledException
' ----- Registrar el error y seguir ejecutandose.
e.ExitApplication = False
ErrorGeneral("Excepcion no manejada", e.Exception)
End Sub

Como ya hemos hecho que la rutina ErrorGeneral registre nuestros errores, podramos apro-
vecharlo aqu.
Esto es todo para programacin funcional y libre de errores. En el siguiente captulo, en que se
cubren las interacciones con la base de datos, haremos uso frecuente de este cdigo de manejo
de errores.

276 | Captulo 9:Programacin funcional

09_PATRICK-CHAPTER_09.indd 276 17/2/10 15:25:12


Captulo 10
ADO.NET

Si alguna vez ha ledo cualquier libro de programacin relacionado con las tecnologas de desa-
rrollo de Microsoft, ya ley un captulo como ste. Parece que todos los libros de programacin
de Windows tienen un captulo obligatorio sobre interaccin con base de datos. La razn para
esta cobertura extendida no es una sorpresa: Microsoft saca una nueva tecnologa de base de
datos cada dos aos, ms o menos.
Si es nuevo en el desarrollo con Windows, an no ha conocido un compendio de las siguientes
herramientas de interaccin con bases de datos, a veces conflictivas, a veces complementarias:
ODBC: conectividad abierta de base de datos (Open Database Connectivity)
ISAM: mtodo de acceso secuencial indexado (Indexed Sequential Access Method)
DAO: objetos de acceso a datos (Data Access Objects)
RDO: objetos de datos remotos (Remote Data Objects)
OLE DB: vinculacin e incrustacin de objetos para base de datos (Object Linking y Em-
bedding for Databases)
ADO: objetos de datos de ActiveX (ActiveX Data Objects)
Cuando revisa esta lista, podra pensar: Guau, es estupendo. Hay tantas opciones para elegir.
Podra verse engaado al pensar esto. La lista no es estupenda; es terrible. Imagine, slo por un mo-
mento, que no estamos hablando de interfaces de base de datos, sino de otros temas, ms prcticos.
Qu pasa si fuera necesario reemplazar el motor de su carro cada dos aos? Qu pasa si la columna
de direccin tuviera que reemplazarse anualmente? Qu pasa si tuviera que cambiar el aceite cada
5000 kilmetros o tres meses, lo que pase primero? Podra imaginarse la vida en ese mundo?
Cada vez que Microsoft introduca una nueva tecnologa de objetos de base de datos en la mez-
cla, fue seguido rpidamente por una estampida de reprogramaciones para llevar las antiguas
aplicaciones heredadas de Visual Basic (y otras) a la ms reciente tecnologa de base de datos.
Esto no siempre era posible, porque las restricciones de tiempo y presupuesto mantenan a or-
ganizaciones en plataformas antiguas. Durante casi una dcada mantuve una aplicacin en la
lnea del cuarto de milln usando DAO; slo recientemente la actualice a tecnologas de .NET.

277

10_PATRICK-CHAPTER_10.indd 277 17/2/10 15:25:41


Aunque ADO, una tecnologa ms flexible y poderosa que DAO, estuvo disponible entre tanto
por muchos aos, el costo en tiempo de pasar de DAO a ADO era prohibitivo.
Hasta ahora, parece que ADO.NET, la biblioteca de base de datos de Microsoft para .NET, es diferen-
te. Lleva siete aos funcionando (al momento de escribir este libro) y Microsoft an no ha bromeado
con los programadores de que habr un reemplazo. ADO.NET es muy flexible, y esa flexibilidad, se
espera, permitir extenderse sobre nuevos avances en tecnologa para el futuro previsible.
Si est familiarizado con la tecnologa ADO, preprese para olvidarla. ADO.NET no es el suce-
sor natural de ADO. Es una tecnologa completamente nueva que no est relacionada con ella,
y aunque comparte alguna terminologa con ADO y otras herramientas antiguas, ADO.NET
hace esto slo para jugar con su mente.

Qu es ADO.NET?
ADO.NET es un conjunto de clases, incluido con .NET Framework, que representa el mtodo
primario mediante el cual las aplicaciones .NET interactan con bases de datos relacionales y
otros sistemas de administracin de bases de datos abiertos y de propietario. Pero no es slo para
interaccin; en realidad, ADO.NET es, en s, una base de datos relacional que se encuentra par-
cialmente en memoria. Puede crear tablas y relaciones (combinaciones) con objetos de ADO.
NET, agregar y eliminar registros, consultar tablas con base en criterios de seleccin y hacer
tareas simples que son tpicas de sistemas de bases de datos relacionales independientes.
Todas las clases incluidas con ADO.NET aparecen en el espacio de nombres System.Data;
otros espacios de nombres subordinados proporcionan clases derivadas, orientadas a plataformas
especficas de bases de datos. Por ejemplo, el espacio de nombres System.Data.SqlClient
tiene como objetivo bases de datos de SQL Server, y System.Data.OracleClient se con-
centra en sistemas RDBMS de Oracle. Otros proveedores de bases de datos pueden desarrollar
implementaciones afinadas de las diversas clases de ADO.NET para que se usen con sus propios
sistemas, y proporcionarlas como un espacio de nombres separado.
ADO.NET implementa una experiencia de datos desconectada. En la programacin de base de
datos tradicional, sobre todo en aplicaciones de escritorio, la conexin entre una aplicacin y su
base de datos era fija y a largo plazo. Cuando el programa empezaba, la conexin tambin lo ha-
ca. Cuando se sala del programa, varias horas despus, la conexin finalmente terminaba. Pero
en un mundo de sitios Web escalables de manera masiva, mantener una base de datos conectada
por horas, hasta el final, es a veces un desperdicio y, a menudo, resulta imposible.
ADO.NET lo estimula a abrir conexiones de datos slo por el tiempo suficiente para obtener los
datos que satisfacen sus necesidades inmediatas. Una vez que los tiene, cierra la conexin, hasta
la prxima vez que necesite recuperar, insertar o actualizar el contenido de la base de datos. Si
usa la siguiente instruccin:
SELECT * FROM Cliente WHERE SaldoVencido > 0

tiene la opcin de 1) recorrer todos los registros una vez, de una manera rpida y simple; o 2)
cargar los datos en un objeto en memoria parecido a una tabla, cerrar la conexin y trabajar con

278 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 278 17/2/10 15:25:42


los registros cargados como si fueran los originales. Si usa el primer mtodo, puede pasar un
tiempo agradable bailando un vals entre los registros, tomndose varios minutos para procesar
cada uno. Pero ADO.NET ve con el seo fruncido este tipo de comportamiento egosta. El
objeto es entrar y salir lo ms rpidamente posible.
Debido a la naturaleza desconectada de ADO.NET, algunas tcnicas comunes en aplicaciones de
base de datos necesitan cambiarse. Por ejemplo, la bsqueda a largo plazo de registros de base
de datos durante una modificacin de usuario (concurrencia pesimista) es difcil de realizar en
el entorno desconectado de ADO.NET. Tendr que usar otros mtodos, como transacciones o
caractersticas atmicas de procedimiento almacenado, para llegar a los mismos resultados.

Revisin general de ADO.NET


ADO.NET divide su mundo en dos hemisferios: proveedores y el conjunto de datos. Imagine su
cocina como un mundo de ADO.NET, en que su refrigerador representa al proveedor y la estufa
el conjunto de datos. El proveedor proporciona acceso a cierto contenido, como la comida, o
una base de datos de Oracle (que suele aparecer en el cajn de carnes y quesos). Es un lugar de
almacenamiento a largo plazo, y el contenido que entra all por lo general se queda all por un
tiempo. Si algo se elimina, es porque ya no es vlido o se ha corrompido.
Un conjunto de datos, como un horno, prepara (galletas) y presenta contenido obtenido origi-
nalmente del almacenamiento a largo plazo. Una vez presentado, se consumir o se regresar al
refrigerador para ms almacenamiento a largo plazo. Esta analoga no es perfecta; en realidad,
algo no huele bien aqu. Pero comunica la idea bsica: los proveedores le dan acceso a datos
almacenados, algunos de los cuales pueden introducirse en la aplicacin y procesarse con ella,
utilizando los datos a corto plazo.

Proveedores
Sistemas grandes de base de datos, como SQL Server y Oracle, son servidores independien-
tes (de all el nombre SQL Server, servidor de SQL) que slo interactan indirectamente con
herramientas y aplicaciones de cliente. Estos sistemas, por lo general, aceptan conexiones de red de
clientes a travs de un puerto TCP/IP o una conexin similar. Una vez autentificado, el cliente hace
todas sus solicitudes a travs de esta conexin antes de desconectarse del sistema.
A principios de la dcada de 1990, Microsoft implement ODBC (con base en otros estndares
existentes), como un sistema comn mediante el cual los clientes se conectaran a servidores de
bases de datos, adems de otras fuentes de datos ms simples. Los clientes ya no tenan que pre-
ocuparse por los protocolos de red necesarios para hablar con una base de datos; todo ese cdigo
se inclua en el controlador ODBC.
Ms adelante, Microsoft liber un sistema de conexin a datos llamado OLE DB, basado en la
tecnologa ActiveX. Pronto aparecieron los controladores OLE DB para sistemas comunes, aun-
que an podra obtener recursos de ODBC mediante un controlador genrico ODBC integrado
en OLE DB.

Revisin general de ADO.NET | 279

10_PATRICK-CHAPTER_10.indd 279 17/2/10 15:25:42


En .NET, ODBC y OLE DB son reemplazados por proveedores, bibliotecas de cdigo que pro-
porcionan toda la comunicacin entre la base de datos y su aplicacin. Los proveedores son una
parte integral de ADO.NET, y tendr que usarlos para llegar a sus bases de datos. Por fortuna,
existen proveedores para los principales sistemas de base de datos, y existe un proveedor OLE
DB para sistemas sin proveedores propios.
Cuatro objetos principales integran la vista del programador para el proveedor:
El objeto Connection
Este objeto dirige las comunicaciones entre su programa y el origen de datos. Incluye pro-
piedades y mtodos que le permiten indicar la ubicacin y los parmetros de conexin para
el origen de datos. Las transacciones de varios comandos son manejadas en este nivel de
objeto.
El objeto Command
Este objeto toma la instruccin SQL que se proporciona, y la prepara para transporte me-
diante el objeto Connection. Puede incluir parmetros en su comando para soporte a pro-
cedimientos almacenados e instrucciones complejas.
El objeto DataReader
DataReader proporciona una manera simple y eficiente de recuperar resultados de una
consulta de datos. Otros objetos en ADO.NET lo usan para recibir y dirigir datos para
usarlos dentro de su programa, pero su cdigo puede usarlo directamente para procesar los
resultados de una instruccin SELECT u otra accin de recuperacin de datos.
El objeto DataAdapter
Este objeto es el que hace posible la comunicacin entre un conjunto de datos y el resto de
un proveedor. Una de sus funciones principales es modificar instrucciones de manipulacin
de datos (las instrucciones SELECT, INSERT, UPDATE y DELETE) generadas por un conjun-
to de datos en un formato que puede ser usado por el origen de datos relacionado.
El uso de estos objetos es un poco complejo, pero no resulta difcil de entender. Para conectarse
a una base de datos relacional, como SQL Server, y procesar datos, siga estos pasos:
1. Establezca una conexin con su origen de datos empleando un objeto Connection.
2. Envuelva una instruccin SQL en un objeto Command.
3. Ejecute ese objeto Command en el contexto del objeto Connection establecido.
4. Si habr de regresarse cualquiera de los resultados, use DataReader para rastrear a travs de
los registros, o una combinacin de DataAdapter y DataSet (o DataTable) para recupe-
rar o almacenar los resultados.
5. Cierre todos los objetos que abri para procesar los datos.
Aunque .NET Framework incluye proveedores de datos para unos cuantos sistemas de datos
diferentes, el resto de lo expuesto en este captulo se concentra slo en el proveedor SQL Server,
expuesto a travs del espacio de nombres System.Data.SqlClient.

280 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 280 17/2/10 15:25:42


SQL Server 2005 incluye soporte para una caracterstica llamada instancias
de usuario, que se usa con bases de datos de SQL Server 2005 Express Edi-
tion. Esta caracterstica permite que un usuario de bajos privilegios acceda
a un archivo de base de datos de SQL Server Express especfico sin necesi-
dad de que un administrador establezca una configuracin de seguridad de
SQL Server para ese usuario. Esta caracterstica es til en entornos donde
el software relacionado se instal mediante el mtodo de implementacin
ClickOnce (analizado en el captulo 25), sin que intervenga el administrador.
Tambin requiere reconfiguracin especfica de la instalacin de SQL Server
Express antes de usarlo. Para conocer ms informacin acerca de esta caracte-
rstica, tome como referencia el artculo Trabajo con instancias de usuario,
en la parte de ADO.NET de la documentacin de MSDN proporcionada
con su instalacin de Visual Studio.

Conjuntos de datos
Si va a hacer ms que slo revisar rpidamente los datos que regresan de una consulta de Data-
Reader, tal vez use un conjunto de datos para almacenar, administrar y, opcionalmente, actuali-
zar esos datos. Cada conjunto proporciona una vista de datos desconectada genrica, sean datos
de un proveedor o datos que gener mediante cdigo. Aunque cada proveedor est unido a una
plataforma de base de datos especfica (como Oracle) o un estndar de comunicacin (como
OLE DB), los objetos en el reino del conjunto de datos son genricos, y pueden interactuar con
cualquier de los proveedores especficos de la plataforma.
Tres objetos principales integran el mundo de los conjuntos de datos:
El objeto DataSet
Cada objeto DataSet acta como una minibase de datos. Puede agregar todas las tablas que
desee a un DataSet, y establecer relaciones de clave externa entre los campos de estas tablas.
Los detalles internos de cada DataSet son un misterio insondable, pero puede exportar un
DataSet completo a XML, y cargarlo de nuevo, ms adelante, si es necesario.

El objeto DataTable
Cada tabla de su DataSet usa un objeto DataTable separado, accesible mediante la co-
leccin Tables del DataSet. Los objetos DataTables tambin son tiles como objetos
independientes. Si planea agregar slo una tabla a su DataSet podra optar por usar slo
un objeto DataTable sin un DataSet. Dentro de cada objeto DataTable, objetos Data-
Column y DataRow separados establecen las definiciones de campo y los valores reales de
datos, respectivamente.
El objeto DataRelation
Use los objetos DataRelation, almacenados dentro de una coleccin Relations de Da-
taSet, para establecer relaciones en el nivel del campo y restricciones entre columnas de sus
objetos DataTable.

Revisin general de ADO.NET | 281

10_PATRICK-CHAPTER_10.indd 281 17/2/10 15:25:42


Aunque los conjuntos de datos son los que se usan con ms frecuencia con proveedores, puede
usarlos de manera independiente para construir su propia coleccin de tablas y relaciones en
memoria. Esto es similar a los conjuntos de registros del lado del cliente que podra construir
con objetos ADO anteriores a .NET, aunque las caractersticas incluidas con ADO.NET hacen
que los conjuntos de datos sean mucho ms poderosos que los antiguos conjuntos de registros.

Visual Basic 2008 incluye conjuntos de datos con tipos fuertes, una carac-
terstica usada para integrar un DataSet con un formato especfico de los
datos o registros. Pueden resultarle tiles en sus aplicaciones, pero no los ana-
lizar en este libro. La nueva tecnologa LINQ usa una caracterstica similar
para ayudarle a establecer relaciones entre LINQ y tablas de base de datos.

Comparacin entre usar y no usar conjuntos de datos


Cuando se usan juntos, los proveedores y los conjuntos de datos le dan una interfaz de extremo a extre-
mo para los valores de datos individuales, de los campos de las tablas de su base de datos a los elementos
en memoria de un registro DataRow. En la figura 10-1 se muestra esta interaccin entre objetos.
Cuando interacta con datos de una base de datos externa, siempre usa las clases de proveedor,
pero depende de usted si tambin quiere usar conjuntos de datos. Ambos mtodos tienen pros y
contras; algunos de ellos aparecen en la tabla 10-1.

Tabla 10-1. Los pros y contras de usar conjuntos de datos.

Sin conjuntos de datos Con conjuntos de datos


Debe proporcionar todas las instrucciones SQL, en el formato que DataSet y DataAdapter trabajan juntos para encargarse
el proveedor espera. Esto se aplica a todas las solicitudes de muchas de las instrucciones SQL.
SELECT, INSERT, UPDATE y DELETE.
Los datos recuperados mediante DataReader son de slo Los datos ledos de la base de datos pueden modificarse en
lectura. Debe usar comandos separados para actualizar datos. memoria y actualizarse como un archivo de procesamiento por
lotes con una sola llamada a mtodo.
Las transferencias de datos son muy eficientes, porque no se Puede haber un poco de afectacin en el rendimiento porque
necesita trabajo adicional para mover datos en una estructura los conjuntos de datos generan los objetos necesarios para cada
compleja de conjunto de datos. registro transferido.
La asignacin de memoria est limitada a los campos de datos de Se requiere asignacin de memoria para todo el conjunto de
un solo registro, ms algunos elementos adicionales mnimos. resultados, adems de algo adicional para cada tabla, campo,
columna y fila del conjunto de resultados.
Slo puede abrirse un DataReader a la vez (a menos que el Cualquier cantidad de conjuntos de datos puede estar en uso a
proveedor sea compatible con MARS, que analizar ms adelante). la vez.
Existe una conexin viva a la base de datos, siempre y cuando Las conexiones de datos slo se mantienen el tiempo suficiente
se use un DataReader. Si le toma cinco minutos revisar un para transferir datos desde la base de datos o hacia sta.
conjunto de resultados porque est haciendo mucho anlisis por
registro, la conexin estar activa durante esos cinco minutos..
DataReader presenta un registro a la vez. Los registros deben Puede saltar entre los registros en un conjunto de datos, y reorga-
procesarse en el orden en que arriban. nizarlos para cumplir con sus necesidades.

282 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 282 17/2/10 15:25:42


Tabla 10-1. Los pros y contras de usar conjuntos de datos (continuacin).

Sin conjuntos de datos Con conjuntos de datos


Gasta mucho tiempo en trabajar con cadenas (para instrucciones Todos los campos de datos estn organizados de manera lgica, como
SQL) y campos de datos sin trabajar. en la base de datos real. Puede interactuar directamente con ellos.
Cada Command y Connection trabaja con un solo origen de Diferentes DataTable dentro de su DataSet pueden
datos con soporte al proveedor. conectarse con distintos orgenes de datos. Adems, puede
trabajar a mano los datos para que cada DataRow contenga
datos de diferentes orgenes.
Debido a que administra todas las instrucciones SQL, tiene un Debido a que se abstrae la vista de los datos, puede tener un
nivel de control (relativamente) elevado sobre todo el proceso de nivel (relativamente) limitado de control sobre todo el proceso
interaccin con datos. de interaccin con todos los datos (aunque el uso avanzado de
conjuntos de datos le da algo de control adicional).

DB

Connection

Command

DataReader

DataAdapter

DataSet

DataTable

DataRow
DataColumn

DataReader

DataTable

Figura 10-1. Proveedores y conjuntos de datos en accin.

Comparacin entre usar y no usar conjuntos de datos | 283

10_PATRICK-CHAPTER_10.indd 283 17/2/10 15:25:43


Para m, la ltima entrada en la tabla 10-1 es la clave. El trabajo de un programador consiste en
controlar la experiencia de software del usuario, y cuanto ms control tenga, mejor. Por eso es
que suelo odiar los asistentes y los generadores de cdigo que me quitan el control a m, el
desarrollador. Sin embargo, hay lmites a mi paranoia; estoy de acuerdo con el cdigo bsico
de plantilla proporcionado por Visual Studio cuando se crean nuevos proyectos. Aun as, ver
mi personalidad controladora de cdigo en el Proyecto Biblioteca, con mi gran dependencia de
DataReaders sobre DataSets. Cuando almaceno datos a largo plazo, por lo general me apego
a los datos en un DataTable sin DataSet contenedor.

Soporte a MARS
Mencion algo llamado MARS en la tabla 10-1. MARS son las iniciales de Multiple Active Re-
sult Sets (conjuntos de resultados mltiples activos). Por lo general, un solo objeto Connection
permite un solo DataReader en uso en cualquier momento determinado. Esta limitacin es bi-
direccional. Si est explorando un DataReader va una instruccin SELECT, no puede usar ins-
trucciones INSERT, UPDATE o DELETE en esa misma conexin, hasta que cierre el DataReader.
Con la introduccin de MARS, una sola conexin puede manejar varias actividades de transmi-
sin de datos en cualquier direccin. SQL Server agreg soporte a MARS con su versin 2005;
Oracle es compatible con caractersticas similares a MARS desde la liberacin inicial de .NET.
Las conexiones de MARS parecen una caracterstica que siempre querr habilitar. Pero agregan
elementos adicionales a su aplicacin que pueden hacerla ms lenta. Adems, MARS no siempre
se combina bien con aplicaciones de varios subprocesos.

Conexin a SQL Server con Visual Studio


Visual Studio tiene muchas herramientas integradas que hacen que trabajar con datos sea tan
simple como arrastrar y colocar. Bueno, en realidad no es tan rpido. Pero al responder unas
cuantas preguntas y arrastrar y colocar un elemento, puede construir una aplicacin completa
que le permite editar datos en su base de datos. Tratmoslo juntos.

Creacin de un origen de datos


Inicie un nuevo proyecto de Windows Forms Visual Studio (slo un proyecto simple de Win-
dows Forms, no uno de los proyectos especficos de la biblioteca). Al seleccionar el comando de
men Datos Mostrar orgenes de datos muestra el panel Orgenes de datos, que se muestra
en la figura 10-2.
Los nuevos proyectos no incluyen ningn origen de datos como opcin predeterminada, de
modo que necesitamos agregar uno. Haga clic en el vnculo Agregar nuevo origen de datos, en
el panel Orgenes de datos. El Asistente para la configuracin de orgenes de datos le gua por el
proceso de creacin de un origen de datos:
1. El primer paso le pregunta De dnde obtendr la aplicacin los datos? Seleccione Base
de datos y haga clic en el botn Siguiente.

284 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 284 17/2/10 15:25:43


Figura 10-2. Dnde estn los orgenes de datos?

2. El segundo paso le pregunta: Qu conexin de datos debera utilizar la aplicacin para co-
nectarse a la base de datos?. Tendremos que crear una nueva conexin para la base de datos
Biblioteca que diseamos en el captulo 4. Haga clic en el botn Nueva conexin.
3. Aparece el cuadro de dilogo Elegir origen de datos. Seleccione Microsoft SQL Server de
la lista Origen de datos y luego haga clic en el botn Continuar. Si ha accedido a este
cuadro de dilogo antes y marc el campo Siempre usar esta seleccin, es posible que
este cuadro de dilogo no aparezca.
4. Aparece el cuadro de dilogo Agregar conexin, para recolectar los detalles de la nueva co-
nexin. Si el campo Origen de datos contiene algo diferente de Microsoft SQL Server,
haga clic en el botn Cambiar, para modificar el tipo de conexin empleando el cuadro de
dilogo mencionado en el paso 3.
5. De regreso al formulario Agregar conexin, llene el campo Nombre del servidor con el nombre
de su instancia de SQL Server. Por fortuna, esta lista desplegable ya tiene las instancias en la lista;
si no, tendr que ingresarla. La opcin predeterminada para SQL Server Express es el nombre
de su equipo, con \SQLEXPRESS adjunto. Si el nombre de su equipo es MISISTEMA, el
nombre de la instancia sera MISISTEMA\SQLEXPRESS.
6. Configure sus parmetros de autentificacin en la seccin Inicio de sesin con el servidor.
Yo us autentificacin estndar de Windows, pero depende de la manera en que configur
los datos en el captulo 4.
7. En la seccin Establecer conexin con una base de datos, seleccione o escriba Biblioteca
para el nombre de la base de datos.
8. Haga clic en el botn Probar conexin, para asegurarse de que todo funciona. Cuando haya
terminado, haga clic en el botn Aceptar para crear la nueva conexin.
9. Muy bien, estamos de regreso en el formulario Asistente para la configuracin de orgenes
de datos. La conexin que acabamos de crear debe aparecer en la lista, como se muestra en
la figura 10-3. Haga clic en Siguiente.

Conexin a SQL Server con Visual Studio | 285

10_PATRICK-CHAPTER_10.indd 285 17/2/10 15:25:43


Figura 10-3. La nueva conexin de base de datos, lista para usarse.

10. El siguiente panel le pregunta si este origen de datos debe volverse parte de los parmetros
configurables para este proyecto. Revisaremos las caractersticas de configuracin de Visual
Basic en el captulo 14. Por ahora, slo acepte la opcin predeterminada y haga clic en Si-
guiente.
11. Casi llegamos al final. Slo faltan 27 pasos! Bromeaba. ste es el ltimo paso en la creacin
del origen de datos. El panel final le muestra una lista de las caractersticas de generacin
de datos de la base de datos Biblioteca. Abra la rama Tablas y seleccione Actividad, como se
muestra en la figura 10-4. Luego haga clic en Finalizar.
Revise el panel Orgenes de datos mostrado en la figura 10-5. Incluye el origen de datos Bi-
bliotecaDataSet con su vnculo con la tabla Actividad.

Uso de un origen de datos


As que cul es este origen de datos, en todo caso? Es simplemente un vnculo con alguna parte
de su base de datos, envuelto en un objeto .NET tpico. Ahora que es parte de su proyecto,
puede usarlo para acceder a los datos en la tabla Actividad a travs del cdigo del proyecto, o
al arrastrar y colocar. En el panel Orgenes de datos, encontrar que la entrada Actividad es en
realidad una lista desplegable. Seleccione Detalles de la lista, como he hecho en la figura 10-6.
(La superficie de Form1 debe desplegarse para que esto funcione.)
Por ltimo, arrastre y coloque la entrada Actividad en la superficie de Form1. Cuando lo suelte,
Visual Studio agregar un conjunto de controles al formulario, junto con unos cuantos controles
ms que no son de interfaz de usuario, justo abajo del formulario (vase la figura 10-7).

286 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 286 17/2/10 15:25:44


Figura 10-4. El paso final para seleccionar la tabla Actividad.

Figura 10-5. Por fin, un origen de datos real.

Figura 10-6. Seleccione la vista Detalles en lugar de DataGrid.

Conexin a SQL Server con Visual Studio | 287

10_PATRICK-CHAPTER_10.indd 287 17/2/10 15:25:45


Figura 10-7. Un programa completo sin escribir una lnea de cdigo.

Con slo arrastrar y colocar, Visual Studio agreg todos los controles y vnculos necesarios
para convertir su formulario en un editor de la tabla Actividad con turbo. Haga la prueba
ahora al oprimir la tecla F5. En la ejecucin del programa puede usar el control de acceso de
grabacin tipo videocasetera de Microsoft Access. Tambin es posible modificar los valores
de cada registro, agregar nuevos o eliminar registros existentes (pero, por favor, regrese las
cosas a su estado original cuando haya terminado; necesitaremos todos los registros originales
ms adelante). Hablando de poder! Hablando de simplicidad! Hablando de lneas no em-
pleadas! Quin necesita programadores pagados como nosotros cuando Visual Studio puede
hacer esto por usted?

Combinacin de datos
En realidad, Visual Studio no est haciendo mucho. Est usando una caracterstica llamada
combinacin de datos para vincular los campos del formulario con el origen de datos, la tabla
Actividad de la base de datos Biblioteca. La combinacin de datos es una caracterstica integra-
da en los controles de Windows Forms que le permiten desplegar y editar valores automtica-
mente en un origen de datos asociado, como una base de datos. Todo est ordenado a travs de
las propiedades del control.
Seleccione el control NombreCompletoTextBox agregado al formulario de este proyecto, y luego
examine sus propiedades. Justo arriba est una seccin de propiedades llamada (DataBindings).
Su subpropiedad Text contiene una referencia ActivityBindingSource NombreCompleto,
una referencia al control que no es de interfaz de usuario ActivityBindingSource tambin
agregada por Visual Studio. ActivityBindingSource, a su vez, contiene una referencia al ob-
jeto BibliotecaDataSet, el origen de datos que creamos antes. Ese origen de datos vincula con
SQL Server, con la base de datos Biblioteca y, por ltimo, con la tabla Actividad y su campo
NombreCompleto. Como comerse un pastelillo!

288 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 288 17/2/10 15:25:46


Si cuenta todos los objetos que participan en esta relacin de combinacin de datos, puede llegar
a algo as como 5283 objetos distintos. No es de sorprender que Visual Studio haya hecho ya
gran parte del trabajo. La combinacin de datos proporciona un conjunto conveniente, pero
tambin le quita mucho de su control como desarrollador. Aunque hay propiedades y eventos
que le permiten administrar aspectos de la combinacin de datos y su proceso actualizado, gran
parte del cdigo esencial est oculto dentro de las porciones de combinacin de datos de .NET.
Tal vez no los pueda tocar, probar, doblar, aguijonear o mutilar, lo que es bastante malo. Un
rpido vistazo a una de mis creencias como programador lo dice todo: el buen software incluye
mximo control para el desarrollador y mnimo control para el usuario.
Parte de su trabajo como desarrollador consiste en proporcionar un entorno con gran cantidad
de secuencias de comandos, para que el usuario acceda a datos importantes. Esto requiere
que tenga control sobre la experiencia del usuario a travs de su cdigo fuente. Por cierto,
diferir gran parte de ese control a otros, cuando use cualquier herramienta proporcionada
por terceros. Siempre y cuando estas herramientas le permitan controlar la experiencia de
usuario a su nivel de satisfaccin, ser estupendo. Pero siempre me he sentido molesto con la
combinacin de datos, excepto cuando implementa un despliegue de datos de slo lectura de
la base de datos. Visual Basic tena caractersticas similares mucho antes de que llegara .NET,
y siempre le han dificultado al desarrollador el control de las diversas interacciones de datos
en el formulario.
Por fortuna, si evade las caractersticas de combinacin de datos, Visual Basic le pasar a usted la
responsabilidad de administrar todas las interacciones entre la base de datos y el usuario.

Interaccin con SQL Server en cdigo


La comunicacin con una base de datos requiere definitivamente ms trabajo que arrastrar y
colocar orgenes de datos, pero quin dijo que programar era un paseo de campo?

Construccin de la cadena de conexin


El primer paso en el camino al estilo de vida del control de datos consiste en conectar la base
de datos empleando una cadena de conexin. Si ha usado ADO, ya est familiarizado con las
cadenas de conexin empleadas en ADO.NET, porque suelen ser iguales. Tal vez ya sabe que es
a travs de las cadenas de conexin que Microsoft mantiene las riendas sobre los desarrolladores
de Windows. No es que sean complejas; no son ms que cadenas de parmetros separados por
puntos y comas. Pero los parmetros que se incluyen, y su formato exacto, son cosa de leyenda.
La documentacin de MSDN incluida con Visual Studio proporciona algunos ejemplos de ca-
denas de conexin, pero no mucho detalle. Un recurso de terceros, http://www.connectionstrings.
com, tambin proporciona numerosos ejemplos de formatos de cadena de conexin vlidos.
La cadena de conexin que usaremos para conectarnos con la base de datos Biblioteca, por fortuna,
no es demasiado compleja. Si usa su inicio de sesin de Microsoft Windows para conectarse a la
base de datos, la siguiente cadena cubrir sus necesidades (como una sola lnea, sin separacin):

Interaccin con SQL Server en cdigo | 289

10_PATRICK-CHAPTER_10.indd 289 17/2/10 15:25:46


Data Source=nombre_instancia;Initial Catalog=Biblioteca;
Integrated Security=true

donde nombre_instancia es reemplazada por el nombre de su instancia de SQL Server u


origen de datos. La cadena de conexin que construimos visualmente antes us MISISTEMA\
SQLEXPRESS como nombre de su origen de datos.
Para usar ID y contraseas de usuario de SQL Server, pruebe este formato:
Data Source= nombre_instancia;Initial Catalog=Biblioteca;
User ID=sa;Password=xyz

Por supuesto, reemplace el ID de usuario (sa) y la contrasea (xyz) con sus propios valores. Si quie-
re incluir soporte a MARS en su conexin, agregue otro componente delimitado por punto y coma:
MultipleActiveResultSets=true

Otras opciones de cadena de conexin le permiten conectarse directamente


a un archivo de base de datos de SQL Server Express (SSE), modificar el
mtodo de creacin de instancias de usuario (a menudo usado con la base
de datos desplegada con ClickOnce) y hacer otros ajustes. Aunque estn un
poco dispersos puede encontrar estas opciones documentadas en la docu-
mentacin de MSDN que se incluye con Visual Studio.

Establecimiento de la conexin
Use la cadena de conexin para crear un objeto SqlConnection, y luego abra la conexin. Cree
una nueva aplicacin de Windows Forms en Visual Studio. Agregue un control Button a la su-
perficie de Form1. Haga doble clic en el botn para acceder a su manejador de eventos Click.
Luego agregue el siguiente cdigo al manejador:
' ----- Supone:
' Imports System.Data
Dim bibliotecaBD As New SqlClient.SqlConnection( _
"Data Source=MISISTEMA\SQLEXPRESS;" & _
"Initial Catalog=Biblioteca;Integrated Security=true")
bibliotecaBD.Open()

Asegrese de reemplazar MISISTEMA con el nombre de su propio sistema. Todo este bloque
me parece mucho ms fcil que los 10 o 15 pasos que tuvo que seguir antes cuando se estableci
la conexin mediante Visual Studio.

Uso de instrucciones SQL


Una vez que la conexin est abierta puede usar SELECT, INSERT, UPDATE, DELETE o cualquier
otra instruccin de un lenguaje de manipulacin de datos (DML, Data Manipulation Language) o
un lenguaje de definicin de datos (DDL, Data Definition language) aceptada por la base de datos.
Un objeto SqlCommand prepara su instruccin SQL para usarla con la conexin abierta. He aqu
una instruccin que devuelve la descripcin de la entrada nmero 1 de la tabla Actividad:
SELECT NombreCompleto FROM Actividad WHERE ID = 1

290 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 290 17/2/10 15:25:46


La creacin de un objeto SqlCommand que envuelve esta instruccin es fcil. El constructor para
el objeto SqlCommand toma una instruccin SQL, ms un objeto SqlConnection. Agregue el
siguiente cdigo al final de su manejador de eventos Button1_Click:
Dim instruccionSql As New SqlClient.SqlCommand( _
"SELECT NombreCompleto FROM Actividad WHERE ID = 1", bibliotecaBD)

Procesamiento de los resultados


Lo nico que queda por hacer es pasar la instruccin SQL a la base de datos, va la conexin,
y recuperar los resultados como un objeto SqlDataReader. Una vez que obtenemos los datos,
procese cada registro empleando el mtodo Read del objeto. Usted accede a campos individuales
por nombre mediante la coleccin predeterminada Item. Agregue este cdigo adicional al final
de su manejador de eventos Button1_Click:
Dim resultadosSql As SqlClient.SqlDataReader = _
instruccinSql.ExecuteReader()
resultadosSql.Read()
MsgBox(CStr(resultadosSql.Item("NombreCompleto")))

' ----- Como Item es la propiedad predeterminada, esto tambien funciona...


' MsgBox(CStr(resultadosSql("NombreCompleto")))

' ----- esta sintaxis acortada tambien funciona...


' MsgBox(CStr(resultadosSql!NombreCompleto))

Al poner juntos todos estos bloques de cdigo se despliega el mensaje mostrado en la figura 10-8.

Figura 10-8. Datos bsicos recuperados de una base de datos.

Cuando haya terminado asegrese de cerrar todas las conexiones que abri. Agregue este ltimo
fragmento de cdigo al final de su manejador de eventos Button1_Click:
resultadosSql.Close()
bibliotecaBD.Close()

Modificacin de datos
La aplicacin de cambios a las tablas de la base de datos est codificada como recuperacin de
datos, pero no se necesita SqlDataReader. En lugar de usar el mtodo ExecuteReader use el
mtodo ExecuteNonQuery, que no devuelve resultados.

Interaccin con SQL Server en cdigo | 291

10_PATRICK-CHAPTER_10.indd 291 17/2/10 15:25:47


Dim instruccinSql As New SqlClient.SqlCommand( _
"UPDATE Actividad SET NombreCompleto = 'Duerme todo el dia'" & _
" WHERE ID = 1", bibliotecaBD)
instruccinSql.ExecuteNonQuery()

SQL Server 2005 tiene una caracterstica conveniente que devolver un solo campo de un nuevo
registro creado mediante la instruccin INSERT. Si busca de nuevo en el diseo de base de datos
del Proyecto Biblioteca, ver que los campos ID en muchas de las tablas se generan automtica-
mente. Por lo general, si quiere recuperar de inmediato el campo ID de un nuevo registro, primero
tiene que usar INSERT con el registro, y luego usar una instruccin SELECT separada, devolviendo
el campo ID del nuevo registro.
INSERT INTO CodigoSerie (NombreCompleto)
VALORES ('Libros infantiles')

SELECT ID FROM CodigoSerie


WHERE NombreCompleto = 'Libros infantiles'

La clusula OUTPUT INSERTED de SQL Server combina ambas instrucciones en una sola accin.
INSERT INTO CodigoSerie (NombreCompleto)
OUTPUT INSERTED.ID
VALORES ('Libros infantiles')

Cuando la instruccin INSERT est completa, SQL Server devuelve el campo ID como un conjun-
to de resultados, como si hubiera usado una instruccin SELECT separada. El mtodo Execute
Scalar de SqlCommand es una manera simple de recuperar un solo valor de una consulta SQL.
instruccinSql = New SqlClient.SqlCommand( _
"INSERT INTO CodigoSerie (NombreCompleto) " & _
"OUTPUT INSERTED.ID VALORES ('Libros infantiles')", _
bibliotecaBD)
Dim nuevoID As Integer = CInt(instruccinSql.ExecuteScalar( ))

Transacciones de base de datos


Las transacciones le permiten acciones tipo todo o nada a travs de varias instrucciones SQL.
Una vez iniciada, todas las instrucciones SQL usadas dentro del contexto de la transaccin
deben completarse, o ninguna de ellas se completar. Si tiene que realizar 10 actualizaciones,
pero la base de datos falla despus de slo cinco de ellas, puede revertir la transaccin al prin-
cipio. La base de datos revierte las primeras instrucciones, restaurando los datos a su estado an-
tes de que empezara la transaccin. (Las actualizaciones de otros usuarios no se ven afectadas
por esta reversin.) Si todas las instrucciones tienen xito puede aceptar toda la transaccin,
haciendo que todos los cambios sean permanentes.
Para el caso de las bases de datos de SQL Server, las transacciones son manejadas por el objeto
SqlTransaction del proveedor. Como otras caractersticas de ADO.NET, es fcil usarlo. Una
transaccin empieza con un mtodo BeginTransaction llamado en la conexin.
Public conjuntoAtomico As SqlClient.SqlTransaction = _
bibliotecaBD.BeginTransaction( )

292 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 292 17/2/10 15:25:47


Para incluir una instruccin SQL en una transaccin, asigne el objeto SqlTransaction a la
propiedad Transaction del objeto SqlCommand.
instruccinSql.Transaction = conjuntoAtomico

Luego llame al mtodo Execute apropiado en el comando. Cuando todos los comandos estn
completos, use el mtodo Commit de la transaccin para que los cambios sean permanentes.
conjuntoAtomico.Commit()

Si necesita, en cambio, abortar la transaccin, utilice el mtodo Rollback.


conjuntoAtomico.Rollback()

Marco de trabajo de la entidad ADO.NET


La versin de ADO.NET de .NET Framework 3.5 (que es la que acompaa a Visual Studio
2008) incluye un nuevo componente: ADO.NET Entity Framework. En parte herramienta de
modelado de relacin de entidad, en parte generador de cdigo, esta nueva tecnologa le ayuda
a generar vistas de datos lgicas de los datos almacenados en su base de datos relacional u otro
origen de datos.
El Entity Framework le permite disear tres tipos de objetos basados en sus datos almacenados:
entidades (similares a las tablas), relaciones (combinaciones de base de datos) y conjuntos de entidades
(entidades relacionadas). Cada tipo est representado por objetos que exponen los miembros de su
base de datos central de una manera ms programable. Por ejemplo, puede disear un objeto de
entidad que represente una tabla en su base de datos, y los miembros del objeto pueden repre-
sentar el campo en un solo registro.
Y qu, se preguntar. Suena como las mismas caractersticas integradas en el objeto Data-
Table de ADO.NET? Pero espere, hay ms. Lo que hace al Entity Framework tan til es 1) su
asignacin de datos fsicos a vistas lgicas; 2) su soporte a herencia de entidad, y 3) su capacidad
para actuar como un proveedor de ADO.NET.
Asignacin de datos
La asignacin de datos es similar a la creacin de una vista en una base de datos relacio-
nal tradicional; puede crear entidades que estn integradas a partir de varios registros de
origen dispersos entre varias tablas de base de datos. Esto incluye vistas de datos primarios-
secundarios; puede crear una entidad Orden que alude al registro de orden principal y
los elementos de lnea de orden mltiples incluidos en el orden. Lgicamente, esta nueva
entidad se trata como un solo elemento que permite la consulta. Cuando solicita datos a
travs de la nueva entidad, no tiene que ensearle cada vez cmo combinar y relacionar las
diversas piezas de datos.
Herencia de entidad
Una vez que ha definido una entidad definida, puede extender la estructura de la entidad a
travs de la herencia. Por ejemplo, tal vez quiera crear una entidad llamada OrdenInterno
basada en su entidad Orden original, agregando miembros que rastrean datos especficos a

Marco de trabajo de la entidad ADO.NET | 293

10_PATRICK-CHAPTER_10.indd 293 17/2/10 15:25:47


rdenes internos. Estos nuevos campos podran estar en una tabla especializada, desencade-
nada por una marca booleana en la principal tabla de rdenes. Pero eso no importa: todo
puede ocultarse por la lgica de la propia entidad. Cuando solicita una instancia de Orden
Interno, slo sabr que slo se refiere al tipo de orden especial internamente marcado, y
no rdenes estndar.
Compatibilidad con proveedor de ADO.NET
Una vez que ha creado sus entidades y la lgica de la asignacin relacionada, puede co-
nectarse a las entidades como si estuvieran almacenadas en su propia base de datos. En
lugar de conectarse a SQL Server y consultar directamente las tablas, puede conectarse al
contexto de asignacin y consultar contra la nueva vista lgica de sus datos.
Parte de la tecnologa que analizar en el captulo 17 tiene el sabor del cdigo concentrado en
el Entity Framework de ADO.NET, pero se orientar especficamente a SQL Server. El Entity
Framework de ADO.NET es la manera principal para conectarse a la nueva tecnologa LINQ
de .NET para bases de datos que no son de Microsoft, como Oracle y DB2. Por desgracia, unos
cuantos meses antes de la liberacin de Visual Studio 2008, Microsoft anunci que Entity Fra-
mework no estara lista a tiempo para la versin principal del producto (lo siento, IBM y Ora-
cle). Fue apuntado para surgir como una versin separado unos meses despus de Visual Studio.
El producto final podra estar o no disponible mientras lee esto.

Resumen
Hay programadores en este mundo que nunca tienen acceso a una base de datos, quienes
nunca se preocupan por conexiones o transacciones o bloqueo de registros o instrucciones
INSERT o integridad referencial. S, hay ese tipo de programadores en el mundo (cinco, tal vez
seis, de acuerdo con el ltimo conteo). Todos los dems programadores deben incluir cdigo
que administra datos externos de algn tipo, sea en una base de datos relacional, un archivo
XML o un archivo de configuracin. ADO.NET es una de las herramientas .NET que faci-
lita la administracin de esos datos. Es muy diferente del viejo sistema ADO, y an no estoy
convencido de que desconectar datos el 100% del tiempo es la manera correcta de hacer las
cosas. Pero cuando considero el poder y la flexibilidad de ADO.NET, no puedo evitar sino
sentir pena por esos seis programadores que nunca usan bases de datos.

Proyecto
Es probable que ms de 50% del cdigo del Proyecto Biblioteca abarcar directamente una base
de datos, o la manipulacin de los datos recuperados a travs de ADO.NET. Crear constante-
mente nuevos objetos Command y DataReader, aunque simple, es muy duro para los dedos.
Debido a que gran parte del cdigo es repetitivo, el cdigo en este proyecto del captulo tratar
de centralizar parte del cdigo bsico, de patrn o machote.

294 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 294 17/2/10 15:25:47


ACCESO AL PROYECTO
Cargue el proyecto Cap10 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap10 (Final) cdigo.

Referencia a los espacios de nombres de datos


El cdigo del Proyecto Biblioteca tiene referencias a varios de los espacios de nombres importan-
tes de .NET, como System, System.Windows.Forms, y Microsoft.VisualBasic. Sin em-
bargo, an no hace referencia a algunos de los espacios de nombres de ADO.NET. (Recuerde
que hacer referencia significa acceder a un DLL de .NET en un proyecto y usar sus tipos en
su cdigo.) Antes de usarlos en el cdigo, necesitamos crear referencias a ellos. Esto se hace a
travs de la ventana de propiedades del proyecto, en la ficha Referencias. Ver una lista de los
ensamblados a los que ya hace referencia la aplicacin (vase la figura 10-9).

Figura 10-9. Referencias incluidas en el Proyecto Biblioteca.

Para agregar una nueva referencia, haga clic en el botn Agregar, que se encuentra justo debajo
de la lista, y seleccione Referencia, si se le pregunta el tipo de referencia que se agregar. En el
formulario Agregar referencia, la ficha .NET debe estar activa. Es muy sorprendente ver cuntos
ensamblados .NET estn ya instalados en su sistema. Pero no se siente slo a ver lo que pasa:
seleccione System.Data y System.Xml de la lista de componentes, y luego haga clic en el botn
Aceptar. La lista de referencias en las propiedades del proyecto deben incluir ahora las bibliotecas
seleccionadas de espacio de nombres.
Ahora podemos hacer referencia directa a las clases del espacio de nombres System.Data. Pero
escribir System.Data antes de cada uso de una clase relacionada con datos ser tedioso. Po-
demos salpicar con instrucciones Imports System.Data todos los archivos del proyecto, pero
Visual Studio proporciona una solucin ms centralizada. Como an tiene abierta la ficha Refe-
rencias, revise abajo, la seccin Espacios de nombres importados. La larga lista de verificacin
indica cules espacios de nombres deben importarse automticamente a travs de su aplicacin.
Estos espacios no requieren instrucciones Imports separadas en su cdigo, pero ste acta como

Proyecto | 295

10_PATRICK-CHAPTER_10.indd 295 17/2/10 15:25:48


si ya los hubiera agregado. Siga adelante y seleccione la casilla de verificacin junto a la entrada
System.Data en esta lista. Luego cierra la ventana de propiedades del proyecto.
La mayor parte del nuevo cdigo de este captulo aparece en el archivo General.vb, de modo
que bralo ahora. Usaremos dos variables en el nivel del proyecto (global) para administrar
la conexin con la base de datos principal de la base de datos Biblioteca. La primera varia-
ble, BibliotecaBD, es un objeto SqlConnection que usa nuestra cadena de conexin con la
base de datos Biblioteca. Un objeto relacionado, SostenerTransac, contendr un objeto Sql
Transaction cuando se realice una transaccin. Agregue estas dos lneas al mdulo General.
Las puse antes del mtodo CenterText.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap10, Elemento 1.

Public BibliotecaBD As System.Data.SqlClient.SqlConnection


Public SostenerTransac As System.Data.SqlClient.SqlTransaction

Conexin a la base de datos


Como el Proyecto Biblioteca depender demasiado de la base de datos, construiremos el objeto
SqlConnection cuando empecemos la aplicacin.

Mantener la conexin a travs de toda la aplicacin es contrario al consejo


que proporcion antes, de que las conexiones de base de datos deben tener
una vida corta. Sin embargo, para mantener el cdigo lo ms simple po-
sible para los fines de la demostracin de tutorial, he elegido este mtodo.
Adems, como el Proyecto Biblioteca est diseado para una base de insta-
lacin pequea, no tiene el requisito de ser muy escalable.

El procedimiento ConectarBaseDeDatos contiene todo el cdigo necesario para crear este ob-
jeto. Por ahora, inclu en cdigo la cadena de conexin en la rutina. En un captulo posterior,
incluiremos esa informacin de conexin como parte de un sistema de configuracin. Agregue
la siguiente rutina a su mdulo General. Asegrese de cambiar la referencia a MISISTEMA
por cualquier cosa que sea necesario en su propio sistema.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap10, Elemento 2.

Public Function ConectarBaseDeDatos() As Boolean


' ----- Conectar a la base de datos. Regresar True si es correcto.
Dim cadenaConexion As String

' ----- Inicializar.

296 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 296 17/2/10 15:25:48


SostenerTransac = Nothing
' ----- Construir la cadena de conexion.
' !!! CUIDADO: Incluido en el codigo, por ahora.
cadenaConexion = "Data Source=MISISTEMA\SQLEXPRESS;" & _
"Initial Catalog=Biblioteca;Integrated Security=true"

' ----- Tratar de abrir la base de datos.


Try
BibliotecaBD = New SqlClient.SqlConnection(cadenaConexion)
BibliotecaBD.Open()
Catch ex As Exception
ErrorGeneral("ConectarBaseDeDatos", ex)
Return False
End Try

' ----- Correcto.


Return True
End Function

La rutina principal de este proyecto es en realidad el evento de aplicacin MyAplication_


Startup, del archivo de cdigo fuente AplicationEvents.vb. (Tiene que usar el botn Mostrar
todos los archivos para verlos.) Para construir el objeto de conexin al principio, agregue el
siguiente cdigo al final de ese manejador de eventos.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap10, Elemento 3.

' ----- Conectar a la base de datos.


If (ConectarBaseDeDatos() = False) Then
Me.HideSplashScreen()
e.Cancel = True
Return
End If

Cuando el usuario sale de la aplicacin Biblioteca, el cdigo llamar al mtodo LimpiarPro-


grama para disponer adecuadamente del objeto de conexin. Regrese al mdulo General.vb y
agregue ese mtodo.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap10, Elemento 4.

Public Sub LimpiarPrograma()


' ----- Preparar para salir del programa.
On Error Resume Next
BibliotecaBD.Close()
End Sub

Proyecto | 297

10_PATRICK-CHAPTER_10.indd 297 17/2/10 15:25:48


Para simplificar las cosas, llamaremos a esta rutina desde el manejador de eventos MyAplica-
tion_Shutdown, de nuevo en el archivo AplicationEvents.vb.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap10, Elemento 5.

LimpiarPrograma()

Interaccin con la base de datos


Ahora que se ha establecido la conexin con la base de datos, es hora de hacer algo con ella. Las
primeras cuatro rutinas centralizadas implementan gran parte del cdigo que analizamos antes:
la creacin de los lectores de datos y las tablas, y el procesamiento del cdigo SQL general. Agr-
guelo al mdulo General.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap10, Elemento 6.

Este fragmento agrega las siguientes siete rutinas:


Function CrearTablaDatos
Dada una instruccin SQL, recupera sus resultados de la base de datos, y los pone en un
objeto DataTable. Un SqlDataAdapter conecta el SqlDataReader con DataTable.
Function CrearLector
Dada una instruccin SQL, recupera sus resultados de la base de datos, devolviendo el ob-
jeto SqlDataReader asociado.
Sub EjecutarSQL
Enva una instruccin SQL a la base de datos para procesamiento.
Function EjecutarSQLRegresar
Enva una instruccin SQL a la base de datos para procesamiento, regresando un solo valor
de resultado.
Sub EmpezarTransac
Empieza una nueva transaccin.
Sub ConfirmarTransac
Confirma la transaccin, haciendo todos los cambios permanentes.
Sub RevertirTransac
Revierte la transaccin, deshaciendo cualquier cambio que haya sido parte de la transaccin.
Ninguna de estas rutinas incluye su propio cdigo de procesamiento de errores; suprimen erro-
res con una instruccin On Error Resume Next, o dependen de la rutina de llamada para

298 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 298 17/2/10 15:25:48


atrapar errores. Esto permite que la rutina que llama tome una accin especfica con base en
el tipo de error generado. Todas estas rutinas son muy similares entre s. He aqu el cdigo de
CrearLector; una parte interesante es el uso del objeto SostenerTransac cuando se realiza
una transaccin.
Public Function CrearLector(ByVal sqlText As String) _
As SqlClient.SqlDataReader
' ----- Dada una instruccion SQL, devuelve un lector de datos.
Dim comandoBD As SqlClient.SqlCommand
Dim rastreoBD As SqlClient.SqlDataReader

' ----- Tratar de ejecutar la instruccion. Observe que no se


' atrapan errores aqu. Depende de la rutina de llamada
' para configurar la verificacion de errores.
comandoBD = New SqlClient.SqlCommand(sqlText, BibliotecaBD)
If Not (SostenerTransac Is Nothing) Then _
comandoBD.Transaction = SostenerTransaction
rastreoBD = comandoBD.ExecuteReader(
)
comandoBD = Nothing
Return rastreoBD
End Function

Procesamiento de valores de datos


La generacin de instrucciones SQL a mano incluye una gran cantidad de manipulacin de cadenas,
adems de procesamiento condicional para la ocasin en que faltan datos. Por ejemplo, si quiere
almacenar un valor de texto en la base de datos, tiene que prepararla para usar una instruccin SQL
(procesamiento especial para comillas individuales), pero si el valor del texto es de longitud cero,
pasa, en cambio, la palabra NULL en la instruccin. Toda esta preparacin de datos puede asfixiar
su cdigo, de modo que por qu no centralizarlo? Las ocho rutinas de esta seccin preparan los
datos para uso en instrucciones SQL o ajustan los datos recuperados para usarlos en la aplicacin.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap10, Elemento 7.

ComboBD
Toma el cdigo numrico asociado con un elemento en un control ComboBox y lo de-
vuelve como una cadena. Si no se selecciona un elemento o si el valor es 1, la rutina
devuelve NULL.
FechaBD(String)
Dada una cadena que contiene una fecha formada, devuelve una fecha lista para usarse en
una instruccin SQL.
FechaBD(Date)
Dado un valor de fecha verdadero, devuelve una fecha de cadena lista para usar en una instruccin
SQL.

Proyecto | 299

10_PATRICK-CHAPTER_10.indd 299 17/2/10 15:25:48


ObtenerDecimalBD
Devuelve un nmero decimal de un conjunto de resultados, aunque el campo contenga un
valor NULL.
ObtenerEnteroBD
Devuelve un nmero entero de un conjunto de resultados, aunque el campo contenga un
valor NULL.
ObtenerTextoBD
Devuelve una cadena de un conjunto de resultados, aunque contenga un valor NULL.
NumBD
Prepara un nmero para usarlo en una instruccin SQL.
TextoBD
Prepara una cadena para usarla en una instruccin SQL.
He aqu el cdigo para la rutina TextoBD. Las cadenas en las instrucciones SQL deben estar
entre comillas individuales, y cualquier comilla individual incrustada debe duplicarse.
Public Function TextoBD(ByVal textoOrigen As String) As String
' ----- Preparar una cadena para insercion en una instruccion SQL.
If (Trim(textoOrigen) = "") Then
Return "NULL"
Else
Return "'" & Replace(textoOrigen, "'", "''") & "'"
End If
End Function

Configuracin en el nivel del sistema


Los ltimos bloques de cdigo dan soporte a la actualizacin rpida y la recuperacin de valores
de configuracin de todo el sistema almacenados en la tabla ValorSistema de la base de da-
tos Biblioteca. La rutina ObtenerValorSistema devuelve los parmetros actuales de un valor
de configuracin cuando se proporciona con el nombre del valor. EstablecerValorSistema
actualizacin (o agrega, si es necesario) un valor de configuracin con nombre. Ambas rutinas
aparecen en el mdulo General.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap10, Elemento 8.

Public Function ObtenerValorSistema( _


ByVal nombreValor As String) As String
' ----- Regresar la parte de datos de un para nombre
' valor-datos del sistema.
Dim textoSql As String
Dim valorRegreso As String

' ----- Recuperar el valor.

300 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 300 17/2/10 15:25:48


valorRegreso = ""
textoSql = "SELECT DatosValor FROM ValorSistema WHERE " & _
"UPPER(NombreValor) = " & TextoBD(UCase(nombreValor))
Try
valorRegreso = ObtenerTextoBD(EjecutarSQLRegresar(textoSql))
Catch ex As Exception
ErrorGeneral("ObtenerValorSistema", ex)
End Try
Return valorRegreso
End Function

Public Sub EstablecerValorSistema(ByVal nombreValor As String, _


ByVal datosValor As String)
' ----- Actualizar un registro en la tabla ValorSistema.
Dim textoSql As String

Try
' ----- Ver si ya existe la entrada.
textoSql = "SELECT COUNT(*) FROM ValorSistema WHERE " & _
"UPPER(NombreValor) = " & TextoBD(UCase(nombreValor))
If (CInt(EjecutarSQLRegresar(textoSql)) > 0) Then
' ----- El valor ya existe.
textoSql = "UPDATE ValorSistema " & _
"SET DatosValor = " & TextoBD(datosValor) & _
" WHERE UPPER(NombreValor) = " & _
TextoBD(UCase(nombreValor))
Else
' ----- Se necesita crear un valor.
textoSql = "INSERT INTO ValorSistema " & _
(NombreValor, DatosValor) VALUES (" & _
TextoBD(nombreValor) & ", " & _
TextoBD(datosValor) & ")"
End If

' ----- Actualizar el valor.


EjecutarSQL(textoSql)
Catch ex As System.Exception
ErrorGeneral("EstablecerValorSistema", ex)
End Try
End Sub

La rutina ObtenerValorSistema es clara. Simplemente recupera un solo valor de la base de


datos. EstablecerValorSistema tiene que revisar primero si el valor de cdigo que se habr
de actualizar existe en la base de datos. Si es as, modifica los registros. De otra manera, agrega
un nuevo registro completo. Para determinar si existe el registro, solicita una cuenta de registros
que coinciden con el nombre del valor del sistema. Consulta la base de datos a travs del mtodo
EjecutarSQLRegresar, que devuelve un solo valor de la consulta. En este caso, el valor es la
cuenta de registros coincidentes.
textoSql = "SELECT COUNT(*) FROM ValorSistema WHERE " & _
"UPPER(NombreValor) = " & TextoBD(UCase(nombreValor))
If (CInt(EjecutarSQLRegresar(textoSql)) > 0) Then

Proyecto | 301

10_PATRICK-CHAPTER_10.indd 301 17/2/10 15:25:48


El uso de la rutina ObtenerValorSistema es fcil, de modo que usmosla de inmediato. Re-
grese al manejador de eventos MyAplication_Startup en AplicationEvents.vb, y agregue el
siguiente cdigo al final de la rutina.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap10, Elemento 9.

' ----- Revisar la version de la base de datos.


Dim versionBDproduccion As String
versionBDproduccion = Trim(ObtenerValorSistema("VersionBaseDatos"))
If (CInt(Val(versionBDproduccion)) <> UsarVersionBD) Then
MsgBox("El programa no puede seguir debido a una " & _
" base de datos incompatible. La version de la base " & _
"de datos actual es '" & versionBDproduccion & _
"'. La version de la aplicacion es '" & _
UsarVersionBD & "'.", _
MsgBoxStyle.OkOnly Or MsgBoxStyle.Critical, TituloPrograma)
LimpiarPrograma()
Me.HideSplashScreen()
e.Cancel = True
Return
End If

De vez en cuando, me resulta necesario modificar la estructura de una base de datos, a tal medida
que las versiones anteriores de una aplicacin dejan de funcionar o causaran dolores de cabeza
importantes. Para evitarlo, agregu un parmetro de versin de base de datos, VersionBaseDa-
tos, y uso este bloque de cdigo para probarlo. Si el programa no coincide con la versin de la
base de datos esperada, se rehusar a ejecutarla.
Ahora que tenemos algunas herramientas bsicas de acceso a base de datos, estamos listos para
empezar a agregar algn cdigo de interaccin con datos reales a la aplicacin Biblioteca.

302 | Captulo 10:ADO.NET

10_PATRICK-CHAPTER_10.indd 302 17/2/10 15:25:48


Captulo 11
Seguridad

Los secretos son divertidos. Con miles de millones de personas en el planeta, no estamos cortos
de eventos e historias realmente interesantes, pero ninguna de ellas mantendr nuestra atencin si
hay algn secreto por descubrir en algn otro lugar. Por ejemplo, el anterior director asociado del
FBI, W. Mark Felt, confirm que l era el famoso Garganta Profunda del caso Watergate, pero
no antes de 30 aos de especulacin y cuchicheos acerca de esa identidad secreta. Otros secretos
son igual de intrigantes, aunque conozcamos parte de l. Superman es fascinante en parte debido
a su otro yo secreto, Clark Kent. Muchos libros incluyen la palabra Secreto en su ttulo para hacer
que el libro y su tema sean ms interesantes, como en Los secretos de la cocina japonesa.
En esta era de sobrecarga de la informacin y de estndares morales cada vez ms permisivos
en la televisin, los secretos parecen escasear. Pero todos tienen informacin importante que
necesitan mantener protegida de los dems, y que incluye a los usuarios de sus programas. Por
fortuna, los programas de .NET y los datos relacionados pueden asegurarse de acuerdo con sus
necesidades, si usa las caractersticas de seguridad disponibles en .NET Framework.
He aqu un secreto que le dir justo ahora: no s mucho acerca de problemas de seguridad en equipos
de cmputo. A principios de la dcada de 1980, trabaj para un vendedor de computadoras que esta-
ba saliendo con su propia implementacin del System V de Unix. La compaa necesitaba confirmar
que su producto sera lo suficientemente seguro para ventas gubernamentales, y se me encarg la tarea
de construir una bibliografa de recursos de seguridad computacionales, incluido el famoso Libro
naranja, un documento de estndares de seguridad gubernamentales cuyo ttulo no rima con nada.
Aunque no recuerdo muchos de los detalles de seguridad, s recuerdo que se necesitaran los
camiones de basura de varias ciudades para disponer de todos los materiales con que se cuenta
en seguridad computacional. La bibliografa que desarroll tena ms de 40 pginas! Y slo era
la tabla de contenido. Un artculo que recuerdo era muy interesante. Analizaba la manera en
que las contraseas se generaban en los sistemas Unix, al menos cuando AT&T estaba a cargo
de ste. La parte interesante era que todo el algoritmo estaba impreso en un libro disponible
pblicamente. Cualquiera podra examinar el libro y ver cmo se generaban las contraseas. Y si
estaba familiarizado con Unix, saba que cada contrasea cifrada de usuario estaba almacenada
en texto simple en el archivo /etc/passwd. Pero no era muy importante.

303

11_PATRICK-CHAPTER_11.indd 303 17/2/10 15:26:22


Aunque el mtodo para derivar la contrasea era del conocimiento pblico, y aunque podra ver
las contraseas cifradas de cualquiera, Unix an se consideraba lo suficientemente seguro como
para usarlo en la milicia.

Caractersticas de seguridad en .NET


La seguridad en .NET incluye muchas caractersticas, pero por lo general caen en tres reas
principales:
Seguridad interna
Las clases y los miembros de clase en .NET pueden protegerse mediante seguridad basada
en usuario o en funcin. Esta seguridad de cdigo de acceso (CAS, Code Access Security)
existe para evitar que los usuarios no autorizados accedan a las poderosas bibliotecas de ca-
ractersticas de .NET. Slo los usuarios que cumplen con un conjunto mnimo o especfico
de derechos pueden usar esas caractersticas protegidas.
Seguridad externa
Debido a que cualquiera puede desarrollar y distribuir una aplicacin .NET, es importante
proteger de cdigo malicioso a los recursos del sistema. ste es un gran problema, sobre
todo con los reportes continuos de hackers que aprovechan los problemas de desborda-
miento de bfer en software de Microsoft y otros. Al igual que CAS evita que el cdigo
acceda a ciertas caractersticas de clase, interacta con el sistema operativo para evitar que
cdigo falso acceda a algunos o todos los artculos y directorios, entradas de registro, recur-
sos de red, perifricos de hardware u otros ensamblados de .NET basados en directivas de
seguridad aplicadas.
Seguridad de datos
Los programas y recursos computacionales no son los nicos que necesitan protegerse. Al-
gunos usuarios pomposos piensan que sus preciosos datos son tan importantes que merecen
ser protegidos con medios de seguridad especiales. Cifrado, firmas digitales y otras carac-
tersticas criptogrficas proporcionan el soporte especial necesario para esos datos.
Debido a que Proyecto Biblioteca interacta con un recurso externo importante (una base de
datos de SQL Server), trata con problemas de seguridad externos, aunque de manera indirecta
a travs de ADO.NET y directivas de seguridad del sistema. An as, debido a que el enfoque
de este libro est puesto en el desarrollo de aplicaciones de negocios tpicas, en este captulo no
se analizarn los temas de seguridad interna ni externa. En cambio, se concentrar en temas de
seguridad de datos, sobre todo el cifrado de datos.

Criptografa y cifrado
Conocer un secreto es una cosa. Mantenerlo seguro y protegido de los dems es otra. Asegurarse
de que un enemigo no lo modifique mientras estamos pasndolo (quiero decir, confindolo) a
alguien ms es otro tema. Confirmar que un secreto que viene de alguien ms es confiable es
otro tema. Asegurarse de que obtenga el mejor trato en un seguro de automviles es un asunto
completamente diferente.

304 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 304 17/2/10 15:26:22


Evidentemente, la seguridad de los datos se relaciona en gran medida con mantener una pieza de
datos protegida de los ojos que nos espan. Y no slo son estos ojos los que nos preocupan. Hace
poco, experiment la pantalla azul de la muerte de Windows cuando trataba de sincronizar los
datos de mi sistema de escritorio con mi agenda electrnica de bolsillo. La posibilidad de corrup-
cin de datos a travs del uso normal diario de la tecnologa es muy amplia. Por fortuna, el pro-
cesador de palabra que estoy usando para procesar este captulo est libr d esa rpci#

Conservar secretos
Cuando las personas piensan en el cifrado y la seguridad de los datos, por lo general se concen-
tran en el aspecto de conservar los secretos. La capacidad para cifrar el contenido criptogr-
ficamente, mantenerlo lejos de un adversario y an conservar la posibilidad de que usted o un
asociado lo pueda descifrar en un momento posterior resulta importante. Las tcnicas de cifrado
van desde las simples aberraciones del lenguaje (como el uso del latn) y las cifras de reemplazo
(sustitucin de letras, usado en los criptogramas) hasta los sistemas de codificacin complejos de
calidad tipo enigma.
El cifrado por software es ahora una parte de la experiencia diaria. Cuando hace compras con
tarjeta de crdito de sitios Web, hay muchas posibilidades de que la informacin de su tarjeta sea
cifrada y transferida con una fidelidad de secreto de 128 bits.
Los mtodos de cifrado usa una o ms claves, adems de una combinacin de funciones de hash
y algoritmos de cifrado, para convertir contenido confidencial en una forma a la que no se tiene
acceso fcil sin la clave original o relacionada. Criptografa simtrica es el nombre usado por m-
todos de cifrado que emplean una sola clave secreta.
El cifrado de clave pblica (tambin conocido como criptografa asimtrica) usa un par de claves
para cifrar y descifrar datos. Una de las claves, una clave pblica, puede darse a cualquier que se
preocupe de comunicarse con usted de manera segura. Puede incluso darla a sus enemigos; es p-
blica. La clave privada relacionada se mantiene segura para que usted la use; nunca la debe mostrar
a nadie, ni siquiera a su madre. El contenido cifrado con una de las claves (y un algoritmo de cifra-
do) slo puede descifrarse ms adelante usando la otra clave. Si su amigo cifra alguna informacin
empleando la clave pblica, nadie excepto usted podr descifrarlo, y requerir su clave privada.
Tambin puede cifrar datos con su clave privada, pero cualquiera podra descifrarlos con la clave
pblica. Veremos los usos para esta accin aparentemente insegura un poco ms adelante.

Estabilidad de los datos


El cifrado de datos ayuda a asegurar la integridad de un bloque de datos, aunque esos datos no
estn cifrados. Si enva a alguien un correo electrnico durante una tormenta, hay posibilidades
de que parte o todo el contenido del correo electrnico pueda modificarse electrnicamente
antes de llegar al destinatario. Digamos que simplemente se presenta esttica en la lnea de trans-
misin para provocar que una frase del contenido se duplique. Cmo sabra si el autor trataba
de hacer algo inteligente o simplemente fue un error computacional?

Criptografa y cifrado | 305

11_PATRICK-CHAPTER_11.indd 305 17/2/10 15:26:22


La inclusin de una suma de verificacin con el contenido puede ayudarle a identificar proble-
mas de datos durante la transmisin. Una suma de verificacin (a veces llamada valor de hash)
toma el contenido original y lo pasa a travs de una funcin que genera un valor corto que
representa los datos originales. Las funciones de suma de verificacin (o algoritmos de hash) son
muy sensibles aun a cambios de un solo byte en el contenido, si ese solo byte fue alterado, reubi-
cado, agregado o eliminado de los datos originales. Al generar una suma de verificacin antes
y despus de la transmisin de datos puede confirmar si el contenido cambi en algo durante
la transferencia.
Las sumas de verificacin representan un cifrado unidireccional de los datos originales. Es imposi-
ble usar la suma de verificacin para obtener el contenido de datos original. Sin embargo, eso es
correcto, porque el objetivo de una suma de verificacin no es entregar contenido secretamente,
sino entregarlo sin cambios. De lo que habl en la seccin Conservar secretos, es del cifrado
bidireccional. Si tiene la clave correcta y el algoritmo correcto, el cifrado bidireccional restaura el
contenido original del contenido cifrado.

Verificacin de identidad
Digamos que recibe un correo electrnico de su jefe que dice Ordene 50 ejemplares del nuevo
libro de Tim Patrick, y que sea de prisa. Cmo sabe que este mensaje es confiable, o provie-
ne realmente de su jefe? En este caso, el solo contenido debe probar que es confiable. Pero si
realmente quisiera verificar la fuente, y su jefe no estuviera disponible, podra emplear firmas
digitales para confirmar la identidad del remitente.
El mtodo de firmas digitales emplea cifrado de clave pblica para trasmitir una contrasea o
un mensaje con el que est de acuerdo, y pasar el contenido cifrado con un correo electrnico
ms largo. Por ejemplo, su jefe podra cifrar el texto Soy el jefe empleando su clave privada.
Cuando reciba el correo electrnico podra descifrar la firma digital empleando la clave pblica
de su jefe. Si al descifrar se obtiene el mensaje Soy el jefe, sabra que el mensaje lo hizo, en
realidad, su jefe.

Cifrado en .NET
Las caractersticas de cifrado de datos y seguridad incluidas con .NET aparecen en el espacio
de nombres System.Security.Cryptography. La mayor parte de las clases en este espacio de
nombres implementan varios algoritmos de cifrado bien conocidos que han sido aceptados por
organizaciones y gobiernos como estndares de cifrado confiables. Por ejemplo, la clase DES-
CryptoServiceProvider proporciona caractersticas basada en el algoritmo de estndar de
cifrado de datos (DES, Data Encryption Standard), un algoritmo desarrollado originalmente
por IBM a mediados de la dcada de 1970.

306 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 306 17/2/10 15:26:23


Criptografa simtrica
La criptografa simtrica usa una sola clave secreta para cifrar y descifrar un bloque de datos.
Aunque estos algoritmos suelen ser muy rpidos (cuando se compara con la criptografa asim-
trica), la necesidad de proporcionar la clave secreta completa a otros para compartir datos puede
hacerlos inherentemente menos seguro. Sin embargo, para muchas aplicaciones, el cifrado de
clave secreta es suficiente.
.NET Framework incluye compatibilidad con cuatro algoritmos de cifrado simtrico:
El estndar de cifrado de datos (DES), un cifrado de bloque de 56 bits con soporte principal a
travs de la clase DESCryptoServiceProvider. Este algoritmo suele ser seguro, pero debi-
do a su tamao de clave pequea (las claves ms pequeas se comprometen ms fcilmente),
es inapropiado para datos demasiado confidenciales.
RC2 (Rivest Cipher nmero 2), un cifrado de bloque de 56 bits con soporte principal a travs de
la clase RC2CryptoServiceProvider. Al principio, Lotus desarroll el cifrado para usarlo
en su producto Lotus Notes. No es arrebatadamente seguro, pero por esta razn, se le han
dado libertades de exportacin ms favorables por parte del gobierno de Estados Unidos.
Rijndael (derivado de los nombres de sus dos diseadores, Daemen and Rijmen), un ci-
frado de bloque de bits variables (entre 128 y 256 bits) con soporte principal en la clase
RijndaelManaged. Est relacionado con un algoritmo similar llamado estndar de cifrado
avanzado (AES, Advanced Encryption Standard), y es el ms seguro de los algoritmos de
clave secreta proporcionado con .NET.
Triple DES, un cifrado de bloque que usa el algoritmo DES tres veces para generar un resultado
seguro, con el soporte principal en la clase TripleDESCryptoServiceProvider. Aunque
ms seguro que el DES simple, aun es mucho ms vulnerable que el estndar Rijndael o AES.
Las diversas clases de proveedor son herramientas que deben usarse junto con otras clases crip-
togrficas para funcionar apropiadamente. Por ejemplo, este cdigo de ejemplo (basado en cdi-
go encontrado en la documentacin de MSDN) usa las clases DESCryptoServiceProvider y
CryptoStream, ambas miembros de System.Security.Cryptography, para cifrar y descifrar
de manera conjunta un bloque de texto:
Imports System
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography

Class CryptoMemoryStream
Public Shared Sub Main()
' ----- Cifrar y descifrar algun texto.
Dim clave As New DESCryptoServiceProvider
Dim versionCifrada() As Byte
Dim versionDescifrada As String

Cifrado en .NET | 307

11_PATRICK-CHAPTER_11.indd 307 17/2/10 15:26:23


' ----- Primero, cifrar algun texto.
versionCifrada = Encrypt("Esto es un secreto.", clave)

' ----- Luego, descifrarlo para obtener el original.


versionDescifrada = Descifrar(versionCifrada, clave)
End Sub

Public Shared Function Cifrar(textoOriginal As String, _


clave As SymmetricAlgorithm) As Byte( )
' ----- Usar un flujo de memoria criptografica y un
' proveedor de clave secreta (DES en este caso)
' para cifrar cierto texto.
Dim flujoBase As New MemoryStream
Dim flujoSecreto As CryptoStream
Dim flujoSalida As StreamWriter
Dim textoCifrado() As Byte

' ----- Un flujo de memoria solo baraja datos de extremo


' a extremo. Agregar CryptoStream a este
' cifrara los datos mientras se mueve por el
' flujo.
flujoSecreto = New CryptoStream(flujoBase, _
clave.CreateEncryptor(), CryptoStreamMode.Write)
flujoSalida = New StreamWriter(flujoSecreto)
flujoSalida.WriteLine(textoOriginal)
flujoSalida.Close()
flujoSecreto.Close()

' ----- Mover el contenido cifrado en una matriz


' de bytes utiles.
textoCifrado = flujoBase.ToArray(
)
flujoBase.Close()
Return textoCifrado
End Function

Public Shared Function Descifrar(textoCifrado(


) As Byte, _
clave As SymmetricAlgorithm) As String
' ----- Evidentemente, esto es lo opuesto de la funcion
' Cifrar(), empleando un lector de flujo
' en lugar de un escritor, y el "descifrador"
' de la clave en lugar del "cifrador".
Dim flujoBase As MemoryStream
Dim flujoSecreto As CryptoStream
Dim flujoEntrada As StreamReader
Dim textoOriginal As String

' ----- Construir un flujo que descifra automaticamente


' los datos que pasan.
flujoBase = New MemoryStream(textoCifrado)
flujoSecreto = New CryptoStream(flujoBase, _
clave.CreateDecryptor(), CryptoStreamMode.Read)
flujoEntrada = New StreamReader(flujoSecreto)

308 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 308 17/2/10 15:26:23


' ----- Mover el contenido descifrado de regreso a una cadena.
textoOriginal = flujoEntrada.ReadLine(
)
flujoEntrada.Close()
flujoSecreto.Close()
flujoBase.Close()
Return textoOriginal
End Function
End Class

Este cdigo combina una clave de cifrado DES con un flujo, una herramienta comn en las
aplicaciones .NET para transferir datos de un estado o ubicacin a otro. (Los flujos son un
mtodo primario usado para leer y escribir archivos.) No es demasiado difcil usar los flujos,
pero el cdigo an parece un poco complejo. Por qu la clase DESCryptoServiceProvider
no simplemente incluye los mtodos Cifrar y Descifrar? sa es mi pregunta, al menos. Estoy
seguro de que tiene algo que ver con mantener la clase genrica para usarlo en muchos entornos
de datos. Aun as, por muy fragmentado que sea este cdigo, seguro que es ms fcil que escribir
yo mismo el cdigo de cifrado. Y es lo bastante general como para cambiar uno de los otros
algoritmos de clave secreta, sin mucho cambio en el cdigo.

Criptografa asimtrica
En la criptografa de clave secreta, puede usar cualquier clave antigua que desee para dar soporte
al proceso de cifrado y descifrado. Siempre y cuando lo mantenga en secreto, el contenido de la
propia clave en realidad no es demasiado importante. Sin embargo, no puede decirse lo mismo
de la criptografa asimtrica (de clave pblica). Debido a que se usan claves separadas para cifrar
y descifrar los datos, deben crearse claves privadas y pblicas especficas de manera especfica
como un par. No puede slo seleccionar claves pblicas y privadas al azar y esperar que funcio-
nen en conjunto.
Los componentes usados para dar soporte a la criptografa asimtrica incluyen generadores
que emiten pares de clave pblica y privada. Una vez generadas, estas claves pueden usarse en su
cdigo para enmascarar datos confidenciales. Y debido al tamao de clave ms grande, es muy
difcil hackear sus datos cifrados.
El cifrado de clave pblica es notoriamente lento; se toma una eternidad ms un da codificar
grandes cantidades de datos usando la clave de origen. sta es una de las razones por las que
los padres fundadores no usaron el cifrado de clave pblica en la declaracin de independencia.
Debido al rendimiento lento del cifrado asimtrico, muchos sistemas de datos seguros usan una
combinacin de cifrado de clave pblica y de clave secreta para proteger datos. La autorizacin
inicial ocurre con los procesos de clave pblica, pero una vez que se abre el canal seguro, los datos
pasados entre los sistemas se cifran usando mtodos de clave secreta ms rpidos.
.NET incluye dos clases de criptografa de clave pblica para su placer de cifrado y descifrado:
El algoritmo de firma digital (DSA, Digital Signature Algorithm), un algoritmo diseado
por el gobierno de Estados Unidos para usarse en firmas digitales, con soporte principal
mediante la clase DSACryptoServiceProvider.

Cifrado en .NET | 309

11_PATRICK-CHAPTER_11.indd 309 17/2/10 15:26:23


El algoritmo RSA (llamado as por sus fundadores Ron Rivest, Adi Shamir y Len Adleman),
un algoritmo asimtrico antiguo aunque generalmente seguro, con soporte primario en la
clase RSACryptoServiceProvider.
Usaremos cifrado simtrico en el Proyecto Biblioteca, pero slo hasta un captulo posterior. Aun
entonces, no entrar en mucho detalle acerca de la manera en que funciona el cifrado asimtrico.
Aunque los antecedentes sobre la generacin de nmeros primos y la factorizacin de grandes
nmeros son fascinantes, esos anlisis estn ms all del alcance de este libro.

Uso de hash
Aunque los algoritmos de hash no le dan la capacidad de cifrar y descifrar datos a voluntad, son
tiles para dar soporte a sistemas que aseguran y verifican el contenido de los datos. Usaremos algo
de hash en datos en el cdigo del proyecto de este captulo, de modo que mantngase alerta.
Es fcil crear un algoritmo de hash. Se necesitaron las mejores mentes de la National Security
Agency y el Massachusetts Institute of Technology para generar sistemas de cifrado confiables de
clave secreta y clave pblica, pero puede desarrollar un algoritmo de hash en slo unos minutos.
Hace unos aos escrib mi propio algoritmo de hash que us durante aos en aplicaciones de
negocios. Ese hecho, por s solo, debe probar lo simple y bsico que pueden ser. He aqu un
algoritmo de hash que acabo de escribir mientras estaba sentado:
Public Function HashCiertotexto(ByVal textoOriginal As String) As Long
' ----- Crear un valor de hash de ciertos datos.
Dim valorHash As Long = 0&
Dim contador As Long

For contador = 1 To Len(textoOriginal)


valorHash += Asc(Mid(textoOriginal, contador, 1))
If (valorHash > (Long.MaxValue * 0.9)) Then _
valorHash /= 2
Next contador
Return valorHash
End Function

En el cdigo, slo sumo los valores ASCII de cada carcter en la cadena de texto, y regreso
el resultado. Hago una revisin en el bucle para asegurar de que no excedo el 90% del valor
mximo Long; no quiero desbordar la variable valorHash y generar un error. Aunque Hash-
Ciertotexto genera una representacin de hash de los datos de entrada, tambin tiene algunas
deficiencias:
Es muy fcil adivinar a partir del valor de hash si el contenido entrante era corto o largo. El
contenido ms corto por lo general generar nmeros pequeos, y los valores de salida ms
largos tienden a indicar contenido de entrada ms largo.
No es muy sensible a algunos tipos de cambios de contenido. Por ejemplo, si reorganiza
varios caracteres en el contenido, probablemente no tendr impacto en el valor de hash. El
cambio de un carcter tendr impacto en el valor, pero si cambia un carcter de A a B y otra
letra cercana de T a S, el valor de hash permanecer sin cambio.

310 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 310 17/2/10 15:26:23


Cuanto ms corto sea el contenido, mayores sern las posibilidades de que dos entradas
generen el mismo valor de hash.
Tal vez quiera algo un poco ms robusto. As que .NET incluye varias herramientas de hash:
Cdigo de autenticacin de mensajes mediante hash /HMAC, Hash-based Message Authenti-
cation Code. Se calcula usando el algoritmo de la funcin de hash seguro nmero 1 (SHA-1,
Secure Hash Algorithm number 1), disponible mediante la clase HMACSHA1. Usa un cdigo
de hash de 160 bits. No hay restricciones especficas sobre la longitud de la clave secreta
usada en el clculo. Aunque es adecuado para situaciones de bajo riesgo, el algoritmo SHA-1
es susceptible al ataque.
Cdigo de autentificacin de mensajes (MAC, Message Authentication Code). Se calcula
usando los algoritmos de clave secreta Triple-DES (descritos antes), disponibles mediante
la clase MACTripleDES. La clave secreta usada en el clculo es de 16 o 24 bytes de largo y el
valor generado es de 8 bytes de largo.
Algoritmo de compendio de mensajes nmero 5 (MD5, Message-Digest 5). Clculo de hash,
disponible mediante la clase MD5CryptoServiceProvider. MD5 es otro algoritmo su-
persecreto diseado por Ron Rivest (el tipo es sorprendente), pero se ha demostrado que
incluye algunos errores que podran hacer que su cifrado constituya un riesgo de seguridad.
El valor de hash resultante es de 128 bits de largo.
Como la clase HMACSHA1, la SHA1Managed calcula un valor de hash empleando la funcin
de hash SHA-1. Sin embargo, est escrito usando slo cdigo administrado por .NET.
HMACSHA1 y alguna otras caractersticas criptogrficas en .NET son slo envolturas alrede-
dor de la API de criptografa (CAPI, Cryptography API), una DLL antes de .NET DLL.
SHA1Managed usa un cdigo de hash de 160 bits.
Otras tres clases (SHA256Managed, SHA384Managed y SHA512Managed) son similares a
SHA1Managed, pero usa cdigos de hash de 256, 384 y 512 bits, respectivamente.
Cada uno de estos algoritmos usa una clave secreta que debe incluirse cada vez que se genera el
hash contra el mismo conjunto de datos de entrada. Siempre y cuando los datos de entrada se
mantengan sin cambio, y la clave secreta sea la misma, el valor de hash resultante se mantendr
sin cambio. Por diseo, aun el cambio ms pequeo en los datos de entrada generan cambios
mayores en el valor de hash de salida.

Otras caractersticas de seguridad


Hay otros elementos que se suman a las caractersticas importantes relacionadas con criptografa
de .NET. Hay unas cuantas caractersticas de seguridad interesantes que no analizar en detalle,
pero que merecen al menos una mencin breve.

Autentificacin de usuario y My.User


El objeto My.User de Visual Basic incluye varias caractersticas de autentificacin que le ayudan
a disear cdigo habilitado por seguridad. Un miembro til es la propiedad Name, que propor-

Otras caractersticas de seguridad | 311

11_PATRICK-CHAPTER_11.indd 311 17/2/10 15:26:23


ciona el nombre del usuario autentificado actual. El mtodo IsInRole le indica si el usuario
activo est incluido, digamos, en el grupo de seguridad Administradores.
En el caso de Windows Forms, los miembros de My.User por lo general aludirn al usuario
que inicia sesin en Windows. Sin embargo, puede usar otros sistemas de autentificacin que
cumplan con sus necesidades especiales de desarrollo. Entre las opciones se incluyen el uso del
sistema Windows Live ID basado en Internet, de Microsoft, otros sistemas de autentificacin
de terceros, o su propio sistema de administracin de usuario personalizado.

La clase SecureString
Es sorprendente que con todas estas herramientas avanzadas, los programadores an gasten mu-
cho de su tiempo construyendo y analizando datos de cadena. Por fortuna, .NET incluye una
gran cantidad de herramientas tiles de manipulacin de cadenas. Por desgracia, no son muy se-
guras. Puede recordar que las cadenas de .NET son inmutables; una vez creadas, nunca cambian.
Con el tiempo, sern destruidas por el proceso de recoleccin de basura. Pero hasta entonces,
se quedan en la memoria, slo esperando a que sean rastrados por algn cdigo diseado por
hackers. Internamente, los datos de cadena se almacenan como texto simple, de modo que si
alguien accede a la memoria, puede copiar el contenido para fines nefastos.
SecureString al rescate! La clase System.Security.SecureString le permite almacenar
cadenas y hacer que regresen, pero internamente el contenido de la cadena queda cifrado. Si
alguien obtiene el contenido interno de una instancia de clase, parecer garabatos.

Resumen
Cuando crea una aplicacin de negocios para alguna organizacin o departamento, tal vez no le
preocupe mucho la seguridad y la integridad de los datos almacenados por las herramientas de
software. Siempre y cuando los datos pasen de la punta de los dedos del usuario a la base de datos
y regresen, todo es como coser y cantar.
Aunque esa concepcin puede funcionar con muchas aplicaciones, hay sistemas y usuarios que
esperan demasiado en seguridad. En ocasiones, necesita confirmar la seguridad y la integridad
de los datos almacenados por la aplicacin, sobre todo si dejarn los confines de su software o
la base de datos asociada. Las caractersticas de seguridad encontradas en el espacio de nombres
System.Security.Cryptography proporcionan una variedad divertida de opciones de ocul-
tamiento y restauracin de datos.

Proyecto
En este captulo veremos la adicin de las siguientes caractersticas enfocadas a la seguridad del
Proyecto Biblioteca:
El formulario de inicio de sesin, que autentifica a los bibliotecarios y otros usuarios ad-
ministrativos.
Formularios del grupo de seguridad y administracin de usuarios.

312 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 312 17/2/10 15:26:23


Una funcin que cifra una contrasea proporcionada por el usuario.
Activacin de algunas de las caractersticas de la aplicacin que dependen de la autentifica-
cin del usuario.

ACCESO AL PROYECTO
Cargue el proyecto Cap11 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, Cap11 (Despus) cdigo.

Soporte a autentificacin
Como todos los datos de la biblioteca estn almacenados en una base de datos de SQL Server,
usamos seguridad de Windows o SQL Server para restringir el acceso a los propios datos. Pero
una vez que nos conectamos con la base de datos, usaremos un sistema de autentificacin perso-
nalizado para habilitar y deshabilitar caractersticas en la aplicacin. Es all donde pondremos en
uso las caractersticas de criptografa de .NET.
Antes de agregar el cdigo interesante, necesitamos agregar algunas variables globales que so-
porten la seguridad en toda la aplicacin. Todos los elementos globales aparecen en el archivo
General.vb, dentro del mdulo GeneralCode.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap11, Elemento 1.

Public IdUsuarioInicio As Integer


Public NombreUsuarioInicio As String
Public IdGrupoInicio As Integer
Public PerfilSeguridad(MaxSeguridadBiblioteca) As Boolean

Aunque la agregamos en un paso anterior, la enumeracin SeguridadBiblioteca es una parte


importante del sistema de seguridad. Sus elementos coinciden con los encontrados en la tabla
Actividad en la base de datos Biblioteca. Cada valor de la enumeracin coincide con un ele-
mento de la matriz PerfilSeguridad que acabamos de agregar al cdigo.
Public Enum SeguridadBiblioteca As Integer
AdministrarAutores = 1
AdministrarTiposAutor = 2
...Aqui va mas...
AdministrarGruposClientes = 22
VerMensajesAdminCliente = 23
End Enum
Public Const MaxSeguridadBiblioteca As SeguridadBiblioteca = _
SeguridadBiblioteca.VerMensajesAdminCliente

Todas las variables recin agregadas almacenan informacin de identidad del administrador acti-
vo. Cuando un cliente es el usuario activo, el programa establece todos estos valores a sus estados

Proyecto | 313

11_PATRICK-CHAPTER_11.indd 313 17/2/10 15:26:23


predeterminados. Como esto debe hacerse cuando el programa empieza, agregaremos una rutina
InicializarSistema a la que se llamar al inicio. Tambin aparece en el mdulo General.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 2.

Public Sub InicializarSistema()


' ----- Inicializar aqui las variables globales.
Dim contador As Integer

' ----- Limpiar los valores relacionados con la seguridad.


IdUsuarioInicio = -1
NombreUsuarioInicio = ""
IdGrupoInicio = -1
For contador = 1 To MaxSeguridadBiblioteca
PerfilSeguridad(contador) = False
Next contador
End Sub

(La matriz PerfilSeguridad tienen elementos que van de 0 a MaxSeguridadBiblioteca,


pero el bucle al final de este cdigo empieza desde el elemento 1. Debido a que la tabla Activi-
dad empieza su cuenta en 1 decid slo omitir el elemento 0.) El mtodo InicializarSistema
es llamado desde el evento MyApplication_Startup en el archivo ApplicationEvents.vb, justo
antes de establecer una conexin con la base de datos. Agreguemos ahora ese cdigo nuevo.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 3.

' ----- Realizar inicializacion general.


InicializarSistema()

Cada vez que un administrador trata de usar el sistema, y cada vez que cierra la sesin y regresa
el programa en modo cliente, todas las variables globales relacionadas con la seguridad deben
restablecerse. Esto se hace en el mtodo ReprocesarConjuntoSeguridad, agregado al m-
dulo General.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 4.

Public Sub ReprocesarConjuntoSeguridad(


)
' ----- Recargar el conjunto de seguridad para el usuario
' actual. Si no hay usuario, limpiar todos los valores.
Dim contador As Integer
Dim textoSql As String
Dim infoBD As SqlClient.SqlDataReader = Nothing

' ----- Limpiar los elementos existentes.


For contador = 1 To MaxSeguridadBiblioteca

314 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 314 17/2/10 15:26:23


PerfilSeguridad(contador) = False
Next contador

' ----- Salir si no hay un usuario conectado.


If (IdUsuarioInicio = -1) Or _
(IdGrupoInicio = -1) Then Return

Try
' ----- Cargar los elementos de seguridad para este usuario.
textoSql = "SELECT IDActividad FROM ActividadGrupo " & _
"WHERE IDGrupo = " & IdGrupoInicio
infoBD = CrearLector(textoSql)
Do While (infoBD.Read)
PerfilSeguridad(CInt(infoBD!IDActividad)) = True
Loop
infoBD.Close()
Catch ex As Exception
' ----- Cierto error relacionado con la base de datos.
ErrorGeneral("ReprocesarConjuntoSeguridad", ex)
If (infoBD IsNot Nothing) Then infoBD.Close(
)

' ----- Cerrar sesion de administrador por recursion.


IdUsuarioInicio = -1
IdGrupoInicio = -1
ReprocesarConjuntoSeguridad()
Finally
infoBD = Nothing
End Try
End Sub

Esta rutina usa cdigo construido en el captulo 10 y captulos anteriores. Cuando detecta a
un usuario autorizado (la variable IdUsuarioInicio), crea un objeto SqlDataReader con las
caractersticas de seguridad permitidas para el usuario, y almacena esos parmetros en la matriz
PerfilSeguridad. Una vez que se ha cargado, un elemento de la matriz que es True representa
una caracterstica de aplicacin que el administrador est autorizado a usar. Analizar la tabla
ActividadGrupo un poco ms adelante, en este mismo captulo.

Si ocurre un error de base de datos durante el procesamiento, el cdigo restablece todo al modo
de cliente, haciendo una llamado recursiva a ReprocesarConjuntoSeguridad para limpiar
la matriz PerfilSeguridad. (La recursin ocurre cuando una rutina se llama a s misma de
manera directa o indirecta.)

Cifrado de contraseas
Todo el contenido de este captulo ha estado construyndose para llegar a este momento, la
seccin donde revelo al ganador de la prxima eleccin presidencial. Momento! Aun mejor
que eso, usar uno de los mtodos hash de .NET para cifrar una contrasea proporcionada por
el administrador antes de almacenarla en la base de datos. Una de las tablas de la base de datos
Biblioteca, NombreUsuario, almacena el perfil de seguridad bsico de cada bibliotecario u otro

Proyecto | 315

11_PATRICK-CHAPTER_11.indd 315 17/2/10 15:26:24


usuario administrativo, incluida una contrasea. Como cualquiera que tenga acceso a la base de
datos podra ver las contraseas almacenadas en esta tabla, las cifraremos para hacerlas menos
tentadoras. (En el caso de clientes que simplemente usarn el programa, no deberan tener acce-
so directo a la base de datos ms all de la aplicacin, pero nunca se sabe.)
Para mantener las cosas seguras, revolveremos la contrasea ingresada por el usuario, emplen-
dola para generar un valor de hash, y almacenar ese valor en el campo de contrasea de la base
de datos para el usuario. Ms adelante, cuando un usuario administrativo quiera obtener acceso
a caractersticas mejoradas, el programa convertir de nuevo la contrasea ingresada en un valor
de hash, y comparar ese valor con la contrasea con hash del registro.
Cada funcin de hash de .NET depende de un cdigo secreto. Como el Proyecto Biblioteca
realizar un cifrado unidireccional, y nunca pedir a ningn otro programa que vuelva a cifrar
la contrasea, usaremos el nombre de inicio de sesin del usuario como clave secreta. Decid
usar la clase de hash HMACSHA1, sobre todo por su capacidad para aceptar una clave de tamao
variable. Aunque se reporta que tiene problemas de seguridad, eso no debe ser un problema
por la manera en que la usamos. Quiero decir, si alguien en realidad entra en la base de datos
tratando de descifrar las contraseas almacenadas en la tabla NombreUsuario, ya tendra acceso
a todo el sistema de Biblioteca.
Por supuesto, el cdigo de cifrado requiere referencias al espacio de nombres System.Secu-
rity.Cryptography. Tambin necesitaremos una referencia a System.Text para parte del
cdigo de soporte. Agregue las instrucciones Import relevantes a la parte superior del archivo
de cdigo General.vb.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 5.

Imports System.Text
Imports System.Security.Cryptography

El barajado real de la contrasea ocurre en la rutina CifrarClave, que hace su entrada en el


mdulo General.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 6.

Public Function CifrarClave(ByVal idInicio As String, _


ByVal textoClave As String) As String
' ----- Dado un nombre y una clave de usuario, cifrar la
' contrasea para que no sea facil descifrarla. No hay
' limite para la longitud de la clave, porque de todos
' modos se va a usar hash en ella.
Dim funcionHash As HMACSHA1
Dim claveSecreta() As Byte

316 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 316 17/2/10 15:26:24


Dim valorHash() As Byte
Dim contador As Integer
Dim resultado As String = ""

' ----- Preparar la clave secreta. Forzarla a mayusculas para


' consistencia, y luego meterla en una matriz de bytes.
claveSecreta = (New UnicodeEncoding).GetBytes(UCase(idInicio))

' ----- Crear el componente de hash usando SHA-1 administrado.


funcionHash = New HMACSHA1(claveSecreta, True)

' ----- Calcular el valor de hash. Una linea simple de codigo.


valorHash = funcionHash.ComputeHash( _
(New UnicodeEncoding).GetBytes(textoClave))

' ----- El valor de hash esta listo, pero me gustan las cosas en
' texto simple cuando es posible. Hay que convertirlo a una
' cadena hexadecimal largo.
For contador = 0 To valorHash.Length - 1
resultado &= Hex(valorHash(contador))
Next contador

' ----- Las contrasenas almacenadas son de 20 caracteres maximo.


Return Left(resultado, 20)
End Function

Los mtodos primarios para interactuar con los proveedores de seguridad en .NET son median-
te una matriz o un flujo de bytes. Opt por usar el mtodo de la matriz de bytes, convirtiendo
los valores de la cadena a travs del mtodo GetBytes del objeto UnicodeEncoding. Una vez
almacenado como una matriz de bytes, paso el ID de inicio de sesin y la contrasea como ar-
gumentos a las caractersticas de la clase HMACSHA1.
Aunque podra almacenar la salida del mtodo ComputeHash directamente en el campo de la
base de datos, decid convertir el resultado en caracteres ASCII legibles para que las cosas se vean
extraas cuando use instrucciones SQL Server contra la tabla NombreUsuario. Mi conversin es
bsica: convertir cada byte en su equivalente hexadecimal imprimible empleando la funcin Hex
de Visual Basic. Luego slo una los resultados. El campo NombreUsuario.Clave slo contiene
20 caracteres de modo que cortar cualquier cosa ms larga.
Slo para asegurarme de que este algoritmo genera una salida razonable, llam a CifrarClave
con unas cuantas entradas diferentes.
MsgBox("Alicia/nada: " & _
CifrarClave("Alicia", "") & vbCrLf & _
"Alicia/password: " & _
CifrarClave("Alicia", "clave") & vbCrLf & _
"Juan/nada: " & _
CifrarClave("Juan", "") & vbCrLf & _
"Juan/password: " & _
CifrarClave("Juan", "clave"))

Proyecto | 317

11_PATRICK-CHAPTER_11.indd 317 17/2/10 15:26:24


Este cdigo gener el siguiente mensaje:
Alicia/nada: B09D7D8577704B407515
Alicia/clave: 7A78B65C5B8791195BE1
Juan/nada: 62A57C892D72624AEFDA
Juan/clave: 4381A4DE46D831CA2D9D

Cmo deshacer algunos cambios anteriores


Las tablas NombreUsuario, NombreGrupo y ActividadGrupo de la base de datos definen los
perfiles de seguridad de cada usuario administrativo. Cada usuario (un registro en NombreUsua-
rio) es parte de un grupo de seguridad (un registro en NombreGrupo). Cada grupo incluye
acceso a cero o ms caractersticas de aplicacin mejoradas; la tabla ActividadGrupo identifica
cules caractersticas coinciden con cada registro de grupo de seguridad.
Para administrar estas tablas, necesitamos agregar formularios de propiedades que editen los
campos de un solo registro de la base de datos. Ya escribimos antes un poco del cdigo. En el
captulo 8 se defini el archivo FormularioCodigoBase.vb, una plantilla para formularios que
editan registros nicos de base de datos. En ese mismo captulo se present el archivo ListaRe-
gistrosEditados.vb, el formulario principal que despliega una lista de los registros de la base de
datos ya definidos. Nuestro editor de registros para usuarios y grupos de seguridad usarn las
caractersticas de estos dos formularios existentes.

Su amable autor, Tim Patrick, est a punto de lanzar un discurso acerca de


algo que realmente le molesta. Por qu no se le une en este discurso?

Cuando diseamos el cdigo para FormularioCodigoBase.vb en el captulo 8, mi objetivo era


mostrar las caractersticas de las clases MustInherit y MustOverride incluidas con Visual Ba-
sic. Son caractersticas muy tiles. Por desgracia, no se mezclan bien con los elementos de inter-
faz de usuario, y he aqu por qu: Visual Studio en realidad crea instancias de sus formularios
en el tiempo del diseo para que pueda interactuar con ellos dentro del editor. Si revisara a fondo
el cdigo fuente de, digamos, un control TextBox, encontrara cdigo especial que trata con la
presentacin en tiempo de diseo del control. Interesante? S. Flexible? S. Perfecto en todos
los casos? No.
El problema (y problema resulta un eufemismo) es que Visual Studio no crear (en realidad,
no puede hacerlo) una instancia de una clase definida como MustInherit. Eso es porque debe
heredarla a travs de otra clase antes de crear instancias. Qu significa esto para usted? Que si trata
de disear un formulario que herede de una plantilla de formulario MustInherit, Visual Stu-
dio no presentar la parte de la interfaz de usuario del formulario para que disfrute su edicin.
An puede acceder al cdigo fuente del formulario, y si as es como quiere disear el formulario
editado, est bien. Pero usted y yo estamos buscando simplicidad en la programacin, y paga-
mos mucho por Visual Studio, as que es seguro que vamos a usar sus herramientas visuales para
editar nuestros formularios visuales.

318 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 318 17/2/10 15:26:24


La conclusin de todo este discurso (y estoy casi al final de mi discurso, pero puede seguir
conmigo, si lo desea) es que debe cambiar el archivo FormularioCodigoBase.vb, eliminando las
palabras clave MustInherit y MustOverride, y haciendo otros ajustes apropiados. Ya he hecho
los cambios a las plantillas antes y final del cdigo del captulo 11.
sta es parte de la realidad de la programacin en un sistema complejo como Visual Studio. En
ocasiones, an despus de que ha hecho toda su investigacin y asignado cuidadosamente las ca-
ractersticas y la estructura de la aplicacin, cae en un comportamiento especfico del diseador o
el compilador que lo obliga a hacer algunos cambios. Una vez que aprende a evitar los problemas
importantes se encuentra con que no son muy frecuentes. Pero cuando ocurren, pueden repre-
sentar un estupendo tema para un discurso.

Administracin de grupos de seguridad


As que regresemos a nuestro editor de registros de NombreGrupo. No lo he agregado al proyec-
to an, de modo que agregumoslo ahora. Debido a que se heredar de otro formulario en el
proyecto, tenemos que permitir que Visual Studio cree una instancia del formulario bsico al
compilar primero la aplicacin. Esto se hace fcilmente a travs del comando de men Generar
Generar biblioteca.
Para crear el nuevo formulario, seleccione el comando de men Proyecto Agregar Windows
Form. Cuando aparezca la ventana Agregar nuevo elemento, seleccione Windows Forms de la
lista Categoras, seguido por Formulario heredado de la lista Plantillas. Escriba NombreGrupo.
vb en el campo Nombre, y luego haga clic en el botn Agregar. Cuando aparezca el formulario
Selector de herencia (vase la figura 11-1), seleccione FormularioCodigoBase de la lista y haga
clic en Aceptar. Aparece el nuevo formulario NombreGrupo, pero se parece de manera notable al
formulario FormularioCodigoBase.

Figura 11-1. Quin dice que no puede elegir a sus propios parientes?

Proyecto | 319

11_PATRICK-CHAPTER_11.indd 319 17/2/10 15:26:25


Agregue dos controles Label, dos controles TextBox, dos controles Button y un control Checked
ListBox del cuadro de herramientas, y establezca sus propiedades utilizando los siguientes valores.

Tipo de control Valores de propiedad


Label (Name): EtqNombreCompleto
AutoSize: True
Location: 8, 10
Text: Nombre de grupo &Seguridad:
TextBox (Name): NombreCompletoRegistro
Location: 128, 8
MaxLength: 50
Size: 248, 20
Label (Name): EtqActivado
AutoSize: True
Location: 8, 34
Text: Actividades &permitidas:
CheckedListBox (Name): ListaActividad
Location: 128, 32
Size: 248, 244
Button (Name): AccAceptar
Location: 208, 288
Size: 80, 24
Text: Aceptar
Button (Name): AccCancelar
DialogResult: Cancel
Location: 296, 288
Size: 80, 24
Text: Cancelar
Form (NombreGrupo) (Name): NombreGrupo
AcceptButton: AccAceptar
CancelButton: AccCancelar
Size: 392, 351
Text: Editor de grupo de seguridad

No olvide ajustar el orden de tabulacin de los controles del formulario.


Agreguemos todo el cdigo completo. Agregue el siguiente fragmento de cdigo al cuerpo del
cdigo fuente de la clase.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap11, Elemento 7.

Hey, son casi 300 lneas de cdigo fuente. Buena escritura. La clase incluye dos miembros priva-
dos. IDActivo contiene el nmero de ID del registro de la base de datos NombreGrupo desple-
gado, o 1 cuando se editan nuevos registros. La marca EmpezarDeNuevo es un poco ms intere-

320 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 320 17/2/10 15:26:25


sante. Recuerde que suponemos que estamos usando un formulario de resumen compartido para
desplegar todos los registros de NombreGrupo ya ingresados. Para permitir que este formulario
genrico, ListaRegistrosEditados.vb, funcione con los diferentes editores de registros, pasamos una
instancia del formulario detallado (NombreGrupo.vb en este caso) al formulario de resumen:
ListaRegistrosEditados.AdministrarRegistros(New Biblioteca.NombreGrupo)

Dentro del cdigo del formulario ListaRegistrosEditados, la instancia de NombreGrupo se


usa de manera repetida, cada vez que el usuario quiere agregar o editar un registro de la base de
datos NombreGrupo. Si el usuario edita un registro, y luego trata de editar otro, los restos del
primero an permanecern en los campos de detalle del formulario. Por tanto, tendremos que
limpiarlos cada vez que agreguemos o editemos un registro diferente. La marca EmpezarDeNue-
vo ayuda en el proceso al restablcer el enfoque en el primer campo del formulario de detalle en
el evento Activated del formulario.
Private Sub NombreGrupo_Activated(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Activated
' ----- Regresar el enfoque al campo principal.
If (EmpezarDeNuevo) Then RegistrarNombreCompleto.Focus( )
EmpezarDeNuevo = False
End Sub

El mtodo privado PrepararCamposFormulario hace la limpieza real y el almacenamiento de


datos con cada nueva llamada a Agregar o Editar. Para los nuevos registros, simplemente limpia
todos los datos ingresados en el formulario. Cuando se edita un registro existente, recupera los
datos relevantes de la base de datos, y almacena valores guardados en los diversos campos del for-
mulario. Las siguientes instrucciones despliegan el nombre del grupo almacenado en el campo
RegistrarNombreCompleto, un control TextBox:
' ----- Cargar los valores almacenados en la base de datos.
textoSql = "SELECT NombreCompleto FROM NombreGrupo WHERE ID = " & _
IDActivo
RegistrarNombreCompleto.Text = CStr(EjecutarSQLRegresar(textoSql))

Casi todas las rutinas del formulario NombreGrupo proporcionan una sobrescritura simple de
los miembros de base de la clase FormularioCodigoBase. El mtodo UsuarioPuedeAgregar,
que simplemente devuelve False en la clase de base, incluye lgica real en la clase heredada.
Usa la matriz PerfilSeguridad que agregamos antes para determinar si el usuario actual tiene
permitido agregar registros de grupo.
Public Overrides Function UsuarioPuedeAgregar(
) As Boolean
' ----- Revisar el acceso de seguridad del usuario: agregar.
Return PerfilSeguridad(SeguridadBiblioteca.AdministrarGrupos)
End Function

Si revisa el cdigo agregado, encontrar sobrescritura para todos los miembros de Formulario-
CodigoBase, excepto para los mtodos UsaBusqueda y BuscarRegistro. La clase derivada
acepta la accin predeterminada para esos dos miembros.
El usuario agrega, edita y elimina registros de nombre de grupo mediante la sobrescritura de
AgregarRegistro, EditarRegistro y EliminarRegistro, respectivamente, cada uno lla-

Proyecto | 321

11_PATRICK-CHAPTER_11.indd 321 17/2/10 15:26:25


mado por el cdigo del formulario ListaRegistrosEditados. He aqu el cdigo de Editar
Registro:
Public Overrides Function EditarRegistro( _
ByVal idRegistro As Integer) As Integer
' ----- Editar un registro existente.
IDActivo = idRegistro
PrepararCamposFormulario()
Me.ShowDialog()
If (Me.DialogResult = Windows.Forms.DialogResult.OK) Then _
Return IDActivo Else Return -1
End Function

Despus de almacenar el ID del registro que habr de editarse en el campo privado IDActivo, el
cdigo carga los datos a travs del mtodo PrepararCamposFormulario, y pide al usuario editar
el registro con la llamada a Me.ShowDialog. El formulario se queda hasta que algn cdigo
o control establece la propiedad DialogResult del formulario. Esto se hace con el evento
AccAceptar_Click, y tambin mediante la propiedad DialogResult del botn AccCan-
celar, que Visual Basic asignar automticamente al formulario cuando el usuario haga clic
en el botn AccCancelar.
La rutina AgregarRegistro es como EditarRegistro, pero asigna -1 al miembro IDActivo
para marcar un nuevo registro. La rutina EliminarRegistro es ms compleja, y usa parte del
cdigo de base de datos que escribimos en el ltimo captulo.
Public Overrides Function EliminarRegistro( _
ByVal idRegistro As Integer) As Boolean
' ----- El usuario quiere eliminar el registro.
Dim textoSql As String
On Error GoTo ErrorHandler
' ----- Confirmar con el usuario.
If (MsgBox("?Realmente desea eliminar el " & _
"grupo de seguridad?", MsgBoxStyle.YesNo Or _
MsgBoxStyle.Question, TituloPrograma) <> _
MsgBoxResult.Yes) Then Return False
' ----- Asegurar que este registro no se usa.
textoSql = "SELECT COUNT(*) FROM NombreUsuario " & _
"WHERE IDGrupo = " & idRegistro
If (CInt(EjecutarSQLRegresar(textoSql)) > 0) Then
MsgBox("No puede eliminar este registro porque " & _
"esta en uso.", MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return False
End If
' ----- Eliminar el registro.
EmpezarTransac()
textoSql = "DELETE FROM ActividadGrupo " & _
"WHERE IDGrupo = " & idRegistro
EjecutarSQL(textoSql)
textoSql = "DELETE FROM NombreGrupo WHERE ID = " & idRegistro
EjecutarSQL(textoSql)

322 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 322 17/2/10 15:26:25


ConfirmarTransac()
Return True
ErrorHandler:
ErrorGeneral("NombreGrupo.EliminarRegistro", Err.GetException(
))
RevertirTransac()
Return False
End Function

Despus de confirmar la eliminacin con el usuario, una rpida revisin determina si el grupo
an se est usando en algn otro lugar de la tabla NombreUsuario. Si todo resulta bien, el regis-
tro se elimina usando una instruccin SQL DELETE. Como necesitamos eliminar datos en dos
tablas, la envuelvo en una transaccin. Si ocurre un error, el manejador de errores al final de la
rutina revertir la transaccin a travs de RevertirTransac.

Aviso sobre la integridad de la base de datos


Si tiene antecedentes en el desarrollo de bases de datos, ya ha visto las fallas en la eliminacin
de cdigo. Aunque me tome tiempo en verificar que el registro no se est usando antes de
eliminarlo, es posible que algn otro usuario lo use entre el momento en que reviso el uso del
registro y cuando realmente lo elimino. Con base en el cdigo y la configuracin de la base
de datos que he presentado hasta ahora, eso sera un problema. Cuando dise este sistema,
esperaba que un solo bibliotecario administrara tareas administrativas como sta, de modo que
no me preocup por estos conflictos y condiciones de carrera.
Si est preocupado por la posibilidad de eliminar registros en uso mediante cdigo como ste,
puede habilitar la integridad referencial en las relaciones de la base de datos. Establec una
relacin entre los campos NombreGrupo.ID y NombreUsuario.IDGrupo, pero slo fue para
fines informativos. Puede reconfigurar esta relacin para que SQL Server imponga la relacin
entre las tablas. Si lo hace, no ser posible eliminar un registro en uso; ocurrir un error en el
programa cuando lo intente. Eso suena bien, y est bien, pero el abuso de la integridad refe-
rencial puede hacer lento el acceso a sus datos. Le dejar la decisin de usar o no esta opcin
de configuracin.

Cuando el usuario hace cambios al registro, un clic en el botn Aceptar extrae los datos de la base
de datos. El manejador de eventos AccAceptar_Click verifica los datos y luego los guarda.
If (ValidarDatosFormulario() = False) Then Return
If (GuardarDatosFormulario() = False) Then Return
Me.DialogResult = Windows.Forms.DialogResult.OK

El mtodo ValidarDatosFormulario hace algunas revisiones para ver si los datos son vlidos,
como solicitar que el usuario ingrese el nombre del grupo de seguridad, y que sea nico. Si todo se
ve bien, la rutina GuardarDatosFormulario genera instrucciones SQL que guardan los datos.
Private Function GuardarDatosFormulario(
) As Boolean
' ----- El usuario quiere guardar los cambios.
' Regresar True si es correcto.

Proyecto | 323

11_PATRICK-CHAPTER_11.indd 323 17/2/10 15:26:25


Dim textoSql As String
Dim nuevoID As Integer = -1

On Error GoTo ErrorHandler

' ----- Preparar para guardar los datos.


Me.Cursor = Windows.Forms.Cursors.WaitCursor
EmpezarTransac()

' ----- Guardar los datos.


If (IDActivo = -1) Then
' ----- Crear una nueva entrada.
textoSql = "INSERT INTO NombreGrupo (NombreCompleto) " & _
"OUTPUT INSERTED.ID VALUES (" & _
TextoBD(Trim(RegistrarNombreCompleto.Text)) & ")"
nuevoID = CInt(EjecutarSQLRegresar(textoSql))
Else
' ----- Actualizar la entrada existente.
nuevoID = IDActivo
textoSql = "UPDATE NombreGrupo SET NombreCompleto = " & _
TextoBD(Trim(RegistrarNombreCompleto.Text)) & _
" WHERE ID = " & IDActivo
EjecutarSQL(textoSql)
End If

' ----- Limpiar cualquier configuracion de seguridad existente.


textoSql = "DELETE FROM ActividadGrupo " & _
"WHERE IDGrupo = " & nuevoID
EjecutarSQL(textoSql)

' ----- Guardar los parametros de seguridad seleccionados.


For Each elementoRevisado As DatosListaElementos In _
ListaActividad.CheckedItems
textoSql = "INSERT INTO ActividadGrupo (IDGrupo, " & _
"IDActividad) VALUES (" & nuevoID & ", " & _
elementoRevisado.DatosElemento & ")"
EjecutarSQL(textoSql)
Next elementoRevisado

' ----- Completar todos los cambios.


ConfirmarTransac()
IDActivo = nuevoID

' ----- Este cambio puede afectar a este usuario.


If (IdGrupoInicio = IDActivo) Then _
ReprocesarConjuntoSeguridad()

' ----- Correcto.


IDActivo = nuevoID
Me.Cursor = Windows.Forms.Cursors.Default
Return True

ErrorHandler:
Me.Cursor = Windows.Forms.Cursors.Default

324 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 324 17/2/10 15:26:25


ErrorGeneral("NombreGrupo.GuardarDatosFormulario", Err.GetException(
))
RevertirTransac()
Return False
End Function

Asegrese de revisar las otras rutinas del formulario NombreGrupo; estn all para dar soporte y
mejorar la experiencia de usuario.

Administracin de usuarios
Tambin necesitamos una forma de administrar registros en la tabla NombreUsuario. Como
el cdigo para ese formulario generalmente sigue lo que ya hemos visto en el formulario Nom-
breGrupo, no lo abrumar con detalles. Ya he agregado NombreUsuario.vb a su proyecto, pero
para evitar errores en su cdigo mientras est a mitad del desarrollo, lo deshabilit (al menos en
la versin Antes del cdigo). Para habilitarlo, seleccione el archivo en la ventana Explorador
de soluciones, Luego, en el panel Propiedades, cambie la propiedad Accin de compilacin de
Ninguna a Compilacin.
El nico cdigo interesante de este formulario es que maneja la contrasea de manera diferente
del formulario NombreGrupo. Para asegurar las cosas lo ms posible, en realidad no cargo la
contrasea guardada en el campo Clave. No hara ningn bien de todos modos, porque he al-
macenado una versin con hash aplicado en la base de datos.
Como uso el Id de inicio de sesin del usuario como clave secreta cuando cifro la contrasea,
debo volver a generarla, si el usuario cambia alguna vez el ID de inicio de sesin. El campo Id
InicioOrigen privado mantiene una copia del ID de inicio de sesin cuando el formulario se
abre por primera vez, y revisa cualquier cambio cuando vuelve a guardar el registro. Si ocurren
cambios se vuelve a generar la contrasea.
resultadoClave = CifrarClave(Trim(RegistroIdInicio.Text), _
Trim(RegistroClave.Text))

El uso de los formularios de edicin NombreUsuario y NombreGrupo requiere algn cdigo adi-
cional en el formulario principal. Agrguelo donde se indica en el archivo FormularioPrincipal.vb.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap11, Elemento 8.

Los controles AdminVinculosGrupos y AdminVinculosUsuarios son etiquetas de vnculos


estilo Web que agregamos al programa unos cuantos captulos antes. El evento LinkClicked
(no el evento Clicked) dispara el despliegue del editor de cdigo. He aqu el cdigo para editar
la tabla NombreGrupo:
Private Sub AdminVinculosGrupos_LinkClicked( _
ByVal sender As Object, ByVal e As System.Windows. _
Forms.LinkLabelLinkClickedEventArgs) _
Handles AdminVinculosGrupos.LinkClicked

Proyecto | 325

11_PATRICK-CHAPTER_11.indd 325 17/2/10 15:26:25


' ----- Permitir que el usuario edite la lista de grupos de seguridad.
If (PerfilSeguridad(SeguridadBiblioteca.AdministrarGrupos) _
= False) Then
MsgBox(MensajeNoAutorizado, MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If

' ----- Editar los registros.


ListaRegistrosEditados.AdministrarRegistros(New Biblioteca.NombreGrupo)
ListaRegistrosEditados = Nothing
End Sub

Experiencia por usuario


Ahora que hemos agregado todo el cdigo de soporte de seguridad al proyecto, podemos empezar
a usar esas caractersticas para cambiar la experiencia de la aplicacin para clientes y administra-
dores. No es adecuado tentar a las personas con darles un poder inmenso, de modo que es mejor
ocultar esas caractersticas que no son accesibles a los usuarios de cliente con menos poder.
En primer lugar, proporcionemos el poder de diferenciacin al agregar el formulario de inicio de
sesin administrativo, que se muestra en la figura 11-2.

Figura 11-2. El formulario oficial de inicio de sesin administrativo del Proyecto Biblioteca.

Ya he agregado el formulario CambiarUsuario.vb al proyecto. Si est usando la versin Antes


del cdigo de este captulo, seleccione CambiarUsuario.vb en el Explorador de soluciones. Lue-
go cambie su propiedad Accin de compilacin (en el panel Propiedades) de Ninguna a Com-
pilacin, al igual que lo hizo con el formulario NombreUsuario.vb.
Todo el trabajo duro ocurre en el manejado de evento AccAceptar_Click del formulario. Si
el usuario selecciona la opcin Regresar a modo de cliente, todos los valores de seguridad se
limpian, y el formulario principal oculta la mayor parte de las caractersticas (mediante el cdigo
agregado ms adelante).
IdUsuarioInicio = -1
NombreUsuarioInicio = ""
IdGrupoInicio = -1
ReprocesarConjuntoSeguridad()

326 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 326 17/2/10 15:26:26


Este formulario se conecta a la aplicacin mediante el evento AccIniciarSesion_Click. Abra
el archivo FormularioPrincipal.vb, haga doble clic en el botn Iniciar sesin, que se encuentra en la
esquina superior derecha, y agregue el siguiente cdigo a la plantilla de evento Click que aparece.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 9.

' ----- Preguntar al usuario si va a modo de cliente o administrativo.


MostrarFormInicio()

No fue mucho cdigo. Agregue tambin al formulario el cdigo del mtodo MostrarFormInicio.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 10.

Private Sub MostrarFormInicio()


' ----- Preguntar al usuario si va a modo de cliente o administrativo.
Dim eleccionUsuario As Windows.Forms.DialogResult
eleccionUsuario = CambiarUsuario.ShowDialog(
)
CambiarUsuario = Nothing
If (eleccionUsuario = Windows.Forms.DialogResult.OK) Then _
ActualizarPantallaParaUsuario()
End Sub

Tambin habilitemos la tecla F12 para que acte como desencadenador de inicio de sesin.
Agregue el siguiente cdigo a la instruccin Select Case en el manejador de eventos Formu-
larioPrincipal_KeyDown.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 11.

Case Keys.F12
' ----- Preguntar al usuario si va a modo de cliente o administrativo.
MostrarFormInicio()
e.Handled = True

La rutina MostrarFormInicio llama a otro mtodo, ActualizarPantallaParaUsuario, que


oculta y muestra varios elementos de despliegue en el formulario principal basado en el perfil
de seguridad del usuario actual. Agrguelo al cdigo de la clase FormularioPrincipal. No
mostrar aqu el cdigo, pero en esencia revisa la variable IdUsuarioInicio, y si tiene un valor
de -1, oculta todas las caractersticas avanzadas de los controles.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 12.

Proyecto | 327

11_PATRICK-CHAPTER_11.indd 327 17/2/10 15:26:26


Actualmente, cuando ejecuta la aplicacin, aparecen todas las caractersticas avanzadas, aunque
ningn administrador haya proporcionado un ID o una contrasea. La llamada a Actualizar-
PantallaParaUsuario cuando el formulario principal aparece por primera vez resuelve ese
problema. Agregue el cdigo siguiente al final del mtodo FormularioPrincipal_Load.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 13.

' ----- Preparar para un usuario cliente.


ActualizarPantallaParaUsuario()

La ltima actualizacin (cinco actualizaciones, en realidad) incluye la limitacin de las princi-


pales secciones del formulario slo para administradores autorizados. Por ejemplo, slo los ad-
ministradores que estn autorizados para ejecutar informes deben tener la capacidad de acceder
al panel de informes en el panel principal. Localice el mtodo TareaInformes en el formulario
principal, y encuentre la lnea que despliega el panel.
PanelInformes.Visible = True

Reemplace esta lnea con el siguiente cdigo.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap11, Elemento 14.

If (PerfilSeguridad(SeguridadBiblioteca.EjecutarInformes)) Then _
PanelInformes.Visible = True

Necesitamos hacer algo en los mtodos TareaSalida, TareaEntrada, TareaAdmin y Tarea


Proceso. En cada caso, reemplace la lnea que dice:
Panel???.Visible = True

con cdigo que revisa los parmetros de seguridad antes de mostrar el panel.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte los fragmentos de cdigo Cap11, Elementos 15 a 18.

Use el fragmento de cdigo 15 para TareaSalida.


Use el fragmento de cdigo 16 para TareaEntrada.
Use el fragmento de cdigo 17 para TareaAdmin.
Use el fragmento de cdigo 18 para TareaProceso.

328 | Captulo 11: Seguridad

11_PATRICK-CHAPTER_11.indd 328 17/2/10 15:26:26


Ejecute el programa y ver que est empezando a parecer una aplicacin real. Si quiere acceder
a las caractersticas mejoradas, pruebe un Id de inicio de sesin admin sin contrasea. Puede
cambiar eso mediante el formulario NombreUsuario, si lo desea!
Como tenemos una manera de asegurar el acceso a los datos y consultas del Proyecto Biblioteca,
pasemos al siguiente captulo y empecemos a concentrarnos en los datos, el punto focal de cual-
quier aplicacin de negocios.

Proyecto | 329

11_PATRICK-CHAPTER_11.indd 329 17/2/10 15:26:26


Captulo 12
Sobrecargas y extensiones

Alguna vez ha deseado hacer cosas ms all de lo que las personas estn diseadas para hacer?
Cmo volar? Todos soamos con eso, pero no podemos hacerlo sin varios cientos de kilos de
turbosina. O qu tal doblar el acero con nuestras manos? Le suena a alguien que conoce?
Tambin estn las opciones de respirar bajo el agua, hacer divisiones de grandes nmeros en la
mente, hablar un idioma extranjero con soltura sin mucho estudio y tener una carrera exitosa
como autor de libros populares de computacin. Ah, uno puede soar.
No es que queramos hacer todo esto, sino que de vez en cuando sera agradable mejorar ligera-
mente con la habilidad para hacer una o dos cosas que estn ms all de nuestras capacidades.
Por desgracia, no funciona para los seres humanos con mucha frecuencia, pero podra funcionar
para los operadores de .NET?
Tal vez ni siquiera sabe que el humilde operador de suma (+) de Visual Basic tiene sueos de
volar, o de hablar hngaro, o de doblar el acero. Bueno, los operadores tambin son personas.
Y ahora sus sueos pueden satisfacerse porque Visual Basic es compatible con la sobrecarga de
operadores.
En este captulo se le mostrar cmo puede dirigir el proceso de mejora de los diversos opera-
dores de Visual Basic. Tambin presentar los mtodos de extensin, que le permiten mejorar las
clases de manera similar, aunque no tenga acceso al cdigo fuente original para esas clases.

Qu es la sobrecarga de un operador?
La sobrecarga de operadores le permite a su cdigo mejorar los operadores bsicos de Visual
Basic y dotarlos con habilidades que el compilador no les haba otorgado previamente. La
sobrecarga no cambia la sintaxis usada cuando se emplean operadores, pero s cambia los tipos
de objetos que cada operador puede administrar. Por ejemplo, el operador de multiplicacin
(*) por lo general slo interacta con nmeros, pero puede hacer que trabaje con su propia
clase Abejorro.
Dim enjambre As Abejorro
Dim unAbejorro As New Abejorro

330

12_PATRICK-CHAPTER_12.indd 330 17/2/10 15:26:47


Dim dosAbejorro As New Abejorro
enjambre = unAbejorro * dosAbejorro

El significado que aplique al operador sobrecargado depende de usted. Aunque normalmente


querra retener la naturaleza aditiva del operador de suma cuando lo sobrecarga, no tiene que
hacerlo. En realidad, puede sobrecargar el operador de suma de modo que reste un valor a otro.
Pero le disparar si hizo que funcionara para m. As que ya lo sabe.
Todas las caractersticas de sobrecarga de operadores se une directamente a una o ms de sus
clases. Las caractersticas sobrecargadas parecen, curiosamente, miembros de funciones estndar,
y aparecen como miembros de sus clases.
Visual Basic incluye dos tipos de operadores: unarios y binarios, definidos con base en el nmero
de operandos reconocidos por el operador. Los operadores unarios aceptan un solo operando,
que siempre aparece a la derecha del nombre o el smbolo del operador. El operador lgico Not
es un operador unario:
valorOpuesto = Not valorOriginal

Los operadores binarios aceptan dos operandos, uno a cada lado del operador. El operador de
multiplicacin es un operador binario:
diez = dos * cinco

La naturaleza de un operador es que una vez que ha hecho su trabajo, el operador y su operando
o sus operandos son reemplazados por el resultado calculado. La expresin 10/5 es reemplaza-
da por el resultado 2 calculado, y este resultado se usa para completar cualquier instruccin o
expresin en que aparece la operacin original. Trabaja como una funcin.
' ----- Estas dos lineas (tal vez) colocan el mismo
' resultado calculado en laRespuesta.
laRespuesta = 2 * 5
laRespuesta = Duplicarlo(5)

Para estar listo para la sobrecarga de operadores, modifique su mente para ver a los operado-
res como funciones. Revise ms all de los confines del universo de su operador, y brase a la
verdad de que los operadores y las funciones son uno mismo. Si alguna vez ha programado en
LISP, realmente lo siento por usted. Pero ya comprende tambin que los operadores son como
funciones. En LISP, todo es una funcin. Para multiplicar dos nmeros en LISP, usa la sintaxis
de prefijo, donde el nombre del operador aparece primero. La expresin siete por tres utiliza
esta sintaxis:
(* 7 3)

Una vez completada, se reemplaza toda la expresin entre parntesis, como en un una funcin,
por su respuesta. La expresin LISP:
(+ 2 (* 7 3))

se vuelve:
(+ 2 21)

Qu es la sobrecarga de un operador? | 331

12_PATRICK-CHAPTER_12.indd 331 17/2/10 15:26:47


se vuelve:
23

La definicin de operadores sobrecargados en Visual Basic 2008 es un poco similar. Si fuera a


traducir la definicin de multiplicacin en el estilo de funcin de Visual Basic, se vera as:
Public Shared Function *( _
ByVal primerOperando As Integer, _
ByVal segundoOperando As Integer) _
As Integer

El operador (*) se vuelve un nombre de funcin, y los operandos juegan el papel de parmetros
de la funcin, generando al final un valor expuesto a travs del valor devuelto por la funcin.
Aunque los operadores no estn definidos como funciones de esta manera en Visual Basic, la
sobrecarga de estos operadores si lo estn.
Para sobrecargar el operador de multiplicacin en nuestra clase imaginaria Abejorro, usamos
la palabra clave Operator para definir una funcin de multiplicacin para operandos de la
clase Abejorro.
Partial Class Abejorro
Public Shared Operator *(ByVal operando1 As Abejorro, _
ByVal operando2 As Abejorro) As Abejorro
' ----- Multiplicar dos abejorros.
Dim resultadoFinal As New Abejorro

' ----- Agregar aqui codigo especial de "multiplicacion", luego...


Return resultadoFinal
End Operator
End Class

Ahora, cuando multiplica dos instancias de Abejorro con el operador de multiplicacin, Vi-
sual Basic reconoce el patrn operando1 * operando2 como coincidencia con un operador de
multiplicacin sobrecargado con dos argumentos Abejorro, y llama a esta funcin Operator
basada en una clase para obtener el resultado.
Todas las declaraciones Operator deben incluir las palabras claves Public y Shared. Si se com-
partieran, se requerira que Visual Basic creara una instancia adicional de la clase tan slo para
acceder al cdigo de operador sobrecargado, y eso no sera muy eficiente.

Qu puede sobrecargar?
Puede cargar casi todos los operadores estndar de Visual Basic (excepto por Is e IsNot), adems
de algunas otras caractersticas. En esta seccin se describe cada operador que es posible sobrecar-
gar, agrupado por tipo general. Cada seccin incluye una tabla de operadores. Para sobrecargar
un operador en una clase, use el nombre de la columna Operador como nombre de la funcin. Si
hubiera un operador llamado XX, la instruccin Operator coincidente sera:
Public Shared Operator XX(...)

332 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 332 17/2/10 15:26:47


Operadores matemticos
Visual Basic define 10 operadores matemticos o pseudomatemticos. Todos, menos uno de
ellos tienen el objetivo de manipular nmeros. El operador restante es el operador de unin
de cadenas (&), que funciona con cadenas, pero que se parece a los dems operadores matem-
ticos en su uso y sintaxis.
Dos de los operadores, ms (+) y menos (), son unarios y binarios. El signo de menos () fun-
ciona como un operador unario de negacin (como en 5) y como un operador de resta
binario (la sintaxis comn 5 2). Cuando se sobrecargan estos operadores, la diferencia recae
en el nmero de argumentos incluidos en la firma del argumento.
Public Shared Operator -(ByVal operando1 As SomeClass, _
ByVal operando2 As AlgunaClase) As AlgunaClase
' ----- Esta es la version binaria de "resta".
End Operator

Public Shared Operator -(ByVal operando1 As AlgunaClase) _


As AlgunaClase
' ----- esta es la version unario de "negacion".
End Operator

En la tabla 12-1 se presenta una lista de los operadores matemticos compatibles con sobrecarga.

Tabla 12-1. Los operadores matemticos que permiten sobrecarga.

Operador Tipo Comentarios


+ Unario El operador unario ms. Puede usar este operador con nmeros, como en +5. Pero si ingre-
sa este valor en Visual Studio, el operador de ms se elimina porque se considera redundante.
Sin embargo, si sobrecarga este operador en una clase propia, Visual Studio retendr la forma
unario de este operador cuando lo use en el cdigo.
' ----- Suponiendo que el operador unario + es sobrecar-
gado...
Dim unZumbido As New Abejorro
Dim masZumbidos As Abejorro = +unZumbido
Debido a que es un operador unario, slo incluye un argumento cuando define el mtodo
Operator.
+ Binario El operador de suma estndar. Recuerde que no slo porque se le llame operador de suma
significa que tiene que retener la connotacin. Sin embargo, debe tratar de sobrecargar los
operadores lo ms cerca que pueda a su significado original. El propio Visual Basic sobrecarga
este operador para permitirle actuar un poco como el operador de unin de cadenas.
Unario ste es el operador unario de negacin que se encuentra justo antes de un valor o expresin.
Binario El operador de resta, aunque si puede idear cmo restar un abejorro a otro, ser mejor pro-
gramador que yo.
* Binario El operador de multiplicacin.
/ Binario El operador estndar de divisin.

Qu puede sobrecargar? | 333

12_PATRICK-CHAPTER_12.indd 333 17/2/10 15:26:47


Tabla 12-1. Los operadores matemticos que permiten sobrecarga (continuacin).

Operador Tipo Comentarios


\ Binario El operador de divisin entera. Recuerde que no es necesario que obtenga ningn entero en
este operador, si no satisface las necesidades de su clase.
^ Binario El operador de exponenciacin (a la x potencia).
Mod Binario El operador de mdulor, en ocasiones llamado el operador del sobrante o el resto, porque
regresa el resto de una accin de divisin.
& Binario El operador de unin de cadenas.

Operadores de comparacin
Visual Basic incluye siete operadores de comparacin bsicos, la mayor parte de ellos usados en
instrucciones If y expresiones similares que requieren un clculo condicional booleano. Los m-
todos Operator para estos operadores de comparacin tienen la misma sintaxis que la usada por
los operadores matemticos, pero casi todos ellos deben implementarse en pares. Por ejemplo,
si sobrecarg el operador de menos que (<), Visual Basic requiere que sobrecarga el operador de
ms que (>)dentro de la misma clase, y para la misma firma de argumentos.
Todos los operadores de comparacin son operadores booleanos. Aunque puede modificar los
tipos de datos de los argumentos pasados al operador, todos deben regresar un valor booleano.
Public Shared Operator <=(ByVal operando1 As AlgunaClase, _
ByVal operando2 As AlgunaClase) As Boolean
' ----- El operador <= devuelve un resultado booleano.
End Operator

En la tabla 12-2 se presentan seis de los siete operadores bsicos de comparacin que puede
sobrecargar. Cada entrada incluye un valor compaero que identifica el operador coincidente
que tambin debe sobrecargarse.

Tabla 12-2. Los operadores de comparacin que permiten sobrecarga.

Operador Tipo Comentarios


= <> El operador igual a compara la equivalencia de dos operandos, regresando True si son iguales.
<> = El operador no es igual a compara la falta de equivalencia de dos operandos, y devuelve True
si no coinciden.
< > El operador menos que devuelve True si el primer operando es menor que el segundo.
> < El operador ms que devuelve True si el primer operando es mayor que el segundo.
<= >= El operador menos que o igual a devuelve True si el primer operando es menor que o igual a
el segundo. No est cansado de leer casi la misma frase una y otra vez?
>= <= El operador ms que o igual a devuelve True si el primer operando es mayor que o igual a el
segundo.

334 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 334 17/2/10 15:26:47


El sptimo operador de comparacin es Like. En Visual Basic estndar, compara el primer ope-
rando con un patrn de cadena, que es un conjunto de caracteres y comodines coincidentes:
If (ciertoValor Like ciertoPatron) Then

No tiene que usar las mismas reglas de patrones cuando sobrecarga el operador Like, y puede aceptar
cualquier tipo de datos para el operando de patrn, pero an debe devolver un resultado booleano.
Public Shared Operator Like(ByVal operando1 As Abejorro, _
ByVal operando2 As Integer) As Boolean
' ----- Ver si Abejorro coincide con un patron Entero.
End Operator

No es necesario que implemente un operador compaero cuando sobrecarga el operador Like.

Operadores lgicos y en el nivel de bit


Entre los operadores lgicos y en el nivel de bits incluidos en Visual Basic, cuatro ya realizan una
doble tarea como operadores sobrecargados. Los operadores en el nivel de bits And, Or, Xor y
Not aceptan operadores enteros, generando resultados numricos con valores transformados en
el nivel de bits individuales. Tambin funcionan como operadores lgicos, aceptando y regresan-
do valores booleanos, con ms frecuencia en instrucciones condicionales. Pero pueden manejar
el estrs de ser sobrecargados un poco ms.
Cuando sobrecarga estos cuatro operadores, lo est haciendo con las versiones de bits, no las
lgicas. En esencia, esto significa que tiene control sobre el valor devuelto, y no se requiere que
sean booleanos.
En la tabla 12-3 se presenta una lista de los ocho operadores lgicos y en el nivel de bits que
pueden sobrecargarse.

Tabla 12-3. Los operadores lgicos y en el nivel de bits que pueden sobrecargarse.

Operador Comentarios
<< El operador de desplazamiento a la izquierda realiza un desplazamiento de bits en un valor entero de origen, moviendo
los bits a la izquierda un nmero especfico de posiciones. Aunque no tiene que usar este operador para realizar un verda-
dero desplazamiento de bits, debe aceptar una cantidad de desplazamiento (un Integer) como segundo operando.
Public Shared Operator <<(ByVal operando1 As Abejorro, _
ByVal operando2 As Integer) As Abejorro
' ----- Agregar aqui codigo de desplazamiento.
End Operator
>> El operador de desplazamiento a la izquierda realiza un desplazamiento de bits igual que el de desplazamiento a la
izquierda, pero mueve los bits a la derecha. Supongo que hace a esos bits conservadores. Su cdigo puede hacer
que el valor devuelto sea ms liberal, si lo quiere, pero al igual que con el operador de desplazamiento a la izquierda,
debe aceptar un Integer como segundo operando.
Not El operador de negacin en el nivel de bits es unario, aceptando slo un argumento de operando.
And El operador de unin en el nivel de bits establece un bit en el valor devuelto si tambin estn establecidos ambos bits
con igual posicin en los operandos de origen.

Qu puede sobrecargar? | 335

12_PATRICK-CHAPTER_12.indd 335 17/2/10 15:26:47


Tabla 12-3. Los operadores lgicos y en el nivel de bits que pueden sobrecargarse (continuacin).

Operador Comentarios
Or El operador de disyuncin en el nivel de bits establece un bit en el valor devuelto si est establecido cualquier de los
bits con igual posicin en los operandos de origen.
Xor El operador de exclusin en el nivel de bits establece un bit en el valor devuelto si slo est establecido uno de los
bits con igual posicin en los operandos de origen.
IsTrue La sobrecarga del operador Or no sobrecarga automticamente el operador OrElse relacionado. Para usar Or
Else, debe sobrecargar el operador especial IsTrue. No se trata de un operador real de Visual Basic, y no puede
llamarlo directamente cuando lo sobrecarga. Pero cuando usa el operador OrElse en lugar de un operador Or
sobrecargado, Visual Basic llama al operador IsTrue cuando es necesario. Debe seguir unas cuantas reglas para
usar el IsTrue sobrecargado:
El operador Or sobrecargado debe devolver el tipo de la clase en que est definido. Si quiere usar OrElse en la
clase Abejorro, la sobrecarga del operador Or en esa clase debe devolver un valor de tipo Abejorro.
El operador IsTrue sobrecargado debe aceptar un solo operando del tipo de la clase contenedora (Abejo-
rro), y devolver un valor booleano.
Debe sobrecargar el operador IsFalse.
La manera en que determina la verdad o falsedad de un Abejorro depende de usted.
IsFalse La sobrecarga de IsFalse funciona como la de IsTrue, y tiene reglas similares, pero se aplica a los operadores
And y AndAlso.

El operador CType
La caracterstica CType de Visual Basic se parece ms a una funcin que a un operador:
resultado = CType(origen, tipo)

Pero las apariencias engaan. No es una verdadera funcin, y como las dems funciones de con-
versin (como CInt), en realidad se procesa en tiempo de compilacin, mucho antes de que el
programa siquiera se ejecute. Al permitirle sobrecargarlo como un operador, Visual Basic le per-
mite crear conversiones personalizadas y especiales entre tipos de datos que no parecen compati-
bles. La siguiente plantilla de mtodo convierte un valor de tipo Abejorro en un Integer:
Public Shared Operator CType(ByVal operando1 As Abejorro) _
As Integer
' ----- Realizar conversion aqui, devolviendo un Integer.
End Operator

Si trata de escribir ese ltimo bloque de cdigo en Visual Basic, se quejar de que le falta la pa-
labra clave Widening o Narrowing (vase la figura 12-1).

Figura 12-1. Visual Basic se queja de todo, a lo ancho y a lo largo.

336 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 336 17/2/10 15:26:48


Mencion las conversiones de ampliacin y estrechamiento, de pasada, en el captulo 2, pero
examinmoslas con ms detalle. Cuando convierte entre algunos tipos de datos esenciales en
Visual Basic, es posible que en algunas ocasiones fallen porque el valor de origen no se adeca al
valor de destino. Esto es cierto cuando convierte un valor Short en uno Byte.
Dim muyGrande As Short = 5000
Dim muyChico As Byte
' ----- Fallan las dos lineas que siguen.
muyChico = muyGrande
muyChico = CByte(muyGrande)

Y es obvio por qu fallan: una variable Byte no puede contener un valor 5000. Pero qu pasa
con este cdigo?
Dim muyGrande As Short = 5
Dim muyChico As Byte
' ----- Las dos lineas siguientes son correctas.
muyChico = muyGrande
muyChico = CByte(muyGrande)

Se ejecutarn bien, porque 5 cabe en una variable Byte con espacio suficiente. (Si Option
Strict est establecido en On, la primera asignacin no podr compilarse.) An as, nada me
detendr de reasignar un valor de 5000 a muyGrande y tratar de asignarlo de nuevo. El problema
es la posibilidad de falla durante la conversin.
Cuando una conversin tiene la posibilidad de fallar debido a que los datos de origen no
caben completamente en la variable de destino, se trata de una conversin de estrechamien-
to. Este tipo de conversiones son una realidad, y siempre y cuando haya revisado los datos
antes de la conversin, no hay ninguna razn para restringir de manera permanente estas
conversiones.
Las conversiones de ensanchamiento van en la direccin opuesta. Ocurren cuando cualquier valor
de origen en el tipo de datos original siempre cabr fcilmente en el tipo de destino. Una con-
versin de estrechamiento siempre ser correcta si los datos de origen son vlidos.
Visual Basic permite que las conversiones de ensanchamiento ocurran automtica, implcita-
mente. No tiene que usar explcitamente CType para forzar la conversin. Si tiene una conver-
sin de ensanchamiento de Abejorro a Integer, tiene Option Strict en On, el siguiente
cdigo debe funcionar muy bien:
Dim valorOrigen As New Abejorro
Dim valorDestino As Integer = valorOrigen

Si la conversin de Abejorro a Integer fue de ensanchamiento, forzara la conversin usando


CType slo para que Visual Basic estuviera seguro de que realmente quiere hacer esto.
Dim valorOrigen As New Abejorro
Dim valorDestino As Integer = CType(valorOrigen, Integer)

Qu puede sobrecargar? | 337

12_PATRICK-CHAPTER_12.indd 337 17/2/10 15:26:48


Cuando cree conversiones personalizadas con el operador CType sobrecargado, debe informar
a Visual Basic si la conversin es de ensanchamiento o de estrechamiento al insertar la palabra
clave Widening o Narrowing entre las palabras clave Shared y Operator.
Public Shared Narrowing Operator CType( _
ByVal operando1 As Abejorro) As Integer
' ----- Realizar aqui conversion de estrechamiento.
End Operator

Otros problemas con la sobrecarga de operadores


Hay otras cuantas reglas que debe seguir cuando sobrecarga operadores, pero primero revisemos
la til clase Abejorro.
Class Abejorro
Public Abejas As Integer

Public Sub New()


' ----- Constructor predeterminado.
Abejas = 0
End Sub

Public Sub New(ByVal abejasIniciales As Integer)


' ----- Asignar un numero inicial de abejas.
Abejas = abejasIniciales
End Sub

Public Shared Operator +(ByVal operando1 As Abejorro, _


ByVal operando2 As Abejorro) As Abejorro
' ----- Unir grupos de Abejorro.
Dim nuevoGrupo As New Abejorro
nuevoGrupo.Abejas = operando1.Abejas + operando2.Abejas
Return nuevoGrupo
End Operator

Public Shared Operator -(ByVal operando1 As Abejorro, _


ByVal operando2 As Abejorro) As Abejorro
' ----- Separar grupos de Abejorro.
Dim nuevoGrupo As New Abejorro
nuevoGrupo.Abejas = operando1.Abejas - operando2.Abejas
If (nuevoGrupo.Abejas < 0) Then nuevoGrupo.Abejas = 0
Return nuevoGrupo
End Operator

Public Shared Operator *(ByVal operando1 As Abejorro, _


ByVal operando2 As Abejorro) As Abejorro
' ----- Crear un enjambre.
Dim nuevoGrupo As New Abejorro
nuevoGrupo.Abejas = operando1.Abejas * operando2.Abejas
Return nuevoGrupo
End Operator

338 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 338 17/2/10 15:26:48


Public Shared Widening Operator CType( _
ByVal operando1 As Abejorro) As Integer
' ----- Realizar conversion aqui.
Return operando1.Abejas
End Operator
End Class

La clase es muy simple; existe para mantener una cuenta simple de abejas. Pero al sobrecargar los
operadores de suma, resta, multiplicacin y CType, podemos usar instancias de abejas con una
sintaxis ms natural.
Dim grupoEstudio1 As New Abejorro(20)
Dim grupoEstudio2 As New Abejorro(15)
Dim grupoEnjambre As Abejorro = grupoEstudio1 * grupoEstudio2
MsgBox("El enjambre contiene " & CInt(grupoEnjambre) & " abejas.")

La ejecucin correcta de este cdigo genera un enjambre de 300 abejas y el mensaje de la figura 12-2.

Figura 12-2. Seguro que las abejas saben cmo multiplicarse.

La inclusin de una sobrecarga de CType que genera un Integer me permiti convertir Abe-
jorro usando el operador CInt. Tambin pude haber cambiado la ltima lnea para usar el
verdadero operador CType.
MsgBox("El enjambre contiene " & _
CType(grupoEnjambre, Integer) & " abejas.")

Requisitos de declaracin
Como ya mencion, siempre debe hacer que los mtodos Operator sean Public Shared. Y
debido a que los operadores sobrecargados necesitan una especie de conexin ntima con su
clase contenedora, por lo menos uno de los operandos o el valor de regreso debe coincidir con
el tipo de la clase contenedora. (En algunas sobrecargas, Visual Basic impone que sea uno de los
operandos el que coincide.) Cualquier de las dos sobrecargas siguientes funcionar bien, porque
Abejorro se usa para uno de los operandos:
Public Shared Operator <=(ByVal operando1 As Abejorro, _
ByVal operando2 As Integer) As booleano
' ----- Comparar un Abejorro con un valor.

Requisitos de declaracin | 339

12_PATRICK-CHAPTER_12.indd 339 17/2/10 15:26:49


End Operator
Public Shared Operator <=(ByVal operando1 As Date, _
ByVal operando2 As Abejorro) As booleano
' ----- Comparar una fecha con un Abejorro.
End Operator

Sin embargo, no puede establecer ambos operandos en un tipo que no sea Abejorro al mismo
tiempo y an mantener la sobrecarga en la clase Abejorro.
Class Abejorro
Public Shared Operator <=(ByVal operando1 As Date, _
ByVal operando2 As Integer) As booleano
' ----- This will not compile.
End Operator
End Class

Sobrecarga de la sobrecarga
Puede sobrecargar operadores sobrecargados. No, querido editor, no escrib la misma palabra
dos veces por error. Puede agregar mltiples variaciones de la firma de argumentos y valor de
regreso de un operador sobrecargado a una sola clase.
Public Shared Widening Operator CType( _
ByVal operando1 As Abejorro) As Integer
' ----- Realizar aqui conversion a Integer.
End Operator

Public Shared Widening Operator CType( _


ByVal operando1 As Abejorro) As Date
' ----- Realizar aqui conversion a Date, de alguna manera.
End Operator

Siempre y cuando las firmas de argumentos o los valores devueltos difieran puede agregar todas
las sobrecargas de un operador que desee. Tampoco necesita usar la palabra clave Overloads.

Sea amable
Es correcto. Sea amable. No slo porque tenga el poder de redefinir la suma para que sea una
divisin, tiene que ser molesto. No haga que los programadores de mantenimiento que tienen
que modificar su cdigo ms adelante trabajen ms debido a su malvada sobrecarga de operado-
res. Cuando agregue sobrecargas, deje que el significado de la nueva caracterstica por lo menos
tenga la sensacin del operador original. Mis compaeros programadores de mantenimiento y
yo se lo agradeceremos.

Mtodos de extensin
Qu pasa si quiere modificar el comportamiento de una clase, pero no tiene acceso al cdigo
fuente? Podra derivarlo de ella y generar una nueva clase, pero no siempre es conveniente.

340 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 340 17/2/10 15:26:49


Podra llamar al desarrollador original y suplicarle que le d el cdigo, pero algunos de estos
programadores son muy rudos cuando se trata de su software.
Otra opcin consiste en usar una nueva caracterstica de Visual Basic 2008: los mtodos de exten-
sin. He aqu cmo funcionan:
1. Decide qu clase quiere extender con los nuevos mtodos.
2. Escribe esos mtodos dentro de un Module estndar en su cdigo fuente.
3. Empieza a usar los nuevos mtodos como si estuvieran incluidos en la definicin de la clase.
El tipo de datos String incluye varios mtodos integrados que devuelven una versin modifica-
da de una instancia de cadena. Por ejemplo, en este cdigo:
Dim cadenaImpositiva As String = "me hablas a mi?"
MsgBox(cadenaImpositiva.ToUpper())

el texto que aparece en el cuadro de mensaje estar en maysculas porque el mtodo ToUpper
devuelve una nueva versin en maysculas de la instancia de cadena original. Un mtodo To-
Lower equiparable funciona a la inversa, pero lo que realmente quiero es el mtodo ToTitle
que capitaliza slo la primera palabra de cada palabra.
MsgBox(cadenaImpositiva.ToTitle())

La clase String no incluye un mtodo ToTitle, pero podemos agregarlo gracias a los mtodos
de extensin. Para crear un mtodo de extensin, cree un mtodo dentro de un mdulo estndar
que acepta el tipo de datos de destino como primer parmetro.
Module MyExtensions
<System.Runtime.CompilerServices.Extension(
)> _
Public Function ToTitle(ByVal textoOrigen As String) As String
Return StrConv(textoOrigen, VbStrConv.ProperCase)
End Function
End Module

Por lo general, llamara a esta funcin como est, pasndola en la cadena original.
MsgBox(ToTitle(cadenaImpositiva))

Y ese cdigo s funciona, pero la adicin del atributo Extension (del espacio de nombres Sys-
tem.Runtime.CompilerServices) convierte ToTitle en un mtodo de extensin, extendien-
do los tipos de datos String. Su cdigo en realidad no est modificando String. Tras bamba-
linas, el compilador de Visual Basic est convirtiendo la sintaxis parecida a un mtodo nuevo en
una sintaxis parecida a una funcin antigua en cada uso de ToTitle.
En s mismos, los mtodos de extensin no hacen mucho. Llamar a ToTitle(cadenaImpositiva)
no es tan diferente de cadenaImpositiva.ToTitle(). Pero al igual que con muchas nuevas
caractersticas de Visual Basic 2008, los mtodos de extensin se agregaron slo para elevar el
precio del producto. Estoy bromeando! En realidad, la nueva caracterstica de mtodos de ex-
tensin es un soporte importante para la nueva tecnologa LINQ.

Mtodos de extensin | 341

12_PATRICK-CHAPTER_12.indd 341 17/2/10 15:26:49


Resumen
La sobrecarga de operadores es una caracterstica muy agradable, pero en realidad no la necesita.
Cualquier cosa que pueda hacer al sobrecargar el operador de suma la puede hacer tambin al
agregar el mtodo Append a una clase. Pero la sobrecarga de operadores le permite llevar las clases
al uso comn de la sintaxis de Visual Basic.
Los mtodos de extensin tambin pueden replicarse usando el cdigo de mtodo estndar, pero
hay algunas caractersticas de LINQ que aprovechan especficamente los mtodos de extensin.
Cuando sobrecargue sus operadores o use mtodos de extensin, asegrese de incluir documen-
tacin o comentarios suficientes para dejar en claro lo que significa desplazar a la izquierda a un
cliente, usar Normalize() en una String o multiplicar una cuenta de banco. Hey, me gustara
saber sobre la ltima opcin.

Proyecto
En el proyecto de este captulo se agregar una gran cantidad de cdigo a la aplicacin Bibliote-
ca; casi 25% de todo el cdigo bsico. Gran parte de l es idntico al cdigo que agregamos en
captulos anteriores, de modo que para qu imprimirlo aqu. Hay mucho que leer, tambin, de
modo que no lo sobrecargar con el pegado de fragmentos de cdigo por aqu y por all. Pero
mientras agrega cada nuevo formulario al proyecto, asegrese de revisar su cdigo antes de fami-
liarizarse con su funcionamiento interno.

ACCESO AL PROYECTO
Cargue el proyecto Cap12 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap12 (Final) cdigo.

Sobrecarga de una conversin


La sobrecarga de operadores es una herramienta til, y le he tomado especial cario a la sobrecar-
ga de CType. Agreguemos una sobrecarga de CType a una clase que diseamos en el captulo 8:
DatosListaElementos. Esta clase expone las propiedades textoElemento y DatosElemento,
proporcionando acceso a aspectos textuales y numricos del contenido de la clase. Su objetivo
principal es permitir el rastreo de los nmeros de ID en los controles ListBox y ComboBox. Si
necesitamos saber el nmero de ID de un elemento seleccionado en un control ListBox (lla-
mmoslo AlgunaLista), usamos cdigo similar al siguiente:
Dim idRegistro As Integer = _
CType(AlgunaLista.SelectedItem, DatosListaElementos).DatosElemento

Ese cdigo es correcto. Pero pienso No sera adecuado convertir la instancia DatosLista
Elementos a un Integer empleando la funcin CInt, y no tener que mezclarse con variables
de miembro como DatosElemento?

342 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 342 17/2/10 15:26:49


Dim idRegistro As Integer = _
CInt(CType(AlgunaLista.SelectedItem, DatosListaElementos))

Hmm. El cdigo no es tan diferente. Pero hey, por qu no? Hagmoslo. Para dar soporte a esta
conversin, necesitamos agregar la sobrecarga de CType a la clase DatosListaElementos. Abra
el archivo de la clase y agregue el siguiente cdigo como un miembro de la clase.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap12, Elemento 1.

Public Shared Widening Operator CType( _


ByVal elementoOrigen As DatosListaElementos) As Integer
' ----- Para convertir en entero, simplemente extraer
' el elemento entero.
Return elementoOrigen.DatosElemento
End Operator

Es muy simple. Esta conversin de ensanchamiento de DatosListaElementos a Integer slo


devuelve la parte Integer de la instancia. Slo hay cuatro o cinco lugares del Proyecto Biblio-
teca actual que tienen acceso directo al miembro DatosElemento, y no es importante regresar
y cambiarlo. Pero usaremos esta sobrecarga de conversin con frecuencia en el nuevo cdigo
agregado en este captulo.

Caractersticas de soporte global


Necesitamos agregar unas cuantas variables y rutinas globales comunes ms para dar soporte a las
diversas caractersticas usadas en toda la aplicacin. (Y para que pueda compilar la aplicacin sin
problemas, tal como est hasta el momento.) Dos nuevas variables globales rastrearn los par-
metros almacenados en la tabla ValorSistema de la base de datos. Agrguelos como miembros
al mdulo General (en General.vb).

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap12, Elemento 2.

Public LugarPredeterminadoElemento As Integer


Public LimiteCoincBusqueda As Integer

El programa Biblioteca identifica libros y otros elementos que estn almacenados en varios luga-
res, como diversas sucursales o almacenes. LugarPredeterminadoElemento indica cul de esas
ubicaciones, de la tabla CodigoLugar, es la predeterminada. La entrada LugarPredetermina-
do de la tabla ValorSistema de la base de datos almacena este valor de manera permanente.
Cuando se buscan libros, autores y otras cosas que podran dar como resultado miles de coinci-
dencias, LimiteCoincBusqueda indica el nmero mximo de coincidencias devueltas por estas
bsquedas. Se almacena como el valor del sistema LimiteBusqueda.

Proyecto | 343

12_PATRICK-CHAPTER_12.indd 343 17/2/10 15:26:49


Como ya estamos en el mdulo General agregue dos funciones auxiliares.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap12, Elemento 3.

ConfirmarLugarPredeterminado
Esta rutina verifica que existe una entrada vlida LugarPredeterminado en la tabla Va-
lorSistema. Devuelve True si es correcta.
ObtenerCopiaDisposicion
Esta rutina proporciona una corta descripcin del estatus actual de una copia del artculo
de la biblioteca especfica. Analiza los registros de artculos y clientes, y devuelve una de las
siguientes cadenas de cdigo de estatus: Nueva Copia Articulo, Regresado, Prestado,
Vencido, Faltante o Referencia.

Extensin de una clase proporcionada por Framework


Qu hay en un nombre? Bueno, si son los nombres de autores en el Proyecto Biblioteca, po-
dran incluir el nombre, el apellido, prefijos (como Dr.) y sufijos (Jr.), y fechas de nacimiento
y muerte. Algunas de estas partes son opcionales, de modo que formar el nombre del autor es
un proceso de varios pasos. Debido a que la aplicacin necesitar formar los nombres de autor
en varios lugares del cdigo, agreguemos una rutina central, FormarNombreAutor, eso funciona
para nosotros.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap12, Elemento 4.

<System.Runtime.CompilerServices.Extension(
)> _
Public Function FormarNombreAutor( _
ByRef infoBD As SqlClient.SqlDataReader) As String
' ----- Dado un registro de autor, regresar el nombre formado.
Dim nombreAutor As String

On Error Resume Next

' ----- Formar el nombre.


nombreAutor = CStr(infoBD!Apellido)
If (IsDBNull(infoBD!Nombre) = False) Then
nombreAutor &= ", " & CStr(infoBD!Nombre)
If (IsDBNull(infoBD!Inicial) = False) Then _
nombreAutor &= " " & CStr(infoBD!Inicial)
End If
If (IsDBNull(infoBD!Sufijo) = False) Then _
nombreAutor &= ", " & CStr(infoBD!Sufijo)

344 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 344 17/2/10 15:26:49


' ----- Agregar las fechas de nacimiento y muerte.
If (IsDBNull(infoBD!FechaNacimiento) = False) Or _
(IsDBNull(infoBD!FechaMuerte) = False) Then
nombreAutor &= " ("
If (IsDBNull(infoBD!FechaNacimiento) = True) Then
nombreAutor &= "????"
Else
nombreAutor &= CStr(Math.Abs(CInt(infoBD!FechaNacimiento)))
If (CInt(infoBD!FechaNacimiento) < 0) Then _
nombreAutor &= "BC"
End If
nombreAutor &= "-"
If (IsDBNull(infoBD!FechaMuerte) = False) Then
nombreAutor &= CStr(Math.Abs(CInt(infoBD!FechaMuerte)))
If (CInt(infoBD!FechaMuerte) < 0) Then _
nombreAutor &= "BC"
End If
nombreAutor &= ")"
End If

' ----- Terminado.


Return nombreAutor
End Function

Esta rutina es un mtodo de extensin que extiende la clase SqlClient.SqlDataReader. El


atributo Extension plenamente calificado hace la conexin entre nuestra extensin persona-
lizada y la clase SqlDataReader definida por el marco de trabajo. Dado un SqlDataReader
generado a partir de los registros en la tabla Autor, la funcin forma y devuelve un nombre de
autor amigable en el formato Prado, Juan Q, Jr. (1900-1999). En cualquier otro lugar de la
aplicacin, se le llama como si fuera un miembro de la instancia lectora de datos.
infoBD.FormarNombreAutor( )

Podramos dejar afuera las caractersticas del mtodo de extensin con slo omitir el atributo
Extension. Luego, las llamadas para la formacin de autor tendra este aspecto:
FormarNombreAutor(infoBD)

Editores de registros y formularios de apoyo


Ahora las cosas se empiezan a agitar. Agregaremos 23 nuevos formularios a la aplicacin en este
captulo. Casi todos ellos implementan editores bsicos de cdigo, similares a los archivos Nom-
breUsuario.vb y NombreGrupo.vb que construimos en el captulo 11. Existen otros formularios
que proporcionan soporte adicional para esos editores de registros. No reimprimir nada que
ya hayamos visto antes, pero sealar algn cdigo nuevo interesante en cada uno de estos 23
formularios.
Si est siguiendo desde la versin Antes del proyecto de este captulo, necesitar habilitar cada
formulario a medida que lo encuentra. Para ello, seleccione el archivo en la ventana Explorador
de soluciones y cambie la propiedad Accin de compilacin (en el panel Propiedad) de Ninguna
a Compilacin.

Proyecto | 345

12_PATRICK-CHAPTER_12.indd 345 17/2/10 15:26:49


Formularios de limitacin de bsqueda
Los primeros cuatro formularios permiten al bibliotecario limitar la sobrecarga de informa-
cin que viene con el uso de una base de datos con miles de libros, editores y autores. Tal vez
recuerde que el formulario genrico ListaRegistrosEditados despliega todos los registros
existentes de una tabla de registros, como opcin predeterminada. Esto funciona bien para los
grupos de seguridad almacenados en la tabla NombreGrupo, porque tal vez no tenga ni siquiera
una docena de ellos. Pero elaborar una lista de todos los libros de una biblioteca pequea puede
generar una lista muy importante. Y dependiendo de la velocidad de su estacin de trabajo,
puede tomarle mucho tiempo cargar todos los ttulos de libros en la lista.
Los cuatro formularios de limitacin de bsqueda le ayudan a reducir el nmero de registros
que aparecen en la lista a la vez. Cuando el bibliotecario accede a la lista de libro y otros elemen-
tos de la biblioteca, el formulario LimitarArticulos (vase la figura 12-3) proporciona una
manera rpida de reducir los resultados de la lista.

Figura 12-3. El formulario LimitarArticulos acta como el encargado de sacar a los clientes molestos de un bar, en
este caso en relacin con los elementos de una lista.

El formulario permite al usuario recuperar todos los registros, o elementos especficos basados en
el nombre del elemento (con soporte a comodines). Una vez que se cargan las coincidencias, el
usuario puede acceder de nuevo a este formulario al hacer clic en el botn Buscar del formulario
ListaRegistrosEditados para estos tipos de editores de cdigo que dan soporte a bsquedas
(autores, artculos, clientes y editores).
Estamos listos para incluir estos cuatro formularios de limitacin de bsqueda al proyecto:
LimitarAutor.vb
Este formulario limita los registros de autor, como se cargan de la tabla Autor.
LimitarArticulos.vb
ste es el formulario del que acabamos de hablar. Limita el despliegue de los elementos de
biblioteca de la tabla ArticuloConNombre.
LimitarCliente.vb
Slo en caso de que los clientes estn volando hacia su biblioteca, este formulario le permite
limitar los registros cargados de la tabla Cliente.
LimitarEditor.vb
Este formulario limita los registros de la tabla Editor.

346 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 346 17/2/10 15:26:50


Editores de palabras clave y temas
Aunque la mayor parte de los editores de registros proporcionan una experiencia de edicin
completa mediante el formulario ListaRegistrosEditados, algunos estn subordinados a
otros formularios de edicin. Las palabras clave y los temas son un buen ejemplo. Aunque cada
una tiene sus propias tablas independientes (Clave y Tema), eleg permitir la edicin de ellas
mediante el formulario que edita elementos de biblioteca individuales, el formulario Articulo-
ConNombre (que se agrega ms adelante). Ese formulario administra todas las interacciones entre
los registros Clave y Tema y la tabla ArticuloConNombre, todo mediante las tablas intermedias
varios a varios ClaveArticulo y TemaArticulo.
Los formularios AgregarPalabraClave y AgregarTema proporcionan un formulario de entra-
da simple para una sola palabra clave o un solo tema. Incluya ahora cada uno de estos formula-
rios al proyecto:
AgregarPalabraClave.vb
AgregarTema.vb

Ms formularios con soporte a artculos con nombre


Como veremos ms adelante, el formulario ArticuloConNombre es uno de los ms complejos
agregados al Proyecto Biblioteca hasta ahora. Administra todos los artculos generalizados de
una biblioteca (como un libro). Cada elemento puede tener varias copias, autores, palabras cla-
ve, temas, etc. Simplemente es demasiado poder de edicin para incluir en un solo formulario.
Ya agregamos dos de los formularios subordinados: AgregarPalabraClave y AgregarTema.
Agreguemos cinco formularios de soporte adicionales:
AgregarLocalizarAutor.vb
Este formulario presenta una interfaz tipo asistente que le permite al usuario agregar un
registro de autor nuevo o existente a un artculo. Autores en el programa Biblioteca es un
trmino genrico que alude a autores, editores, ilustradores, artistas, etc. Los tres pasos de
este formulario le permiten al usuario 1) indicar el tipo de autor mediante la tabla Codigo-
TipoAutor; 2) realizar una bsqueda de un autor existente, por nombre, y 3) seleccionar
de una lista de nombres de autor coincidentes. Si el autor deseado no se encuentra an en
la base de datos, el ltimo paso permite que se agregue un nuevo autor. En la figura 12-4 se
muestran los primeros dos de estos pasos.

Figura 12-4. Los primeros dos de tres pasos del asistente para autores.

Proyecto | 347

12_PATRICK-CHAPTER_12.indd 347 17/2/10 15:26:50


Parte de la lgica es controlada mediante el manejador de eventos del botn Siguiente. El
cdigo de esta rutina vara con base en el panel del asistente actual desplegado (como se in-
dica en la variable del nivel de clase PanelActivo). He aqu el cdigo que se ejecuta cuando
el usuario hace clic en Siguiente despus de seleccionar el tipo de autor:
' ----- Asegurarse de que se seleccione un tipo de nombre.
If (CInt(CType(TipoNombre.SelectedItem, _
DatosListaElementos)) = -1) Then
MsgBox("Por favor, seleccione un tipo de nombre de la lista.", _
MsgBoxStyle.OkOnly Or MsgBoxStyle.Exclamation, _
TituloPrograma)
TipoNombre.Focus()
Return
End If

' ----- Mover al panel de busqueda.


PanelActivo = PanelCriterios
SegundoPanel.Visible = True
PrimerPanel.Visible = False
AccAtras.Enabled = True
Apellido.Focus()

Observa la primera lnea lgica de ese cdigo? Utilizamos la funcin de conversin CInt
para obtener un valor de DatosElemento de un elemento de la lista. Esto llama a nuestro
operador CType sobrecargado en la clase DatosListaElementos.
AgregarLocalizarEditor.vb
Este formulario es como AgregarLocalizarAutor, pero se concentra en los editores. Su
asistente slo tiene dos pasos porque los editores no estn agrupados por tipo. Localiza y agre-
ga registros a la tabla Editor. Cuando es hora de agregar un editor a un artculo, el formulario
del editor del elemento llama a la funcin pblica AgregarLocalizarEditor.Preguntar
Usuario. Esta funcin devuelve el ID del registro del editor seleccionado, o -1 para abortar
la adicin de un editor. Un valor devuelto de -2 limpia cualquier ID de editor seleccionado.
AgregarLocalizarSerie.vb
El formulario es similar a AgregarLocalizarEditor, pero pide registros de la tabla Co-
digoSerie.

EditarAutorArticulo.vb
Una vez ms, se ha agregado un autor a un artculo, la nica manera de cambiarlo a un
autor diferente consiste en eliminar el autor incorrecto y agregar el correcto por separado
mediante el formato AgregarLocalizarAutor. Pero si el usuario simplemente seleccion
el tipo de autor equivocado (como Editor en lugar de Ilustrador), es una carga buscar
de nuevo el nombre del autor para cambiar el tipo. El formulario EditarAutorArticulo
permite que el usuario modifique el tipo de un autor ya agregado a un elemento. Modifica
el campo de la base de datos AutorArticulo.TipoAutor.

348 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 348 17/2/10 15:26:50


CopiaArticulo.vb
Una biblioteca tal vez tendr varios ejemplares de un libro, CD u otro artculo en particu-
lar. En el programa Biblioteca, esto significa que cada registro ArticuloConNombre puede
tener ms de un registro CopiaArticulo adjunto. Cada copia se edita mediante el formu-
lario CopiaArticulo (vea la figura 12-5).

Figura 12-5. Detalles que slo un bibliotecario podra adorar.


Aunque este cdigo no se hereda de FormularioCodigoBase como otros editores de regis-
tros, an tiene muchas de las caractersticas de esos formularios, incluida una rutina Guar-
darDatosFormulario que escribe registros en la base de datos.

Algo interesante que tiene este formulario es soporte para leer cdigos de barras. Muchos lec-
tores de cdigos de barras actan como una cua, insertando el texto de un cdigo de barras
escaneado en un flujo de entrada de teclado de la computadora. Cualquier programa que
monitoree cdigos de barras simplemente tiene que monitorear entrada normal de texto.
Los escneres de cdigo de barras adjuntan un retorno de carro (la tecla Enter) al final del
cdigo de barras transmitido. Esto permite que un programa detecte el final del nmero de
cdigo de barras. Pero en casi todos los datos del programa Biblioteca, la tecla Enter dispara el
botn Aceptar y cierra el formulario. No queremos que esto suceda aqu. Para evitarlo, agre-
garemos algn cdigo a este formulario que deshabilita el clic automtico en el botn Aceptar
cada vez que el punto de insercin est en el campo de entrada de texto CodigoBarras.

Proyecto | 349

12_PATRICK-CHAPTER_12.indd 349 17/2/10 15:26:51


INSERCIN DE FRAGMENTO DE CDIGO
Inserte el fragmento de cdigo Cap12, Elemento 5.

Private Sub RegistroCodigoBarras_Enter( _


ByVal sender As Object, ByVal e As System.EventArgs) _
Handles RegistroCodigoBarras.Enter
' ----- Resaltar todo el texto.
RegistroCodigoBarras.SelectAll()
' ----- No permitir que Enter cierre el formulario.
Me.AcceptButton = Nothing
End Sub
Private Sub RegistroCodigoBarras_Leave( _
ByVal sender As Object, ByVal e As System.EventArgs) _
Handles RegistroCodigoBarras.Leave
' ----- Permitir que Enter cierre de nuevo el formulario.
Me.AcceptButton = AccAceptar
End Sub
Private Sub RegistroCodigoBarras_KeyPress(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles RegistroCodigoBarras.KeyPress
' ----- Ignorar la tecla enter.
If (e.KeyChar = ChrW(Keys.Return)) Then e.Handled = True
End Sub

Con este cdigo, cuando el usuario oprime la tecla Enter en el campo CodigoBarras ma-
nualmente, el formulario no se cierra. Pero es un pequeo precio que hay que pagar para el
soporte a cdigo de barras.

Editores de cdigo heredados


Doce de los formularios agregados en este captulo heredan directamente de la clase Formula-
rioCodigoBase. Agrguelos al proyecto mientras reviso cada uno.
Autor.vb
El formulario Autor edita registros en la tabla Autor de la base de datos. Como una clase
derivada tpica de FormularioCodigoBase, sobrescribe muchos de los elementos pbli-
cos de su clase base. Dos de las sobrescrituras que an no se han usado en captulos ante-
riores son los mtodos UsaBusqueda y BuscarRegistro. stos permiten al usuario del
formulario ListaRegistrosEditados limitar los autores desplegados mediante el uso
del formulario LimitarAutor descrito antes en este captulo. (RellenarListaConRe-
gistros tambin sobrescribe las llamadas de BuscarRegistro para preguntar al usuario
la lista inicial de autores que se desplegar.)
En BuscarRegistro, la llamada a LimitarAutor.PreguntarUsuario devuelve una ca-
dena separada por comas en el formato Apellido, Nombre.
' ----- Preguntar al usuario por el nombre del autor limitado.
coincidenciasExcedidas = False

350 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 350 17/2/10 15:26:51


limiteUsuario = (New LimitarAutor).PreguntarUsuario( )
If (limiteUsuario = "") Then Return

El usuario puede incluir el asterisco (*) como comodn en las partes de nombre o apelli-
do. El asterisco se ha vuelto un carcter comn para usar en todos los tipos de bsqueda
con comodn. Por desgracia, no es soportado en las instrucciones SELECT de SQL Server,
que usa, en cambio, el carcter de porcentaje (%) como comodn (como muchas otras
plataformas de base de datos que cumplen con SQL). Como BuscarRegistros extrae
el apellido y el nombre, asegrese de que se usa el carcter comodn adecuado.
' ----- Usar los limites para ayudar a preparar el texto de busqueda.
limiteApellido = Trim(ObtenerSubCadena(limiteUsuario, ",", 1))
limiteNombre = Trim(ObtenerSubCadena(limiteUsuario, ",", 2))
If ((limiteApellido & limiteNombre) = "") Then Return
If (InStr(limiteApellido, "*") = 0) Then limiteApellido &= "*"
If (InStr(limiteNombre, "*") = 0) Then limiteNombre &= "*"
limiteApellido = Replace(limiteApellido, "*", "%")
limiteNombre = Replace(limiteNombre, "*", "%")

Este cdigo usa la rutina personalizada ObtenerSubCadena ya agregada al mdulo General.


Una vez que las partes del nombre se han extrado, la funcin Replace de VisualBasic reemplaza
todas las instancias de * con %. Encontrar cdigo similar en los otros editores de registros que le
permiten lmites en la lista de registros, como el formulario Editor que se agregar ms adelante.
Mientras tiene el cdigo fuente abierto para este formulario, acrquese a la parte superior.
All, encontrar una instruccin Imports interesante:
Imports MVB = Microsoft.VisualBasic

Por lo general, Imports es seguido de inmediato por un espacio de nombres. Esta variacin in-
cluye el prefijo MVB =, que define un mtodo abreviado para el espacio de nombres Microsoft.
VisualBasic de cdigo en este archivo. Si Visual Basic importa demasiados espacios de nom-
bres en una clase existente que tambin define una gran cantidad de miembros pblicos, est lla-
mado a tener conflictos entre nombres de miembro. En este caso, el conflicto est en el miembro
del formulario Left. Debido a que este cdigo fuente para el formulario Autor ve todo a travs
del prisma de ese formulario, cuando incluye la palabra clave Left en su lgica, el cdigo supone
de manera natural que se refiere a la propiedad Left del formulario, lo que establece la posicin
izquierda del formulario. El problema es que Left tambin es una funcin comn de manipula-
cin de cadena que extrae los caracteres del extremo izquierdo de una cadena ms larga:
cadenaMasCorta = Left(cadenaMasLarga, 5)

En un formulario, este cdigo genera un error, porque piensa que Left se refiere a Me.Left.
Para usar la versin de cadena de Left, tiene que incluir su espacio de nombres como prefijo:
cadenaMasCorta = Microsoft.VisualBasic.Left( _
cadenaMasLarga, 5)

La instruccin especial Imports nos permite usar un sustituto ms corto para el espacio de
nombres ms bien largo Microsoft.VisualBasic:
cadenaMasCorta = MVB.Left(cadenaMasLarga, 5)

Proyecto | 351

12_PATRICK-CHAPTER_12.indd 351 17/2/10 15:26:51


Encontrar unas cuantas instancias de este cdigo en ste y otros formularios que incluyan
el mtodo abreviado MVB.
El formulario Autor tiene un elemento notable ms. Una etiqueta Nombres coincidentes
aparece cerca de la parte inferior del formulario, como se muestra en la figura 12-6.

Figura 12-6. La parte inferior del formulario Autor que muestra Nombres coincidentes.

Este campo ayuda al usuario a evitar la adicin del mismo autor a la base de datos dos ve-
ces. A medida que se hacen cambios a los campos Apellido y Nombre, el campo Nombres
coincidentes obtiene actualizaciones de nombres de autor encontrados en la tabla Autor.
La rutina ActualizarAutoresCoincidentes cuenta el nmero de autores coincidentes
a travs del cdigo siguiente:
textoSql = "SELECT COUNT(*) AS LaCuenta " & _
"FROM Autor WHERE Apellido LIKE " & _
DBText(Trim(RegistroApellido.Text))
If (Trim(RegistroNombre.Text) <> "") Then
textoSql &= " And Nombre LIKE " & _
TextoBD(MVB.Left(Trim( _
RegistroNombre.Text), 1) & "%")
End If
cuentaCoincidencias = CInt(EjecutarSQLRegresar(textoSql))

Esto es similar al cdigo de bsqueda en la rutina SearchForLimit, pero tambin agrega


un comodn al nombre, antes de hacer la bsqueda.
CodigoTipoAutor.vb
El formulario CodigoTipoAutor edita registro en la tabla CodigoTipoAutor relacionada.
Quin saba?
CodigoEstatusCopia.vb
Este formulario edita registros en la tabla CodigoEstatusCopia base de datos.
CodigoLugar.vb
Como es de esperar, este formulario edita registros en la tabla CodigoLugar. Una vez que
haya agregado por lo menos un registro a esa tabla, podr establecer el lugar predeterminado
para la base de datos. Analizar esto de nuevo un poco ms adelante en este captulo.
CodigoTipoMedio.vb
El formulario CodigoTipoMedio, que edita registros en la tabla CodigoTipoMedio, inclu-
ye unos cuantos campos ms que otros editores de las tablas Cdigo. La mayor parte de
los campos aceptan entrada numrica. Aunque hago una revisin fiel de datos numricos v-
lidos justo antes de escribir el registro a la base de datos, trato de evitar datos no numricos

352 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 352 17/2/10 15:26:52


que se muestren en primer lugar al restringir los tecleos aceptables. Por ejemplo, el evento
KeyPress del campo de texto RegistroRevisionDatos incluye este cdigo:
' ----- Slo permitir digitos y retrocesos.
If (e.KeyChar = vbBack) Or _
(IsNumeric(e.KeyChar)) Then Return
e.Handled = True

Al establecer la propiedad e.Handled en True se evita que Visual haga algo ms (mucho)
con la tecla ingresada. Es una manera rpida y fcil de disponer de un tecleo de entradas
del usuario.
CodigoGrupoCliente.vb
Este formulario edita registros de la tabla CodigoGrupoCliente.
CodigoSerie.vb
Este editor administra registros en la tabla CodigoSerie. Ya mencion la manera en que
los nombres de serie y las palabras clave estn subordinados a elementos con nombre. Pero
tambin tiene sentido para m proporcionar administracin directa de nombre de series,
en caso de que quiera construir una lista comn antes de agregar artculos individuales de
la biblioteca. As que este formulario realiza una tarea doble: puede acceder a l median-
te el editor estndar de registros ListaRegistrosEditados, y tambin se usa desde un
elemento con nombre especificado a travs del formulario an no agregado ArticuloCon-
Nombre.
Cuando se editan nombres de serie especficos de artculos, el usuario obtiene primero un
nombre de serie, al escribirlo. Como no quiere que el usuario tenga que escribir de nuevo
los nombre de serie en este formulario de editor, quiero pasar el nombre de serie en el for-
mulario CodigoSerie, pero ninguno de los mtodos pblicos sobrescritos son compatibles
con esto. De modo que necesitar agregar un nuevo mtodo que acepte el nombre escrito.
El miembro AgregarRegistro ya sobrescribe la funcin base del mismo nombre.
Public Overrides Function AgregarRegistro(
) As Integer
' ----- Agregar un nuevo registro.
IDActivo = -1
PrepararCamposFormulario()
Me.ShowDialog()
If (Me.DialogResult = Windows.Forms. _
DialogResult.OK) Then _
Return IDActivo Else Return -1
End Function

Agreguemos una sobrecarga a esta funcin que incluye un argumento de cadena. El llamador
pasar el texto originalmente escrito al argumento. Lo asignare a la propiedad Text del con-
trol RecordFullName, para que se muestre apropiadamente cuando se abre el formulario.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap12, Elemento 6.

Proyecto | 353

12_PATRICK-CHAPTER_12.indd 353 17/2/10 15:26:52


Public Overloads Function AgregarRegistro( _
(ByVal textoSerie As String) As Integer
' ----- Agregar un nuevo registro, pero usar un valor inicial ingresado
' antes por el usuario.
IDActivo = -1
PrepararCamposFormulario()
RegistroNombreCompleto.Text = textoSerie
Me.ShowDialog()
If (Me.DialogResult = Windows.Forms.DialogResult.OK) Then _
Return IDActivo Else Return -1
End Function

S, podramos haber usado algn nombre distinto de AgregarRegistro para esta funcin y
evitado agregar una sobrecarga. Pero es agradable mantener la consistencia de las cosas.
Festivos.vb
Este formulario administra los registros de la tabla Festivo. En un captulo posterior, agre-
gar una cach de das festivos dentro del programa para rpido acceso.
Cliente.vb
El formulario Cliente proporciona servicios de edicin para registros en la tabla Cliente,
y aparece en la figura 12-7.

Figura 12-7. La mayor parte del formulario Cliente (se oculta la ficha de detalles).

354 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 354 17/2/10 15:26:52


Este formulario incluye una FichaControl para ayudarle a dividir el nmero de campo
que el usuario usa a la vez. Si alguna vez ha usado el control de fichas incluido con Visual
Basic 6.0, rpidamente apreciar el reemplazo de .NET. Administra toda la lgica de cambio
de panel automticamente cuando el usuario selecciona una ficha diferente. Cada panel es
una instancia de clase separada TabPage. En su cdigo, forzar que el control de ficha des-
pliegue una ficha diferente es tan fcil como asignar la instancia de TabPage apropiada a
la propiedad SelectedTab del objeto FichaControl, como con esta lnea de cdigo de la
funcin ValidarDatosFormulario:
FichaCliente.SelectedTab = FichaGeneral

Aunque este formulario tiene un aspecto muy complejo, est integrado casi por completo
por cdigo que hemos visto en otros formularios. Ms all de las sobreescrituras estndar
de los miembros de FormularioCodigoBase, este formulario incluye soporte a rastreo de
cdigo de barras prestado del formulario CopiaArticulo, la lgica de contrasea prestada
del formulario NombreUsuario, y cdigo de asignacin de nombres similar al usado en el
formulario Autor.
Inclu un botn Administrar artculos de cliente el formulario, pero no agregaremos su lgi-
ca hasta un captulo posterior. Una funcin pblica adicional, EditarRegistroLimitado,
se vuelve importante en este momento.
Editor.vb
El formulario Editor permite al usuario editar los registros de la tabla Editor. Es un for-
mulario muy simple, con slo dos campos de entrada de datos. Un campo Estatus indica
cuntos registros ArticuloConNombre vinculan a este editor. Aparece un pequeo botn a
la derecha del campo de entrada de texto para el sitio Web del editor. ste es el botn
mostrarme el sitio Web, y cuando se hace clic en l, se trae la pgina Web proporcionada
en el explorador predeterminado del usuario. Para habilitar este botn, agregue el siguiente
cdigo al manejador de eventos Click del botn MostrarWeb.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap12, Elemento 7.

' ----- Mostrar el sitio Web desplegado en el campo.


Dim nuevoProceso As ProcessStartInfo

On Error Resume Next


If (Trim(RegistroWeb.Text) = "") Then Return
nuevoProceso = New ProcessStartInfo(Trim(RegistroWeb.Text))
Process.Start(nuevoProceso)

ValorSistema.vb
Este editor de cdigo maneja elementos de la tabla ValorSistema. Aunque lo conectare-
mos con un vnculo en el formulario Biblioteca en este captulo, cambiaremos este mtodo
de acceso en un captulo posterior.

Proyecto | 355

12_PATRICK-CHAPTER_12.indd 355 17/2/10 15:26:52


Bueno, eso representa 11 de los 12 formularios derivados. El ltimo es el formulario Articulo-
ConNombre, mostrado en la figura 12-8.

Figura 12-8. El formulario ArticuloConNombre con la ficha General activa.

El formulario ArticuloConNombre es el ms largo y complejo de los que derivan de Formu-


larioCodigoBase. Edita de manera principal artculos de la biblioteca registrados en la tabla
ArticuloConNombre de la base de datos. Es complejo porque tambin administra registros
directa o indirectamente en las tablas subordinadas: AutorArticulo, CopiaArticulo, Cla-
veArticulo, TemaArticulo e, indirectamente, Autor, Clave, Editor y Tema.
Todos los campos de las fichas General y Clasificacin son campos de entrada de datos bsicos
que fluyen directamente en la tabla ArticuloConNombre, al igual que lo hace con los dems
formularios de edicin de registros. Los campos Editor y Serie usan formularios separados de
seleccin (AgregarLocalizarEditor y AgregarLocalizarSerie) para obtener los valores
de ID almacenados en ArticuloConNombre. He aqu el cdigo que busca el editor:
' ----- Preguntar al usuario.
nuevoEditor = (New AgregarLocalizarEditor).PreguntarUsuario()
If (nuevoEditor = -1) Then Return

' ----- Revisar para limpiar el editor.


If (nuevoEditor = -2) Then

356 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 356 17/2/10 15:26:53


RegistroEditor.Text = "No disponible"
IDEditor = -1
Return
End If

Las otras cuatro fichas (Autores/nombres, Temas, Palabras clave y Copias) administran registros
subordinados. El cdigo es muy consistente entre las cuatro fichas diferentes, de modo que limi-
tar los comentarios a la ficha Autores/nombres (vase la figura 12-9).

Figura 12-9. El formulario ArticuloConNombre con la ficha Autores/nombres activa.

Los controles de esta ficha son muy similares a los del formulario ListaRegistrosEditados;
existen para administrar un conjunto de registros en una tabla. En este caso, la tabla AutorAr-
ticulo. Para conocer la lista de presentacin, eleg usar un control ListView en lugar de uno
ListBox estndar. Al establecer en Details la propiedad View, y en True el campo FullRow-
Select del control ListView, y modificar su coleccin Columns (vase la figura 12-10), puede
convertirla rpidamente en un cuadro de lista de varias columnas.
Cuando agregue un elemento a la lista, tambin tiene que agregar subelementos para hacer que
cualquier cosa aparezca en todo, excepto la primera columna.
Dim nuevoArticulo As Windows.Forms.ListViewItem = _
ListaAutores.Items.Add("John Smith")
nuevoArticulo.SubItems.Add("Ilustrador")

El botn Agregar despliega el formulario AgregarLocalizarAutor, mientras que el botn


Propiedades despliega, en cambio, el formulario EditarAutorArticulo.
Antes de que pueda agregarse cualquiera de los registros subordinados, debe existir el registro prin-
cipal en la base de datos. Esto es porque los registros secundarios incluyen el nmero de ID del

Proyecto | 357

12_PATRICK-CHAPTER_12.indd 357 17/2/10 15:26:54


Figura 12-10. El editor ColumnHeader de un control ListView.

registro principal, y sin un registro principal, no hay un nmero de ID principal. Si revisa cada una
de las rutinas del botn Agregar en este formulario, encontrar cdigo como el siguiente:
' ----- El registro debe guardarse primero.
If (IDActivo = -1) Then
' ----- Confirmar con el usuario.
If (MsgBox("El artculo debe guardarse primero en la base " & _
"de datos antes de que pueda agregarse la palabra clave. " & _
"Le gustara guardar el registro ahora?", _
MsgBoxStyle.YesNo Or MsgBoxStyle.Question, _
TituloPrograma) <> MsgBoxResult.Yes) Then Return

' ----- Verificar y guardar los datos.


If (ValidarDatosFormulario() = False) Then Return
If (GuardarDatosFormulario() = False) Then Return
End If

Si ste es un registro ArticuloConNombre completamente nuevo (IDActivo = 1), este cdigo


lo guardar antes de permitir que el usuario agregue el registro subordinado. Cualquier dato no
vlido que evite que el registro se guarde ser capturado en la llamada a ValidarDatosFormu-
lario.
En realidad, las llamadas a ValidarDatosFormulario y GuardarDatosFormulario son las
mismas que ocurren cuando el usuario hace clic en el botn Aceptar. Por lo general, eso desenca-
dena un regreso del nmero de ID del nuevo registro al formulario que llama. Pero qu pasa si

358 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 358 17/2/10 15:26:54


GuardarDatosFormulario obtiene llamadas al agregar un autor, pero entonces el usuario hace
clic en el botn Cancelar (que por lo general devuelve un valor 1 para indicar no hay registro
agregado)? Para evitar eso, la funcin GuardarDatosFormulario establece una variable en el
nivel de clase llamada SesionGuardada:
SesionGuardada = True

Esta marca se limpia cuando el formulario se abre por primera vez, pero se establece en True
cada vez que cambia un registro subordinado. Las funciones sobrescritas AddRecord y EditRe-
cord del formulario ArticuloConNombre revisa esta marca antes de regresar al formulario que
llama.
If (Me.DialogResult = Windows.Forms.DialogResult.OK) Or _
(SesionGuardada = True) Then Return IDActivo Else Return -1

Hay grandes cantidades de cdigo interesante adicional en el formulario ArticuloConNombre.


Pero en casi 1400 lneas (sin contar el diseador de cdigo relacionado), tendr que dejar que
lo investigue por su cuenta.

Conexin de los editores al formulario principal


Muy bien, respire hondo. Fue demasiado cdigo para revisar. Pero si ejecuta ahora el programa,
no ver ninguna diferencia. An necesitamos conectar todos los editores de registro al formu-
lario principal. Todos se conectan mediante los controles LinkLabel del panel Administracin
del formulario principal (PanelAdmin). Necesitamos agregar 12 manejadores de eventos Link-
Clicked para acceder todos los nuevos y diversos formularios. Siga adelante y agrguelos ahora
a la clase FormularioPrincipal.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap12, Elemento 8.

Cada uno de los manejadores de eventos LinkClicked es casi una imagen de espejo del otro,
excepto por unas cuantos nombres de instancia de objetos por aqu y por all. He aqu el cdigo
que maneja un clic en la etiqueta de vnculo del editor:
Private Sub AdminVinculoEditores_LinkClicked( _
ByVal sender As System.Object, ByVal e As _
System.Windows.Forms.LinkLabelLinkClickedEventArgs) _
Handles AdminVinculoEditores.LinkClicked
' ----- Asegurar que el usuario tiene permitido hacer esto.
If (PerfilSeguridad(SeguridadBiblioteca.AdministrarEditores) = _
False) Then
MsgBox(MensajeNoAutorizado, MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If

Proyecto | 359

12_PATRICK-CHAPTER_12.indd 359 17/2/10 15:26:54


' ----- Dejar que el usuario edite la lista de editores.
ListaRegistrosEditados.AdministrarRegistros(New Biblioteca.Editor)
ListaRegistrosEditados = Nothing
End Sub

Despus de hacer una rpida revisin de seguridad, el cdigo llama al formulario estndar Lis-
taRegistrosEditados, pasndole una instancia del editor de registro que habr de usar.
Hay an unos cuantos vnculos inactivos en el panel Administracin que habilitaremos en ca-
ptulos posteriores.

Establecimiento de la ubicacin predeterminada


El programa est ahora listo para ejecutarse con todas sus nuevas caractersticas incluidas. De-
bido a que slo agregamos caractersticas administrativas, debe hacer clic en el botn Iniciar
sesin de la esquina superior derecha del formulario principal antes de obtener acceso al panel
Administracin y sus caractersticas. A menos que lo cambie, su nombre de usuario de inicio de
sesin es admin sin contrasea.
Aunque ahora puede ejecutar el programa y acceder a todos los editores de registros, no podr
agregar nuevas copias de artculos hasta que establezca una ubicacin predeterminada. Para es-
tablecer la ubicacin:
1. Agregue por lo menos una ubicacin a travs del vnculo Ubicaciones en el panel Administra-
cin.
2. Obtenga el nmero de ID del registro CodigoLugar que quiere que sea el predeterminado. Pue-
de usar las caractersticas de consulta de SQL Server Management Studio Express para acceder a
los registros de esta tabla. Si es la primera vez que ha agregado registros a la tabla CodigoLugar,
el primer artculo que agregue tendr valor de ID de 1.
3. De regreso en el programa Biblioteca, edite la tabla ValorSistema a travs del vnculo Valores
del sistema del panel Administracin.
4. Agregue o modifique el valor del sistema LugarPredeterminado, estableciendo su valor en el
nmero de ID del registro de ubicacin predeterminado.
Como opcin, puede actualizar el registro LugarPredeterminado en la tabla ValorSistema
empleando SQL Server Management Studio Express. Si el ID de la ubicacin que habr de usar
es 1, utilice esta instruccin SQL para hacer el cambio:
UPDATE ValorSistema
SET DatosValor = '1'
WHERE NombreValor = 'LugarPredeterminado'

En un captulo futuro, agregaremos un mtodo ms amigable con el usuario para actualizar esta
ubicacin predeterminada.
Hablando de esto ltimo, estamos por ingresar al mundo no amigable con el usuario, pero s con
la lgica de los datos de texto estructurados: XML.

360 | Captulo 12: Sobrecargas y extensiones

12_PATRICK-CHAPTER_12.indd 360 17/2/10 15:26:54


Captulo 13
XML

Debido a que las computadoras son computadoras y las personas son personas, por lo general
tienen necesidades diferentes cuando se trata de poner los datos en un formato til. XML es un
intento de organizar datos en una estructura que sea til para la gente y para el software.
XML se ha puesto de moda en aos recientes, pero sus races son muy antiguas. Se deriva de
SGML (Standard Generalized Markup Language, lenguaje estndar de marcado generalizado),
como HTML (son primos!). SGML, a su vez, proviene de GML (Generalized Markup Lan-
guage, lenguaje de marcado generalizado), un metalenguaje (un lenguaje que describe a otro)
diseado por IBM en la dcada de 1960. As que culpe a IBM si quiere, pero de todos modos
estar en contacto regular con XML mientras desarrolla aplicaciones .NET.
Tambin podra decirlo desde el principio: amar a XML, o lo odiar. Pero tal vez har ambas
cosas. Se trata de una bestia extraa, este XML, como lo esperara de cualquier acrnimo que
toma letras de la parte intermedia de las palabras que representa (eXtensible Markup Langua-
ge, lenguaje extensible de marcado). XML representa un alfabeto de tecnologas de manipula-
cin de datos, un alfabeto que, extraamente, tiene siete X. Pero basta de bromas; extendamos
nuestra comprensin de esta tecnologa bsica de .NET.

Qu es XML?
XML no es ms que un formato de datos que es legible para los seres humanos y para la m-
quina. Alguna vez ha tratado de abrir un documento de Microsoft Word en el Bloc de notas?
Buena suerte (vase la figura 13-1). Aunque podra distinguir fcilmente el texto principal
del documento, la mayor parte de lo que ve son jeroglficos. Eso se debe a que se trata de un
formato binario de propietario. Es de propietario porque, francamente, no debe estar hurgando
all. Para eso est Microsoft Word. Y es binario, porque puede almacenar de manera conve-
niente una gran cantidad de informacin en poco espacio de disco. Con este tipo de archivos,
puedo almacenar mis datos de la manera en que lo prefiera. En realidad, puedo escribir mis
datos de manera grandiosa y no darle permiso a nadie para verlos, porque es mo, mo, todo
mo.

361

13_PATRICK-CHAPTER_13.indd 361 17/2/10 15:27:21


Figura 13-1. Este captulo en el Bloc de notas.

Los archivos binarios son estupendos para almacenar cualquier tipo de datos: nmeros, cadenas,
imgenes cifradas en base-64, flujos de plticas en red, cualquier cosa. El problema es que, a
menos que sepa la estructura exacta que us para escribirlo, hay pocas posibilidades de poder
recuperar sus datos. Esto es bueno si su objetivo es la discrecin, pero si alguna vez necesita
compartir esos datos con otra persona o programa, o peor an, depurar la salida de su programa
errante, tendr problemas. Si un solo byte se altera, todo el archivo podra quedar inutilizado.
Existen, por supuesto, otras maneras de almacenar sus datos. En el caso de archivos que almace-
nan registros de datos, los archivos delimitados por comas y CSV (comma-separated value, valor
separado por comas), proporcionan un medio de transferencia conveniente, en un formato ms
amigable para los seres humanos. Por ejemplo, considere estos datos de la base de datos de ejem-
plo Northwind Traders, almacenada como valores separados por comas:
IdProductoo,NombreProductoo,Idproveedor,Categora,CostoUnitario,Disponible
"1","Chai","652","Bebidas","$18.00","Si"
"2","Chang","9874","Bebidas","$19.00","No"
"3","Jarabe de anis","9874","Condimentos","Descuento","Si"

Ahora est mejor. Es muy fcil comprender estos datos. Cada pieza de datos est agrupada por
comas, y la primera fila indica lo que contiene cada columna. Y la mejor parte es que muchos
programas ya saben leer archivos en este formato. Si guarda estos datos en un archivo de texto con
una extensin .csv y la abre en Microsoft Excel, los datos aparecen automticamente en columnas.
Pero podra estar mejor. Por ejemplo, qu significan esos valores 652 y 9874? Y es correcto
que el costo unitario del Jarabe de ans sea Descuento? Seguro, puedo cargar estos datos en

362 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 362 17/2/10 15:27:22


mi programa, pero puedo hacer cualquier cosa con ellos? Por lo menos es fcil leerlos para las
personas y los programas computacionales, y no es lo que dije en relacin con XML?
Bueno, s. Aunque XML incluye reglas y caractersticas que lo hacen ms flexible que su archivo de
datos de texto promedio, no es tan diferente. A pesar de todo el ruido que provoca, XML slo es una
manera de almacenar datos. Cualquiera de las bonitas caractersticas analizadas en este captulo po-
dra realizarse fcilmente con datos almacenados en texto ms simple o formatos binarios de propie-
tario. En realidad, a menudo es ms rpido y conveniente desarrollar con un formato de propietario,
porque sus datos contendrn exactamente lo que necesita, y nada ms, sin ningn suavizante.
Una vez dicho eso, XML incluye muchos aspectos que lo hacen un contendiente fuerte cuando
considere un formato de datos:
Es simple de leer
Cada elemento de datos incluye un tipo de ttulo. Los buenos ttulos son fciles de leer.
Es fcil de procesar
Todos los datos incluyen etiquetas de inicio y de final, de modo que un programa puede
procesar los datos sin mucho esfuerzo. Y un mal elemento no necesariamente arruinar todo
el archivo.
Es flexible
Puede almacenar cualquier tipo de datos en XML. Es slo un archivo de texto, despus
de todo. Si tiene cierto formato de archivo XML usado en la versin 1 de su programa, y
le agrega caractersticas en la versin 2, puede hacerlo de una manera en que an permita
que los programas de la versin 1 usen los archivos de la versin 2 sin problemas.
Se describe a s mismo
XML incluye varias caractersticas que le permiten describir el contenido de un archivo XML
determinado. Dos de los ms populares son DTD (Document Type Definition, definicin
de tipo de documento) y XSD (XML Schema Definition, definicin de esquema XML). Se
usan estas herramientas para indicar exactamente lo que espera que contenga su archivo de
datos. Adems, XML le permite insertar documentos en el contenido sin que tengan impacto
en los datos reales.
Se verifica a s mismo
Hay herramientas disponibles, incluidas en .NET, que pueden confirmar la integridad y el
formato de un archivo XML al comparar el contenido del DTD o XSD asociado. Esto le
permite verificar un archivo antes de procesarlo.
Es un estndar abierto
XML ha ganado aceptacin extendida, aun entre plataformas de cmputo divergentes.
Est integrado en .NET
sta habr de ser la mayor razn para usarlo. En realidad, no podr deshacerse de XML en
.NET, aunque lo intente. Est en todos lados.
Pero tambin hay malas noticias:

Qu es XML? | 363

13_PATRICK-CHAPTER_13.indd 363 17/2/10 15:27:22


Es pesado
El contenido de XML incluye una cantidad de informacin estructural repetida, y por lo ge-
neral grandes cantidades de espacio en blanco. Podra abreviar muchos de los elementos de la
estructura y eliminar todos los espacios en blanco (XML no los necesita), pero eso eliminara los
aspectos legibles para los seres humanos de los datos. Algunas plataformas, como los navegado-
res de los telfonos celulares, prefieren mantener pocos datos. XML es todo menos pequeo.
Es texto
Espere un minuto, eso es algo bueno (casi siempre). En ocasiones slo necesita almacenar
datos binarios, como imgenes. En realidad no puede almacenar verdaderos datos binarios
en un archivo XML sin violar una de las reglas bsicas de XML: slo texto! A menudo, los
datos binarios estn codificados en un formato parecido al texto, como base-64 (que usa
caracteres legibles para almacenar datos binarios).
Es ineficiente
Esto es resultado de tener datos en un formato semilegible para los seres humanos, muy
descriptivo, en lugar de una forma binaria compacta y tersa. Simplemente, el equipo de
cmputo requiere ms tiempo para rastrear texto en busca de parntesis angulares (<>) que
para mover unos cuantos bytes directamente de un bloque de datos binarios en un lugar
de la memoria.
Es legible para los seres humanos
No hay muchos secretos en un archivo XML. Y aunque podra cifrar los elementos de datos
en el archivo, o todo el archivo, para el caso, eso sera como hacer a un lado el propsito
final de usar XML.
Es legible para la mquina
Si est esperando que la persona promedio recoja una impresin XML y la lea en su silla
mecedora, pinselo de nuevo. XML no es apropiado para todo tipo de archivo de datos.
No es inmune a errores
Como lo sigo repitiendo, XML es slo un archivo de texto. Si lo abre en el Bloc de notas y
deja que su hijo juegue en el teclado, el contenido tendr problemas. XML no es una pana-
cea; slo es un formato de archivo til.

La Regla de XML
Antes de que revisemos algn XML real, necesita conocer La Regla. Debe obedecer La Regla con
cada pieza de texto XML que escriba.

LA REGLA
Si lo abre, cirrelo.

Eso es todo. No la olvide. Obedzcala. Viva con ella. Ms adelante le explicar lo que significa.

364 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 364 17/2/10 15:27:22


Contenido XML
No hay una mejor manera de aprender acerca de XML que empezar a revisarlo. Si nunca ha
usado XML, pero ha escrito algo en HTML, esto debe parecerle un poco familiar.

Algo de XML bsico


He aqu un fragmento simple de XML para que lo disfrute:
<?xml version="1.0"?>
<hola>
<alli>
<!Por fin, datos reales aqu. -->
<mundo destino="todos">piense en XML</world>
<cuentaTotal>694.34</cuentaTotal>
<adios />
</alli>
</hola>

Hey, no dije que iba a ser interesante. Como le mencion antes, son slo datos, y para colmo, sin
acentos, pero son datos tiles, y he aqu por qu:
Se trata obviamente de XML
Esto queda claro desde la primera lnea, que siempre empieza con <?xml . . . Esta lnea tam-
bin indica el nmero de versin de XML, que le dice a las rutinas de procesamiento de XML
(analizadores sintcticos) que ajusten el comportamiento, si es necesario. Eso es previsin.
Est estructurado
XML es una estructura de datos jerrquica. Es decir, puede tener elementos de datos in-
sertados dentro de otros elementos de datos a cualquier profundidad que quiera. Todos
los elementos estn rodeados por un conjunto de etiquetas. En este ejemplo, las etiquetas
son hola, alli, mundo, cuentaTotal, y adios. Las etiquetas siempre aparecen dentro de
< parntesis angulares >, y siempre lo hacen en parejas, como en <hola>...</hola>. (Aqu
es donde se aplica La regla: Si lo abre, cirrelo.) No olvide la diagonal (/) justo antes del
nombre de la etiqueta en el parntesis de cierre. Esta sintaxis le permite organizar sus datos
en unidades con nombre especficamente organizadas. En el caso de pares de etiquetas que
no tienen nada entre ellas, puede usar la sintaxis corta <nombreetiqueta />, como lo hice
con la etiqueta adios. Por cierto, las etiquetas XML son sensibles al uso de maysculas y
minsculas, de modo que escriba con cuidado.
Es legible
Es legible para los seres humanos, gracias a todos los espacios en blanco, aunque podra
eliminarlos y an tener XML. Tambin es legible para el equipo de cmputo, debido al uso
consistente de etiquetas.
Es una sola unidad de datos
Todos los archivos XML tienen un solo elemento raz en que deben aparecer todos los dems
elementos. En el ejemplo, <hola> es el elemento raz. Una vez que se cierra (mediante su
etiqueta de cierre) no puede agregar elementos adicionales. Nada. Nunca.

Contenido XML | 365

13_PATRICK-CHAPTER_13.indd 365 17/2/10 15:27:22


Contiene comentarios
Ve esa lnea <!--...-->? Es un comentario. Puede pegar comentarios aqu y all como si
fueran etiquetas que flotan libremente.
Contiene atributos
XML es compatible con dos variedades de datos: datos reales y atributos. Los valores de
datos reales se encuentran entre las parejas de etiquetas ms internas, como con piense
en XML y 694.34 en el ejemplo. Los atributos proporcionan informacin extendida acerca
de las propias etiquetas. Inclu un atributo llamado destino en el elemento mundo. El
contenido de todos los atributos debe ir entre comillas. Podra haber hecho que este atri-
buto fuera, en cambio, un subelemento, y mucha gente lo hace. Hay desacuerdos entre los
programadores sobre cundo los datos deben ser un elemento o un atributo. Deje que su
conciencia lo gue.
As que ah lo tiene: datos XML limpios y puros.

Algo de XML bsico (y con sentido)


Veamos el aspecto que esos datos delimitados por comas de Northwind Traders que present
antes tendran en XML.
<?xml version="1.0"?>
<listaProductos>
<proveedor ID="652" NombreCompleto="Bebidas R Us">
<producto ID="1" disponible="Si">
<nombreProducto>Chai</nombreProducto>
<categoria>Bebidas</categoria>
<costoUnitario>18.00</costoUnitario>
</producto>
</proveedor>
<proveedor ID="9874" NombreCompleto="Vendemos Comida">
<producto ID="2" disponible="No">
<nombreProducto>Chang</nombreProducto>
<categoria>Bebidas</categoria>
<costoUnitario>19.00</costoUnitario>
</producto>
<producto ID="3" disponible="Si" descuento="true">
<nombreProducto>Jarabe de anis</nombreProducto>
<categoria>Condimentos</categoria>
<costoUnitario>12.00</costoUnitario>
</producto>
</proveedor>
</listaProductos>

Al mover los datos a XML se ha aumentado mucho el tamao del contenido. Pero con un
aumento en el tamao viene uno en el valor de procesamiento. Yo pude obtener de inmediato
algunos beneficios de la estructura jerrquica de XML. En los datos originales, proveedor
era slo otra columna. Pero en la versin de XML, todos los datos estn ahora agrupados en
secciones de proveedor, lo que tiene sentido (al menos si as es como estaba planeando usar
los datos).

366 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 366 17/2/10 15:27:22


Tambin puede ver que segu La Regla. Cada etiqueta de inicio tiene una etiqueta de cierre co-
rrespondiente. No importa lo que haga, no olvide La Regla.
Ahora, se estar diciendo: Tim, pude haber agrupado los datos por proveedor una vez que car-
gu los datos delimitados por comas en mi programa. Y a eso lo que digo es: Tiene razn. Le
expliqu que XML era slo otro formato de datos. En s mismo, el contenido de XML no es muy
atractivo. En realidad, son las herramientas que usa con sus datos XML las que lo hacen destacar.
Debido a que XML usa una estructura consistente pero jerrquica para el manejo de los datos,
es muy fcil desarrollar herramientas que podran procesar datos consistentes pero genricos en
maneras que parezcan interesantes y especficas.

Qu pasa con la parte legible para los seres humanos?


Una de las herramientas usadas con XML es XSLT, que son las siglas de XSL Transformations
(transformaciones de XSL; XSL, a su vez, son las siglas de eXtensible Stylesheet Language, len-
guaje extensible de hoja de estilos). XSLT es un lenguaje de creacin de secuencias de comandos
difcil de usar que le permite transformar algunos datos XML en cualquier otro formato de datos
o de salida que desee. Se trata slo de un puado de lenguajes relacionados con XSL creados para
manipular datos XML de manera compleja. Listo para la diversin prctica con XSL? Tome
el fragmento til de XML de la lista anterior (el ejemplo <listaProductos>) y reemplace la
primera lnea ?xml con las dos lneas siguientes:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="hola.xsl"?>

Guarde todo ese hermoso texto XML en un archivo de su escritorio como hola.xml. A continua-
cin, ponga la siguiente secuencia de comandos XSLT en otro archivo de su escritorio llamado
hola.xsl. (Observe que divid una lnea con un marcador especial para que el contenido quepa en
este libro. Por favor, no divida la lista separada por comas en esa lnea en el archivo.)
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:text>
IdProducto,NombreProducto,IdProveedor,Categoria,
<smbolo>CostoUnitario,Disponible
</xsl:text>
<BR/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="proveedor">
<xsl:variable name="IdSup" select="@ID"/>
<xsl:for-each select="producto">
"<xsl:value-of select="@ID"/>",
"<xsl:value-of select="nombreProducto"/>",
"<xsl:value-of select="$IdSup"/>",
"<xsl:value-of select="categoria"/>",
"<xsl:choose>

Contenido XML | 367

13_PATRICK-CHAPTER_13.indd 367 17/2/10 15:27:22


<xsl:when test="@descuento=true">Descuento</xsl:when>
<xsl:otherwise>
$<xsl:value-of select="costoUnitario"/>
</xsl:otherwise>
</xsl:choose>",
"<xsl:value-of select="@disponible"/>"
<BR/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Le dije que era difcil de usar y an ms difcil de revisar. Muy bien, pasemos al espectculo.
Tengo Internet Explorer instalado en mi sistema, pero esto debe funcionar con la mayor parte de
los navegadores. Abra el archivo hola.xml en su navegador, y sorpresa!, debe aparecer el siguiente
texto hermosamente formado:
IdProducto,NombreProducto,IdProveedor,Categoria,CostoUnitario,Disponible
"1", "Chai", "652", "Bebidas", " $18.00", "Si"
"2", "Chang", "9874", "Bebidas", " $19.00", "No"
"3", "Jarabe de anis", "9874", "Condimentos", "Descuento", "Si"

Ahora es ms legible. XML y XSLT juntos han hecho posible este avance en la tecnologa de los datos.
(Hice un poco de trampa en este ejemplo. Notar las entradas <BR/> en la secuencia de comandos
XSLT que no aparecen en la salida final. Lo agregu para que aparecieran de manera correcta en su
explorador.) En serio, aunque pude generar un conjunto de datos separados por comas con XSLT, las
tareas ms comunes para XSLT incluyen la generacin de HTML formado agradablemente con base
en los datos XML, o la generacin de un nuevo documento XML con una vista alterna especfica
de los datos originales. Cmo funciona? En esencia, los elementos <xsl:template> le indican al
analizador sintctico que busque etiquetas en el documento XML que coincidan con algn patrn
(como proveedor). Cuando lo encuentra, aplica todo lo que se encuentra dentro de las etiquetas
<xsl:template> a la etiqueta XML correspondiente y su contenido. El patrn especificado en los
atributos coincidentes usa una tecnologa XML llamada XPath, un sistema para buscar genrica-
mente etiquetas que coinciden dentro de su documento XML.
Suena confuso? Bueno, lo es, y no deje que empiece a explicar todo lo que me tom escribir
esa corta secuencia de comandos XSLT. La creacin de secuencias de comandos XSLT est,
dichosamente, ms all del alcance de este libro. Por supuesto, hay herramientas que facilitan
el trabajo. Pero XSLT slo es til si los datos XML se manipulan de manera correcta. Podra
escribir una transformacin de XSL para reportar las inconsistencias de los datos encontradas
en un documento XML, pero no funcionar si alguna de las etiquetas de su documento est
mal escrita u organizada de manera inconsistente. Para eso, necesita otro avance en la tecnologa
XML: XSD.

Esquemas XML
XSD (XML Structure Definitions, definiciones de estructura XML) le permite definir el esquema
(el lenguaje o vocabulario) de su documento XML particular. Recuerde que XML es un estndar
genrico muy abierto; puede definir las etiquetas de la manera que quiera y a nadie le preocupa-
r, al menos hasta que tenga que procesar las etiquetas con su software. Si no son correctas, es

368 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 368 17/2/10 15:27:22


muy probable que su procesamiento falle. XSD le permite definir las reglas que debe seguir su
documento XML si habr de considerarse vlido para sus fines. (DTD, o Document Type Defi-
nition, definicin de tipo de documento, es una tecnologa similar, aunque ms antigua. Tiene
soporte amplio en las herramientas XML, pero no es tan flexible como XSD. Tambin hay otros
lenguajes de definicin de esquemas similares a XSD, pero como ste se encuentra integrado en
.NET, nos concentraremos en l.)
Los esquemas XSD son tan cautivadores como las secuencias de comandos XSLT. Creemos un
XSD para nuestro ejemplo XML original <listaProductos> que ya se present. En primer lu-
gar, necesitamos cambiar la parte superior del XML para que sepa que est disponible un archivo
de esquema XSD. Cambie esto:
<?xml version="1.0"?>
<listaProductos>

a esto:
<?xml version="1.0"?>
<listaProductos xmlns="ListaProductosSimple"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="hola.xsd">

Estas directivas le indican al analizador sintctico XML que busque el esquema en hola.xsd.
Tambin definen un espacio de nombres; se explicar ms sobre esto en prrafos posteriores. El
archivo hola.xsd contiene el siguiente esquema:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="ListaProductosSimple">
<xs:element name="listaProductos" type="ListaTiposProducto"/>

<xs:complexType name="ListaTiposProducto">
<xs:sequence>
<xs:element name="proveedor" type="TipoProveedor"
maxOccurs="desunido"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="TipoProveedor">
<xs:sequence>
<xs:element name="producto" type="TipoProducto"
maxOccurs="desunido"/>
</xs:sequence>
<xs:attribute name="ID" type="xs:integer"/>
<xs:attribute name="NombreCompleto" type="xs:string"/>
</xs:complexType>

<xs:complexType name="TipoProducto">
<xs:sequence>
<xs:element name="nombreProducto" type="xs:string"/>
<xs:element name="categoria" type="xs:string"/>
<xs:element name="costoUnitario" type="xs:decimal"/>
</xs:sequence>
<xs:attribute name="ID" type="xs:integer"/>

Contenido XML | 369

13_PATRICK-CHAPTER_13.indd 369 17/2/10 15:27:22


<xs:attribute name="disponible" type="TipoSiONo"/>
<xs:attribute name="descuento" type="xs:boolean"/>
</xs:complexType>
<xs:simpleType name="TipoSiONo">
<xs:restriction base="xs:string">
<xs:enumeration value="Si"/>
<xs:enumeration value="No"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

Se ve horrible, o no? En realidad, es ms sencillo que XSLT. En esencia, el esquema dice que cada
elemento (o etiqueta o nodo) en mi documento XML, he aqu los subelementos y atributos
que contienen y el tipo de datos de cada uno. Incluso puede crear sus propios tipos de datos (en
realidad, factores limitantes en los tipos de datos existentes), como hice con el tipo de datos Tipo-
SiONo, que limita el valor relacionado a las cadenas Si y No.
Puede revisar el archivo XML con el esquema XSD adjunto en su explorador, pero no sera tan
interesante. Slo le muestra el XML. Pero los esquemas sern tiles cuando necesite evaluar la
calidad de los datos XML que entran en sus aplicaciones de software de fuentes externas.

Espacios de nombres XML


La lista de productos XML mostrada antes es agradable, pero alguien ms podra salir con un
documento de lista de productos que sea igual de agradable, pero con reglas de nomenclatura y
formato diferentes. Por ejemplo, alguien ms podra crear un documento que tenga este aspecto:
<?xml version="1.0"?>
<productosCompletos>
<vendedor ID="652" nombreVendedor="Bebidas R Us">
<articulo ID="1" disponible="Si">
<nombreArticulo>Chai</nombreArticulo>
<grupo>Bebidas</grupo>
<precioUnitario>18.00</precioUnitario>
</articulo>
</vendedor>
</productosCompletos>

Todos los datos son iguales, pero las etiquetas son diferentes. Este tipo de documento sera in-
compatible con software escrito para funcionar con nuestro documento original. Si se ejecuta
el documento a travs de nuestro XSD, nos indicara rpidamente que tenemos un conjunto de
datos falso, pero sera ms agradable si algo nos lo indica desde el principio. Ingrese espacios
de nombres. Los espacios de nombres proporcionan un mtodo conveniente para decir: Esta
etiqueta particular en el documento XML usa este lenguaje definido por XSD. Observe el ini-
cio del esquema XSD mostrado antes:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

Esta lnea configura un espacio de nombres llamado xs al usar el atributo xmlns. (La parte :xs
le indica a XML lo que quiere que sea su espacio de nombres.) El valor del atributo es un iden-
tificador uniforme de recursos (URI, Uniform Resource Identifier), slo que debe ser un valor

370 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 370 17/2/10 15:27:22


nico que est seguro de que nadie ms va a usar. Por lo general, se usa la direccin de sitio Web
para nuestra propia empresa; no es necesario que exista el sitio Web. Incluso puede poner su
nmero telefnico all, siempre y cuando sea nico.
La manera ms comn de usar un espacio de nombres es aadir un prefijo de las etiquetas rele-
vantes en su documento XML con el nuevo espacio de nombres, como en xs:schema en lugar
de slo schema. Esto le indica al analizador de sintaxis: Si ests revisando mi sintaxis contra
un esquema XSD, usa el que defino por el espacio de nombres xs. Tambin puede usar un
espacio de nombres predeterminado para un elemento determinado y todos sus descendientes
al incluir el atributo xmlns en el elemento ms externo. Luego todos los elementos dentro de
ese elemento ms externo usarn el espacio de nombres especificado. Us este mtodo en uno
de los ejemplos anteriores:
<listaProductos xmlns="ListaProductosSimple"...

En el caso de archivos XML bsicos que slo sern usados por su programa, tal vez no necesite
preocuparse con los espacios de nombres. En realidad resulta prctico cuando est creando datos
XML que usan algn estndar pblico. Tambin hay casos donde un solo archivo XML podra
contener datos relacionados con dos o ms usos distintivos de XML. En este caso, diferentes
partes de su archivo XML podran hacer referencia a espacios de nombres diferentes.
Al igual que con otras partes del mundo XML, XSD y los espacios de nombres no son tan fciles de
usar, pero resultan flexibles y poderosos. Como siempre, hay herramientas, incluidas herramientas
de Visual Studio, que le permiten construir todo esto sin tener que pensar en los detalles.
Como lo seguir diciendo, XML slo son datos, y si su programa y sus datos no se comprenden entre
s, tal vez sera adecuado regresar al cincel y la piedra. XML y sus tecnologas relacionadas proporcio-
nan un mtodo para ayudarle a asegurar que sus datos estn listos para usarlos en su aplicacin.

Uso de XML en .NET: el viejo estilo


Visual Basic incluye dos mtodos principales para trabajar con contenido XML: el viejo estilo y
el nuevo. El viejo estilo usa clases del espacio de nombres System.Xml, y proporciona el tradi-
cional acceso a etiquetas, atributos y datos XML basado en objetos. El nuevo estilo, introducido
en la versin 2008, usa clases en el espacio de nombres System.Xml.Linq y proporciona acceso
a contenido XML directamente dentro del cdigo fuente de la sintaxis de Visual Basic. Analizar
ambos mtodos en este captulo, empezando con el viejo estilo.
Debido a que no es divertido manejar XML como un gran conjunto de texto, .NET incluye varias
clases que manejan datos XML. Todas estas herramientas aparecen en el espacio de nombres Sys-
tem.Xml y sus espacios subordinados:

System.Xml
La principal coleccin de clases relacionadas con XML al viejo estilo.
System.Xml.Linq
Las clases que integran XML con tecnologas LINQ. sta es la nueva manera de la que
hablar ms tarde.

Uso de XML en .NET: el viejo estilo | 371

13_PATRICK-CHAPTER_13.indd 371 17/2/10 15:27:23


System.Xml.Schema
Clases que crean y usan esquemas XSD.
System.Xml.Serialization
Clases que leen y escriben documentos XML mediante el flujo estndar de .NET.
System.Xml.XPath
Clases que implementan la tecnologa XPath usada para buscar documentos XML.
System.Xml.Xsl
Clases que habilitan transformaciones XSL.
Las caractersticas incluidas en cada clase se unen muy de cerca a la estructura de XML y tecno-
logas relacionadas como XSD y XSLT.

Las clases bsicas de XML, en esencia


El espacio de nombres System.Xml incluye las clases ms bsicas que usar para administrar da-
tos XML. Un documento XmlDocument es la vista en la memoria de su documento XML real:
Dim misDatos As New System.Xml.XmlDocument

Su documento est integrado por declaraciones (esa cosa <?xml...?> en la parte superior),
elementos de datos (todas las etiquetas especficas de su documento), atributos (dentro de cada
etiqueta de elemento inicial) y comentarios. Estn representadas por las clases XmlDeclara-
tion, XmlElement, XmlAttribute y XmlCommment, respectivamente. Juntas, a estas cuatro
unidades principales de su documento se les denomina nodos, representados genricamente por
la clase XmlNode. (Las cuatro clases especficas heredan de la clase XmlNode ms bsica.) Cuando
construya un documento XML a mano en memoria, usar clases individuales como XmlEle-
ment. Ms adelante, cuando necesite rastrear un documento existente, ser ms fcil de usar la
clase XmlNode genrica.
Construyamos un subconjunto de los datos de producto de nuestro ejemplo XML.
<?xml version="1.0"?>
<listaProductos>
<!--Actualmente vendemos estos articulos. -->
<proveedor ID="652" NombreCompleto="Bebidas R Us">
<producto ID="1" disponible="Si">
<nombreProducto>Chai</nombreProducto>
<categoria>Bebidas</categoria>
<costoUnitario>18.00</costoUnitario>
</producto>
</proveedor>
</listaProductos>

Declare todas las variables que usar y luego selas.


Dim productos As XmlDocument
Dim declararProducto As XmlDeclaration
Dim establecerRaiz As XmlElement
Dim proveedor As XmlElement

372 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 372 17/2/10 15:27:23


Dim producto As XmlElement
Dim valorProducto As XmlElement
Dim comentario As XmlComment

' ----- Crear el documento con una declaracion valida.


productos = New XmlDocument
declararProducto = productos.CreateXmlDeclaration("1.0", _
Nothing, String.Empty)
productos.InsertBefore(declararProducto, productos.DocumentElement)

' ----- Crear el elemento raiz, <listaProductos>.


establecerRaiz = productos.CreateElement("listaProductos")
productos.InsertAfter(establecerRaiz, declararProducto)

' ----- Agregar un bonito comentario.


comentario = productos.CreateComment( _
" Actualmente vendemos estos articulos. ")
establecerRaiz.AppendChild(comentario)

' ------ Crear el elemento proveedor, <proveedor>.


' Incluidos los atributos.
proveedor = productos.CreateElement("proveedor")
proveedor.SetAttribute("ID", "652")
proveedor.SetAttribute("NombreCompleto", "Bebidas R Us")
establecerRaiz.AppendChild(proveedor)

' -----Crear el elemento producto, <producto>, con los


' valores de datos subordinados.
producto = productos.CreateElement("producto")
producto.SetAttribute("ID", "1")
producto.SetAttribute("disponible", "si")
proveedor.AppendChild(producto)

valorProducto = productos.CreateElement("nombreProducto")
valorProducto.InnerText = "Chai"
producto.AppendChild(valorProducto)

valorProducto = productos.CreateElement("categoria")
valorProducto.InnerText = "Bebidas"
producto.AppendChild(valorProducto)

valorProducto = productos.CreateElement("costoUnitario")
valorProducto.InnerText = "18.00"
producto.AppendChild(valorProducto)

Realmente funciona, tambin. Para probarlo, ponga este cdigo en el evento Click de un botn
y termnelo con la siguiente lnea:
productos.Save("c:\productos.xml")

Ejecute el programa y vea el archivo c:\productos.xml para ver los datos de producto de XML.
Hay muchas maneras diferentes de usar las clases XML para crear un documento XML en me-
moria. Por ejemplo, aunque us el mtodo SetAttribute para agregar atributos a los nodos

Uso de XML en .NET: el viejo estilo | 373

13_PATRICK-CHAPTER_13.indd 373 17/2/10 15:27:23


proveedor y producto, pude haber creado objetos de atributo separados, y anexarlos en esos
nodos, como lo hice para los elementos principales.
Dim datosAtributo As XmlAttribute
datosAtributo = productos.CreateAttribute("ID")
datosAtributo.Value = "652"
proveedor.SetAttributeNode(datosAtributo)

Bueno, esto es agradable y todo, pero qu pasa si tiene algn XML en un archivo, y slo quiere car-
garlo en un objeto XmlDocument? Simplemente use el mtodo Load del objeto XmlDocument.
Dim productos As XmlDocument
productos = New XmlDocument
productos.Load("c:\productos.xml")

Para los casos en que slo quiera leer o escribir XML en un archivo, y no se preocupe mucho por ma-
nipularlo en la memoria, las clases XmlTextReader y XmlTextWriter le permiten leer y escribir
rpidamente datos XML mediante un flujo de texto. Pero si quiere hacer algo con los datos XML en
su programa, los mtodos Load y Save del objeto XmlDocument son una mejor opcin.

Bsqueda de agujas y pajares


En nuestros datos de ejemplo, todos nuestros productos aparecen en los grupos proveedor. Si
slo quiere una lista de productos, sin importar el proveedor, pedimos al objeto XmlDocument
que proporcione esos datos mediante un objeto XmlNodeList.
Dim soloProductos As XmlNodeList
Dim unProducto As XmlNode

' ----- Primero, obtener la lista.


soloProductos = productos.GetElementsByTagName("producto")

' ----- Luego hacer algo con ellos.


For Each unProducto In soloProductos
' ----- Poner codigo interesante aqui.
Next unProducto
MsgBox("Procesado " & soloProductos.Count.ToString(
) & _
" producto(s).")

Para conocer una seleccin ms compleja de nodos dentro del documento, el espacio de nom-
bres System.Xml.XPath implementa el lenguaje de bsqueda XPath, que le da una mayor
flexibilidad en la localizacin de elementos. La documentacin de Visual Studio describe los
mtodos y la sintaxis de bsqueda usada con estas clases.

Verificacin de esquema
Un objeto XmlDocument puede incluir cualquier tipo de contenido XML al azar, pero vlido,
aunque tambin puede verificar el documento contra un esquema XSD. Si su documento XML
alude a un esquema XSD, incluye un DTD o usa XDR (esquemas XML Data Reduced, reduci-
dos de datos XML, similares a XSD), un XmlReader, cuando se configur con el XmlReader-
Settings apropiado, comparar apropiadamente sus datos XML contra las reglas definidas, y
lanzar una excepcin si hay un problema.

374 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 374 17/2/10 15:27:23


Dim productos As New XmlDocument
Dim leerXml As XmlTextReader
Dim conVerifi As New XmlReaderSettings
Dim lecturaXmlCorrecta As XmlReader

' ----- Abrir el archivo XML y procesar esquemas


' a los que se hace referencia dentro del contenido.
conVerifi.ValidationType = ValidationType.Schema
leerXml = New XmlTextReader("c:\temp\productos.xml")
lecturaXmlCorrecta = XmlReader.Create(leerXml, conVerifi)

' ----- Cargar contenido, o lanzar excepcion


' si falla la validacion.
productos.Load(lecturaXmlCorrecta)

' ----- Limpiar.


lecturaXmlCorrecta.Close()
leerXml.Close()

XML Transformations
Las transformaciones de XSL Transformations no son ms difciles que cualquier otra manipula-
cin de XML. As como hay muchas maneras de obtener datos de origen XML (desde un archi-
vo, construyendo uno a mano con XmlDocument, etc.), hay muchas maneras de transformar los
datos. Si slo quiere ir de un archivo de entrada a uno de salida, el siguiente cdigo proporciona
un mtodo rpido y eficiente. Usa una instancia de System.Xml.Xsl.XslCompiledTrans-
form para hacer magia.
' ----- Arriba: Imports System.Xml.Xsl
Dim xslTrans As XslCompiledTransform

' ----- Abrir el archivo XSL como una transformacion.


xslTrans = New XslCompiledTransform()
xslTrans.Load("c:\convertir.xsl")

' ----- Convertir y guardar la salida.


xslTrans.Transform("c:\entrada.xml", "c:\salida.txt")

Uso de XML en .NET: el nuevo estilo


Cuando sali Visual Basic, nadie haba odo de XML. Pero ahora est en todos lados. Es como
esa cosa negra y viscosa que estaba unida a Peter Parker en el Hombre Araa 3, pero sin todos
los espectaculares efectos especiales. Y ahora en Visual Basic 2008, XML es parte de la propia
sintaxis del lenguaje. Cundo terminar?
Resulta que hacer que XML sea parte del lenguaje es estupendo. En la seccin del viejo estilo que
vimos pginas antes, le mostr algn cdigo que cre la lista de producto XML para Chai. El
contenido XML fue de 11 lneas, pero tom casi 50 lneas de cdigo producirla. Sin embargo, s
puede construir ese mismo contenido XML empleando el nuevo estilo en casi las 11 lneas finales.

Uso de XML en .NET: el nuevo estilo | 375

13_PATRICK-CHAPTER_13.indd 375 17/2/10 15:27:23


Dim articuloChai As System.Xml.Linq.XDocument = _
<?xml version="1.0"?>
<listaProductos>
<!-- Actualmente vendemos estos articulos. -->
<proveedor ID="652" NombreCompleto="Bebidas R Us">
<producto ID="1" disponible="Si">
<nombreProducto>Chai</nombreProducto>
<categoria>Bebidas</categoria>
<costoUnitario>18.00</costoUnitario>
</producto>
</proveedor>
</listaProductos>

Qu tal eso? Excepto por la primera lnea de declaracin, el contenido es idntico al XML final.
La nueva caracterstica Literales de XML facilita mucho la construccin de documentos XML. El
contenido se almacena en el nuevo objeto XDocument, parte del espacio de nombres System.
Xml.Linq. Si slo quiere almacenar una seccin de XML en lugar de todo el documento, use,
en cambio, la clase XElement.
Dim seccionProducto As System.Xml.Linq.XElement = _
<producto ID="1" disponible="Si">
<nombreProducto>Chai</nombreProducto>
<categoria>Bebidas</categoria>
<costoUnitario>18.00</costoUnitario>
</producto>

Si tiene habilitadas las inferencias de tipo en su programa (Option Infer On), ni siquiera ne-
cesita indicarle a Visual Basic si es un XElement o un XDocument.
Dim seccionProducto = _
<producto ID="1" disponible="Si">
<nombreProducto>Chai</nombreProducto>
<categoria>Bebidas</categoria>
<costoUnitario>18.00</costoUnitario>
</producto>

Al igual que la clase XmlDocument, la clase XDocument incluye mtodos Load y Save para
administrar XML basado en archivos.

Expresiones XML incrustadas


Incluir XML en su cdigo fuente es algo sorprendente, pero seguir siendo sorprendente slo si
siempre vende Chai en $18.00 por unidad. El contenido XML real suele provenir de datos de
variables. Y a pesar del nombre Literal de XML, las literales de XML pueden incluir conteni-
do variable que no es literal mediante expresiones XML incrustadas. Cada vez que quiera agregar
datos de una variable o expresin a su texto XML, debe usar los smbolos especiales <%= y %>
para desplazar sus datos personalizados.
Dim idProducto As Integer = 1
Dim nombreProducto As String = "Chai"
Dim productoCategoria As String = "Beverage"
Dim precioProducto As Decimal = 18@

376 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 376 17/2/10 15:27:23


Dim hayDisponible As Boolean = True
Dim seccionProducto = _
<producto ID=<%= idProducto %>
disponible=<%= Format(hayDisponible, "Si/No") %>>
<nombreProducto><%= nombreProducto %></nombreProducto>
<categoria><%= productoCategoria %></categoria>
<costoUnitario><%= precioProducto %></costoUnitario>
</producto>

Por supuesto, para generar un catlogo completo de productos, necesita escribir mucho. En el
captulo 17, presentar algunas maneras adicionales de incrustar expresiones XML con tablas de
datos completas.

Propiedades de ejes XML


En pginas anteriores de este captulo, en Bsqueda de agujas y pajares, le mostr cmo podra
acceder a secciones especficas de documentos XML del viejo estilo. Los objetos XML del nuevo
estilo incluyen maneras de rastrear y acceder a partes del rbol XML. Se les denominan propie-
dades de ejes XML y estn incluidas en tres variedades amigables con la sintaxis:
Eje elemento secundario-miembro
Puede acceder a una etiqueta secundaria inmediata de cualquier XElement al emplear el
nombre del elemento secundario como miembro del objeto primario, incluyendo el nom-
bre del secundario en un conjunto de parntesis angulares:
elementoSecundario = elementoPrimario.<nombreSecundario>

Eje elemento descendente-miembro


Una variacin de la sintaxis del eje elemento secundario-miembro le permite acceder a
miembros con nombre a cualquier profundidad dentro de un elemento primario. En lugar
de usar slo un punto (.) entre los nombres primario y secundario, use tres puntos:
conjuntoDeElementos = elementoPrimario...<nombreElementoDescendente>

Eje de atributos
Puede acceder a cualquier atributo de un elemento al tratar el nombre del atributo como un
nombre de miembro, antecediendo el nombre del atributo con el carcter @:
valorAtributo = elementoPrimario.@nombreAtributo

El siguiente bloque de cdigo rastrea la lista de productos diseada antes en este captulo, des-
plegando el nmero de ID y el nombre de cada producto en la consola:
For Each unProducto In productosCompletos...<producto>
Console.WriteLine(unProducto.@ID & ": " & _
unProducto.<nombreProducto>.Value)
Next unProducto

Este cdigo utiliza los tres estilos de eje. El bucle For Each...Next revisa todas las entradas
<producto> coincidentes al usar un eje elemento descendente-miembro. En cada elemento de
producto coincidente, el cdigo accede al atributo ID empleando un eje de atributos, y obtiene
el nombre del producto usando un eje elemento secundario-miembro, junto con la propiedad
Value del elemento secundario devuelto. La salida tiene este aspecto:

Uso de XML en .NET: el nuevo estilo | 377

13_PATRICK-CHAPTER_13.indd 377 17/2/10 15:27:23


1: Chai
2: Chang
3: Jarabe de anis

Para conocer maneras ms avanzadas de rastrear contenido XML y seleccionar elementos secun-
darios con base en criterios complejos, consulte el captulo 17.

Espacios de nombres y esquemas para literales XML


Al igual que con el estilo antiguo de administrar XML, el nuevo le permite incluir espacios de
nombres en el contenido de su XML. Para agregar un prefijo de espacio de nombres, simplemen-
te inclyalo en el contenido como lo hara en cualquier otro escenario XML.
Dim articulosAlimenticios = _
<?xml version="1.0"?>
<menu:articulos xmlns:menu="http://www.timaki.com/menu">
<menu:articulo>
<menu:name>Pizza</menu:name>
<menu:price>12.99</menu:price>
</menu:articulo>
<menu:articulo>
<menu:name>Palillos de pan</menu:name>
<menu:price>1.99</menu:price>
</menu:articulo>
</menu:articulos>

Tambin puede definir el espacio de nombres, la parte xmlns, al usar una variacin de la instruc-
cin Imports de Visual Basic.
Imports <xmlns:menu="http://www.timaki.com/menu">
...despues...
Dim articulosAlimenticios = _
<?xml version="1.0"?>
<menu:articulos>
...etcetera...

Visual Basic an insertar la definicin xmlns en el lugar correcto del contenido XML. En
realidad est almacenado como un objeto XNamespace distintivo dentro de XDocument o
XElement. Para generar un objeto XNamespace para su propio uso, Visual Basic incluye una
nueva funcin GetXmlNamespace.
Dim soloespacioNombres = GetXmlNamespace(menu)

Resumen
Hay una gran cantidad de caractersticas tiles en los varios espacios de nombres de System.
Xml y puede administrar datos complejos en maneras efectivas. No siempre es la manera ms
eficiente de administrar datos, pero si ha estructurados datos jerrquicos, puede ser el mtodo
ms directo y claro.

378 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 378 17/2/10 15:27:23


Aunque XML surge por todos lados en.NET Framework, y en todas las aplicaciones que se escri-
ban en .NET, en realidad podra escribir aplicaciones largas e interesantes sin revisar una sola lnea
de contenido XML. Aunque su aplicacin necesite interactuar con contenido XML, las nuevas
caractersticas de XML incluidas en Visual Basic facilitan tanto la administracin de XML como
escribir el contenido directamente en el Bloc de notas. Espere un minuto, eso no es fcil ni diver-
tido. Pero es mucho mejor que armar el contenido pieza por pieza mediante unin de cadenas.
XML es un formato de datos muy til y flexible que lleg para quedarse. Aunque siempre care-
cer de la velocidad de los estndares de datos ms compactos, sus beneficios son cuantiosos. Se
ha hablado de introducir un formato XML binario como estndar, aunque no ha surgido an
nada concreto. Si el XML binario no se vuelve un estndar, tal vez seguir usando las mismas
clases y mtodos introducidos en este captulo, con la posible adicin de una propiedad Out
putFormat (Text or Binary).

Proyecto
El administrador del sistema Biblioteca querr ver estadsticas e informacin de un vistazo, o
ejecutar informes que proporcionen un resumen significativo, o vistas detalladas de datos del
sistema. Aunque como programador podra tratar de aadir cada tipo concebible de informe
que el usuario necesite, la experiencia me ha enseado que eso no es posible. Los usuarios
siempre quieren la luna, por lo general en la forma de varios extraos y esotricos informes que
s que usarn una vez y nunca volvern a ver (aunque llamarn una vez al ao pidiendo que se
vuelva a escribir el mismo tipo de informe). No me gusta volver a compilar y relanzar toda la
aplicacin cada vez que un usuario necesite un nuevo informe. En cambio, mantengo los in-
formes fuera de la aplicacin, almacenados como programas separados. Luego, a partir de un
formulario de la aplicacin principal, pongo a su disposicin esos informes externos en una
bonita y conveniente lista.
Para implementar esta caracterstica genrica, uso el archivo de configuracin de informes, un
simple archivo XML que contiene informacin sobre los informes disponibles, y la manera
de ejecutarlos. Quiero que mi lista de seleccin tenga elementos con sangra para que puedan
agrupar los informes de manera visible, para mayor conveniencia. Para esto, crear mi archivo
XML en una jerarqua de profundidad ilimitada, y cada nivel representar un nivel adicional de
sangra desplegada. Por ejemplo, digamos que quiere el siguiente esquema de informes (con los
ttulos de grupo de informes en negritas):

Informes de detalle
Informes diarios
Informes mensuales
Valor mensual
Inventario mensual

Proyecto | 379

13_PATRICK-CHAPTER_13.indd 379 17/2/10 15:27:23


Informes de resumen
Resumen de inventario
La configuracin XML seguira esta estructura:
<Grupo name="Informes de detalle">
<Elemento name="Informe diario"/>
<Grupo name="Informes mensuales">
<Elemento name="Valor mensual"/>
<Elemento name="Inventario mensual"/>
</Grupo>
</Grupo>
<Grupo name="Informes de resumen">
<Elemento name="Resumen de inventario"/>
</Grupo>

Por supuesto, esto es XML muy simplificado (sin mencionar que no cumple con los requisitos).
Adems de la jerarqua, tambin quiero incluir soporte para varios mtodos de informes. Para
simplificar las cosas, el Proyecto Biblioteca incluir tres tipos de informes:
Informes integrados
La aplicacin incluye una cantidad limitada de informes que estn integrados de manera
permanente en la aplicacin (el ensamblado) principal. Los informes estn numerados a
partir del 1, y en este momento tengo cinco informes en mente. El diseador del archivo
de configuracin XML puede elegir si los incluye en el despliegue de los informes o no con
slo incluirlos en el archivo. En ausencia de un archivo de configuracin, estos informes
aparecern en la lista como opcin predeterminada. Adems del nmero de informe (1 a 5),
cada entrada tiene un texto de despliegue y una descripcin larga.
Informes de la aplicacin
Estos informes son archivos EXE separados y distintos, y se inician mediante los mtodos
de inicio estndar. Cada entrada incluye un texto de despliegue, la ruta completa a la apli-
cacin, argumentos opcionales, una marca que se pasar para la identidad del usuario que
inicia el informe, y una descripcin larga.
Informes de URL
Estos informes son simples llamadas a pginas Web, o cualquier otro URL vlido. Por ejemplo,
podra incluir una entrada de informe que tenga un mailto: al escritorio de ayuda de la orga-
nizacin. Cada entrada incluye el texto de despliegue, el propio URL y una descripcin larga.
Las actividades del proyecto de este captulo incluyen la codificacin y la documentacin del
nuevo recurso externo (el formato de archivo XML).

ACCESO AL PROYECTO
Cargue el proyecto Cap13 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap13 (Final) cdigo.

380 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 380 17/2/10 15:27:24


Actualice la documentacin tcnica
En primer lugar, agreguemos documentacin clara a la estructura del archivo de configuracin
XML. No hay una manera fcil de comunicar la estructura de un archivo XML a un usuario
ordinario. Aunque esa documentacin es un requisito, se espera que la aplicacin tambin in-
cluya una herramienta que le permita a un administrador construir el archivo de configuracin.
Por desgracia, ese tipo de programa no se incluye en el proyecto de este libro. Se deja como un
ejercicio para el lector. (Siempre quise decir eso.)

Archivo de configuracin de informe


La aplicacin de biblioteca puede configurarse para ejecutar cualquier nmero de informes
mediante el formulario Informes. La lista de informes disponibles se administra mediante
un archivo de configuracin de informe XML, que contiene grupos y elementos. Todos
los elementos son informes, y aparecen dentro de un grupo. Puede anidar grupos dentro de
grupos a cualquier profundidad, y la lista de informes desplegada en el programa Biblioteca
aadir sangra a cada grupo subordinado para ayudar al usuario a ver la organizacin de los
informes. No hay lmite para la anidacin de grupos.
El elemento raz del archivo XML debe denominarse <listaInformes>, y puede contener
cualquier nmero de elementos de datos <grupoInformes> y <elementoInformes>:
<elementoInformes>: representa una sola entrada del informe. Esta entrada tiene un atri-
buto obligatorio, y hasta cinco elementos de datos subordinados, dependiendo de la confi-
guracin del atributo:
tipo (atributo): establece uno de los siguientes valores:

integrado: ejecuta uno de los programas integrados. Este tipo de informe usa los
elementos de datos <textoDespliegue>, <rutaInforme> y <descripcion>.

programa: ejecuta un pgina EXE separado. Este tipo de informe usa los elemen-
tos de datos <textoDespliegue>, <rutaInforme>, <argsInforme>, <marcas-
Informe>, y <descripcion>.

url: inicia un URL, como una pgina Web o una direccin de correo electrnico
mailto con la direccin de un destinatario. Este tipo de informe usa los elementos
de datos <textoDespliegue>, <rutaInforme> y <descripcion>.

<textoDespliegue>: un nombre corto o una descripcin para este informe, como
aparecer en la lista de opciones de informes. Este elemento es obligatorio para todos
los tipos de informes.

<rutaInforme>: la ruta completa, el URL o el nmero del informe, dependiendo
del tipo de ste. Para los informes de programa (EXE), es el UNC completo o la ruta
de unidad basada en letras, sin argumentos adicionales. Para el caso de informes in-
tegrados, es un nmero de informe, de 1 a 5 (los valores y sus significados aparecen
ms adelante en esta seccin). Para informes de URL, es el URL real, como en http://
misitio.com/miinforme.aspx o mailto:escritorioayuda@misitio.com. Este elemento es
obligatorio para todos los tipos de informes.

Proyecto | 381

13_PATRICK-CHAPTER_13.indd 381 17/2/10 15:27:24



<argsInforme>: para informes de programa (EXE), esta entrada incluye cualquier
argumento de lnea de comandos que habr de incluirse cuando se ejecute el programa.
Este elemento es vlido slo para informes de programa (EXE) y siempre es opcional.

<marcasInforme>: para informes de programa (EXE), esta entrada indica las marcas
opcionales que deben adjuntarse al comando de aplicacin como argumentos. En este
momento, la nica marca es U. Cuando este elemento se establece en U, el argumento -u
idusuario se adjunta a la cadena del comando (donde idusuario es el ID de inicio
de sesin del usuario, del campo de base de datos NombreUsuario.IdInicio). Este
elemento es vlido slo para los informes de programa (EXE) y siempre es opcional.

<descripcion>: se trata de una descripcin ms larga, textual del informe, de hasta
200 caracteres, que aparecer en el formulario Informes cuando el usuario seleccione el
informe de la lista. Esta descripcin debe ayudar al usuario a sistema el informe correc-
to. Este elemento es vlido para todos los tipos de informes, pero siempre es opcional.
<grupoInformes>: representa un grupo de categoras, usado para agrupar de manera visi-
ble y agregar sangras a los informes de la lista de despliegue. Este elemento debe contener
exactamente un elemento <textoDespliegue>, pero puede contener cualquier nmero de
elementos <elementoInformes> o <grupoInformes>:
<textoDespliegue>: un nombre corto o una descripcin para este informe, como
aparecer en la lista de opciones de informes. Este elemento es obligatorio.
Cuando se use el tipo de informe integrado, el elemento <rutaInforme> se establece en
uno de los siguientes valores enteros:
1. Informe de artculos prestados
2. Informe de artculos vencidos
3. Informe de artculos faltantes
4. Informe de multas adeudadas por clientes
5. Informe de estadsticas de la base de datos de biblioteca
Esta descripcin tcnica aparece en el documento del kit de recursos tcnicos, desarrollado ori-
ginalmente en el captulo 4.

Cree la clase de entrada del informe


Con la capacidad de .NET de almacenar objetos completos como elementos ListBox, pode-
mos crear una clase personalizada que contenga toda la informacin necesaria para seleccionar
y ejecutar un informe de la lista de informes. Esta clase es muy simple, y no tiene ms que cam-
pos pblicos bsicos, adems de una funcin ToString de sobrescritura, usada por el control
ListBox para desplegar apropiadamente cada elemento de la lista.
En el proyecto Biblioteca, agregue un nuevo archivo de clase llamado ElementoInforme.vb me-
diante el comando de men Proyecto Agregar clase. Agregue la siguiente enumeracin al

382 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 382 17/2/10 15:27:24


archivo, pero agrguela fuera de los lmites de Class...End Class. Esta enumeracin indica el
tipo de entrada que representa cada elemento de la lista.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap13, Elemento 1.

Public Enum ElementoInformeEnum


' ----- El tipo de articulo en la lista de seleccion del informe.
EtiquetaGrupo = 0
PrestadoIntegrado = 1
VencidoIntegrado = 2
FaltanteIntegrado = 3
MultasDebidasIntegrado = 4
estadisticasIntegrado = 5
ProgramaExe = 6
ProgramaUrl = 7
End Enum

En este mismo archivo, agregue los miembros de la clase ElementoInforme. Esta clase contiene
toda la informacin que necesitamos para ejecutar informes cargados del archivo de configuracin.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap13, Elemento 2.

' ----- Instancia de articulos de seleccion de informes


' usada en el formulario SeleccionarInforme.
Public TipoElemento As ElementoInformeEnum
Public Sangria As Integer ' El nivel de Sangria empieza en 0.
Public DesplegarTexto As String
Public RutaInforme As String ' Solo ProgramaExe / ProgramaUrl
Public ArgsInforme As String ' Solo ProgramaExe
Public Descripcion As String

Public Overrides Function ToString( ) As String


' ----- Desplegar una cadena con sangria hecha con espacios.
Return StrDup(Sangria * 5, " ") & DesplegarTexto
End Function

Disee el formulario del informe


Los bibliotecarios y los administradores usan el formulario Seleccionar informe (vase la figura
13-2) para ver los informes. El formulario incluye un control ListBox que despliega todos los
informes y grupos de informes, un botn Ejecutar que inicia un informe y un botn Cerrar que
devuelve al usuario al formulario principal. Una etiqueta despliega la descripcin completa de
un informe, cuando est disponible, justo abajo del ListBox.

Proyecto | 383

13_PATRICK-CHAPTER_13.indd 383 17/2/10 15:27:24


Figura 13-2. El formulario Seleccionar informe.

Agregue un nuevo archivo de formulario llamado SeleccionarInforme.vb mediante el comando de


men Proyecto Agregar Windows Form. Agregue los controles y los parmetros que aparecen
en la tabla 13-1.

Tabla 13-1. Controles y valores para el formulario Seleccionar informe.

Control/formulario Tipo Valores


EtqInformes Label (Name): EtqInformes
Location: 8, 8
Text: &Informes
TodosLosInformes ListBox (Name): TodosLosInformes
Location: 8, 24
Size: 392, 160
EtqDescripcion Label (Name): EtqDescripcion
Location: 8, 200
Text: Descripcion del informe
DescripcionCompleta Label (Name): DescripcionCompleta
AutoSize: False
Location: 32, 224
Size: 358, 64
Text: Informe no seleccionado.
UseMnemonic: False

384 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 384 17/2/10 15:27:24


Tabla 13-1. Controles y valores para el formulario Seleccionar informe (continuacin).

Control/formulario Tipo Valores


AccEjecutar Button (Name): AccEjecutar
DialogResult: None
Location: 222, 304
Size: 80, 24
Text: Run
ActClose Button (Name): AccCerrar
DialogResult: Cancel
Location: 320, 304
Size: 80, 24
Text: Close
SeleccionarInforme Form (Name): SeleccionarInforme
AcceptButton: AccEjecutar
CancelButton: AccCerrar
ControlBox: False
FormBorderStyle: FixedDialog
StartPosition: CenterScreen
Text: Informes de biblioteca

Ajuste el orden de tabulacin de los nuevos controles al seleccionar el formulario, y luego usar el
comando de men Ver Orden de tabulacin.
Aunque tal vez el administrador ha asignado nombres tiles a cada informe, la suavidad de cada
nombre an puede confundir al usuario. Cada informe incluye una descripcin completa opcio-
nal. A medida que el usuario seleccione informes de la lista, un manejador de eventos actualiza
la etiqueta DescripcionCompleta que se encuentra justo debajo de la lista principal. Agregue
este miembro de controlador de eventos a la clase.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap13, Elemento 3.

Private Sub TodosLosInformes_SelectedIndexChanged( _


ByVal sender As Object, ByVal e As System.EventArgs) _
Handles TodosLosInformes.SelectedIndexChanged
' ----- Desplegar una descripcion del informe, si la hay.
Dim entradaInforme As Biblioteca.ElementoInforme

' ----- Limpiar cualquier descripcion anterior.


DescripcionCompleta.Text = "No hay un informe seleccionado."
If (TodosLosInformes.SelectedIndex <> -1) Then
' ----- Localizar el contenido y desplegarlo.
entradaInforme = CType(TodosLosInformes.SelectedItem, _

Proyecto | 385

13_PATRICK-CHAPTER_13.indd 385 17/2/10 15:27:24


Biblioteca.ElementoInforme)
DescripcionCompleta.Text = entradaInforme.Descripcion
End If
End Sub

Llenar informes a partir del archivo de configuracin


El mtodo ActualizarListaInformes carga los datos del archivo de configuracin de infor-
mes y procesa los resultados. Con el tiempo, la ubicacin de este archivo se guardar en el archivo
de configuracin de la aplicacin, pero slo lo agregaremos hasta un captulo posterior. Por ahora,
pongamos un lugar de archivo de prueba dentro del cdigo, y marqumoslo para posterior actua-
lizacin. Opt por usar los objetos XML al estilo antiguo para este cdigo, porque las caractersti-
cas XML necesarias para que el cdigo sea fcil de escribir se vern en un captulo posterior.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap13, Elemento 4.

Private Sub ActualizarListaInformes()


' ----- Cargar en la lista de informes disponibles.
Dim archivoConf As String
Dim datosConf As Xml.XmlDocument
Dim entradaInforme As ElementoInforme
Dim contador As Integer
On Error GoTo ErrorHandler
' ----- Limpiar la lista existente.
TodosLosInformes.Items.Clear()
' ----- Obtener la ubicacion del archivo de configuracion.
' TODO: Cargar esto de la configuracion de la aplicacion.
' Por ahora, solo codificar el valor.
archivoConf = "c:\ConfigInforme.txt"
' ----- Cargar el archivo de configuracion.
If (archivoConf <> "") Then
If (System.IO.File.Exists(archivoConf)) Then
' ----- Cargar el archivo.
datosConf = New Xml.XmlDocument
datosConf.Load(archivoConf)
' ----- Procesar el archivo de configuracion.
CargarGrupoInforme(datosConf.DocumentElement, 0)
End If
End If
' ----- Si el archivo de configuracion no arroja informes
' en la lista, agregar los informes predeterminados.
If (TodosLosInformes.Items.Count = 0) Then
For contador = 1 To _
CInt(ElementoInformeEnum.estadisticasIntegrado)
' ----- Generar la entrada del informe.

386 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 386 17/2/10 15:27:25


entradaInforme = New ElementoInforme
entradaInforme.Sangria = 0
entradaInforme.TipoElemento = CType(contador, ElementoInformeEnum)
Select Case entradaInforme.TipoElemento
Case ElementoInformeEnum.PrestadoIntegrado
entradaInforme.DesplegarTexto = "Articulos prestados"
Case ElementoInformeEnum.VencidoIntegrado
entradaInforme.DesplegarTexto = "Articulos vencidos"
Case ElementoInformeEnum.FaltanteIntegrado
entradaInforme.DesplegarTexto = "Articulos faltantes"
Case ElementoInformeEnum.MultasDebidasIntegrado
entradaInforme.DesplegarTexto = "Multas que adeudan los clientes"
Case ElementoInformeEnum.estadisticasIntegrado
entradaInforme.DesplegarTexto = "Estadisticas de la base de datos"
End Select
' ----- Agregar la entrada del informe a la lista.
TodosLosInformes.Items.Add(entradaInforme)
Next contador
End If
Return
ErrorHandler:
ErrorGeneral("SeleccionarInforme.ActualizarListaInformes", _
Err.GetException())
Resume Next
End Sub

Debido a que el archivo de configuracin del informe permite anidar grupos de informes en
cualquier nivel, necesitamos usar una rutina recursiva para descender de manera repetida a cada
nivel sucesivo. La rutina CargarGrupoInforme, llamada por ActualizarListaInformes,
agrega todos los elementos y grupos de informes dentro de un grupo de informes inicial. Es
llamada al principio desde el punto de referencia del elemento raz <listaInformes>. Cada
vez que encuentra un elemento secundario <grupoInformes> se llama a s mismo una vez ms,
pero esta vez a partir del punto de referencia del elemento secundario <grupoInformes>.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap13, Elemento 5.

Private Sub CargarGrupoInforme(ByVal nodoGrupo As Xml.XmlNode, _


ByVal nivelSangria As Integer)
' ----- Agregar los grupos y articulos de este nivel,
' y hacer las recursiones necesarias.
Dim nodoRastreo As Xml.XmlNode
Dim nodoDetalle As Xml.XmlNode
Dim entradaInforme As ElementoInforme
' ----- Procesar cada articulo o grupo.
For Each nodoRastreo In nodoGrupo.ChildNodes
' ----- Generar un articulo de contenido para la lista.
entradaInforme = New ElementoInforme
entradaInforme.Sangria = nivelSangria

Proyecto | 387

13_PATRICK-CHAPTER_13.indd 387 17/2/10 15:27:25


' ----- Obtener el nodo de despliegie.
nodoDetalle = nodoRastreo.SelectSingleNode("textoDespliegue")
If (nodoDetalle Is Nothing) Then Continue For
entradaInforme.DesplegarTexto = Trim(nodoDetalle.InnerText)

If (nodoRastreo.Name = "grupoInformes") Then


' ----- Empezar un nuevo grupo de despliegue.
entradaInforme.TipoElemento = ElementoInformeEnum.EtiquetaGrupo
TodosLosInformes.Items.Add(entradaInforme)

' ----- Recorrer de manera recursiva articulos secundarios.


CargarGrupoInforme(nodoRastreo, nivelSangria + 1)
ElseIf (nodoRastreo.Name = "elementoInformes") Then
' ----- Este es un articulo. Registrar su ubicacion.
nodoDetalle = nodoRastreo.SelectSingleNode("rutaInforme")
If Not (nodoDetalle Is Nothing) Then _
entradaInforme.RutaInforme = _
Trim(nodoDetalle.InnerText)

' ----- Obtener cualquier argumento de linea de comandos.


nodoDetalle = nodoRastreo.SelectSingleNode("argsInforme")
If Not (nodoDetalle Is Nothing) Then _
entradaInforme.ArgsInforme = _
Trim(nodoDetalle.InnerText)

' ----- Obtener cualquier marca especifica del articulo.


nodoDetalle = nodoRastreo.SelectSingleNode("marcasInforme")
If Not (nodoDetalle Is Nothing) Then
' ---- "U" agrega "-u id iniciosesion" al comando.
If (InStr(UCase(nodoDetalle.InnerText), "U") > 0) _
And (NombreUsuarioInicio <> "") Then _
entradaInforme.ArgsInforme = _
Trim(entradaInforme.ArgsInforme & " -u " & _
NombreUsuarioInicio)
End If

' ----- Almacenar la descripcion completa.


nodoDetalle = nodoRastreo.SelectSingleNode("descripcion")
If Not (nodoDetalle Is Nothing) Then _
entradaInforme.Descripcion = _
Trim(nodoDetalle.InnerText)

' ----- Entonces que tipo de entrada es?


If (nodoRastreo.Attributes("type").Value = _
"integrado") Then
' ----- Programa integrado. Revisar ID valido.
If (IsNumeric(entradaInforme.RutaInforme) = False) Or _
(Val(entradaInforme.RutaInforme) < 1) Or _
(Val(entradaInforme.RutaInforme) > _
CInt(ElementoInformeEnum.estadisticasIntegrado)) Then _
Continue For
entradaInforme.TipoElemento = CType(CInt( _
entradaInforme.RutaInforme), ElementoInformeEnum)
TodosLosInformes.Items.Add(entradaInforme)

388 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 388 17/2/10 15:27:25


ElseIf (nodoRastreo.Attributes("tipo").Value = _
"programa") Then
' ----- Informe basado en programa EXE.
If (entradaInforme.RutaInforme = "") Then Continue For
entradaInforme.TipoElemento = ElementoInformeEnum.ProgramaExe
TodosLosInformes.Items.Add(entradaInforme)
ElseIf (nodoRastreo.Attributes("tipo").Value = _
"url") Then
' ----- Informe basado en URL.
If (entradaInforme.RutaInforme = "") Then Continue For
entradaInforme.TipoElemento = ElementoInformeEnum.ProgramaUrl
TodosLosInformes.Items.Add(entradaInforme)
End If
End If
Next nodoRastreo
Return

ErrorHandler:
ErrorGeneral("SeleccionarInforme.CargarGrupoInforme", _
Err.GetException( ))
Resume Next
End Sub

Agregue el evento Load del formulario, que carga el contenido del archivo de configuracin.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap13, Elemento 6.

Private Sub SeleccionarInforme_Load(ByVal sender As Object, _


ByVal e As System.EventArgs) Handles MyBase.Load
' ----- Desplegar la lista de informes.
ActualizarListaInformes( )
End Sub

Ejecucin de los informes


Ahora que todos los grupos y elementos aparecen en la lista, tenemos que ejecutar los informes
reales. El evento Click del botn AccEjecutar maneja esta tarea. Por ahora, slo agregaremos
el marco conceptual para dar soporte a la llamada a cada informe. Los informes integrados se
agregarn en el captulo 21.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap13, Elemento 7.

Private Sub AccEjecutar_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles AccEjecutar.Click
' ----- Ejecutar el informe seleccionado.
Dim entradaInforme As Biblioteca.ElementoInforme
On Error GoTo ErrorHandler

Proyecto | 389

13_PATRICK-CHAPTER_13.indd 389 17/2/10 15:27:25


' ----- Asegurar que este seleccionado un informe.
If (TodosLosInformes.SelectedIndex = -1) Then
MsgBox("Por favor, seleccione un informe de la lista.", _
MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, _
TituloPrograma)
Return
End If

' ----- Diferente codigo para cada tipo de entrada.


entradaInforme = CType(TodosLosInformes.SelectedItem, _
Biblioteca.ElementoInforme)
Me.Cursor = Windows.Forms.Cursors.WaitCursor
Select Case entradaInforme.TipoElemento
Case ElementoInformeEnum.EtiquetaGrupo
' ----- No hay informe para el grupo de entradas.
MsgBox("Por favor seleccione un informe de la lista.", _
MsgBoxStyle.OKOnly Or MsgBoxStyle.Exclamation, _
TituloPrograma)
Case ElementoInformeEnum.PrestadoIntegrado
' ----- Articulos prestados
' TODO: Escribir InformeBasicoPrestado( )
Case ElementoInformeEnum.VencidoIntegrado
' ----- Articulos vencidos
' TODO: Escribir InformeBasicoVencido( )
Case ElementoInformeEnum.FaltanteIntegrado
' ----- Articulos faltantes
' TODO: Escribir InformeBasicoFaltante( )
Case ElementoInformeEnum.MultasDebidasIntegrado
' ----- Multas que adeudan los clientes
' TODO: Escribir InformeBasicoMultas( )
Case ElementoInformeEnum.estadisticasIntegrado
' ----- Estadisticas de base de datos de biblioteca
' TODO: Escribir InformeBasicoEstadisticas( )
Case ElementoInformeEnum.ProgramaExe
' ----- Iniciar un programa.
Process.Start("""" & entradaInforme.RutaInforme & _
""" " & entradaInforme.ArgsInforme)
Case ElementoInformeEnum.ProgramaUrl
' ----- Iniciar un URL.
Process.Start(entradaInforme.RutaInforme)
End Select
Me.Cursor = Windows.Forms.Cursors.Default
Return

ErrorHandler:
ErrorGeneral("SeleccionarInforme.AccEjecutar_Click", _
Err.GetException())
Resume Next
End Sub

Para los informes externos, el manejador de eventos llama al mtodo Process.Start. Este
mtodo sorprendente acepta una expresin estndar de lnea de comandos o cualquier URL o
direccin de pgina Web vlida.

390 | Captulo 13: XML

13_PATRICK-CHAPTER_13.indd 390 17/2/10 15:27:25


Conexin del formulario para seleccionar informes
Para que los informes estn a disposicin del usuario, debemos habilitar un vnculo con el for-
mulario de informe del formulario principal. Incluimos un panel distintivo en ese formulario
slo para impresin de informes. El botn AccCrearInformes de ese panel desencadena una
llamada al nuevo formulario de seleccin de informes. Cree un nuevo controlador de eventos
para el botn AccCrearInformes y agregue el siguiente cdigo.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap13, Elemento 8.

' ----- Mostrar el formulario informes.


SeleccionarInforme.ShowDialog()

Ahora que tenemos un firme conocimiento del mundo de XML, dejemos que Visual Basic haga
todo el trabajo difcil de manipularlo para fines de configuracin de la aplicacin.

Proyecto | 391

13_PATRICK-CHAPTER_13.indd 391 17/2/10 15:27:25


Captulo 14
Configuraciones de la aplicacin

Hace casi un siglo, el presidente Abraham Lincoln empez su famoso discurso de Gettysburg
con Hace casi un siglo Por qu esta referencia potica a la fundacin de Estados Unidos
hace 87 aos? Pudo haber empezado el discurso diciendo: La ltima semana, estaba hablando
con miembros de mi gabinete o an Estos tres soldados confederados entraron en un bar
Pero se apeg a la ancdota de varias dcadas antes.
Lincoln comprenda que sus escuchas, como seres humanos, tenan una liga con el pasado, un
cario por lo familiar, un amor por los automviles deportivos rpidos y un deseo de ver que se
restauraba la estabilidad de una era anterior. As es la gente. Les gusta la paz, no la guerra. Les
gusta lo establecido, no el cambio. Les gusta comer en la mesa cuando regresan a su casa despus
de un da difcil en la oficina. Les gustan las filas cortas en el parque de diversiones. Les gusta ver
a su equipo favorito de ftbol ganar de vez en cuando.
A la gente le gusta saber que las cosas estn configuradas de una manera que tenga sentido para
ellos, configuradas de una manera que les sea familiar y conocida. Esperan esto en vida y lo
esperan en su software. Por eso, Visual Basic incluye caractersticas que le permiten mantener
configuraciones especficas de usuario y de la aplicacin.

Una breve historia sobre las configuraciones


Desde ese corto pero dinmico discurso de Lincoln, los programadores han buscado una manera
conveniente de mantener valores configurables en sus aplicaciones. En los primeros das del de-
sarrollo de MS-DOS, haba una configuracin libre para todos; cada programa proporcionaba
su propio sistema de configuracin. Muchas aplicaciones no necesitaban configuraciones espe-
cializadas, pero quienes la hacan a menudo guardaban los valores de configuracin con los datos
administrados por la aplicacin, todo en archivos de propietario .dat.
Con el advenimiento del desarrollo de Windows, Microsoft introdujo administracin de configu-
racin basada en archivos mediante su interfaz de programacin de aplicaciones (API, Application
Programaming Interface). La API de perfil privado llama a (GetPrivateProfileInt, Get
PrivateProfileCadena, SetPrivateProfileCadena y unos cuantos ms), que proporciona

392

14_PATRICK-CHAPTER_14.indd 392 17/2/10 15:27:56


una manera estndar de almacenar valores de configuracin cortos en un formato de archivo de
texto abierto y fcil de comprender. Microsoft usaba estos archivos INI (llamados as por su ex-
tensin .ini) para su propia configuracin. Unos cuantos de estos archivos an residen en la carpeta
Windows de su sistema. He aqu el contenido que encontr en el archivo win.ini de mi sistema:
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
[CDWINSETUP]
AUTOUNLOAD=No
[MSUCE]
Advanced=0
CodePage=Unicode
Font=Arial

El formato de un archivo INI era simple de comprender. Cada archivo inclua secciones con
nombre definidas entre corchetes, como en [fonts]. Cada seccin mantena un conjunto de
pares clave-valor en la forma clave=valor. El formato era lo bastante simple como para que
cualquiera pudiera usar el Bloc de notas para hacer cambios. Ni siquiera era difcil que un pro-
grama escribiera sus propias rutinas de administracin del archivo INI, pero incluirlos en la API
de Windows haca eso mucho ms atractivo.
Pero entonces lleg el amontonamiento. Con tantos programas optando por almacenar sus ar-
chivos de configuracin en una ubicacin central conocida, la carpeta Windows se volvi rpi-
damente el equivalente en archivo de la Gran Estacin Central a las 5:00 p.m. en un viernes. La
velocidad era un problema, tambin, porque el anlisis y la reescritura constante de los archivos
INI consuman recursos preciosos de la CPU.
Microsoft surgi con una solucin: el registro. Esta base de datos de pares clave-valor limpi el
sistema de archivos y trajo mejoras en velocidad a la administracin de la configuracin. Tambin
agreg nuevas configuraciones de seguridad definidas por el administrador para acceder al regis-
tro, y proporcion soporte para los mismos datos de tipo fuertemente delimitados. Pero las carac-
tersticas de la nueva API no fueron las ms intuitivas (aunque Visual Basic s inclua comandos
simples, como GetSetting, que proporcionaba acceso limitado a claves y valores de registro).
El registro llev tecnologa al problema de los valores de configuracin, pero no fue un triunfo
completo. Con tantos vendedores metiendo montones de datos en el registro, el crecimiento
inusual se volvi otra vez un problema. Y como el sistema administraba todo el acceso al registro,
cuanto ms grande era ste, peor era el rendimiento.
El lanzamiento inicial de .NET inclua archivos especficos de la aplicacin, una especie de re-
greso a los das ya pasados del archivo INI. En cierta manera, los archivos app.config y web.
config eran mejores que los archivos INI porque incluan contenido XML estructurado. Pero
haba algo de qu alegrarse. Los archivos INI tenan estructura y poda actualizarlos en el Bloc
de notas. Los archivos de configuracin de .NET eran notablemente difciles de actualizar, ya sea

Una breve historia sobre las configuraciones | 393

14_PATRICK-CHAPTER_14.indd 393 17/2/10 15:27:56


dentro de una aplicacin de .NET o externamente en el Bloc de notas (debido a algunos raros
problemas de administracin en cach). Adems, los archivos .config no tenan la seguridad ni el
tipo de datos fuertes disponibles en el registro.
Los valores de configuracin han dado a los programadores algn nivel de ansiedad desde la prime-
ra aparicin de Windows. Pero un nuevo sistema de configuracin mejorado, aadido por primera
vez a Visual Basic en 2005, buscaba cambiar todo esto.

Configuracin en Visual Basic 2008


El sistema de configuracin en Visual Basic 2008 es un mtodo de varios archivos, basado en
XML, de tipo fuerte y fcil de administrar. Es una metodologa concentrada en archivos que
incluye estas caractersticas y beneficios:
Los datos estn almacenados en formato XML para procesamiento eficiente por parte de las
bibliotecas .NET. Aunque no es texto de forma libre, XML no tiene una dificultad excesiva
cuando los simples mortales necesitan hacer actualizaciones manuales.
Los datos almacenados en cada archivo especfico de la configuracin son de tipo fuerte,
reduciendo errores del procesamiento de datos no vlidos.
Las configuraciones se administran por aplicacin, por usuario y aun por versin de en-
samblado para promover la seguridad y reducir los conflictos. Tambin puede almacenar
varios conjuntos de configuraciones por aplicacin, segn se necesite, como un conjunto de
configuraciones por documento abierto por su aplicacin. (No se analizar en este captulo,
pero puede buscar en lnea Propiedad SettingsKey en la ayuda en lnea, para conocer in-
formacin adicional sobre esta caracterstica.)
Visual Studio incluye una herramienta de administracin amigable con el usuario, usada
para configurar valores dentro de una aplicacin.
Visual Basic tiene su propia interfaz simple para facilitar el uso y la actualizacin de confi-
guraciones en tiempo de ejecucin.
Pero no todo es diversin y juego. Como desarrollador, tiene que hacer parte del levantamiento
de pesas, como asignar nombres significativos para cada configuracin (UbicacionFormula-
rioPrincipal, ConexionBaseDeDatos, etc.), y modificar el comportamiento de su programa,
segn sea necesario, con base en las configuraciones almacenadas.
La configuracin real aparece en archivos XML dispersos por todo el sistema de archivos:
En tiempo de diseo, todas las configuraciones que cree se almacenan en un archivo Set-
tings.settings, almacenado en el subdirectorio My Proyect de su carpeta de cdigo fuente. He
aqu el archivo Settings.settings como existe hasta ahora en el Proyecto Biblioteca:
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/
VisualStudio/2004/01/settings"
CurrentProfile="(Default)">
<Profiles>

394 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 394 17/2/10 15:27:56


<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

En tiempo de ejecucin, todos los parmetros especficos del usuario aparecen en el archivo
user.config, almacenado por lo general en C:\Documents and Settings\<usuario>\Configuracin
local\Application Data\<compaia>\<datosaplicacin>\<version>, donde <usuario>
es el nombre de usuario de Windows, <compaia> es el nombre de la compaa guardado en
el ensamblado, <datosaplicacion> es una combinacin de valores que ayudan a diferenciar
las configuraciones basadas en el uso y <version> es la versin en cuatro partes del nmero
del ensamblado. Al parecer, es un lugar difcil para almacenar configuraciones, pero mantiene
las cosas ordenadas. (La ubicacin del archivo user.config es un poco diferente, si despliega una
aplicacin empleando ClickOnce, un mtodo descrito en el captulo 25.)
Tal vez se est preguntando si esto contribuye a la aglomeracin en el disco. S! Cada vez
que sube el nmero de versin de su aplicacin, .NET crea un nuevo archivo de configura-
cin para acompaarlo. Hay una manera de mitigar esto, de alguna manera, pero con discos
duros de 120 GB, nadie se est quejando ms acerca del uso del espacio en disco.
Algunos valores estn centrados en la aplicacin, y se aplican a todos los usuarios de la
aplicacin en una estacin de trabajo particular. Se almacenan en el archivo app.config que
aparece en la misma carpeta que el ejecutable de su ensamblado. Los parmetros aparecen
en una rama de XML llamada <applicationsettings> dentro de este archivo. Los pa-
rmetros concentrados en la aplicacin no pueden ser modificados por la aplicacin; debe
actualizar manualmente el archivo app.config para forzar un cambio.
El sistema de configuracin es un lugar estupendo para almacenar el estado, que son las cosas que
el programa recuerda de la ltima vez que se ejecut, pero que no deben incluirse en el cdigo
fuente.

Adicin de parmetros a un proyecto


La ventana Propiedades del proyecto dentro de Visual Studio 2008 proporciona control centraliza-
do de los valores de configuracin de una aplicacin. El panel Configuracin de esta ventana, que
se muestra en la figura 14-1, proporciona acceso a los valores personalizados de la aplicacin.
Para agregar una configuracin, escriba su Nombre, seleccione su Tipo de datos de la lista des-
plegable, elija el mbito (Usuario o Aplicacin) e ingrese su Valor usando cualquier editor de va-
lores que est disponible para el tipo seleccionado. La lista Tipo incluye muchas selecciones pre-
determinadas, incluidos los tipos de datos, fuentes, colores y tamaos relacionados con el dibujo
bsico de Visual Basic. Tambin est incluido un tipo (Cadena de conexin) que, cuando se
selecciona, habilita un generador de cadenas Propiedades de la conexin en la columna Valor.
Es importante que seleccione el tipo correcto de cada configuracin almacenada; de otra manera,
su estacin de trabajo explotar. En realidad, creo que se corregir eso en una versin beta pos-
terior. Se debe realmente a que todos los parmetros tienen tipos fuertes. Si establece el tipo en
Integer, no podr incluir la palabra None como una marca especial, como podra hacerlo en un

Configuracin en Visual Basic 2008 | 395

14_PATRICK-CHAPTER_14.indd 395 17/2/10 15:27:56


Figura 14-1. El panel Configuracin, sin valores definidos.

archivo INI. Puede elegir cualquier tipo .NET vlido para el tipo de datos, aunque los tipos com-
plejos sin sus propios editores personalizados requerirn que establezca su valor mediante cdigo.
Qu sucede cuando agrega un nueva configuracin a un proyecto de Visual Basic? Descubrmoslo.
Agregar dos parmetros a un nuevo proyecto de Windows Forms: un Integer denominado Li
mitePrecaucion, y un System.Drawing.Font llamado FuenteNota (vase la figura 14-2).

Figura 14-2. El panel Configuracin, con dos nuevas configuraciones.

Como ya lo sabe, Visual Studio es slo una envoltura amigable con el usuario alrededor de c-
digo .NET, y el panel Configuracin no es diferente. As, los cambios reales ocurren en algn
lugar del cdigo, o ms correctamente, en el cdigo y el archivo Settings.settings. Si elige Mostrar
todos los archivos en el panel Explorador de soluciones, y expande My Proyect seguido por Set-
tings.settings, encontrar que este archivo XML tiene su propio archivo de configuracin fuente
de Visual Basic, Settings.Designer.vb.
Si abre el archivo Settings.Designer.vb, encontrar el siguiente cdigo parcial:
Namespace My
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration. _
ApplicationSettingsBase

396 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 396 17/2/10 15:27:57


<Global.System.Configuration. _
UserScopedSettingAttribute(), _
Global.System.Diagnostics. _
DebuggerNonUserCodeAttribute( ), _
Global.System.Configuration. _
DefaultSettingValueAttribute("25")> _
Public Property LimitePrecaucion(
) As Integer
Get
Return CType(Me("LimitePrecaucion"),Integer)
End Get
Set
Me("LimitePrecaucion") = valor
End Set
End Property

<Global.System.Configuration. _
UserScopedSettingAttribute(), _
Global.System.Diagnostics. _
DebuggerNonUserCodeAttribute( ), _
Global.System.Configuration. _
DefaultSettingValueAttribute( _
"Arial, 14.25pt, style=Bold")> _
Public Property FuenteNota() _
As Global.System.Drawing.Font
Get
Return CType(Me("FuenteNota"), _
Global.System.Drawing.Font)
End Get
Set
Me("FuenteNota") = valor
End Set
End Property
End Class
End Namespace

Exclu una gran cantidad de cdigo adicional. Es sorprendente la cantidad de cdigo que Mi-
crosoft carga en atributos preescritos, y en realidad no es posible saber lo que hay dentro. Puedo
adivinar lo que hace el atributo DefaultSettingValueAttribute para cada configuracin
(asigna el valor predeterminado inicial de la configuracin), pero algunos de los dems son mis-
terios. Oh, bueno. Ni siquiera los ancestros tenan respuestas para todo.
Pero el cdigo que permanece es muy claro. Visual Studio genera dos propiedades dentro de la
clase My.MySettings, llamadas (vaya sorpresa) LimitePrecaucion y FuenteNota. He aqu
la entrada de la propiedad para FuenteNota:
Public Property FuenteNota() As Global.System.Drawing.Font
Get
Return CType(Me("FuenteNota"), _
Global.System.Drawing.Font)
End Get
Set
Me("FuenteNota") = valor
End Set
End Property

Configuracin en Visual Basic 2008 | 397

14_PATRICK-CHAPTER_14.indd 397 17/2/10 15:27:57


No querr encontrar ningn miembro de clase privada que almacene los valores ocultos
LimitePrecaucion y FuenteNota. En cambio, en algn otro lugar de esta clase parcial hay
una propiedad predeterminada (llamada Item) que obtiene y establece cada valor definido de la
propiedad, al que se accede mediante Me("algo").
La configuracin disponible mediante esta propiedad predeterminada est cargada directamente
desde el XML almacenado en el archivo Settings.settings. (Este archivo est compilado en la apli-
cacin; no tiene que distribuir Settings.settings con la aplicacin.) He aqu el contenido de ese
archivo con nuestros dos nuevos valores de configuracin:
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/
VisualStudio/2004/01/settings"
CurrentProfile="(Default)"
GeneratedClassNamespace="My"
GeneratedClassName="MySettings"
UseMySettingsClassName="true">
<Profiles />
<Settings>
<Setting Name="LimitePrecaucion"
Type="System.Int32" Scope="Usuario">
<Valor Profile="(Default)">25</Valor>
</Setting>
<Setting Name="FuenteNota"
Type="System.Drawing.Font" Scope="Usuario">
<Valor Profile="(Default)">
Arial, 14.25pt, style=Bold</Valor>
</Setting>
</Settings>
</SettingsFile>

Cada configuracin contiene atributos o entradas Name, Type, Scope y Valor distintivos, que co-
inciden con las cuatro columnas que aparecieron en el editor de configuraciones de Visual Studio.

My.Settings
Visual Basic crea una instancia de la clase My.MySettings que acabamos de ver, y lo pone a
disposicin como My.Settings. A medida que agrega parmetros a su proyecto, se vuelven
miembros de clase con tipo fuerte de My.Settings. Para acceder a uno, simplemente haga
referencia a l directamente en su cdigo.
MsgBox("La fuente para nota es: " & _
My.Settings.FuenteNota.ToCadena())

(La salida para este cdigo aparece en la figura 14-3.) La My.Settings.FuenteNota es una ins-
tancia real de System.Drawing.Font que puede usar como cualquier otra instancia de Font.
Puede modificar el valor de cualquier configuracin con mbito Usuario, y hacer que el nuevo
valor se preserve para su siguiente uso de la aplicacin (es decir, para el siguiente uso del usuario
actual de la aplicacin).
My.Settings.LimitePrecaucion = 30

398 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 398 17/2/10 15:27:58


Figura 14-3. Asegrese de tomar nota de esta fuente.

Todos los cambios hechos a estos parmetros se guardaron automticamente en los archivos
de configuracin especficos del usuario, como opcin predeterminada. Si no quiere que las
actualizaciones se guarden automticamente, establezca la marca My.Application.SaveMy
SettingsOnExit en False. Luego, cuando est listo para guardar los nuevos valores, use el
mtodo My.Settings.Save.
Las configuraciones vienen en tres deliciosos sabores: predeterminadas, persistentes y actuales. Las
configuraciones predeterminadas son los valores definidos por el programador a travs del editor de
configuraciones de Visual Studio. Las configuraciones persistentes incluyen los cambios guardados
en configuraciones especficas, y las configuraciones predeterminadas son las que nunca han
sido alteradas por el usuario. Las configuraciones actuales incluyen cualquier cambio hecho a las
configuraciones durante la sesin actual, pero an no guardados. Puede jugar con estos estados
usando miembros del objeto My.Settings:
El mtodo Save, como ya se mencion, guarda todas las configuraciones actuales en un
estado persistente.
El mtodo Reload restaura cualquier valor actual con las versiones persistentes.
El mtodo Reset elimina todas las configuraciones actuales y persistentes, y regresa todas
las entradas de configuracin a sus valores predeterminados.
Uno de los aspectos ms extraos es que son especficos de la versin. Si lanza su aplicacin
como versin 1.0.0.0, y luego libera la versin 1.1.0.0, cada usuario perder todos los valores
persistentes anteriores. En realidad, no se perdern, pero se quedarn en la tierra del 1.0.0.0.
Si siempre quiere tener las configuraciones ms actualizadas de acuerdo con las modificaciones
del usuario, tendr que asegurarse de que las configuraciones anteriores tienen la capacidad de
actualizarse cuando se instala una nueva versin. My.Settings incluye un mtodo Upgrade
que hace el trabajo de manera automtica. Pero si el usuario instala una versin ms reciente y
actualiza las configuraciones, hace cambios a esos cdigos y luego llama de nuevo a Upgrade, se
perder cualquier cambio hecho desde la ltima actualizacin.
Para sortear este problema, el cdigo debe actualizar las configuraciones slo cuando aparezca
una nueva versin. La manera ms fcil de hacer esto incluye una configuracin llamada algo
as como SettingsUpgraded y establecerla en False. Revise esta marca antes de llamar a Up
grade. Si un es False, resulta seguro llamar a Upgrade. Una vez que el cdigo actualice la
configuracin, cambie SettingsUpgraded a True.

Configuracin en Visual Basic 2008 | 399

14_PATRICK-CHAPTER_14.indd 399 17/2/10 15:27:58


If (My.Settings.SettingsUpgraded = False) Then
My.Settings.Upgrade()
My.Setttings.SettingsUpgraded = True
End If

Esta necesidad de actualizar la configuracin cada vez que se haga el cambio an ms nfimo de cada
versin menor a un ensamblado parece un poco difcil. Pero es necesario dar soporte al objetivo de
.NET de una instalacin completa. El usuario debe tener la capacidad de instalar dos versiones dis-
tintas de su aplicacin en la misma estacin de trabajo, y usar cada una sin interferencia de la otra.
El almacenamiento de las configuraciones especficas de la versin ayuda a lograr este objetivo.

Configuraciones de unin
Aunque el uso y la actualizacin de sus valores de configuracin predeterminados pueden ser
excitantes, an ms excitante es que los campos en su Windows Forms y sus controles relaciona-
dos pueden interactuar interactivamente con los parmetros persistentes. Al unir las propiedades
especficas del formulario y el control al sistema de configuraciones, Visual Basic guarda autom-
ticamente y restaura las preferencias controladas por el usuario dentro de la interfaz de usuario.
Un uso tpico para las configuraciones de unin es hacer que la aplicacin recuerde dnde apa-
reci un formulario particular en la pantalla cuando el programa se ejecutaba por ltima vez.
La propiedad Location del formulario mantiene su posicin en pantalla. El hecho de recordar
este valor de los parmetros requiere dos pasos. En primer lugar, se debe crear una configuracin
de tipo System.Drawing.Point para mantener el valor de ubicacin persistente. En segundo
lugar, se debe indicar en las propiedades del formulario que su valor Location debe persistir
para la nueva entrada de parmetros.
El primer paso se realiza al agregar un parmetro System.Drawing.Point con mbito para
el nuevo usuario en el panel Configuracin, de las propiedades del proyecto. Llammoslo
PosicionFormularioPrincipal y deje el campo Valor en blanco por ahora.
De regreso en el editor del formulario, seleccione el propio objeto del formulario, y luego acceda
al panel Propiedades. Expanda la propiedad (ApplicationSettings) para localizar la subpropie-
dad (PropertyBinding). Al hacer clic en el botn de esta entrada se despliega el cuadro de
dilogo Configuracin de la aplicacin. Este proceso de seleccin aparece en la figura 14-4.
Busque la entrada Location en la lista y elija PosicionFormularioPrincipal como valor. Ahora,
cada vez que ejecute la aplicacin que contiene esta configuracin de unin, el formulario mo-
dificado recordar su ubicacin anterior.

Resumen
Al igual que con XML, el sistema de configuracin de .NET es una de esas caractersticas in-
ternas, tras bambalinas; no deje que el jefe conozca que hace que su programa sea estupendo
para usar, pero sin todas esas cosas llamativas. De manera personal, los encontr un poco difcil
de compartir con mis preciosos archivos INI y de todas, su simplicidad. Pero la automatizacin
adjunta al sistema de configuracin hace que la migracin sea simple.

400 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 400 17/2/10 15:27:58


Figura 14-4. Despliegue del cuadro de dilogo de configuracin de una aplicacin para un formulario.

Proyecto
Por supuesto, agregaremos parmetros al Proyecto Biblioteca en este captulo, pero tambin
regresaremos y empezaremos a usar algunas de esas configuraciones en el cdigo que ingresamos
antes como valores codificados.
Realmente luch por decidir si se usan valores de configuracin con mbito de la aplicacin o
mbito del usuario para algunos de los parmetros que realmente cambian, como la cadena de
conexin de base de datos. Por ltimo, decid usar el rea del usuario para que pudieran modi-
ficarse mediante las caractersticas del programa. Los valores de mbito de la aplicacin son de
slo lectura y slo pueden actualizarse fuera del programa, de modo que sa es la idea. Lo que
se espera con los parmetros del mbito de la aplicacin es que el administrador del sistema los
administre, al usar el Bloc de notas o el archivo XML, o a travs de alguna herramienta adminis-
trativa personalizada. Como no vamos a tomar el tiempo en el proyecto de este libro de escribir
una herramienta de administracin separada, mantendremos todo en el nivel del usuario y per-
mitiremos la modificacin a travs de todo el programa Biblioteca.

ACCESO AL PROYECTO
Cargue el proyecto Cap14 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap14 (Final) cdigo.

Actualice la documentacin tcnica


Documentemos los parmetros usados por la aplicacin en el Kit de recursos del proyecto.
Agregue el siguiente contenido en el archivo de procesamiento de palabras del Kit de recursos.

Proyecto | 401

14_PATRICK-CHAPTER_14.indd 401 17/2/10 15:27:59


Configuraciones de usuario
El Proyecto Biblioteca usa el sistema de configuracin de Visual Basic para dar seguimiento a
los valores de estado especficos del usuario mantenidos entre usos de la aplicacin. Todos es-
tos parmetros estn almacenados en un archivo XML en la parte del usuario del directorio
C:\Documents and Settings (o equivalente), en un formato determinado por .NET. La siguiente
es una lista de los parmetros reconocidos por el programa Biblioteca:
ConexionBD (String)
Una cadena de conexin formada apropiadamente que identifica la base de datos de SQL
Server usada por la aplicacin. Si se omite, la aplicacin le pedir la ubicacin de la base de
datos al principio.
ArchivoAyuda (String)
Indica la ubicacin de UNC o de letra de unidad basada en letras del archivo de ayuda b-
sico en lnea de la aplicacin, con una extensin .chm.
ArchivoAyudaAdmin (String)
Indica la ubicacin de UNC o de letra de unidad basada en letras del archivo de ayuda ad-
ministrativo en lnea de la aplicacin, con una extensin .chm.
OcultarInicioSesion (Boolean)
Indica si el botn Iniciar sesin de la esquina superior derecha del formulario principal de
Biblioteca debe ocultarse de la vista cuando se est en modo de cliente (no administrativo).
Use True para ocultar el botn o False para mostrarlo. Si se est omitiendo el campo se
supone False.
PosicionFormularioPrincipal (System.Drawing.Point)
La posicin en la esquina superior izquierda del formulario Biblioteca principal. Este valor
se actualiza cada vez que la aplicacin se cierra.
EnvioRecibo (String)
Cualquier dato de carcter simple para enviar a la impresora que recibe al final de cada bo-
leta. Este texto puede incluir los siguientes caracteres especiales:
\n
Carcter de nueva lnea (ASCII 10).
\r
Carcter de retorno de carro (ASCII 13).
\e
Carcter de escape (ASCII 27).
\x??
Cualquier valor ASCII, donde ?? es un cdigo hexadecimal de dos caracteres.
\\
El carcter de diagonal invertida (\ ).

402 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 402 17/2/10 15:27:59


ImpresoraRecibo (String)
El nombre de ruta UNC de la impresora del recibo usada por esta estacin de trabajo para
imprimir los recibos de prstamo del cliente y los recibos de pago.
AnchoRecibo (Integer)
El ancho, en caracteres, de cada lnea en la impresora del recibo. Si falta o est vaco, la
pgina usa un ancho predeterminado de 40 caracteres.
ConfigInforme (String)
Indica la ubicacin UNC o basa en letra de la unidad del archivo de configuracin de
informe XML. Este archivo tiene el formato XML descrito en la seccin Archivo de con-
figuracin del informe de este documento. Este archivo indica los informes disponibles en
la aplicacin.
ConfiguracionesActualizadas (Boolean)
Cuando se actualiza la aplicacin desde una versin ms antigua, esta marca indica si los
parmetros relacionados con esa versin ms antigua ya se han actualizado en esta nueva
versin. El valor predeterminado es False para todas las nuevas versiones.
UsarRecibos (Boolean)
Indica si los recibos impresos habrn de usarse en esta estacin de trabajo. Si falta este cam-
po se supone False.
Esta descripcin tcnica aparece en el documento Kit de recursos tcnicos, desarrollado original-
mente en el captulo 4 y que se actualiza en captulos posteriores. Parte del contenido agregado
aqu hace referencia a caractersticas y contenido tcnico que no se agregar hasta captulos
posteriores, de modo que no gaste mucho tiempo pensando en caractersticas que pensaba que
ya haba olvidado.

Agregue las configuraciones


Como conocemos todas las configuraciones que agregaremos a la aplicacin, agregumoslas
ahora. Abra la ventana de propiedades del proyecto y seleccione las aplicaciones. Agregue cada
valor a la aplicacin usando la tabla 14-1 como gua. Si un parmetro de la tabla 14-1 no tiene
un valor en la lista, deje en blanco el campo Valor tambin en el editor de configuraciones.
Tabla 14-1. Configuracin predeterminada para el Proyecto Biblioteca.

Nombre Tipo mbito Valor


ConexionBD String Usuario
ArchivoAyuda String Usuario
ArchivoAyudaAdmin String Usuario
OcultarInicioSesion Boolean Usuario False
PosicionFormularioPrincipal System.Drawing.Point Usuario
EnvioRecibo String Usuario
ImpresoraRecibo String Usuario

Proyecto | 403

14_PATRICK-CHAPTER_14.indd 403 17/2/10 15:27:59


Tabla 14-1. Configuracin predeterminada para el Proyecto Biblioteca (continuacin).

Nombre Tipo mbito Valor


AnchoRecibo Integer Usuario 40
ConfigInforme String Usuario
ConfiguracionesActualizadas Boolean Usuario False
UsarRecibos Boolean Usuario False

Asegrese de escribir los nombres de las configuraciones como aparecen aqu. La aplicacin no
los podr encontrar con nombres escritos de manera incorrecta.

Posicionamiento del formulario principal


Le mostr cmo vincular el valor de la propiedad del formulario o el control a uno de los valores
indicados en este captulo, as que hagmoslo en la realidad en el proyecto. Vincularemos la
propiedad Location del formulario principal a la configuracin PosicionFormularioPrin
cipal. Slo para refrescarle la memoria, siga estos pasos para habilitar el vnculo:
1. Abra FormularioPrincipal.vb en la vista Diseo.
2. Asegrese de que el propio formulario est seleccionado, no uno de sus controles subordinados.
3. En el panel Propiedades, expanda la propiedad (ApplicationSettings).
4. Seleccione la subpropiedad (PropertyBinding) y haga clic en el botn en su rea de valor.
5. Localice la propiedad Location en la lista de unin.
6. Seleccione la configuracin PosicionFormularioPrincipal para el valor de la propiedad
Location. Debe ser la nica configuracin disponible porque es la nica que definimos co-
mo tipo System.Drawing.Point.
7. Haga clic en el botn Aceptar para habilitar el vnculo.

Uso de cach y configuraciones


Aunque todas las configuraciones estn al alcance con slo escribir My.Settings.algo en el
cdigo, algunas configuraciones pueden estar no definidas al principio, y usarlas podra requerir
una gran cantidad de cdigo repetitivo que revise que las configuraciones son vlidas. Para redu-
cir el cdigo general y los ciclos de CPU, incluiremos en cach algunos de los valores para fcil
uso en toda la aplicacin.
Agreguemos tres variables globales ms para incluir en cach algunas de las configuraciones.
Abra el mdulo General.vb y agregue estos nuevos tres miembros de clase.
INSERCIN DE FRAGMENTO DE CDIGO
Inserte el fragmento de cdigo Cap14, Elemento 1.

404 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 404 17/2/10 15:27:59


Public ArchivoAyudaPrincipal As String
Public ArchivoAyudaAdminPrincipal As String
Public DiasGraciaMulta As Integer

Demos a estas variables valores iniciales en el mtodo InicializarSistema donde el cdigo


ya inicializa algunos otros valores. Agregue las siguientes instrucciones a esa rutina en el mdulo
General.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap14, Elemento 2.

DiasGraciaMulta = 1

' ----- Localizar los archivos de ayuda en linea.


ArchivoAyudaPrincipal = My.Settings.ArchivoAyuda & ""
ArchivoAyudaAdminPrincipal = My.Settings.ArchivoAyudaAdmin & ""

En un captulo anterior, almacenamos algunas configuraciones en la tabla ValorSistema que


aplica a todas las estaciones de trabajo que se conectan a la base de datos. Como estamos de todos
modos incluyendo las configuraciones en cach, debemos agregar algn cdigo para incluir en
cach estos valores almacenados en esta base de datos para que no tengamos que abrir y cerrarla.
Agregue el mtodo CargarConfiguracionesBasesDeDatos al mdulo General.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap14, Elemento 3.

Public Sub CargarConfiguracionesBasesDeDatos(


)
' ----- Obtener algunos valores en el nivel de sistema
' del almacenamiento de la base de datos.
Dim contenerTexto As String

On Error Resume Next

' ----- Obtener la ubicacion predeterminada.


contenerTexto = ObtenerValorSistema("LugarPredeterminado")
If (contenerTexto = "") Then contenerTexto = "-1"
LugarPredeterminadoElemento = CInt(contenerTexto)

' ----- Obtener el numero maximo de coincidencias de busqueda.


contenerTexto = ObtenerValorSistema("LimiteBusqueda")
If (contenerTexto = "") Then contenerTexto = "-1"
LimiteCoincBusqueda = CInt(contenerTexto)

' ----- Obtener el numero de dias que se debe esperar


' antes de cobrar multas.
contenerTexto = ObtenerValorSistema("GraciaEnMulta")
If (contenerTexto = "") Then contenerTexto = "-1"
DiasGraciaMulta = CInt(contenerTexto)
End Sub

Proyecto | 405

14_PATRICK-CHAPTER_14.indd 405 17/2/10 15:27:59


Llamaremos a esta rutina durante el inicio de la aplicacin, justo despus de abrir y confirmar la
base de datos. Agregue el siguiente cdigo al final del manejador de eventos MyApplication_
Startup. Si ha pasado tiempo, recuerde que este manejador est en el archivo ApplicationEvents.
vb, uno de los archivos ocultos normalmente de la vista en el Explorador de soluciones.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap14, Elemento 4.

' ----- Cargar algunas configuraciones que residen en la base de datos.


CargarConfiguracionesBasesDeDatos()

Es hora de usar realmente la configuracin. El parmetro My.Settings.OcultarInicioSe


sion indica si debe aparecer el botn Iniciar sesin (AccIniciarSesion) en el formulario de la
aplicacin principal de Biblioteca cuando se ejecuta en el modo de no administrador (no biblio-
tecario). El administrador an puede desplegar el formulario de inicio de sesin mediante la te-
cla F12, aunque el botn est oculto. En un entorno donde los clientes pueden ser desconocidos,
el sistema ser ligeramente ms seguro si se elimina la tentacin de un botn Iniciar sesin.
La rutina ActualizarPantallaParaUsuario en la clase FormularioPrincipal incluye c-
digo para el modo de usuario (IdUsuarioInicio = -1) y modo administrador (IdUsuario
Inicio <> -1). En el bloque de modo de usuario (el primero), reemplace esta lnea:
AccIniciarSesion.Visible = True

con el cdigo siguiente:

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap14, Elemento 5.

' ----- Mostrar u ocultar el boton Iniciar sesion para las configuraciones.
AccIniciarSesion.Visible = Not My.Settings.OcultarInicioSesion

Adicin de formularios de configuracin


Es hora de agregar los formularios que administrarn todas las diversas configuraciones de la
aplicacin, tanto las almacenadas localmente en el archivo de configuracin concentrado en el
usuario como las configuraciones de todo el sistema almacenadas en la base de datos. La mayor
parte de las configuraciones son muy simples (slo cadenas bsicas, nmeros y marcas boolea-
nas), de modo que no debe sobrecargar al administrador para que tenga todo lo que aparece en
un solo formulario. Pero antes de que lleguemos a ese formulario, agregaremos un formulario
que nos permita administrar la conexin de base de datos.
Pensaba en la manera de llamar al cuadro de dilogo de propiedades de conexiones que Visual
Studio usa para establecer las cadenas de conexin. Estoy seguro de que es posible, pero propor-
ciona mucha ms flexibilidad de la que necesitamos en este proyecto. Por ejemplo, da soporte
a la configuracin de bases de datos que no son de SQL Server, lo que no es de inters para el

406 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 406 17/2/10 15:27:59


Proyecto Biblioteca. En cambio, disearemos un formulario simple que slo recolecte esos valo-
res de datos que necesitamos para generar la cadena de conexin de la Biblioteca. El formulario
LocalizarBaseDatos aparece en la figura 14-5.

Figura 14-5. El nuevo formulario Localizar la base de datos.

Ya he agregado el formulario y sus controles al proyecto. Abra el archivo LocalizarBaseDatos.vb para


ver el formulario. Cuatro de los campos de este formulario son campos de entrada de texto bsicos
(uno con un carcter de mscara de contrasea). El quinto campo de entrada, Autentificacin,
permite al usuario seleccionar entre autentificacin de Microsoft Windows y de SQL Server.
La mayor parte del cdigo del formulario es paralelo a lo que hemos visto en muchos de los otros
formularios que ya se encuentran en la aplicacin. Siga adelante y agregue ahora todo el cdigo
del formulario.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap14, Elemento 6.

El trabajo significativo de este formulario ocurre en el evento Load cuando la cadena de co-
nexin existente se analiza en los datos del campo de entrada distintivos, y en la rutina
PromptUser, donde se integran las partes.
Hay muchas maneras diferentes en que puede dividir la cadena de conexin en sus partes bsi-
cas. Yo tomo el mtodo bsico divide y conquistars, extrayendo cada componente separado por
dos puntos y signos de igual. He aqu el bloque principal de cdigo del manejador de evento
Load que hace el recorte y la extraccin:
' ----- Cargar los datos existentes.
cadenaConexion = My.Settings.ConexionBD & ""
For contador = 1 To ContarSubCadena(cadenaConexion, ";") + 1
' ----- Cada parte delimitada por comas tiene el formato
' "clave=valor".
unaClave = ObtenerSubCadena(cadenaConexion, ";", contador)
unValor = Trim(ObtenerSubCadena(unaClave, "=", 2))

Proyecto | 407

14_PATRICK-CHAPTER_14.indd 407 17/2/10 15:28:00


unaClave = Replace(UCase(Trim(ObtenerSubCadena( _
unaClave, "=", 1))), " ", "")

' ----- Procesar cada parte.


Select Case unaClave
Case "ORIGEN DATOS"
' ----- Mostrar el host del servidor.
RegistroServidor.Text = unValor
Case "CATALOGOINICIAL"
' ----- Mostrar el nombre de la base de datos predeterminada.
RegistroBaseDatos.Text = unValor
Case "SEGURIDADINTEGRADA"
' ----- Solo revisar "true". Se supone el valor de False.
If (UCase(unValor) = "TRUE") Then _
RegistroAutentificacion.SelectedIndex = _
RegistroAutentificacion.Items.IndexOf( _
AutentificacionTipoWindows)
Case "IDUSUARIO"
' ----- Un ID de usuario fuerza la autentificacion SQL.
RegistroAutentificacion.SelectedIndex = _
RegistroAutentificacion.Items.IndexOf( _
AutentificacionTipoSQL)
RegistroUsuario.Text = unValor
Case "CLAVEUSUARIO"
' ----- Una clave fuerza la autentificacion SQL.
RegistroAutentificacion.SelectedIndex = _
RegistroAutentificacion.Items.IndexOf( _
AutentificacionTipoSQL)
RegistroClaveUsuario.Text = unValor
End Select
Next contador

Unir las partes es menos complicado. He aqu el cdigo de unin de cadenas encontrado en la
rutina PreguntarUsuario:
nuevaConexion = "Data Source=" & Trim(RegistroServidor.Text) & _
";Initial Catalog=" & Trim(RegistroBaseDatos.Text)
If (CInt(CType(RegistroAutentificacion.SelectedItem, _
DatosListaElementos)) = AutentificacionTipoWindows) Then
' ----- Usar seguridad de Windows.
nuevaConexion &= ";Integrated Security=true"
Else
' ----- Usar seguridad de SQL Server.
nuevaConexion &= ";User ID=" & Trim(RegistroUsuario.Text) & _
";Password=" & Trim(RegistroClaveUsuario.Text)
End If

Aunque el formulario LocalizarBaseDatos hace todo el anlisis sintctico y la construccin de


la cadena de conexin, no actualiza en realidad las configuraciones guardadas. En cambio, devuel-
ve la cadena de conexin recin construida y depende de la llamada al cdigo para guardarla.
Ahora, regresemos a nuestro editor de configuracin de un solo formulario, Mantenimiento.vb. Este
formulario hace todas las modificaciones directas de los valores en la base de datos y los elementos
locales de My.Settings. En las figuras 14-6 y 14-7 se muestran los dos panes principales del

408 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 408 17/2/10 15:28:00


Figura 14-6. El nuevo formulario Mantenimiento mostrando el panel Todo el sistema.

formulario Mantenimiento. Las configuraciones centralizadas almacenadas en la base de datos


son de todo el sistema y los valores especficos de la estacin de trabajo son a los que se accede
a travs de My.Settings.
Este formulario empieza su trabajo en su manejador de eventos Load, Mantenimiento_Load.
Esta rutina configura las opciones en algunos campos desplegables, incluida una lista de fuentes.
El cdigo recorre en bucle la coleccin de fuentes instaladas que estn disponibles mediante el
objeto GDI+ System.Drawing.Text.InstalledFontCollection.
Dim todasLasFuentes As New _
System.Drawing.Text.InstalledFontCollection
RegistroNombreFuente.Items.Add(New DatosListaElementos( _
"<Not Selected>", -1))
For contador = 0 To todasLasFuentes.Families.Length - 1
RegistroNombreFuente.Items.Add(New DatosListaElementos( _
todasLasFuentes.Families(contador).Name, contador))
Next contador

La rutina tambin incluye cdigo similar para cargar una lista de impresoras instaladas.
For Each impresoraInstalada As String En _
PrinterSettings.InstalledPrinters
RegistroLugarImpresora.Items.Add(impresoraInstalada)
Next impresoraInstalada

Proyecto | 409

14_PATRICK-CHAPTER_14.indd 409 17/2/10 15:28:00


Figura 14-7. El nuevo formulario Mantenimiento que muestra el panel Especficos de la estacin de trabajo.

Una vez que todo est configurado, el procedimiento RellenarValoresActuales completa


la inicializacin. Su cdigo recupera todos los valores actuales de la base de datos y del objeto
My.Settings, y almacena esos valores en los diversos campos de entrada de datos en pantalla.
Ya he agregado el cdigo especfico de la base de datos. Siga adelante y agregue el cdigo espec-
fico de la configuracin.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap14, Elemento 7.

ConexionBiblioteca = My.Settings.ConexionBD & ""


RegistroLugarBD.Text = ObtenerTextoPantallaBD(ConexionBiblioteca)
RegistroLugarConfiguracion.Text = My.Settings.ConfigInforme & ""
RegistroAyudaBasica.Text = My.Settings.ArchivoAyuda & ""
RegistroAyudaAdmin.Text = My.Settings.ArchivoAyudaAdmin & ""
HabilitarRecibos.Checked = My.Settings.UsarRecibos
RegistroLugarImpresora.Text = My.Settings.ImpresoraRecibo & ""
RegistroAnchoImpresora.Text = CStr(My.Settings.AnchoRecibo)
RegistroEnvioRecibo.Text = My.Settings.EnvioRecibo & ""
OcultarInicioSesion.Checked = My.Settings.OcultarInicioSesion

410 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 410 17/2/10 15:28:01


La mayor parte del cdigo de este formulario trata con interaccin bsica con el usuario mientras
el formulario est en uso. Por ejemplo, el manejador de eventos AccLugarBD_Click despliega el
formulario LocalizarBaseDatos que agregamos antes. Agregue el cdigo fuente relevante a ese
manejador de eventos.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap14, Elemento 8.

' ----- Preguntar los detalles de la conexion con la base de datos.


Dim nuevaConexion As String

' ----- Preguntar al usuario la nueva configuracin.


nuevaConexion = LocalizarBaseDatos.PreguntarUsuario()
If (nuevaConexion = "") Then Return

' ----- Almacenar el nuevo valor.


ConexionBiblioteca = nuevaConexion
RegistroLugarBD.Text = ObtenerTextoPantallaBD(ConexionBiblioteca)

Varios de los parmetros especifican las ubicaciones de archivos usados por la aplicacin, como
los archivos de ayuda en lnea. El usuario puede escribir la ruta al archivo directamente, o usar
el cuadro de dilogo Abrir archivos para localizar el archivo visualmente. Para desplegar este
cuadro de dilogo he agregado un control OpenFileDialog llamado LocalizarArchivo.
Usarlo es cosa de configurar las diversas propiedades especficas de archivo y llamar al mtodo
Show Dialog. He aqu parte del cdigo incluido en el manejador de eventos AccAyudaBasi
ca_Click usado para localizar el archivo no administrativo en lnea:
' ----- Configurar la estructura del archivo.
LocalizarArchivo.DefaultExt = "chm"
LocalizarArchivo.FileName = RegistroAyudaBasica.Text
LocalizarArchivo.Filter = "Archivos de ayuda (*.chm)|*.chm|" & _
"Todos los archivos (*.*)|*.*"
LocalizarArchivo.FilterIndex = 1
LocalizarArchivo.Title = "Localizar ayuda"

' ----- Preguntar al usuario.


If (LocalizarArchivo.ShowDialog() <> _
Windows.Forms.DialogResult.OK) Then Return

' ----- Guardar la ruta dell archivo.


RegistroAyudaBasica.Text = LocalizarArchivo.FileName

Una vez que el usuario ha hecho los diversos cambios de configuracin, un clic en el botn
Aceptar guarda cada una de las configuraciones en su rea de almacenamiento. He incluido
el cdigo de guardado concentrado en la base de datos en la rutina GuardarDatosFormu
lario. Le permitir agregar el cdigo concentrado en configuraciones, cerca del final de la
rutina.

Proyecto | 411

14_PATRICK-CHAPTER_14.indd 411 17/2/10 15:28:01


INSERCIN DE FRAGMENTO DE CDIGO
Inserte el fragmento de cdigo Cap14, Elemento 9.

My.Settings.ConexionBD = ConexionBiblioteca
My.Settings.ConfigInforme = Trim(RegistroLugarConfiguracion.Text)
My.Settings.ArchivoAyuda = Trim(RegistroAyudaBasica.Text)
My.Settings.ArchivoAyudaAdmin = Trim(RegistroAyudaAdmin.Text)
My.Settings.OcultarInicioSesion = OcultarInicioSesion.Checked
My.Settings.UsarRecibos = HabilitarRecibos.Checked
My.Settings.ImpresoraRecibo = Trim(RegistroLugarImpresora.Text)
My.Settings.EnvioRecibo = RegistroEnvioRecibo.Text

' ----- Guardar el ancho de la impresora del recibo.


If (Trim(RegistroAnchoImpresora.Text) = "") Then
My.Settings.AnchoRecibo = AnchoImpresoraReciboPredeterminado
Else
My.Settings.AnchoRecibo = CInt(RegistroAnchoImpresora.Text)
End If

Aunque el formulario Mantenimiento proporciona una interfaz amigable con el usuario para
las configuraciones de almacenamiento de base de datos, tal vez recuerde que ya escribi cdigo
para actualizar registros de la tabla ValorSistema mediante el archivo ValorSistema.vb. En el
captulo 12 conectamos ese formulario con el formulario principal, pero vamos a alterar esa
lgica. En primer lugar, agregaremos la llamada al formulario ValorSistema del manejador de
eventos AccTodosLosValores_Click del formulario Mantenimiento.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap14, Elemento 10.

' ----- Dejar que el usuario edite la lista de valores del sistema.
Dim FormularioRegistros As Biblioteca.ListaRegistrosEditados

' ----- Editar los registros.


FormularioRegistros = New Biblioteca.ListaRegistrosEditados
FormularioRegistros.ManageRecords(New Biblioteca.ValorSistema)
FormularioRegistros = Nothing

' ----- Actualizar los elementos del despliegue.


RellenarValoresActuales()

Luego cambiaremos el manejador de eventos AdminVinculosValores_LinkClicked del For-


mularioPrincipal.vb. En la actualidad, llama directamente al editor de ValorSistema. Reem-
place esa parte del cdigo del manejador LinkClicked con cdigo que llama, en cambio, al
formulario Mantenimiento.

412 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 412 17/2/10 15:28:01


INSERCIN DE FRAGMENTO DE CDIGO
Inserte el fragmento de cdigo Cap14, Elemento 11.

' ----- Acceder a la parte de mantenimiento del programa.


Mantenimiento.ShowDialog()

Conexin con la base de datos configurada


El ltimo cambio en este captulo usa la cadena de conexin configurada para establecer la
conexin con la base de datos. Cuando escribimos originalmente la rutina ConectarBaseDe
Datos en el mdulo General, agregamos una cadena de conexin codificada slo para que el
programa funcionara.
' ----- Construir la cadena de conexin.
' !!! CUIDADO: Incluida en el codigo, por ahora.
cadenaConexion = "Datos Source=MYSYSTEM\SQLEXPRESS;" & _
"Initial Catalog=Biblioteca;Integrated Security=true"

Ahora que tenemos disponibles una cadena de conexin configurada por el usuario, la usaremos.
Los cambios que debemos hacer a esta rutina son de alguna manera extensos, de modo que slo
reemplace el contenido existente de la funcin con el cdigo actualizado.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap14, Elemento 12.

' ----- Conectar con la base de datos. Regresar True si se tiene exito.
Dim cadenaConexion As String
Dim configCambiada As Boolean

' ----- Inicializar.


SostenerTransac = Nothing
configCambiada = False

' ----- Obtener la cadena de conexion.


If (Trim(My.Settings.ConexionBD & "") = "") Then
' ----- Informar al usuario acerca de la necesidad de
' configurar la base de datos.
If (MsgBox("Esta copia de la Aplicacin no se ha " & _
"configurado para conectarse con la base de datos " & _
"Biblioteca. Si conoce las configuraciones de la base " & _
"de datos puede configurarla ahora. Indique si desea " & _
"seguir adelante", MsgBoxStyle.YesNo Or _
MsgBoxStyle.Question, Titulo
<> MsgBoxResult.Yes) Then Return False

Proyecto | 413

14_PATRICK-CHAPTER_14.indd 413 17/2/10 15:28:01


' ----- Preguntar los detalles de la nueva conexion.
cadenaConexion = LocalizarBaseDatos.PreguntarUsuario(
)
If (cadenaConexion = "") Then Return False
configCambiada = True
Else
cadenaConexion = My.Settings.ConexionBD
End If

TryConnectingAgain:

' ----- Tratar de abrir la base de datos.


Try
BibliotecaBD = New SqlClient.SqlConnection(cadenaConexion)
BibliotecaBD.Open()
Catch ex As Exception
' ----- Alguna falla en la base de datos.
ErrorGeneral("ConectarBaseDeDatos", ex)

' ----- Tal vez solo es un problema de configuracion.


If (MsgBox("Tal vez la conexin con la base de datos haya " & _
"fallado debido a una configuracion no valida. " & _
"Indique si desea cambiar la configuracion de la " & _
"base de datos en este momento.", _
MsgBoxStyle.YesNo Or MsgBoxStyle.Question, _
TituloPrograma) <> MsgBoxResult.Yes) Then Return False

' ----- Preguntar los nuevos detalles.


cadenaConexion = LocalizarBaseDatos.PromptUser(
)
If (cadenaConexion = "") Then Return False
configCambiada = True
GoTo TryConnectingAgain
End Try

' ----- Guardar la configuracion cambiada, si es necesario.


If (configCambiada = True) Then _
My.Settings.ConexionBD = cadenaConexion

' ----- Correcto.


Return True

El aspecto bsico del cdigo incluye la configuracin de la variable cadenaConexion con la


cadena de conexin persistente, y emplendola para abrir el objeto BibliotecaBD. El nuevo
cdigo obtiene la cadena de conexin de My.Settings.ConexionBD. Si por alguna razn la
cadena de conexin falta o falla en generar una conexin abierta de base de datos, se pide al
usuario que proporcione o corrija la cadena de conexin mediante nuestro nuevo formulario
LocalizarBaseDatos.

414 | Captulo 14: Configuraciones de la aplicacin

14_PATRICK-CHAPTER_14.indd 414 17/2/10 15:28:01


El programa regresa a una condicin donde usted puede ejecutarlo. La primera vez que lo ejecu-
ta, le pedir que proporcione la informacin de conexin con la base de datos. Los valores que
proporcione coincidirn con la versin codificada que sola estar en la rutina ConectarBase
DeDatos:
Establecer servidor/host para MYSERVER\SQLEXPRESS o el nombre de su host real de
SQL Server.
Establecer el nombre de la base de datos en Biblioteca o cualquier otro nombre que haya
asignado antes a su base de datos de biblioteca.
Establecer la autentificacin en Microsoft Windows si usa seguridad integrada de Win-
dows. Si necesita conectarse usando el sistema de seguridad de SQL Server, establezca este
campo en SQL Server e ingrese un ID de usuario y una contrasea vlidos.
En el siguiente captulo, nos concentraremos en las tcnicas de manipulacin de archivos. Aun-
que actualizamos el archivo de configuracin en este captulo, se hizo de manera indirecta me-
diante caractersticas proporcionadas por el marco conceptual. En el captulo 15 analizaremos
de manera ms directa los mtodos para manipular archivos.

Proyecto | 415

14_PATRICK-CHAPTER_14.indd 415 17/2/10 15:28:02


Captulo 15
Archivos y directorios

El desarrollo de software en el siglo xxi ha convertido a los programadores en un montn de


debiluchos. En los viejos das de las computadoras, los desarrolladores tenan que soldar pro-
gramas a mano en la computadora. Los clculos complejos se tomaban das en realizarse, y un
alambre mal conectado significa envenenamiento por plomo o algo peor. El sufrimiento era real,
y los viejos ejemplares de Popular Electronics estaban llenos de artculos de programadores que se
volvan locos en sus intentos de crear un algoritmo ms de clculo de balstica.
La vida mejor tremendamente para los programadores cuando John von Neumann y otros
sugirieron que una computadora podra almacenar la lgica de un algoritmo y procesarlo di-
rectamente desde la memoria en lugar de hacerlo mediante configuraciones cableadas. Los in-
genieros pusieron pronto sus programas en tarjetas perforadas y cintas de papel. El peligro de
envenenamiento por plomo fue reemplazado rpidamente por el mucho ms malvado de los
cortes con el papel.
Las tarjetas perforadas eran estupendas (hasta que se le caa la pila que le llev das u horas en-
samblar). Algn programador dej caer en algn lugar demasiadas pilas de tarjetas y proclam:
Ya basta!, voy a inventar el disco duro y tecnologas relacionadas como IDE y SCSI. Seguro
que me volver fabulosamente rico, pero por lo menos no tendr que volver a tratar con estas
estpidas tarjetas.
Y luego naci el sistema de archivos, el almacenamiento estructurado de programas e infor-
macin en una superficie de disco. Los sistemas de archivo han sido parte de las tecnologas de
Microsoft desde que Bill Gates cortej por primera vez a IBM. No es coincidencia que DOS
en MS-DOS sean las siglas de sistema operativo de disco (Disk Operating System). Bill saba lo
esencial que eran los sistemas de archivos, igual que usted.
En este captulo hablaremos acerca de las interacciones con archivos y directorios, las principales
unidades de almacenamiento y organizacin en el sistema de archivos de Windows. Tambin
veremos algunas de las tecnologas y caractersticas que .NET proporciona para manipular ar-
chivos y su contenido. Slo asegrese de voltear las pginas con cuidado; no quiero que se corte
con el papel.

416

15_PATRICK-CHAPTER_15.indd 416 17/2/10 15:28:26


La administracin tradicional de archivos de Visual Basic
Visual Basic ha incluido importantes caractersticas de administracin de archivos desde su pri-
mera versin. En realidad, ms caractersticas en Visual Basic tratan con la manipulacin de
archivos y directorios que con algo ms.
La mayor parte de las funciones que le permiten leer y modificar contenido de archivos usan un ma-
nejador de archivos, un identificador numrico que alude a un archivo abierto especfico. Este
manejador de archivos es generado con la funcin FreeFile, y debe obtenerse antes de llamar
a cualquier caracterstica de archivos tradicional de Visual Basic.
Dim idArchivo As Integer
idArchivo = FreeFile()
FileOpen(idArchivo, "C:\DatosPruena.txt", OpenMode.Append)
PrintLine(idArchivo, "Salida importante a un archivo.")
FileClose(idArchivo)

La manipulacin de archivos basada en manejador funciona bien, pero es de principios de la d-


cada de 1990. No es una tecnologa .NET real, y no est basada en absoluto en objetos (a menos
que considera que Integer es un objeto). Por tanto, no lo voy a cubrir en este libro, ni a usarlo
en el Proyecto Biblioteca. En la tabla 15-1, se presenta una lista de las principales caractersticas
de Visual Basic que usan manejadores de archivos. Si necesita saber acerca de las caractersticas de
Visual Basic basadas en manejador de archivos, o si su trabajo se relaciona con migrar aplicaciones
de Visual Basic previas a .NET, use esta tabla para que le ayude a localizar los detalles de carac-
tersticas plenas en la documentacin tcnica proporcionada con Visual Basic.

Tabla 15-1. Caractersticas de Visual Basic que usan manejadores de archivos.

Caracterstica Descripcin
EOF Regresa un Boolean indicando si la posicin actual en el archivo est en el final o lo ha rebasado. Use esta
funcin para determinar cundo dejar de leer los datos existentes de un archivo.
FileAttr Accede a los atributos del archivo establecidos actualmente en un manejador de archivos abierto.
FileClose Cierra un archivo especfico abierto empleando un manejador de archivos.
FileGet Recupera datos estructurados de un archivo y los almacena en un objeto coincidente.
FileGetObject Igual que FileGet, pero con soporte a un tipo de datos ligeramente diferente.
FileOpen Abre un archivo para entrada o salida.
FilePut Escribe un objeto en un archivo de una manera estructurada.
FilePutObject Igual que FilePut, pero con soporte a tipos de datos ligeramente diferentes.
FileWidth Establece el ancho de lnea predeterminado para los archivos de salida de texto formados.
FreeFile Devuelve el siguiente manejador de archivos disponible.
Input Recupera un valor escrito previamente o un archivo empleando Write o WriteLine.
InputString Recupera un nmero especfico de caracteres de un archivo de entrada.

La administracin tradicional de archivos de Visual Basic | 417

15_PATRICK-CHAPTER_15.indd 417 17/2/10 15:28:26


Tabla 15-1. Caractersticas de Visual Basic que usan manejadores de archivos (continuacin).

Caracterstica Descripcin
LineInput Devuelve una lnea completa de entrada de un archivo.
Loc Devuelve el byte actual o la ubicacin de registro en el archivo.
Lock Bloquea un archivo o registro especfico en un archivo para que otros no puedan hacer cambios.
LOF Devuelve la longitud de un archivo abierto, en bytes.
Print Enva salida de texto a un archivo.
PrintLine Enva salida de texto a un archivo, que finaliza con un terminador de lnea.
Reset Cierra todos los archivos abierto con manejadores de archivos.
Seek Obtiene o establece la posicin actual en un archivo.
SPC Esta funcin ayuda a formar texto para salida a archivos de texto en columnas.
TAB Esta funcin ayuda a formar texto para salida a archivos de texto en columnas.
Unlock Elimina bloqueos establecidos antes con Lock.
Write Escribe datos en un archivo empleando un formato consistente que puede leerse fcilmente ms adelante.
WriteLine Igual que Write, pero finaliza la salida con un terminador de lnea.

Manipulacin de archivos mediante flujo


El .NET Framework incluye un nuevo mtodo orientado a objetos para leer y escribir ar-
chivos: flujos. El objeto abstracto Stream, encontrado en System.IO.Stream, define una
interfaz genrica para un fragmento de datos. No importan dnde estn los datos: en un
archivo, en un bloque de memoria, en una variable String (si tiene un bloque de datos
que puede leer o escribir de byte en byte, puede disear una clase de flujo derivada para que
interacte con ella).

Caractersticas de flujo
Las caractersticas bsicas de un objeto Stream incluyen los mtodos Read y Write que le per-
miten leer o escribir bytes. Mientras los datos se leen de un flujo o se escriben en uno, el objeto
Stream mantiene una posicin actual dentro del flujo que puede ajustar usando el mtodo
Seek, o examinar usando la propiedad Position. La propiedad Length indica el tamao de los
datos legibles. La clase tambin expone variaciones de esas caractersticas bsicas para permitir la
mayor flexibilidad posible.
No todos los flujos dan soporte a todas las caractersticas. Algunos son de slo lectura, construc-
tores slo en sentido directo, no compatibles con escritura o bsqueda. Otros flujos dan soporte
a todas las caractersticas. Las que estarn disponibles para usted dependern del tipo de flujo
que use. Como el propio Stream es abstracto, debe crear una instancia de una de sus clases de-
rivadas. .NET define varios flujos tiles listos para que los use:

418 | Captulo 15:Archivos y directorios

15_PATRICK-CHAPTER_15.indd 418 17/2/10 15:28:26


FileStream
El objeto FileStream le permite acceder al contenido de un archivo empleando los m-
todos bsicos de la clase genrica Stream. Los objetos FileStream dan soporte a lectura,
escritura y bsqueda, aunque si abre un archivo de slo lectura, no podr escribir en l.
MemoryStream
Un flujo basado en un bloque de memoria simple. Puede crear un flujo de memoria de cual-
quier tamao, y usarlo para almacenar temporalmente y recuperar cualquier dato.
NetworkStream
Esta clase abstrae datos que provienen de un conector de red. Mientras que la mayor parte de las
clases de flujo derivadas residen en System.IO, esta clase se sita en System.Net.Sockets.
BufferedStream
Agrega soporte de bfer a un flujo para mejorar el rendimiento en flujos con problemas de
latencia. Usted envuelve un objeto BufferedStream alrededor de otro flujo para usarlo.
CryptoStream
Este flujo le permite adjuntar un proveedor de servicio criptogrfico, lo que da como re-
sultado una salida cifrada de una entrada simple, o viceversa. En el captulo 11 se incluyen
ejemplos que usan este tipo de flujo.
DeflateStream and GZipStream
Le permite usar un flujo para comprimir o descomprimir datos, a medida que se procesan,
todas usando algoritmos de compresin estndar.
Los flujos son tiles por s mismos, pero tambin puede combinar flujos de modo que un flujo de red
entrante pueda cifrarse de inmediato, comprimirse o almacenarse en un bloque de memoria de flujo.

Uso de un flujo
El uso de un flujo es simple; en primer lugar, se crea y luego se empieza a leer y escribir bytes a
la izquierda o la derecha. He aqu un cdigo de ejemplo que escrib y que ingresa y extrae datos
de un flujo de memoria. Se basa de manera general en el cdigo que encontrar en la documen-
tacin de MSDN para la clase MemoryStream.
' ----- El flujo, o aqui y alla de nuevo.
Dim posicion As Integer
Dim flujoMem As IO.MemoryStream
Dim caracsOrigen() As Byte
Dim bytesDestino() As Byte
Dim caracsDestino() As Char
Dim comoUnicode As New System.Text.UnicodeEncoding(
)

' ----- Crear un flujo de memoria con espacio para 100 bytes.
flujoMem = New IO.MemoryStream(100)

' ----- Convertir los datos de texto a una matriz de bytes.


caracsOrigen = comoUnicode.GetBytes( _

Manipulacin de archivos mediante flujo | 419

15_PATRICK-CHAPTER_15.indd 419 17/2/10 15:28:27


"Esta es una prueba del sistema de programacion de emergencia.")

Try
' ----- Almacenar los datos convertidos en bytes del flujo.
flujoMem.Write(caracsOrigen, 0, caracsOrigen.Length)
' ----- La posicion esta al final de los datos escritos.
' para leer hacia atras, debemos mover el puntero al
' principio de nuevo.
flujoMem.Seek(0, IO.SeekOrigin.Begin)

' ----- Leer un fragmento del texto/bytes a la vez.


bytesDestino = New Byte(CInt(flujoMem.Length)) {}
posicion = flujoMem.Read(bytesDestino, 0, 25)

' ----- Obtener los datos restantes de uno en uno,


' solo para divertirnos.
While (posicion < flujoMem.Length)
bytesDestino(posicion) = CByte(flujoMem.ReadByte())
posicion += 1
End While

' ----- Convertir la matriz de regreso a un conjunto de caracteres.


caracsDestino = New Char(comoUnicode.GetCharCount( _
bytesDestino, 0, posicion)) {}
comoUnicode.GetDecoder().GetChars(bytesDestino, 0, _
posicion, caracsDestino, 0)

' ----- Probar que el texto ha regresado.


MsgBox(caracsDestino)
Finally
flujoMem.Close()
End Try

Se espera que los comentarios hagan ms claro el cdigo. Despus de crear un flujo de memoria,
incluyo un bloque de texto en l y luego lo leo de regreso. (El texto permanece en el flujo; al leer-
lo no lo elimina). En realidad, el flujo de texto es muy simple. La mayor parte del cdigo trata
con conversiones entre bytes y caracteres. Si parece muy complicado, es que lo es.

Ms all de los bytes de flujo


Para m, toda esa conversin entre bytes y caracteres es para las aves. Cuando escribo aplicaciones
de negocios, por lo general trato con fechas, nmeros y cadenas: nombres de clientes, fechas de
pedido, montos de pago, etc. Es raro que tenga necesidad de trabajar en el nivel de bytes. Es se-
guro que deseo que haya una manera de enviar estas cosas de bytes por un flujo de programacin
propio para que no tenga que verlo ms.
Suerte que tengo! .NET hace que algunos deseos se vuelvan realidad. Aunque puede manipular
flujos directamente si en realidad lo quiere o lo desea, el espacio de nombres System.IO tambin
incluye varias clases que proporcionan un bfer ms amigable con el programador entre usted
y el flujo. Estas clases (implementadas como lectores y escritores de datos de flujo distintivos)
proporcionan mtodos simplificados para almacenar tipos de datos especficos y recuperarlos.

420 | Captulo 15:Archivos y directorios

15_PATRICK-CHAPTER_15.indd 420 17/2/10 15:28:27


Los lectores y escritores estn diseados para procesamiento de datos en una sola direccin, de
principio a fin. Despus de crear o acceder a un flujo, se envuelve ste con un lector o un escritor,
y se empieza a recorrer la extensin del flujo desde el principio. Siempre tiene acceso al flujo si
necesita un control ms fino en cualquier punto.
Hay tres pares principales de lectores y escritores:
BinaryReader y BinaryWriter
Estas clases facilitan la escritura y posterior lectura de los tipos centrales de Visual Basic a un
flujo que (generalmente) no es de texto, y desde ste, el mtodo BinaryWriter.Write in-
cluye sobrecargas para escribir Byte, Char, enteros con signo y sin signo de varios tamaos,
Boolean, Decimal y Double, String y matrices y bloques de Byte y Char. Lo curioso es
que se omite una sobrecarga de los valores Date.
La contraparte BinaryReader incluye mtodos separados Read para cada uno de los tipos
de datos que permiten la escritura. El mtodo ReadDouble devuelve un valor Double del
archivo y hay mtodos similares para los otros tipos de datos.
StreamReader y StreamWriter
Estas clases suelen usarse para procesar archivos de texto basados en lnea. La clase Stream
Reader incluye un mtodo ReadLine que devuelve la siguiente lnea de texto en el flujo
entrante como una String estndar. El mtodo StreamWriter.Write relacionado in-
cluye todas las sobrecargas de BinaryWriter.Write, y tambin tiene una versin que
le permite formar una cadena para salida. El lector incluye caractersticas que le permiten
leer datos de carcter en carcter, de bloque en bloque o todo un archivo a la vez.
StringReader y StringWriter
Este par de clases proporciona las mismas caractersticas que el par StreamReader y
StreamWriter, pero usa la instancia estndar String para almacenamiento de datos en
lugar de un archivo.
Un par adicional (TextReader y TextWriter) proporciona la clase base para los otros lectores
y escritores no binarios. No puede crear instancias de ellas directamente, pero le permiten tratar
las versiones de flujo y cadena de los lectores y escritores de manera genrica.
Con estas nuevas herramientas es ms fcil procesar datos que no son Byte mediante flujos. He
aqu una reescritura del cdigo del flujo de memoria simple que escrib antes, ajustado para usar
un StreamReader y StreamWriter:

' ----- El flujo, o para alla y para atras de nuevo.


Dim flujoMem As IO.MemoryStream
Dim paraEscritura As IO.StreamWriter
Dim paraLectura As IO.StreamReader
Dim mensajeFinal As String
Dim comoUnicode As New System.Text.UnicodeEncoding(
)

' ----- Crear un flujo de memoria con espacio para 100 bytes.
flujoMem = New IO.MemoryStream(100)

Manipulacin de archivos mediante flujo | 421

15_PATRICK-CHAPTER_15.indd 421 17/2/10 15:28:27


Try
' ----- Envolver el flujo con un escritor.
paraEscritura = New IO.StreamWriter(flujoMem, comoUnicode)

' ----- Almacenar los datos originales en el flujo.


paraEscritura.WriteLine( _
"Esta es una prueba del sistema de programacion de emergencia.")
paraEscritura.Flush()

' ----- La posicion esta al final de los datos escritos.


' para leer hacia atras, debemos mover el puntero al
' principio de nuevo.
flujoMem.Seek(0, IO.SeekOrigin.Begin)

' ----- Crear un lector para obtener de nuevo los datos de regreso.
paraLectura = New IO.StreamReader(flujoMem, comoUnicode)

' ----- Obtener la cadena original.


mensajeFinal = paraLectura.ReadToEnd(
)

' ----- Probar que el texto esta de regreso.


MsgBox(mensajeFinal)
Finally
flujoMem.Close()
End Try

Es seguro que el cdigo es un poco ms agradable sin toda esa conversin de cdigo que hace
ms complejo el trabajo. (Podramos simplificarlo an ms al dejar fuera lo de la codificacin
opcional en Unicode.) Por supuesto, todo an se est convirtiendo a bytes bajo la superficie;
el flujo de memoria slo conoce de bytes. Pero StreamWriter y StreamReader nos quitan la
carga, realizando todas las conversiones por nosotros.

Lectura de un archivo mediante un flujo


La mayor parte del procesamiento de Stream se relaciona con archivos, as que usemos Stream
Reader para procesar un archivo de texto. Aunque ya decidimos en el captulo 14 que los archi-
vos INI son cosa del pasado, podra ser divertido escribir una rutina que extraiga un valor de un
archivo INI heredado. Considere un archivo que contenga este texto:
[Section0]
Key1=abc
Key2=def

[Section1]
Key1=ghi
Key2=jkl

[Section2]
Key1=mno
Key2=pqr

422 | Captulo 15:Archivos y directorios

15_PATRICK-CHAPTER_15.indd 422 17/2/10 15:28:27


Ahora hay algo que no ve todos los das, y con buena razn! Aun as, si queremos obtener el
valor de Key2 en la seccin Section1 (el valor jkl), tendramos que regresar de nuevo a la
llamada a la API de GetPrivateProfileString desde esos malos das de la programacin
previa a .NET. O podramos implementar un StreamReader en una funcin personalizada por
nuestra cuenta.
Public Function ObtenerValorINI(ByVal nombreSeccion As String, _
ByVal nombreClave As String, ByVal archivoIni As String) _
As String
' ----- Dado un nombre de seccin y de clave para un archivo INI,
' regresar la entrada con el valor coincidente.
Dim leerINI As IO.StreamReader
Dim unaLinea As String
Dim comparar As String
Dim encontrar As Boolean

On Error GoTo ErrorHandler

' ----- Abrir el archivo.


If (My.Computer.FileSystem.FileExists(archivoIni) = False) _
Then Return ""
leerINI = New IO.StreamReader(archivoIni)

' ----- Buscar la seccin coincidente.


encontrar = False
comparar = "[" & Trim(UCase(nombreSeccion)) & "]"
Do While (leerINI.EndOfStream = False)
unaLinea = leerINI.ReadLine()
If (Trim(UCase(unaLinea)) = comparar) Then
' ----- Encontrar la seccion coincidente.
encontrar = True
Exit Do
End If
Loop

' ----- Salir antes si el nombre de la seccion no se encuentra.


If (encontrar = False) Then
leerINI.Close()
Return ""
End If

' ----- Buscar la clave coincidente.


comparar = Trim(UCase(nombreClave))
Do While (leerINI.EndOfStream = False)
' ----- Si alcanzamos otra seccion, entonces la
' clave no estaba alli.
unaLinea = Trim(leerINI.ReadLine( ))
If (Len(unaLinea) = 0) Then Continue Do
If (unaLinea.Substring(0, 1) = "[") Then Exit Do

' ----- Ignorar las lineas sin un signo "=".


If (InStr(unaLinea, "=") = 0) Then Continue Do

Manipulacin de archivos mediante flujo | 423

15_PATRICK-CHAPTER_15.indd 423 17/2/10 15:28:27


' ----- Ver si se encuentra la clave. Por cierto,
' estoy usando Substring() en lugar de Left( )
' de modo que no tengo que preocuparme por conflictos
' con Form.Left en caso de que deje esta rutina en una
' clase Form.
If (Trim(UCase(unaLinea.Substring(0, _
InStr(unaLinea, "=") - 1))) = comparar) Then
' ----- Encontrar la clave coincidente.
leerINI.Close()
Return Trim(Mid(unaLinea, InStr(unaLinea, "=") + 1))
End If
Loop

' ----- Si llegamos hasta aqu, entonces esta faltando la clave.


leerINI.Close()
Return ""

ErrorHandler:
' ----- Regresar una cadena vacia si hay un error.
On Error Resume Next
If (leerINI IsNot Nothing) Then leerINI.Close(
)
leerINI = Nothing
Return ""
End Function

Esta rutina no es un reemplazo exacto de GetPrivateProfileString; no da soporte a un valor


de regreso predeterminado, ni realiza almacenamiento en cach para mayor velocidad. Podra
mejorar la rutina con mejor manejo de errores. Pero recupera el valor que buscamos, y lo hace al
leer el archivo INI de lnea en lnea mediante un StreamReader.
MsgBox(ObtenerValorINI("Section1", "Key2", rutaArchivoIni))
' ----- Despliega 'jkl

Administracin de archivo con el espacio de nombres My


El espacio de nombres My incluye varias caractersticas de administracin de archivos en su rama
My.Computer.FileSystem, incluidas caractersticas que crean flujos para lectura y escritura.

Comparacin entre el espacio de nombres My y los


comandos de Visual Basic
La mayor parte de los miembros del objeto My.Computer.FileSystem existen para reemplazar
o complementar las caractersticas de administracin de archivos ya presentes en Visual Basic.
En la tabla 15-2 se presenta una lista de las caractersticas de interaccin con archivos y directo-
rios ms perdurables en Visual Basic, y sus equivalentes en My.Computer.FileSystem.

424 | Captulo 15:Archivos y directorios

15_PATRICK-CHAPTER_15.indd 424 17/2/10 15:28:27


Tabla 15-2. Dos maneras de hacer lo mismo.

Caracterstica de
Propsito Equivalente en My.Computer.FileSystem
Visual Basic
ChDir Cambiar el directorio de trabajo La propiedad FileSystem.CurrentDirectory obtiene y
actual en una unidad especfica o establece el directorio de trabajo para que la aplicacin lo
predeterminada. comprenda. Usted establece el directorio activo con una cadena de
ruta absoluta o relativa.
ChDrive Cambiar la unidad de trabajo actual. La propiedad FileSystem.CurrentDirectory no slo
reporta o cambia el directorio activo, tambin modifica la unidad activa.
CurDir Identificar el directorio de trabajo Una vez ms, FileSystem.CurrentDirectory es el
actual y la unidad como una cadena sustituto de esta caracterstica del directorio de Visual Basic.
de ruta completa. CurDir tiene un poco ms de flexibilidad: le permite determinar
el directorio actual en una unidad distinta de la actual. Este puede
hacerse con FileSystem.CurrentDirectory.
Dir Recuperar archivos y directorios en un Los mtodos FileSystem.GetDirectories y
directorio primario que coincide con FileSystem.GetFiles son compatibles con patrones de
un patrn de nombre especfico. comodines cuando se recuperan nombres de directorio y archivo
coincidentes. Dir requiere que lo llame una vez para cada entrada
que se devuelve, y no funciona bien cuando se procesan direcciones
anidadas. Los equivalentes de FileSystem devuelven coleccio-
nes de elementos coincidentes, y pueden descender opcionalmente
por todo el rbol de subdirectorios de una ruta base.
FileCopy Hacer una copia de un archivo. FileSystem.CopyFile proporciona algunas caractersticas
amigables con el usuario ms all de FileCopy. Pero qu pasa
con lo inverso de File y Copy?
FileDateTime Recuperar la fecha y hora de creacin Se usa el mtodo FileSystem.GetFileInfo para recu-
o modificacin de un archivo. perar el objeto FileInfo repleto de detalles acerca de un archivo.
Probablemente se concentrar en la propiedad FileInfo.
LastWriteTime, pero tambin puede obtener la hora de crea-
cin del original y la del ltimo acceso, caractersticas no disponibles a
travs de la funcin inferior y ahora en desdicha FileDateTime.
FileLen Recuperar la longitud de un archivo, Se obtiene un objeto FileInfo mediante el mtodo
en bytes. FileSystem.GetFileInfo, y se accede a la propiedad
Length de ese objeto para obtener el tamao del archivo en bytes.
GetAttr Recuperar los atributos de un archivo Se obtienen detalles de un archivo a travs del mtodo FileSystem.
como un campo de bits. GetFileInfo, y se usa la propiedad Attributes del
objeto FileInfo para examinar su atributo de eleccin. Este
objeto tambin expone un valor IsReadOnl y booleano.
Kill Eliminar un archivo de un directorio Los mtodos FileSystem.DeleteFile y FileSystem.
vaco. DeleteDirectory reemplazan el procedimiento Kill y
proporcionan opciones adicionales no disponibles con Kill.
Adems, no tendr a la polica tocando su puerta preguntando por
qu escribe constantemente Matar, Matar, Matar (Kill).

Administracin de archivo con el espacio de nombres My | 425

15_PATRICK-CHAPTER_15.indd 425 17/2/10 15:28:27


Tabla 15-2. Dos maneras de hacer lo mismo (continuacin).

Caracterstica de
Propsito Equivalente en My.Computer.FileSystem
Visual Basic
MkDir Crear un nuevo directorio. El mtodo FileSystem.CreateDirectory es un reempla-
zo gentil de MkDir. De cualquier manera, mkdir es un antiguo
comando Unix, y usted no est programando en Unix, o s?
Rename Cambiar el nombre de un archivo o Rename es reemplazado por mtodos FileSystem.
directorio. RenameFile y FileSystem.
RenameDirectory distintivos.
RmDir Eliminar un directorio, aunque FileSystem.DeleteDirectory elimina directorio que
contenga archivos. an contienen otros archivos, una accin que rechazaba RmDir.Tam-
bin hay una opcin para enviar los archivos a la Papelera de reciclaje.
SetAttr Modificar los atributos de un archivo Mismo proceso indicado antes para GetAttr. Las propiedades
empleando un campo de bits. Attributes and IsReadOnly del objeto FileInfo son
valores de lectura/escritura, suponiendo que tiene los derechos de
seguridad necesarios para cambiar los atributos.

Por qu Microsoft introducira tantas nuevas caractersticas My que duplican caractersticas exis-
tentes de Visual Basic? Tal vez es una manera de traer consistencia a las prcticas de programa-
cin basadas en archivos mediante un mtodo ms orientado a objetos. O tal vez es slo otra
movida de Microsoft, el gobierno de Estados Unidos, los Caballeros Templarios, Burger King y
otros grupos que pretenden la dominacin mundial al controlarlo a usted, su familia y su comu-
nidad mediante la "mano oculta de instrucciones de cdigo fuente extra largas.

Lectura y escritura de archivos mediante My


Los mtodos My.Computer.FileSystem.OpenTextFileReader y el paralelo OpenText
FileWriter proporcionan mtodos abreviados al constructor basado en nombres de archivo
para los objetos StreamReader y StreamWriter. La instruccin:
Dim flujoEntrada As IO.StreamReader = _
My.Computer.FileSystem.OpenTextFileReader( _
rutaNombreArchivo)

es idntica a:
Dim flujoEntrada As New IO.StreamReader(rutaNombreArchivo)

Para m, la segunda versin es mejor debido a su tersa naturaleza, pero queda entre usted y su
equipo de revisin de cdigo fuente la decisin de cul usar.
Si quiere cargar todo el contenido de un archivo en una matriz String o Byte, no es necesario
abrir un flujo ahora que My incluye los mtodos My.Computer.FileSystem.ReadAllText y el
relacionado ReadAllBytes. Esta instruccin vuelca todo el contenido de un archivo en String:
Dim archivoCompleto As String = _
My.Computer.FileSystem.ReadAllText( _
rutaNombreArchivo)

426 | Captulo 15:Archivos y directorios

15_PATRICK-CHAPTER_15.indd 426 17/2/10 15:28:27


Los mtodos My.Computer.FileSystem.WriteAllText y WriteAllBytes hacen lo mismo,
pero en la direccin opuesta. Hay un argumento booleano append que le permite adjuntar o
reemplazar el nuevo contenido en relacin con el contenido existente en el archivo.
My.Computer.FileSystem.WriteAllText( _
rutaNombreArchivo, dataToWrite, True) ' True=append

Una caracterstica que siempre se ha extraado en Visual Basic es la capacidad de rastrear de


manera conveniente un archivo delimitado (como uno delimitado por tabuladores o por comas)
o un archivo de campo de ancho fijo, y extraer los campos en cada lnea sin una gran cantidad
de cdigo de anlisis adicional. Visual Basic incluye ahora el objeto Microsoft.VisualBa-
sic.FileIO.TextFieldParser que simplifica este proceso. Este objeto le permite indicar un
delimitador de campo (como el carcter de tabulador) o una matriz de tamaos de columnas.
Una vez que lo asocie con una ruta de archivo, lee cada lnea de datos, dividiendo los campos dis-
tintivos en una matriz de cadena. El mtodo My.Computer.FileSystem.OpenTextField
Parser abre el archivo y define el mtodo de anlisis en una barrida.

Dim camposDatos() As String


Dim archivoOrigen As FileIO.TextFieldParser

' ----- Abrir el archivo con los campos delimitados por tabuladores.
archivoOrigen = My.Computer.FileSystem.OpenTextFieldParser( _
archivoOrigenPath, vbTab)

' ----- Procesar cada linea.


Do While Not archivoOrigen.EndOfData
camposDatos = archivoOrigen.ReadFields(
)
' ----- camposDatos es una matriz de cadena simple,
' de modo que puede examinar cada campo directamente.
If (camposDatos(0) = "NEW") Then
' ----- etcetera...
Loop
archivoOrigen.Close()

El objeto TextFieldParser tambin puede detectar lneas de comentarios e ignorarlos en si-


lencio. Estoy seguro de que est usando un StreamReader oculto secretamente dentro de la caja
negra del objeto. Aunque el funcionamiento interno est oculto de la vista, las caractersticas
expuestas de este objeto facilitan procesar los archivos de texto basados en campos.

Resumen
La administracin y manipulacin de archivos no es ciruga cerebral. Pero con el sistema de
archivos como eje principal de cualquier sistema operativo, las herramientas y los mtodos para
leer y actualizar archivos parecen multiplicarse como conejos. El .NET Framework usa Stream
como su principal mtodo de interaccin con archivos, de modo que esto debe ayudarle a sim-
plificar las cosas. Por supuesto, apila docenas de clases de envoltura sobre el flujo bsico, pero
se es otro tema.

Resumen | 427

15_PATRICK-CHAPTER_15.indd 427 17/2/10 15:28:27


En cuanto a la administracin de archivos y directorios, .NET va en la direccin opuesta, dndo-
le cada vez ms caractersticas de lenguaje y de objeto para realizar las mismas tareas bsicas. Ms
all de las caractersticas tradicionales de Visual Basic y el espacio de nombres My que introduje
en este captulo, hay caractersticas adicionales duplicadas en las bibliotecas de clase de .NET.
Use los mtodos que satisfagan sus necesidades, e incluya en un archivo las dems para referencia
futura.

Proyecto
Tengo algunas noticias buenas y otras malas. Las malas noticias son que el Proyecto Biblioteca
no lee ni escribe en archivos estndar, y no tiene necesidad de flujos de archivo. Eso significa que
no agregaremos cdigo al proyecto de este captulo. Las buenas noticias son que an tenemos
algunas cosas interesantes de las cuales hablar. Adems, me imagino que como hemos terminado
ms de la mitad del libro, puede tomarse un descanso.

ACCESO AL PROYECTO
Este captulo no incluye plantillas de proyecto, as no se preocupe en buscarlas en Visual
Studio.

Configuracin de la salida de registro


Cada vez que ocurre un error en la aplicacin Biblioteca, la rutina ErrorGeneral muestra el
mensaje de error al usuario, y luego lo registra a cualquier escucha de registro configurado.
Public Sub ErrorGeneral(ByVal nombreRutina As String, _
ByVal elError As System.Exception)
' ----- Reportar un error al usuario.
On Error Resume Next

MsgBox("El siguiente error ha ocurrido en el lugar '" & _


nombreRutina & ":" & vbCrLf & vbCrLf & _
elError.Message, MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, ProgramTitle)
My.Application.Log.WriteException(elError)
End Sub

Pero, quin est escuchando? Si usted est ejecutando el programa dentro de Visual Studio,
Visual Basic siempre configura un escucha de registro que despliega el texto en el panel de la
Ventana Inmediato. Pero eso no es muy bueno en una aplicacin compilada e implementada.
Puede disear sus propios escuchas de registro, pero .NET tambin incluye varios escuchas pre-
definidos, todos los cuales pueden habilitarse y configurarse mediante el archivo app.config de la
aplicacin. Si accede a la versin Final del proyecto del captulo 14, encontrar contenido en
su archivo app.config que configura uno de esos escuchas. He aqu una parte de ese archivo, que
le muestra slo las secciones relevantes:

428 | Captulo 15:Archivos y directorios

15_PATRICK-CHAPTER_15.indd 428 17/2/10 15:28:28


<system.diagnostics>
<sources>
<! En esta seccion se define la configuracion del registro
para My.Application.Log -->
<source name="DefaultSource" switchName="DefaultSwitch">
<listeners>
<add name="FileLog"/>
</listeners>
</source>
</sources>

<switches>
<add name="DefaultSwitch" value="Information" />
</switches>

<sharedListeners>
<add name="FileLog" type=
"Microsoft.VisualBasic.Logging.FileLogTraceListener,
Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a,
processorArchitecture=MSIL"
initializeData="FileLogWriter"/>
</sharedListeners>
</system.diagnostics>

La seccin <sharedListeners> define los detalles de un escucha de registro particular. En este


caso, es el escucha FileLogTraceListener, una clase en el espacio de nombres Microsoft.
VisualBasic.Logging. Est habilitado en la seccin <source>/<listeners>, donde est in-
cluido mediante una etiqueta <add>. Hay muchas cosas aqu que parecen bizarras o demasiado
exigentes (como las fichas de clave pblica). Por fortuna, est todo documentado en MSDN, si
alguna vez necesita detalles.
El escucha FileLogTraceListener enva datos de registro relevantes a un archivo de registro
especfico de la aplicacin. Como opcin predeterminada en Windows Vista, el archivo reside
en:
C:\Users\nombreusuario\Application Data\
Compaia\Producto\Version\NombreApl.log

La parte nombreusuario es reemplazada por el nombre del usuario que ha iniciado sesin. Las
partes Compaia, Producto y Version representan el nombre de la compaa, el nombre del
producto y el nmero de la versin de su ensamblado, como est definido en los asistentes de su
ensamblado. NombreApl es el nombre de su aplicacin con la extensin .exe eliminada. En mi
sistema Windows Vista, el archivo de registro para el Proyecto Biblioteca aparece aqu:
C:\Users\nombreusuario\Application Data\
ACME\Biblioteca\1.0.0.0\Library.log

Si no le gusta esa ubicacin puede cambiar la salida a cualquier otra que elija. Para ello, necesi-
tar modificar la etiqueta <add> en la seccin <sharedListeners>, agregando dos atributos
adicionales a la etiqueta.

Proyecto | 429

15_PATRICK-CHAPTER_15.indd 429 17/2/10 15:28:28


<sharedListeners>
<add name="FileLog" type=
"Microsoft.VisualBasic.Logging.FileLogTraceListener,
Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a,
processorArchitecture=MSIL"
initializeData="FileLogWriter"
location="Personalizada"
customLocation="c:\temp\" />
</sharedListeners>

Los nuevos atributos location y customLocation harn el truco. Establezca el atributo


customLocation al directorio donde debe ir el archivo de registro. Estos atributos vinculan
con propiedades del mismo nombre en la clase FileLogTraceListener. La documentacin de
Visual Studio describe estas propiedades y atributos, ms otros que estn disponibles para que
los configure mediante app.config.
Este cambio de app.config est basado en el artculo de MSDN titulado Cmo escribir in-
formacin de eventos en un archivo de texto que puede buscar en su ayuda en lnea. (Use la
caracterstica Busca, no ndice.)

Otras opciones de salida de registro


Otro artculo de MSDN, Paseo: Cambio del lugar en que My.Application.Log escribe infor-
macin, describe cmo enviar salida de registro con ms opciones que slo un archivo de texto
simple. Analiza maneras de registro informacin de aplicacin al Registro de eventos del sistema,
a un archivo delimitado o a un archivo con formato XML y a la consola de despliegue.
Algunos de los cambios que necesita hacer al archivo app.config son, una vez ms, misteriosos, as
que slo los presentar aqu para revisin. Agregue el siguiente contenido al archivo app.config
para definir a los escuchas disponibles:

<add name="EventLog"
type="System.Diagnostics.EventLogTraceListener,
System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="sample application"/>

<add name="Delimited"
type="System.Diagnostics.DelimitedListTraceListener,
System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="c:\temp\CiertoArchivo.txt"
delimiter=";;;"
traceOutputOptions="DateTime" />

<add name="XmlWriter"
type="System.Diagnostics.XmlWriterTraceListener,
System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"

430 | Captulo 15:Archivos y directorios

15_PATRICK-CHAPTER_15.indd 430 17/2/10 15:28:28


initializeData="c:\temp\CiertoArchivo.xml" />
<add name="Console"
type="System.Diagnostics.ConsoleTraceListener,
System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="true" />

El atributo initializeData en cada entrada contiene los valores enviados a los argumentos del
constructor de clase relevante. Otros atributos (excepto type) modifican las propiedades del mis-
mo nombre en la clase especificada mediante el atributo type. Para todas las opciones disponibles
para usted de cada escucha, revise la entrada de su clase en la documentacin de Visual Studio.
Para habilitar cualquiera de estos escuchas utilice una etiqueta <add> en la seccin <sour
ce>/<listeners>. El siguiente bloque XML permite todos los escuchas definidos en el pro-
yecto de este captulo:
<sources>
<!-- En esta seccion se define la configuracion del registro
para My.Application.Log -->
<source name="DefaultSource" switchName="DefaultSwitch">
<listeners>
<add name="FileLog"/>
<add name="EventLog" />
<add name="Delimited" />
<add name="XmlWriter" />
<add name="Console" />
</listeners>
</source>
</sources>

Obtencin de una fuente de cdigo de barras


Como nos queda poco tiempo hablaremos acerca de obtener una fuente de cdigo de barras. El
Proyecto Biblioteca incluir soporte a impresin de cdigo de barras, pero slo si tiene instalada
una fuente de cdigo de barras en su sistema. No es una emergencia, pero debe obtener una
antes de llegar al captulo 18, donde desarrollaremos el cdigo de configuracin del cdigo de
barras.
Cuando descarg el cdigo para este libro, no inclua una fuente de cdigo de barras. Se debe
a temas de licencia y cosas por el estilo, usted comprende. Pero las fuentes de cdigo de barras
son fciles de obtener. Puede comprar una fuente de cdigo de barras profesional, si quiere, y si
planea implementar este proyecto en una configuracin de biblioteca real, probablemente debe
hacerlo. Pero si slo est leyendo este libro por su gran sentido del humor, puede descargar una
de las muchas fuentes de cdigo de barras gratuitas disponibles en Internet. He incluido algunos
vnculos a proveedores de fuentes de cdigo de barras en el sitio Web donde obtuvo el cdigo
fuente de este libro. Aunque no planee usar las caractersticas de impresin de cdigo de barras,
le recomiendo que descargue una fuente de cdigo de barras gratuita slo para que pueda probar
algunas de las caractersticas del captulo 18.

Proyecto | 431

15_PATRICK-CHAPTER_15.indd 431 17/2/10 15:28:28


Una vez que haya instalado la fuente, necesitar indicarle al programa Biblioteca que la use. El
formulario de configuracin que diseamos en el captulo anterior inclua un campo de selec-
cin para esta fuente. Es el campo Nombre de fuente de cdigo de barras. Puede verlo en medio
de la figura 14-6. Lo hice un parmetro de todo el sistema por que parece mejor tener a todos
los administradores en una sola biblioteca usando una fuente comn.
Si su fuente es una de cdigo de barras Code 3 of 9 (tambin llamada Code 39), asegrese
de seleccionar el campo Code 39 o Code 3 of 9 en ese mismo formulario. (El proveedor de
fuente le har saber si es una fuente Code 3 of 9 o no.) Estas fuentes requieren un asterisco antes y
despus del nmero de cdigo de barras. Al seleccionar este campo har que el puntero Biblioteca
agregue automticamente los caracteres de asterisco.
Bueno, ya me cans de hablar acerca de archivos, sean de fuentes o de configuracin. En el si-
guiente captulo regresaremos al mundo del cdigo y su gemelo fraterno, los datos.

432 | Captulo 15:Archivos y directorios

15_PATRICK-CHAPTER_15.indd 432 17/2/10 15:28:28


Captulo 16
Genricos

Cuando estaba en la preparatoria, mi familia compraba en ocasiones en una tienda de abarrotes


local llamada Fedmart. Signos en las ventanas establecan claramente que no haba conexin entre
Fedmart y el gobierno federal, pero las personas seguan comprando de todas maneras. Tenan
estas pequeas pizzas congeladas de un dlar que mi mam compraba en grandes cantidades para
m y mis amigos, adolescentes a los que no nos preocupaba muchos lo que bajaba por el esfago.
Casi en toda la tienda se mostraban los tpicos productos de abarrotes, pero haba un pasillo
cerca del borde sur de la tienda que slo venda productos genricos. Caminar por esta seccin
era como hacerlo por una televisin en blanco y negro; todas las etiquetas de productos eran de
color claro o blanco, con letras negras simples. Y eran baratos. Hacan el trabajo, pero apenas.
Nunca querra que se acabara la catsup de marca en medio de una comilona de barbacoa con sus
amigos y ofrecer una botella de catsup genrica como reemplazo. De alguna manera, recuerdo
claramente haber ledo cmo cumpla con los estndares federales de la salsa catsup en las letras
negras de la etiqueta blanca de ese sustituto acuoso. En ese momento tuve una epifana, de sbi-
to me di cuenta de que cambiara la manera en que pensaba acerca de la vida en Estados Unidos
para siempre: el gobierno tena un estndar federal para la catsup!
Lo triste es que Fedmart cerr antes de que saliera de la preparatoria, dejando un vaco en el mer-
cado de la catsup genrica y el papel aluminio. Como programador de Visual Basic, an puede
tener acceso a los genricos, mediante la tecnologa de los genricos de .NET. Los genricos (la
capacidad de usar marcadores de posicin para tipos de datos) aparecieron por primera vez en
Visual Basic 2005 y el .NET Framework 2.0 relacionado. En este captulo se le proporcionan los
detalles especficos de los genricos.

Qu son los genricos?


En .NET, los genricos son una tecnologa que le permite definir marcadores de posicin de
tipos de datos dentro de tipos o mtodos. Digamos que necesita definir una clase para llevar
registro de los datos de clientes, pero no quiere imponer un formato especfico en el valor ID
del cliente. Parte de su cdigo necesita interactuar con objetos de cliente utilizando el valor
Integer de ID, mientras que otra parte de la configuracin usar una clave alfanumrica para

433

16_PATRICK-CHAPTER_16.indd 433 17/2/10 15:28:53


el cliente. Se podra preguntar: Por qu no slo incluye ambos tipos de identificadores como
campos distintivos en el registro de su cliente? Eso no funcionara porque estoy tratando de salir
con un ejemplo razonablemente simple y responder esa pregunta me distraera. As que he aqu
la versin numrica de la clase:
Class ClienteConIDNumerico
Public ID As Integer
Public NombreCompleto As String
End Class

sta es la variante que usa una ID string:


Class ClienteConIDCadena
Public ID As String
Public NombreCompleto As String
End Class

Por supuesto, podra definir ID como System.Object, y apegarse a cualquier cosa que quiere en
ese campo. Pero System.Object se considera de tipo dbil y no hay nada que evite que mezcle
valores ID Integer y String para diferentes instancias en una matriz de objetos de cliente.
Lo que quiere es un sistema que le permite definir las clases de manera genrica, y mantener la
especificacin de los tipos de datos de ID hasta que en realidad cree una instancia de la clase,
o una coleccin completa de instancias de clase relacionados. Con este tipo de sistema podra
definir una versin de propsito general de la clase personalizada.
Class ClienteConAlgunID
Public ID As <DatatypePlaceholder>
Public NombreCompleto As String
End Class

Ms adelante, cuando es hora de crear una instancia, podran indicar al lenguaje cul tipo de
datos usar para el marcador de posicin.
Dim unCliente As ClienteConAlgunID(reemplazando _
<MarcadorTipoDatos> with Integer)

Esto es lo que los genricos le permiten hacer. He aqu la sintaxis real de Visual Basic que define
la clase de cliente no especfica:
Class ClienteConAlgunID(Of T)
Public ID As T
Public NombreCompleto As String
End Class

El marcador de posicin general, T, aparece en una clusula especial Of, slo despus del nombre
de clase. (No tiene que poner nombre al marcado de posicin T, pero se ha vuelto una tradicin
cuando se presenta cdigo de ejemplo usando genricos.) Como tipo de datos, T puede usarse
en cualquier lugar dentro de la definicin de clase donde no quiere definir de antemano el tipo
de datos. La clase, y su miembro ID, est lista ahora para crear una instancia de ella con un tipo
de datos de reemplazo para T. Para crear una nueva instancia pruebe este cdigo:
Dim clienteNumero As ClienteConAlgunID(Of Integer)

434 | Captulo 16: Genricos

16_PATRICK-CHAPTER_16.indd 434 17/2/10 15:28:54


Cuando (Of Integer) se adjunta al final de la definicin de clase, Visual Basic acta como si
en realidad declarara una variable para una clase que tiene un miembro Integer llamado ID. En
realidad lo hace. Cuando crea una instancia de una clase genrica, el compilador define una clase
separada que parece una clase no genrica con todos los marcadores de posicin reemplazados.
Dim cliente1 As New ClienteConAlgunID(Of Integer)
Dim cliente2 As New ClienteConAlgunID(Of Integer)
Dim cliente3 As New ClienteConAlgunID(Of String)

Estas lneas definen dos instancias de ClienteConAlgunID(Of Integer), y una de


ClienteConAlgunID(Of String). cliente1 y cliente2 son, en realidad, instancias del mis-
mo tipo de datos, pero cliente3 es una instancia de un tipo de datos completamente diferente.
Las asignaciones entre cliente1 y cliente2 funcionarn, pero no puede mezclar cualquiera de
ellas con cliente3 sin realizar una conversin explcita.
' ----- Esto funciona bien.
cliente1 = cliente2
' ----- Esto no se compila.
cliente3 = cliente1

Como tipos de datos en tiempo de compilacin verdadero generados automticamente por el


compilador, muestran toda la personalidad de las otras clases no genricas. Aun IntelliSense de
Visual Studio detecta apropiadamente el tipo de datos sustituidos. En la figura 16-1 se incluye un
cuadro con informacin sobre herramientas, justo a la derecha de la lista de seleccin de miem-
bros de instancia, que identifican apropiadamente el miembro cliente1.ID como Integer.

Figura 16-1. Felicidades, Sr. y Sra. Genricos: es un Entero.

Dentro de la definicin de clase, el marcador de posicin T puede aparecer en cualquier lugar,


aun dentro de las listas de argumentos y declaraciones de variables locales.
Class AlgunaClase(Of T)
Public Function TransformData(ByVal sourceData As T) As T
' ----- Agregar aqui codigo de transformacion generico.
Dim datosTrabajo As T
...
End Function
End Class

Qu son los genricos? | 435

16_PATRICK-CHAPTER_16.indd 435 17/2/10 15:28:54


Los genricos funcionan con estructuras e interfaces, tambin.
Structure AlgunaEstructura(Of T)
Public MiembroGenerico As T
End Structure
Interface IAlgunaInterfaz(Of T)
Sub TrabajaConDatos(ByVal losDatos As T)
End Interface

Variaciones en las declaraciones de los genricos


Si hubiera un requisito mnimo del gobierno federal para los marcadores de posicin de tipo de
datos, la implementacin de los genricos slo describira que se cumple con l. Es agradable
posponer la definicin de los tipos de datos hasta el ltimo minuto. Pero los genricos .NET no
se detienen all.

Marcadores de posicin mltiples


Los marcadores de posicin genricos (tambin conocidos como parmetros de tipo) son como
las navajas que compra en la TV por la noche. No tiene una; tiene ms! No importa cuntas
necesite, las tendr todas. Cada clase genrica puede incluir varios marcadores de posicin al
agregarlos a la clusula inicial Of.
Class VariosTipos(Of T1, T2)
Public Miembro1 As T1
Public Miembro2 As T2
End Class

Como antes, no se le pide que use los nombres aburridos T1 y T2. Cualquier nombre que elija,
inclyalo como una lista separada por comas despus de la palabra clave Of. Cuando est listo
para crear una instancia, replique la lista delimitada por comas en el mismo orden, pero em-
pleando tipos reales. En esta instruccin, Integer reemplaza a T1 y String reemplaza a T2:
Dim usarInstancia As VariosTipos(Of Integer, String)

Tipo de datos y restricciones de interfaz


Los parmetros de tipo que incluya en un genrico, como T, aceptar cualquier tipo de datos
vlidos, incluidos Integer, String, System.Windows.Forms.Form, o sus propios tipos perso-
nalizados. Es decir, T puede ser reemplazado por cualquier cosa que derive de System.Object,
que es todo. Incluso puede imaginar la instruccin:
Class AlgunaClase(Of T)

siendo reemplazada por:


Class AlgunaClase(Of T As System.Object)

agregando la clusula As para que se parezca a otras declaraciones de Visual Basic. Bueno, puede
dejar de imaginar y empezar a actuar: los marcadores de posicin dan soporte a la clusula

436 | Captulo 16: Genricos

16_PATRICK-CHAPTER_16.indd 436 17/2/10 15:28:54


As. Si no incluye una clusula As, Visual Basic supone que quiso decir As System.Object, pero
puede seguir As con cualquier tipo que desee.
Class FormOnlyClass(Of T As System.Windows.Forms.Form)

Al agregar la clusula As a una clase especfica, impone una restriccin en el tipo genrico, una
limitacin que debe cumplir para usar el tipo. En este caso, la restriccin dice: Puede propor-
cionar cualquier valor de clase para T, siempre y cuando derive de System.Windows.Forms.
Form. Esto significa que puede crear una instancia de FormOnlyClass empleando uno de los
formularios de su aplicacin, pero no clases distintas de Form.
' ----- Esto funciona.
Dim usarForm As FormOnlyClass(Of Form1)

' ----- Esto no funciona.


Dim usarForm As FormOnlyClass(Of Integer)

Cuando agregue una restriccin a un parmetro de tipo, tendr impacto en las caractersticas
que puede usar con ese parmetro de tipo. Considere esta clase genrica destinada a trabajar con
formularios, pero no declarada de esa manera:
Class TrabajarConForms(Of T)
Public Sub CambiarLeyenda(ByVal cualForm As T, _
ByVal nuevaLeyenda As String)
' ----- La siguiente linea no se compila.
cualForm.Text = nuevaLeyenda
End Sub
End Class

En esta clase, la asignacin a cualForm.Text fallar porque la clase TrabajarConForms no


sabe que usted planea usarla con formularios. Slo sabe que planea usar T y T es, como opcin
predeterminada, del tipo System.Object. No hay una propiedad Text en la clase System.
Object. Yo lo revis.
Si cambiamos la definicin de TrabajarConForms para que acepte objetos Form, la salida para
compilar este cdigo cambia de manera importante.
Class TrabajarConForms(Of T As Windows.Forms.Form)
Public Sub CambiarLeyenda(ByVal cualForm As T, _
ByVal nuevaLeyenda As String)
' ----- Claro! Ahora se compila.
cualForm.Text = nuevaLeyenda
End Sub
End Class

Debido a que T tiene que ser del tipo Form o algo derivado de Form, Visual Basic sabe que todos
los miembros de la clase Form, incluido Text, estn disponibles para todas las cosas de T. Por
tanto, la asignacin a cualForm.Text funciona.
Adems de clases, tambin puede usar interfaces para restringir sus tipos genricos.
Class LanzarClase(Of T As IDisposable)

Variaciones en las declaraciones de los genricos | 437

16_PATRICK-CHAPTER_16.indd 437 17/2/10 15:28:54


Las instancias de LanzarClase pueden crearse segn se necesite, pero slo si el tipo proporcio-
nado con la declaracin implementa la interfaz IDisposable.
' ----- Esto funciona. Plumas usa IDisposable.
Dim plumaDesechable As LanzarClase(Of System.Drawing.Pen)

' ----- Esto no funciona, porque el tipo de datos Integer


' no implementa IDisposable.
Dim numeroDesechable As LanzarClase(Of Integer)

Pero espere, hay ms! Vea, le dije que era como comprar navajas en TV. Adems de sus tipos e
interfaces para todo tipo, tambin puede seguir la clusula As en el marcador de posicin gen-
rico con la palabra clave New.
Class AlgunaClase(Of T As New)

La clusula As New le dice al tipo genrico: Acepta cualquier tipo de T, pero slo si ese tipo
incluye un constructor que no requiere argumentos. Es decir, T debe incluir un constructor pre-
determinado. Una vez definido podr crear nuevas instancias de T (cualquier tipo que resulte)
en su tipo genrico.
Class AlgunaClase(Of T As New)
Public Sub AlgunaSub()
Dim algunaVariable As New T
End Sub
End Class

Si su clase genrica incluye parmetros de varios tipos, cada parmetro incluye su propia clase As
con un tipo distintivo o restriccin de interfaz.

Restricciones simultneas
Es agradable que cada una de esas navajas pueda rebanar una sanda, pero qu pasa si quiere
cortar madera con la misma navaja, o usarla para reparar el cableado elctrico? Est buscando
una herramienta multifuncional, como la de cada marcador genrico de posicin. Si necesita
un marcador de posicin para incluir en una restriccin para una clase especfica, una interfaz y
New a la vez, puede hacerlo. Despus de la palabra clave As, incluya las diversas restricciones
entre llaves.
Class AlgunaClase(Of T As {Windows.Forms.Form, _
IDisposable, New})

Ahora, cualquier tipo que proporcione en la clusula Of cuando cree una instancia de esta clase
debe cumplir todas las restricciones, no slo una de ellas. Y he aqu algo nuevo: puede incluir ms
de una restriccin a interfaz a la vez.
Class AlgunaClase(Of T As {ISerializable, IDisposable})

Y an puede incluir una restriccin de clase y la restriccin New, aun con estas mltiples inter-
faces. (No puede incluir ms de una restriccin de clase para un solo marcador de posicin.)
Si su tipo genrico incluye varios parmetros, cada uno de ellos tiene su propio conjunto de
restricciones mltiples.

438 | Captulo 16: Genricos

16_PATRICK-CHAPTER_16.indd 438 17/2/10 15:28:55


Anidado de tipos genricos
Los tipos genricos pueden incluir sus propios tipos anidados.
Class Nivel1(Of T1)
Public Miembro1Nivel As T1
Class Nivel2(Of T2)
Public Miembro1Nivel2 As T1
Public Miembro2Nivel2 As T2
End Class
End Class

Puede anidar los genricos a la profundidad que necesite.

Tipos no genricos con miembros genricos


Si los tipos genricos parecen un poco terrorficos o abrumadores, no se espante. No tiene que
crear un tipo genrico completo para usar las nuevas caractersticas genricas. Puede agregar
soporte genrico a un solo mtodo dentro de una clase que de otra manera sera normal.
Class AlgunaClase
' ----- La propia clase no tiene la clausula generica
' Of, de modo que no es generica. Pero...

Public Shared Sub RevertirValores(Of T) _


(ByRef primero As T, ByRef segundo As T)
' ----- Este metodo es generico con su propia clausula Of.

' ----- Revertir el contenido de las dos variables.


Dim contenerPrimero As T

contenerPrimero = primero
primero = segundo
segundo = contenerPrimero
End Sub
End Class

Los mtodos genricos son tiles cuando necesita tener una variable local del tipo de marcador
de posicin dentro del mtodo (como se hace aqu con contenerPrimero), pero no conoce el
tipo de antemano. El uso de este mtodo RevertirValores revertido funciona como cualquier
otro mtodo, con la clusula Of adicional.
Dim x As Integer = 5
Dim y As Integer = 10
AlgunaClase.RevertirValores(Of Integer)(x, y)
MsgBox(x) ' Despliega 10

Si estar usando el marcador de posicin para uno o ms de los argumentos de mtodo, Visual
Basic inferir el tipo con base en el valor pasado. Si Visual Basic puede adivinar el tipo de esta
manera, ni siquiera necesita la clusula Of cuando llame al mtodo genrico.
AlgunaClase.RevertirValores(x, y)

Variaciones en las declaraciones de los genricos | 439

16_PATRICK-CHAPTER_16.indd 439 17/2/10 15:28:55


Al igual que con los tipos genricos, los mtodos genricos le permiten agregar restricciones a los
marcadores de posicin.

Sobrecarga de tipos y mtodos genricos


Ya mencion cmo crea el compilador, en esencia, clases separadas para cada variacin de una
clase genrica que usted crea. Esto significa que estas dos instancias en realidad usan clases com-
pletamente diferentes y, por lo general, no relacionadas:
Dim versionNumerica As AlgunaClase(Of Integer)
Dim versionTextual As AlgunaClase(Of String)

De modo que AlgunaClase(Of Integer) y AlgunaClase(Of String) son clases completa-


mente distintas, aunque tengan el mismo nombre base. De cierta manera, Visual Basic est sobre-
cargando el nombre de la clase por usted, permitiendo usarlo de dos (o ms) manera diferentes.
Los genricos tambin le permiten participar en el juego de la sobrecarga de clases. Por lo gene-
ral, slo puede crear una clase con un nombre determinado (dentro de un espacio de nombres
particular). Pero con los genricos puede reutilizar un nombre de clase, siempre y cuando los
marcadores de posicin usados entre las clases sean lo bastante diferentes, en nmero o en res-
tricciones aplicadas.
Class AlgunaClase(Of T1)
' ----- Esta es una clase generica con un marcador de posicion.
End Class

Class AlgunaClase(Of T1, T2)


' ----- Esta es una clase generica completamente
' diferente con dos marcadores de posicin.
End Class

Visual Basic se imaginar cul versin usar con base en la clusula Of que incluya con la decla-
racin de instancia.
Dim versionSimple As AlgunaClase(Integer)
Dim versionCompleja As AlgunaClase(Integer, String)

Genricos y colecciones
Los genricos realmente brillan en el rea de las colecciones. La versin inicial de .NET tena,
entre los miles de clases posiblemente tiles, un conjunto de clases de coleccin, todas en el
espacio de nombres System.Collections. Cada coleccin le permite insertar todas las instan-
cias diferentes que desee dentro de esa coleccin, y recuperarlas ms adelante. Las colecciones
difieren en la manera en que la incluye y las recupera, pero le permiten incluir cualquier tipo de
objeto en la coleccin.
Una de las clases de coleccin es System.Collections.Stack. Las pilas le permiten almace-
nar objetos como panqus: el primer objeto que agregue a la pila va en la parte inferior, y cada
uno que agregue va en la parte superior del objeto anterior. Cuando est listo para comer un
panqu (quiero decir, eliminar un elemento) lo toma de la parte superior (a este sistema ltimo
en entrar, primero en salir se le suele llamar LIFO, por Last In, First Out). Los mtodos
Push y Pop administran la adicin y eliminacin de objetos.

440 | Captulo 16: Genricos

16_PATRICK-CHAPTER_16.indd 440 17/2/10 15:28:55


Dim pilaNumerica As New Collections.Stack
pilaNumerica.Push(10)
pilaNumerica.Push(20)
pilaNumerica.Push(30)
MsgBox(pilaNumerica.Pop()) 'Despliega 30
MsgBox(pilaNumerica.Pop()) 'Despliega 20
MsgBox(pilaNumerica.Pop()) 'Despliega 10

Tambin hay un mtodo Peek que busca el elemento superior, pero no lo retira de la pila. Lo
que pasa con las pilas (y otras colecciones similares) es que no tiene que poner slo un tipo de
objeto en ella. Puede mezclar todos los que quiera.
Dim pilaNumerica As New Collections.Stack
pilaNumerica.Push(10) 'Integer
pilaNumerica.Push("Estoy hurgando.") 'String
pilaNumerica.Push(Me.Boton1) 'Control

La pila no es de cuidado, porque slo est tratando todo como System.Object. Pero qu
pasara si necesitara asegurar que slo los enteros se pusieran en la pila? Qu pasara si quiera
limitar una pila a un tipo de datos especfico, pero no quiere escribir clases de pilas separadas
para cada tipo posible?
Esto me suena como un trabajo para los genricos. Tambin le son as a Microsoft. De modo
que agregu una gran cantidad de nuevas colecciones genricas al marco conceptual. Aparecen
en el espacio de nombres System.Collections.Generic. Hay unas cuantas clases diferen-
tes en este espacio de nombres, incluidas clases para listas vinculadas, colas, galletas con chips
de chocolate y diccionarios. Y hey, hay una clase llamada Stack(Of T). Eso es lo nico que
necesitamos.
Dim pilaNumerica As New Collections.Generic.Stack(Of Integer)
pilaNumerica.Push(10)
pilaNumerica.Push(20)
pilaNumerica.Push(30)

Ahora, si tratamos de agregar algo diferente de un Integer a pilaNumerica, ocurre un error.


' ----- Esto no funciona.
pilaNumerica.Push("Probare de nuevo.")

Tipos genricos que pueden ser nulos


En el captulo 6 introduje los tipos que pueden ser nulos, una manera de permitir que Nothing
se use con tipos de valor.
Dim numeroONada As Integer?

Aunque no puede saberlo a partir de la lnea de cdigo fuente, los tipos que pueden ser nulos en reali-
dad estn implementados usando genricos. La versin completa de la declaracin numeroONada es:
Dim numeroONada As Nullable(Of Integer)

Visual Basic simplemente mejor un mtodo abreviado para esta sintaxis mediante el sufijo ?
Puede usar cualquier sintaxis para declarar sus instancias como nulas.

Variaciones en las declaraciones de los genricos | 441

16_PATRICK-CHAPTER_16.indd 441 17/2/10 15:28:55


Resumen
Tener genricos disponibles para desarrollo .NET realmente hace que Visual Basic sea an ms
flexible y til que todo lo que ha odo de l. Siempre tiene la capacidad de usar marcadores de
posicin para datos (se les llaman variables). Los genricos proporcionan el mismo tipo de fun-
cionalidad de marcador de posicin, con tipos de datos en lugar de simples datos.
Cuando controla todos los aspectos de desarrollo de una aplicacin, podra pensar que los gen-
ricos no son para usted. Despus de todo, no va a dejar que una variable Integer se deslice en
una coleccin de datos. Pero son muy prcticos para imponer estndares dentro de su cdigo,
lo que es bueno.

Proyecto
Cuando un cliente saca un libro u otro artculo de la biblioteca, la fecha de vencimiento se
calcula automticamente con base en un nmero de das almacenado en el campo de la base de
datos CodigoTipoMedio.DiasPrestado. Pero qu pasa si esa fecha calculada es un da festivo,
y la biblioteca est cerrada? El cliente podra regresar el libro hasta el da siguiente, e incurrira
en una multa. Esta multa, aunque pequea, podra iniciar una reaccin en cadena en la vida del
cliente que lo llevara a la pobreza, la desesperacin y la adiccin a las telenovelas. Por fortuna,
esto puede evitarse al agregar una lista de das festivos al proyecto. Si la fecha de devolucin de
un artculo falla en un da festivo documentado, el programa ajusta la fecha hacia delante, hasta
que encuentra la siguiente fecha no festiva.

ACCESO AL PROYECTO
Cargue el proyecto Cap16 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap16 (Final) cdigo.

Administracin de das festivos


Como una aplicacin pequea e independiente que administra por completo sus propios datos,
no hay en realidad una presin para que Biblioteca use genricos. Sin embargo, stos propor-
cionan ms ventajas que slo limitar los tipos de datos almacenados en una clase o coleccin.
Tambin mejoran la conversin de datos en el soporte de IntelliSense, porque Visual Basic puede
saber de inmediato, por ejemplo, qu tipo de datos aparecer en la coleccin.
Almacenaremos todos los das festivos administrados por el proyecto Biblioteca en la tabla
Festivos de la base de datos. El contenido de esta tabla apenas cambiar, y se acceder a l de
manera frecuente durante el proceso de prstamo. Para agilizar las cosas, incluiremos en cach los
datos dentro de la aplicacin. Y para simplificar la administracin de ese cach, almacenaremos
los fas festivos en una coleccin genrica.

442 | Captulo 16: Genricos

16_PATRICK-CHAPTER_16.indd 442 17/2/10 15:28:55


En primer lugar, crearemos la clase que contiene una sola entrada de das festivos. Agregue una
nueva clase al proyecto mediante el comando de men Proyecto Agregar clase, y asgnele el
nombre ConjuntoFestivos.vb. Aparece la estructura familiar de una clase vaca.
Public Class ConjuntoFestivos

End Class

La tabla Festivos de la base de datos incluye dos campos principales usados en el clculo de
das festivos: TipoEntrada y DetalleEntrada. Almacenemos estos miembros de la clase, y
agreguemos una marca que asegure que la entrada es vlida.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap16, Elemento 1.

Private TipoFestivos As String


Private DetalleFestivos As String
Private EsValido As Boolean

Llenaremos a estos miembros privados a travs del constructor de clases.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap16, Elemento 2.

Public Sub New(ByVal TipoEntrada As String, _


ByVal DetalleEntrada As String)
' ----- Crear una nueva instancia de la entrada Festivos.
TipoFestivos = Left(Trim(UCase(TipoEntrada)), 1)
DetalleFestivos = DetalleEntrada

' ----- Ver si los detalles son validos.


EsValido = True
Select Case TipoFestivos
Case "A"
' ----- El detalle debe estar en el formato mm/dd.
EsValido = EsFecha(DetalleEntrada & "/2004")
Case "E"
' ----- El detalle es un numero de 1 a 7.
If (Val(DetalleEntrada) < 1) Or _
(Val(DetalleEntrada) > 7) Then EsValido = False
Case "O"
' ----- El detalle debe ser una fecha valida.
EsValido = EsFecha(DetalleEntrada)
Case Else
' ---- No valido. Esto nunca debe suceder.
EsValido = False
End Select
End Sub

Proyecto | 443

16_PATRICK-CHAPTER_16.indd 443 17/2/10 15:28:55


Evidentemente, las entradas de das festivos tienen un sistema de codificacin propio, y no sera
justo forzar a cdigo de otro lugar de la aplicacin a que trate con las complejidades de las compa-
raciones entre fechas de festividades. De modo que agreguemos un mtodo pblico a la clase que
indique si una fecha determinada coincide con los das festivos almacenados en una instancia.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap16, Elemento 3.

Public Function EsFestivo(ByVal cualFecha As Date) As Boolean


' ----- Dada una fecha, ver si coincide con el tipo de entrada
' de esta instancia.
Dim generarFecha As String

' ----- Si este registro no es valido, entonces nunca


' coincidira con un dia festivo.
If (EsValido = False) Then Return False

Select Case TipoFestivos


Case "A"
' ----- Anual.
generarFecha = DetalleFestivo& "/" & Year(cualFecha)
If (IsDate(generarFecha)) Then
Return CBool(CDate(generarFecha) = cualFecha)
Else
' ----- Debe ser 2/29 en caso de bisiesto.
Return False
End If
Case "E"
' ----- Dia de la semana.
Return CBool(Val(DetalleFestivos) = _
Weekday(cualFecha, FirstDayOfWeek.Sunday))
Case "O"
' ----- Ver si es una coincidencia exacta de una vez.
Return CBool(CDate(DetalleFestivos) = cualFecha)
End Select
End Function

Hemos terminado con esa clase. Ahora slo necesitamos un lugar para mantener nuestros regis-
tros de das festivos. El espacio de nombres System.Collections.Generic incluye unas cuan-
tas clases de coleccin diferentes que podemos usar. Como lo nico que realmente necesitamos
hacer con las festividades una vez que estn en la coleccin es revisarlas, buscando coincidencias,
la lista estndar, sin complicaciones, parece mejor. Su nombre de clase es List(Of T), y su
consulta principal, de acuerdo con la documentacin de .NET, es que le permita a los miembros
acceder por ndice. Eso es correcto.

444 | Captulo 16: Genricos

16_PATRICK-CHAPTER_16.indd 444 17/2/10 15:28:55


Abra el archivo General.vb y encuentre dnde aparecen las variables globales, en algn lugar
cerca de la parte superior. Luego agregue una definicin para la coleccin global que almacenar
todos los das festivos.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap16, Elemento 4.

Public TodasLasFestividades As Collections.Generic.List( _


Of Biblioteca.ConjuntoFestivos)

All est! All est! La clusula Of. sta es una coleccin genrica. S! Muy bien, la fiesta
termin; hora de partir.
Localice el mtodo InitializarSistema, an en el archivo General.vb, y agregue el cdigo que
inicializar el cach de das festivos globales.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap16, Elemento 5.

TodasLasFestividades = New Collections.Generic.List(Of ConjuntoFestivos)

Eso es para la infraestructura. Agreguemos algunas rutinas que accedan a esta lista genrica.
Necesitamos una rutina que nos indique, True o False, si una fecha determinada (la fecha de
vencimiento planeada de un artculo de la biblioteca) coincide con cualquiera de los das festivos
o no. Agregue la funcin EsFechaFestiva a General.vb.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap16, Elemento 6.

Public Function EsFechaFestiva(ByVal cualFecha As Date) _


As Boolean
' ----- Ver si la fecha dada es una festividad.
Dim unFestivo As Biblioteca.ConjuntoFestivos

' ----- Revisar las festividades, buscando una coincidencia.


For Each unFestivo In TodasLasFestividades
If (unFestivo.EsFestivo(cualFecha)) Then Return True
Next unFestivo

' ----- No hay festividades.


Return False
End Function

Proyecto | 445

16_PATRICK-CHAPTER_16.indd 445 17/2/10 15:28:55


Esta rutina, EsFechaFestiva, muestra dnde son realmente prcticos los genricos. Es en la
instruccin For Each donde la magia ocurre. En una coleccin normal, no estaramos seguros
del tipo de elementos que almacenaramos en la coleccin, si ConjuntoFestivos o String
o Integer. Bueno, lo sabramos porque somos el desarrollador, pero Visual Basic es un poco
tonto en esta rea, y supone que usted combin los datos en una coleccin.
Pero como unimos la coleccin TodasLasFestividades a la clase ConjuntoFestivos usando
la clusula Of ConjuntoFestivos, ahora Visual Basic comprende que slo vamos a almacenar
elementos de ConjuntoFestivos en la coleccin TodasLasFestividades. Eso significa que
no tenemos explcitamente que convertir elementos recuperados de la coleccin al tipo de datos
ConjuntoFestivos. Si estuviramos usando una clase genrica, el cdigo se parecera a ste:
Dim buscarFestivos As System.Object
Dim unFestivo As Library.ConjuntoFestivos

For Each buscarFestivos In TodasLasFestividades


unFestivo = CType(buscarFestivos, Biblioteca.ConjuntoFestivos)
If (unFestivo.EsFestivo(cualFecha)) Then Return True
Loop

Como todo lo que son colecciones no genricas se reduce a System.Object, tendramos que
convertir explcitamente cada objeto de la coleccin a ConjuntoFestivos empleando CType o
una funcin de conversin similar. Pero con una coleccin genrica, Visual Basic se ocupa de eso.
An necesitamos incluir en cach los das festivos de la base de datos, de modo que agregue un
mtodo ActualizarFestivos a General.vb que haga esto.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap16, Elemento 7.

Public Sub ActualizarFestivos()


' ----- Cargar la lista de Festividades.
Dim textoSql As String
Dim infoBD As SqlClient.SqlDataReader
Dim nuevasFestividades As Biblioteca.ConjuntoFestivos

On Error GoTo ErrorHandler

' ----- Limpiar la lista actual de festividades.


TodasLasFestividades.Clear()

' ----- Obtener las festividades de la base de datos.


textoSql = "SELECT * FROM Festivos"
infoBD = CrearLector(textoSql)
Do While infoBD.Read
nuevasFestividades = New Biblioteca.ConjuntoFestivos( _
CStr(infoBD!TipoEntrada), CStr(infoBD!DetalleEntrada))
TodasLasFestividades.Add(nuevasFestividades)

446 | Captulo 16: Genricos

16_PATRICK-CHAPTER_16.indd 446 17/2/10 15:28:55


Loop
infoBD.Close()
Return

ErrorHandler:
ErrorGeneral("ActualizarFestivos", Err.GetException(
))
On Error Resume Next
If Not (infoBD Is Nothing) Then _
infoBD.Close() : infoBD = Nothing
Return
End Sub

Ya ha visto mucho cdigo como ste, cdigo que carga registros de una tabla de base de datos en
el programa. No desafiar su inteligencia al explicrselo lnea por lnea.
Hay dos lugares donde necesitamos llamar a ActualizarFestivos: cuando inicia el programa,
y despus, cada vez que se hacen cambios a la lista de festividades. No nos preocuparemos acerca
de que otros usuarios cambien la lista; nos concentraremos en las situaciones en que la aplicacin
local la actualiza. En primer lugar, abra el a veces oculto archivo ApplicationEvents.vb, y agregue
este cdigo al manejador de eventos MyApplication_Startup, justo despus de la llamada
existente a CargarConfiguracionesBaseDeDatos().

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap16, Elemento 8.

ActualizarFestivos()

Una sola cosa ms. Abra el archivo FormularioPrincipal.vb y localice el manejador de eventos
AdminVinculosFestividades_LinkClicked. Es el que le permite al usuario editar la lista de
das festivos. Agregue la misma lnea ActualizarFestivos() al final de esta rutina.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap16, Elemento 9.

' ----- Volver a cargar las festividades si han cambiado.


ActualizarFestivos()

Como puede ver en esta rutina, ya agregamos el editor para administrar la lista de festividades,
lo nico que queda por hacer es acceder a la lista de festividades cuando se pidan prestados
artculos. Haremos eso en un captulo posterior.

Proyecto | 447

16_PATRICK-CHAPTER_16.indd 447 17/2/10 15:28:56


Captulo 17
LINQ

Hace muchos aos el control remoto de mi televisor se descompuso. Haba recibido este aparato
de segunda mano de un amigo estudiante (eso debe hablar de la calidad del televisor) y ya era un
poco vieja. Pero an poda ver La isla de Gilligan, entonces por qu quejarse? Pero cuando me
puse en contacto con el fabricante para tener un control de reemplazo, me dijeron que costara
75 dlares! El televisor no costaba eso, y estoy seguro que costaba todava menos producir La
isla de Gilligan.
La TV era casi intil sin el control remoto, de modo que sal y compr un control remoto univer-
sal. Estos dispositivos prcticos tienen los cdigos infrarrojos que los fabricantes de televisores
ms comunes incluyen en sus circuitos. Simplemente rastrea todos los cdigos para encontrar
el de su televisor, y en cosa de minutos (y esto demuestra el milagro moderno de la electrnica)
an tiene la funcionalidad que tena con su control original. Perd todo el uso del sistema de
subtitulaje integrado, pero los botones de encendido, canal y volumen parecan funcionar.
A pesar de sus deficiencias, el control remoto universal poda controlar un televisor, una videoca-
setera y un reproductor de DVD, todo a travs de un conjunto comn de botones. Imagine un
control remoto universal para el desarrollo de Visual Basic. Bueno, deje de imaginar y empiece
a revisar su gua de televisin: ahora Visual Basic tiene el respaldo de LINQ, una nueva caracte-
rstica en Visual Basic 2008 que le permite consultar orgenes de datos sin relacin empleando
una sintaxis comn.

Qu es LINQ?
LINQ, abreviatura de consulta integrada de lenguaje (Language INtegrated Query), no es slo
una sino alrededor de un milln de nuevas tecnologas de Visual Basic y .NET que funcionan en
conjunto para facilitarle su vida en la programacin. Bueno, no es tan fcil en todos los casos. Al
igual que con cualquier nueva tecnologa, tiene cosas buenas y malas.

448

17_PATRICK-CHAPTER_17.indd 448 17/2/10 15:29:26


Lo bueno
LINQ existe porque algunos desalentados programadores de Microsoft estaban cansados de
acceder a datos en sus bases de datos de manera diferente de cmo lo hacen en sus datos basados
en archivos, objetos en memoria o XML. Con LINQ, una sola sintaxis le permite acceder a
todos estos tipos de datos diferentes, y ms. La propia sintaxis es similar a SQL, el lenguaje de
consulta de base de datos con el que ya est familiarizado usted, sus socios de programacin y
un equipo de hackers en el FBI.
Visual Basic 2008 incluye soporte de LINQ a tablas y objetos de bases de datos de SQL Server
(LINQ to SQL), conjuntos de datos de ADO.NET (LINQ to ADO.NET y LINQ to Data-
Set), coleccin de objeto en memoria como matrices o colecciones genricas (LINQ to Objects)
y XML (LINQ to XML). Poco despus, la versin oficial de Visual Studio 2008, Microsoft
relanz ADO.NET Entity Framework (LINQ to Entities), que proporciona soporte mejorado
a LINQ a SQL Server, Oracle, DB2 y otras plataformas de base de datos. Es un estupendo inicio,
pero las buenas noticias no terminan all.
LINQ es extensible. Eso significa que puede mejorar LINQ para que pueda consultar cualquier
tipo de datos que especifique. LINQ to Spreadsheet, LINQ to Tab-Delimited-File y LINQ to
DVD-Chapter-Content son posibles. Es un control remoto universal en su lenguaje de pro-
gramacin? Por muy excitante que sean estas posibilidades, no tengo espacio en este libro para
mostrarle cmo desarrollarlos, y es de donde vienen las malas noticias.

Lo malo
LINQ es un sistema abultado para consulta de datos (una vez que ha establecido la conexin
entre las instrucciones de consulta y los datos). Para algunos de los tipos de LINQ, sobre todo
LINQ to Objects, no hay demasiado que conectar, de modo que la consulta es simple. Para
otras variedades de LINQ, sobre todo del tipo de base de datos, debe crear clases intermedias
que unan sus solicitudes de datos. LINQ es una tecnologa genrica que puede interactuar con
cualquier dato una vez que proporcione el pegamento. Y ese pegamento puede ser muy firme,
en ocasiones.
Como ejemplo, considere LINQ to SQL. Esta implementacin de LINQ necesita una clase que
representa las tablas y los registros que consultar mediante LINQ. No es difcil crear esta clase,
y se parecen mucho a las tablas originales de base de datos. Sin embargo, si modifica la estructura
de su tabla, necesitar modificar la clase intermedia para aprovechar los cambios a la tabla. Es
una tarea que de todos modos necesitara hacer, aun sin LINQ, pero es algo que debe tener en
mente cuando considere la manera de que los programadores aprovechan LINQ.
La naturaleza intermedia de LINQ tambin significa que algn procesamiento de datos puede
ser ms lento cuando se compara con la realizacin de la misma tarea sin LINQ. Capas adiciona-
les de datos y cdigo significan trabajo adicional para su equipo. Pero eso ya es vida en el mundo
de .NET Framework, de modo que yo no evitara LINQ debido a ello.

Qu es LINQ? | 449

17_PATRICK-CHAPTER_17.indd 449 17/2/10 15:29:26


Tecnologas de soporte
LINQ es algo importante para Microsoft y para .NET Framework. La mayor parte de las nuevas
caractersticas agregadas a la edicin 2008 de Visual Basic se introdujeron principalmente para
dar soporte a LINQ. Antes de usar LINQ, echemos un vistazo a las tecnologas que lo hicieron
posible.
Expresiones de consulta, el corazn de los datos mediante LINQ. En este captulo se
analizan expresiones de consulta de manera detallada.
Expresiones lambda, analizados en el captulo 9.
Mtodos de extensin, cubiertos en el captulo 12.
Inferencia de tipo local, analizado en el captulo 6.
Tipos annimos, algo que es nuevo para Visual Basic en 2008, pero tambin algo que ya he
analizado. Le dar los detalles despus de esta lista.
Delegados relajados, una caracterstica que le permite a Visual Basic hacer suposiciones
informadas sobre la coincidencia entre un mtodo y un delegado. Es similar a la inferencia
de tipo, pero para delegados en lugar de tipos simples.
Soporte a literales XML, propiedades de eje XML, expresiones incrustadas XML y espacio
de nombres XML dentro de su cdigo fuente. Tal vez recuerde todas estas caractersticas de
lo expuesto en el captulo 13.
Tipos que pueden ser nulos, analizados en el captulo 6, con alguna exposicin extendida en
el captulo de genricos en el captulo 16.
Mtodos parciales, que aparecieron en el captulo 8.
Inicializadotes de objeto, demostrados en el captulo 9.
Otras nuevas caractersticas de lenguaje y compilador que no deben ser importantes porque
no tienen nuevos nombres llamativos.

Tipos annimos
Los tipos annimos son nuevas caractersticas incluidas en Visual Basic para dar soporte a LINQ,
pero puede usarlos tambin en su propio cdigo. Son exactamente lo que indican: tipos sin
nombre. Bueno, eso no es completamente exacto. Los tipos tienen nombres, pero son generados
de manera automtica por el compilador de Visual Basic, y nunca se muestran directamente en
su cdigo fuente.
Considere una clase tpica diseada para contener informacin sobre selecciones de sushi.
Class Sushi
Public NombrePescado As Cadena
Public CostoPorcion As Decimal
End Class

450 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 450 17/2/10 15:29:27


La creacin de una instancia de esta clase es simple.
Dim comidaSabrosa As New Sushi
comidaSabrosa.NombrePescado = "maguro"
comidaSabrosa.CostoPorcion = 3.5@

O, empleando la sintaxis de inicializador de objetos de la que habl en el captulo 9, puede crear


la instancia y rellanar sus campos, en una instruccin.
Dim comidaSabrosa As New Sushi With { _
.NombrePescado = "maguro", .CostoPorcion = 3.5@}

Los tipos annimos toman esta tersa sintaxis y la llevan un paso adelante al dejar fuera por com-
pleto el nombre de la clase.
Dim comidaSabrosa = New With { _
.NombrePescado = "maguro", .CostoPorcion = 3.5@}

La instancia comidaSabrosa es ahora una instancia de una clase con dos miembros, una cadena
llamada NombrePescado y un valor decimal llamado CostoPorcion. Lo nico que no tiene es
un nombre de clase que usted conozca. Pero Visual Basic sabe lo que es.
Slo por diversin compil el ltimo bloque de cdigo y busqu el nombre del tipo generado.
Helo aqu:
VB$AnonymousType_0`2<T0,T1>

Hmm. An pienso que el sushi sabe mejor. Lo que es realmente interesante es que Visual Basic
cre un tipo genrico con dos tipos de marcadores de posicin de parmetros: T0 (tal vez vincu-
lado con el miembro de cadena NombrePescado) y T1 (tal vez el decimal CostoPorcion).
Los tipos annimos son usuarios importantes de la inferencia de tipo. Visual Basic est adivinan-
do el tipo de datos de cada miembro con base en los datos que proporcione con cada nombre. En
las instancias del sushi, el miembro CostoPorcion es de tipo Decimal con base en las literales
decimales proporcionadas con la definicin de instancia.

LINQ to Objects
LINQ le permite consultar datos de muchas fuentes de datos diferentes, y cada interaccin
de LINQ a datos es administrada por un proveedor de LINQ. Present a los proveedores inclui-
dos con Visual Basic 2008 un poco antes; todos tienen el nombre LINQ to algo. Para m, el
ms sencillo de los proveedores es LINQ to Objects, designado para interactuar con conjuntos
de objetos en memoria. LINQ to Objects le permite procesar consultas con base en colec-
ciones de objetos, matrices de Visual Basic y cualquier objeto que d soporte a las interfaces
IEnumerable o IEnumerable(De T) de NET, incluidas sus propias colecciones persona-
lizadas. (Varios objetos dentro del mundo de ADO.NET dan soporte a estas interfaces, pero
estos tipos caen bajo el proveedor LINQ to DataSet, que se analiza ms adelante.)
Cuando ejecute consultas de LINQ to Objects, la salida de la consulta es un nuevo conjunto de
objetos que contiene un subconjunto de los datos de objeto de origen. Esto le permite ejecutar

LINQ to Objects | 451

17_PATRICK-CHAPTER_17.indd 451 17/2/10 15:29:27


consultas al decir cosas como Hey LINQ, a partir de la lista de empleados y sus propiedades,
dame slo los nombres de los empleados contratados en los pasados 90 das. Este conjunto de
resultados, una coleccin basada en IEnumerable, puede consultarse adicionalmente o usarse
como lo hara con cualquier otra coleccin en su cdigo Visual Basic.

Aunque LINQ tiene un nmero finito de operadores y palabras clave, pueden


usarse en una rica variedad de combinaciones, slo algunos de los cuales pre-
sentar en este captulo. Para ejemplos adicionales y descripciones de sintaxis,
vea la seccin LINQ de la documentacin de MSDN incluida con su copia de
Visual Studio.

Antes de que entremos en algunos de los proveedores LINQ ms compleja, descubramos la sin-
taxis en las consultas de LINQ empleando LINQ to Objects. En las siguientes secciones usar
dos pequeas colecciones de libros como mis datos de origen de consulta.. He aqu la definicin
de cada libro que incluye unos cuantos miembros razonables:
Class Libro
Public Titulo As String
Public IDAutor As String
Public Paginas As Integer
End Class

Los autores aparecen en una clase separada. Las instancias Libro y Autor coinciden a travs del
campo comn IDAutor.
Class Autor
Public IDAutor As String
Public NombreCompleto As String
End Class

Crear dos pequeas colecciones para administrar los autores y libros.


Dim Escritores As New Generic.List(De Autor)
Dim Biblioteca As New Generic.List(De Libro)

Escritores.Add(New Autor With _


{.IDAutor = "LT", .NombreCompleto = "Tolstoi, Leon"})
Escritores.Add(New Autor With _
{.IDAutor = "LW", .NombreCompleto = "Wallace, Lew"})
Escritores.Add(New Autor With _
{.IDAutor = "JB", .NombreCompleto = "Barrie, J. M."})

Biblioteca.Add(Nuevo libro con _


{.Titulo = "Guerra y paz", _
.IDAutor = "LT", .Paginas = 1424})
Biblioteca.Add(Nuevo libro con _
{.Titulo = "Anna Karenina", _
.IDAutor = "LT", .Paginas = 976})
Biblioteca.Add(Nuevo libro con _
{.Titulo = "Ben-Hur", _

452 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 452 17/2/10 15:29:27


.IDAutor = "LW", .Paginas = 544})
Biblioteca.Add(Nuevo libro con _
{.Titulo = "Peter Pan", _
.IDAutor = "JB", .Paginas = 192})

Para facilitar nuestra comprensin de la salida de cada consulta, pretendamos que he escrito un
mtodo que despliegue los resultados de cualquier consulta en un formulario de tabla. Llamar
a la rutina MostrarResultados.

Expresiones bsicas de consulta


Las expresiones LINQ estn integradas a partir de clusulas de consulta que tienen el mismo
aspecto que las clusulas en instrucciones SQL en el nivel de la base de datos. Con excepcin
de la clusula From, que debe aparecer primero, las dems suelen aparecer en cualquier orden
dentro de la consulta.

La clusula From
Toda consulta bsica a LINQ empieza con la palabra clave From.
Dim bolsaDeLibros = From lb En Biblioteca
MostrarResultados(bolsaDeLibros)
' Resultados --> Guerra y paz LT 1424
' Anna Karenina LT 976
' Ben-Hur LW 544
' Peter Pan JB 192

Estas cuatro palabras son la consulta LINQ ms corta que puede escribir. Almacen los resulta-
dos de la consulta en la variable bolsaDeLibros (con su tipo de datos inferido por la consulta),
pero la consulta tambin puede usarse directamente como una expresin.
MostrarResultados(From lb In Biblioteca)

La variable lb incluida en la consulta es conocida como variable de rango o variable de iteracin.


(No tiene que usar lb; slo escog el nombre al azar. Es una variable, as que dle cualquier
nombre que desee.) Esta variable proporciona una manera de identificar objetos y miembros de
objetos de los datos de origen dentro de la consulta. Como Biblioteca es una coleccin, no
tendra sentido decir Biblioteca.Titulo cuando se haga referencia al titulo de un solo libro.
En cambio, har referencia a lb.Titulo.
De manera personal, encuentro esta sintaxis variable In source un poco indirecta.
Prefiero con mucho la sintaxis de alias de tabla usada en las consultas SQL.
SELECT * FROM Biblioteca AS lb

La palabra clave AS de SQL realiza casi la misma funcin que la palabra clave In en LINQ. Sin
embargo, a pesar de mi tensin interna, prevalece la sintaxis In; no puede usar la sintaxis AS en
LINQ porque la palabra clave As en Visual Basic se usa para asignacin de tipos de datos.

Expresiones bsicas de consulta | 453

17_PATRICK-CHAPTER_17.indd 453 17/2/10 15:29:27


La clusula Select
Si usa la clusula From en su consulta, devuelve todos los datos del conjunto de objetos original,
incluidos todos los miembros de los objetos. Si quiere limitar los resultados a slo algunos de los
miembros use la clusula Select para identificar los campos que habrn de incluirse.
Dim bolsaDeLibros = From lb In Biblioteca _
Select lb.IDAutor, lb.Titulo
MostrarResultados(bolsaDeLibros)
' Resultados --> LT Guerra y paz
' LT Anna Karenina
' LW Ben-Hur
' JB Peter Pan

El conjunto de resultados de esta nueva consulta omite el conteo de pginas encontrado en


los datos originales. Eso es porque la consulta a LINQ solicit slo los campos IDAutor y
Titulo; el miembro Paginas no se incluye en la clusula Select. Adems, observe que
he invertido el orden de los campos IDAutor y Titulo de la definicin de clase original.
Esta inversin se reflej en los resultados impresos.
Tras bambalinas, LINQ est creando un nuevo tipo annimo que incluye dos miembros: un
campo de cadena IDAutor y uno Titulo. Una instancia de este tipo annimo se crea para cada
registro de consulta resultante. Estas instancias estn incluidas en una nueva coleccin que est
basada en IEnumerable(Of T). Esto le permite usar los resultados de la consulta en una nueva,
o en cualquier cdigo que normalmente interactuara con una coleccin de resultados, como
una instruccin For Each.
Dim bolsaDeLibros = From lb In Biblioteca _
Select lb.IDAutor, lb.Titulo
For Each unResultado En bolsaDeLibros
MsgBox(unResultado.Titulo)
Next unResultado
' El bucle despliega --> Guerra y paz
' Anna Karenina
' Ben-Hur
' Peter Pan

Adems de migrar campos de los objetos originales sobre el conjunto de resultados, puede usar
operadores y funciones para modificar los resultados. En el siguiente ejemplo se usa la funcin
StrReverse para modificar el nombre del ttulo antes de compilar los resultados:
Dim backward = From lb In Biblioteca _
Select StrReverse(lb.Titulo)
MostrarResultados(backward)
' Resultados --> zap y arreuG
' anineraK annA
' ruH-neB
' naP reteP

454 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 454 17/2/10 15:29:27


Aunque estamos muy al principio de nuestro anlisis de LINQ, debe saber
ahora que el trabajo con LINQ requiere una gran cantidad de experimenta-
cin. A pesar de su objetivo de consistencia, LINQ est lleno de sorpresas. Por
ejemplo, en el caso anterior no cre la coleccin de tipo annimo que esperaba.
En cambio, discerni que el conjunto de resultados slo contena cadenas y
cre un conjunto de cadenas simple en lugar de una coleccin de tipos con un
miembro de cadena. Est en guardia contra pequeos golpes como ste cuando
escriba consultas de LINQ.

La clusula Distinct
Como opcin predeterminada, la clusula Select devuelve todos los registros desde el origen.
Obtener informacin completa es algo bueno, pero en ocasiones es demasiado bueno, sobre
todo cuando la informacin contiene duplicados. Por ejemplo, esta consulta devuelve slo el ID
de autor de cada libro disponible:
Dim soloID = From lb In Biblioteca _
Select lb.IDAutor
MostrarResultados(soloID)
' Resultados --> LT
' LT
' LW
' JB

Los resultados estn completos, pero LT apareci dos veces. Dependiendo de sus necesidades,
eso podra ser algo malo. Al agregar la clusula Distinct puede deshacerse de las duplicaciones
innecesarias.
Dim soloID = From lb In Biblioteca _
Select lb.IDAutor _
Distinct
MostrarResultados(soloID)
' Resultados --> LT
' LW
' JB

La palabra clave Distinct busca registros completos de duplicados. Un registro slo se excluye
si todos los campos en ese registro coinciden exactamente con todos los campos de otro.

La clusula Where
Mientras que la clusula Select le permite deshacerse de los campos no deseados, la clusula
Where le permite eliminar objetos completos con base en criterios que usted especifique.
Dim grandesLibros = From lb In Biblioteca _
Where lb.Paginas >= 1000
MostrarResultados(grandesLibros)
' Resultados --> Guerra y paz LT 1424

Expresiones bsicas de consulta | 455

17_PATRICK-CHAPTER_17.indd 455 17/2/10 15:29:27


Esta consulta examina todos los registros de origen entrantes en la coleccin Biblioteca e in-
cluye un objeto de origen en los resultados slo si tiene una cuenta de pginas mayor de 1000.
Las clusulas Where pueden ser complejas, con varios criterios unidos con las palabras clave And
y Or, y agrupadas entre parntesis.
Dim opciones = From lb In Biblioteca _
Where lb.Paginas >= 1000 _
Or (lb.Paginas < 1000 _
And InStr(lb.Titulo, "-") > 0) _
Select lb.Titulo
MostrarResultados(grandesLibros)
' Resultados --> Guerra y paz
' Ben-Hur

La ltima caracterstica tambin mostr cmo incluir caractersticas que no son de LINQ, como
la funcin InStr, en sus criterios, permitindole que restrinja los resultados con base en los
resultados calculados.

La clusula Order By
No se garantiza que los resultados de LINQ, dependiendo del origen de los datos, aparezcan en
un orden particular. Para generar resultados de consulta en un orden especfico, utilice la clu-
sula Order By. Las palabras clave Order By preceden uno o ms campos de origen o valores
calculados, delimitados por comas y, como opcin, puede incluir la palabra clave Ascending
o Descending para invertir el orden de cada campo. (Ascending es la opcin predeterminada
para cada campo.)
Dim bolsaDeLibros = From lb In Biblioteca _
Select lb.Paginas, lb.Titulo _
Order By Paginas Descending
MostrarResultados(bolsaDeLibros)
' Resultados --> 1424 Guerra y paz
' 976 Anna Karenina
' 544 Ben-Hur
' 192 Peter Pan

Los campos incluidos en la clusula Order By deben estar presentes en la clusula Select; deje
fuera el prefijo de la variable de rango (lb en este caso). Si utiliza una clusula From sin una
Select debe incluir el prefijo de la variable de rango en sus campos Order By.

Unin de orgenes
Si slo fuera a consultar datos de una sola coleccin de datos u origen, tal vez no necesitara algo
como LINQ, en primer lugar. Cuando llega el momento de que combine resultados de tablas
diferentes, LINQ proporciona de nuevo una sintaxis parecida a SQL para unir las tablas. En
realidad, proporciona dos variaciones, haciendo paralelo con las variaciones de sintaxis a las que
dan soporte diferentes vendedores SQL.

456 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 456 17/2/10 15:29:27


La primera sintaxis usa la palabra clave Join para especificar un vnculo especfico de un campo. La
siguiente consulta hace una unin interna de las tablas Biblioteca y Escritores en el punto
de conexin esperado IDAutor.
Dim bolsaDeLibros = From lb In Biblioteca _
Join au In Escritores _
On lb.IDAutor Equals au.IDAutor _
Select lb.Titulo, au.NombreCompleto _
Order By lb.Titulo
MostrarResultados(bolsaDeLibros)
' Resultados --> Anna Karenina Tolstoi, Leon
' Ben-Hur Wallace, Lew
' Peter Pan Barrie, J. M.
' Guerra y paz Tolstoi, Leon

Las palabras clave especiales On y Equals ayudan en la sintaxis de unin. Si su unin incluye cla-
ves mltiples puede usar la palabra clave And para especificar los vnculos de claves diferentes.
Dim resultados = From t1 In Tabla1 _
Join t2 In Tabla2 _
On t1.Clave1 Equals t2.Clave1 _
And t1.Clave2 Equals t2.Clave2

La sintaxis de la segunda unin le permite usar la clusula Where para indicar los vnculos del campo.
Dim bolsaDeLibros = From lb In Biblioteca, _
au In Escritores _
Where lb.IDAutor = au.IDAutor _
Select lb.Titulo, au.NombreCompleto _
Order By lb.Titulo
' Mismos resultados que antes

LINQ incluye otra variacin de unin que genera resultados de consulta genricos. En esas con-
sultas, uno de los campos en cada registro resultante ser una coleccin que contiene varios
resultados. Esta sintaxis permite a LINQ devolver una lista de todos los autores, un autor por
fila, donde cada registro de auto incluye un campo libros, posiblemente con varios valores.
Dim librosAutor = From au In Escritores _
Group Join lb In Biblioteca _
On au.IDAutor Equals lb.IDAutor _
Into Publicado = Group _
Select au.NombreCompleto, Publicado _
Order By NombreCompleto
MostrarResultados(librosAutor)
' Resultados --> Barrie, J. M. Peter Pan
' Tolstoi, Leon Guerra y paz
' Anna Karenina
Wallace, Lew Ben-Hur

Esta consulta tiene una sintaxis un poco extraa, pero crea con xito un conjunto de resultados
con dos columnas: NombreCompleto (para el nombre del autor) y Publicado (para la coleccin
de libros publicados por un autor especfico). Para cada registro devuelto, el miembro Publica-
do es una coleccin subordinada que puede procesarse como cualquier otra coleccin.

Expresiones bsicas de consulta | 457

17_PATRICK-CHAPTER_17.indd 457 17/2/10 15:29:27


Skip y Take
La clusula Skip le permite omitir los primeros x registros en el conjunto de resultados, echn-
dolos en realidad a la basura, como cscaras de pltano indeseables. La clusula Take hace justo
lo opuesto, manteniendo slo los primeros registros en los resultados generados. La siguiente
consulta omite los primeros dos registros en la coleccin de datos original, regresando slo los
registros que siguen los valores ignorados:
Dim algunosLibros = From lb In Biblioteca _
Select lb.IDAutor, lb.Titulo _
Skip 2
MostrarResultados(algunosLibros)
' Resultados --> LW Ben-Hur
' JB Peter Pan

Las clusulas Skip While y Take While relacionadas le permiten usar una expresin booleana,
en lugar de un nmero para indicar cundo seguir omitiendo o tomando datos.
Skip y Take son tiles para disponer los resultados en pginas, como cuando se muestra slo
una pgina de resultados a la vez de un conjunto ms largo de resultados consultados. Se puede
usar lgica similar a la siguiente para mostrar slo los registros destinados para PaginaActual:
Dim unaPaginaImportante = From lb In Biblioteca _
Select lb.IDAutor, lb.Titulo _
Skip ElementosPorPagina * PaginaActual _
Take ElementosPorPagina

Una sola advertencia acerca de Skip y Take: s hay diferencias cuando las pone en su consulta.
(Explicar la razn tcnica por la que est en la seccin Ejecucin diferida, ms adelante en este
captulo.) Por ejemplo, considere esta consulta basada en los datos de nuestro libro original:
Dim algunosLibros = From lb In Biblioteca _
Order By lb.Titulo _
Take 2

Esta consulta devuelve Anna Karenina seguida por Ben-Hur, como lo esperara. Pero si mueve
la clusula Take a un lugar anterior, puede obtener un resultado diferente.
Dim algunosLibros = From lb In Biblioteca _
Take 2 _
Order By lb.Titulo

Esta vez, la consulta devuelve Anna Karenina seguida por Guerra y paz. En la primera
consulta, el contenido de Biblioteca se orden por Titulo antes de que se tomaran los dos
registros. En la segunda consulta, los dos registros se tomaron primero, antes de que se aplicara
cualquier ordenamiento.
No slo Take y Skip sufren un impacto por este ordenamiento. Todas las clusulas de su con-
sulta se ven afectadas. Es esencial pensar en la lgica de su consulta, porque una clusula mal
colocada puede darle resultados inesperados.

458 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 458 17/2/10 15:29:27


Conversin de resultados a otras formas
Debido a que los resultados de cualquier consulta de LINQ se adecua a la interfaz IInumerable
(Of T), quedan listas de inmediato para usarse en otras consultas o bsquedas enumerables. Si
necesita acceder a los registros de la forma ms tradicional para otros propsitos, LINQ propor-
ciona unas cuantas caractersticas de conversin que rpidamente mueven los resultados en una
matriz o una coleccin genrica.
Cada resultado de consulta incluye tres mtodos que realizan estas conversiones: ToArray,
ToDictionary y ToList. ToArray convierte los resultados en una matriz estndar de Visual
Basic, con un registro de resultados almacenados en cada elemento de matriz.
Dim resultadosConsulta = From ...
Dim versionMatriz = resultadosConsulta.ToArray(
)

ToList realiza una operacin similar, creando una nueva coleccin Generic.List basada en
los resultados de la consulta. ToDictionary crea una coleccin Generic.Dictionary, pero
debe proporcionar una funcin a ToDictionary que extrae la clave. En la mayor parte de los
casos, bastar una expresin lambda que identifique el campo clave.
Dim autores = From au In Escritores _
Order By au.NombreCompleto
Dim diccAutores = autores.ToDictionary(Function(x) x.IDAutor)
MsgBox(diccAutores("LW").NombreCompleto)
' Resultados --> Wallace, Lew

Consultas agregadas
Las consultas agregadas le permiten sumar informacin de una consulta ms larga en un re-
sultado condensado o nico. En lugar de empezar con la palabra clave From, las consultas agre-
gadas puras empiezan con la palabra clave Aggregate. Cada consulta agregada usa una o ms
funciones agregadas, como la funcin Sum de la siguiente consulta:
Dim librosNum = Aggregate lb In Biblioteca _
Into Sum(lb.Paginas)
MsgBox(librosNum) ' Despliega: 3136

LINQ incluye ochos funciones agregadas estndar, mostradas en la tabla 17-1. Cada funcin
acepta una expresin que indica lo que debe agregarse durante la consulta.
Tabla 17-1. Funciones agregadas estndar.

Funcin Descripcin
All Devuelve un valor booleano que indica si la expresin que le pas es verdadera para todos los registros. La
clusula All(lb.Paginas > 1000) devolvera False porque slo un libro tiene ms de 1000
pginas.
Any Similar a All, pero devuelve True si slo uno de los registros coincide con la expresin de criterios
proporcionada.

Consultas agregadas | 459

17_PATRICK-CHAPTER_17.indd 459 17/2/10 15:29:28


Tabla 17-1. Funciones agregadas estndar (continuacin).

Funcin Descripcin
Average Devuelve el promedio de cualquier expresin que se pase.
Count Devuelve una cuenta de registros con resultados de expresin True. Para devolver una cuenta de todos
los registros en una consulta, use Count(True).
LongCount Igual que Count, pero devuelve Long en lugar de un Integer.
Max Devuelve la expresin numrica mxima a partir del conjunto de registros.
Min Devuelve la expresin numrica mnima a partir del conjunto de registros.
Sum Devuelve la suma de las expresiones numricas a partir del conjunto de resultados.

Si incluye ms de una funcin agregada en la consulta, el conjunto de resultados es un solo regis-


tro que incluye varios campos con nombre. Use un alias antes de la funcin agregada para darle
un nombre. (Los alias estn permitidos en todos los tipos de consultas, no slo agregados.)
Dim librosNum = Aggregate lb In Biblioteca _
Into TotalPages = Sum(lb.Paginas), _
AvgPages = Average(lb.Paginas)
MsgBox(librosNum.AvgPages) ' Despliega: 784

Tambin puede incluir expresiones agregadas en consultas estndar no agregadas. La siguiente


consulta devuelve una cuenta de libros escritos por cada autor, empleando la funcin agregada
Count para sumar los resultados de cada autor:
Dim librosAutor = From au In Escritores _
Group Join lb In Biblioteca _
On au.IDAutor Equals lb.IDAutor _
Into LibrosNum = Count(True) _
Select au.NombreCompleto, LibrosNum _
Order By NombreCompleto
MostrarResultados(librosAutor)
' Resultados --> Barrie, J. M. 1
' Tolstoi, Leon 2
' Wallace, Lew 1

Expresiones de consulta avanzada


Tal vez se est preguntando cundo se mostrarn en mis ejemplos algunas de las nuevas carac-
tersticas de tecnologa como expresiones lambda y mtodos de extensin. Bueno, en cierta
manera, ya lo hicieron. Cuando crea consultas de LINQ empleando expresiones de consulta, el
compilador de Visual Basic convierte lo que escribe en cdigo que usa mtodos de extensin y
expresiones lambda. Podra recordar del captulo 9 que las expresiones lambda se actualizan por
s mismas en el compilador para simplificarse. Una vez que sus consultas se dividan en partculas
subamicas, la CPU est lista para actuar.
Pero no tiene que empezar con consultas completas. Puede crear sus propias consultas em-
pleando mtodos de extensin y expresiones lambda. Los mtodos extendidos en cuestin estn

460 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 460 17/2/10 15:29:28


adjuntos a la interfaz IInumerable. Esto significa que cualquier cosa que parece una coleccin
o matriz puede participar en consultas basados en mtodos de extensin, empleando expresiones
lambda como argumentos.
Convirtamos una de nuestras consultas anteriores en su contraparte de mtodo de extensin.
Dim grandesLibros = From lb In Biblioteca _
Where lb.Paginas >= 1000

Es la consulta que slo devuelve libros grandes. La misma consulta que emplea mtodos de
extensin tiene este aspecto:
Dim grandesLibros = Biblioteca.Where(Function(lb) lb.Paginas >= 1000)

En este ejemplo, el mtodo Where es en realidad un mtodo de extensin de la interfaz IInu-


merable, que tambin incluye Select, OrderBy, Join, GroupJoin, Count, Max, Min y otros
mtodos que corresponden a operadores dentro del lenguaje de consulta LINQ. Como expuse
en el captulo 12 puede agregar sus propios mtodos de extensin en la interfaz IInumerable,
dndole incluso ms manera de personalizar sus consultas de LINQ.

LINQ to XML
En el captulo 13 introduje las literales XML, contenido XML que est incrustado en su
cdigo fuente de Visual Basic. Cuando trae LINQ al frente, de pronto tiene una manera
de generar documentos XML largos al combinar conjuntos de registros con una plantilla de
literal XML.
El siguiente bloque de cdigo crea un documento XML empleando nuestras colecciones Bi-
blioteca y Escritores, entremezclando LINQ y XML de una manera que en realidad hace
que me duela la cabeza:
Dim libroXML As XDocument = _
<?xml version="1.0"?>
<listalibros>
<%= From lb In Biblioteca _
Join au In Escritores _
On lb.IDAutor Equals au.IDAutor _
Order By lb.Titulo _
Select _
<libro>
<titulo><%= lb.Titulo %></titulo>
<autor><%= au.NombreCompleto %></autor>
<paginas><%= lb.Paginas %></paginas>
</libro> _
%>
</listalibros>

libroXML.Save("libros.xml")

Observa cmo debe poner los caracteres de continuacin de lnea en las partes LINQ del
cdigo, pero no en la parte XML? S, y tambin lo odio. Pero genera XML agradable. Si busca

LINQ to XML | 461

17_PATRICK-CHAPTER_17.indd 461 17/2/10 15:29:28


en el archivo libros.xml generados por este cdigo, contiene contenido combinado con xito
del XML y nuestras colecciones originales. Tambin tiene unas bonitas sangras.
<?xml version="1.0" encoding="utf-8"?>
<listalibros>
<libro>
<titulo>Anna Karenina</titulo>
<autor>Tolstoi, Leon</autor>
<paginas>976</paginas>
</libro>
<libro>
<titulo>Ben-Hur</titulo>
<autor>Wallace, Lew</autor>
<paginas>544</paginas>
</libro>
<libro>
<titulo>Peter Pan</titulo>
<autor>Barrie, J. M.</autor>
<paginas>192</paginas>
</libro>
<libro>
<titulo>Guerra y paz</titulo>
<autor>Tolstoi, Leon</autor>
<paginas>1424</paginas>
</libro>
</listalibros>

La clave para entremezclar XML y LINQ es colocar correctamente los marcadores <%= y %>
alrededor del cdigo especfico de LINQ. Si observa con cuidado el ejemplo, ver que hay dos
conjuntos de marcadores, uno dentro de otro.
<%= From ...
<titulo><%= lb.Titulo %></titulo>
... %>

El conjunto externo de marcadores rodea toda la consulta LINQ, mientras que cada conjun-
to interno de marcadores identifica una variable de reemplazo para incluirla en el contenido
XML.
As como es fcil generar XML usando LINQ, es igual de fcil consultar datos de documentos
XML existentes. Recargar el XML que acabamos de guardar nos permite consultar una lista de
ttulos de libros al entremezclar LINQ con propiedades de eje XML.
Dim libroXML As XDocument = _
XDocument.Load("libros.xml")
Dim desdeXML = From bx In libroXML...<libro> _
Select bx.<titulo>.Value
MostrarResultados(desdeXML)
' Resultados --> Anna Karenina
' Ben-Hur
' Peter Pan
' Guerra y paz

462 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 462 17/2/10 15:29:28


LINQ para datos relacionados con ADO.NET
Con el enfoque de ADO.NET en la consulta de datos, es comprensible que haya declarado la
guerra a fondo a su nuevo enemigo, LINQ. Oh, espere, se llam a tregua en la versin Beta 1.
ADO.NET y LINQ ahora funcionan muy bien juntos. En realidad, ADO.NET tiene tres pro-
veedores de LINQ.

LINQ to Entities
Poco despus del lanzamiento de Visual Studio 2008, Microsoft lanz ADO.NET Entity Fra-
mework. Esta interfaz entre su cdigo de programacin y una base de datos le permitir definir
una vista lgica de su sistema. Por ejemplo, puede crear una entidad llamada Order que incluya
sus tablas de cliente, vendedor, encabezado de orden, detalle de orden y productos, todo en una
vista lgica. Los procedimientos almacenados relacionados pueden ser parte del paquete.
El marco conceptual hace toda la magia al crear un conjunto de clases intermedias y contenido
estructurado XML relacionado que administra el vnculo entre las vistas lgicas y fsicas de los
datos. Estas clases pueden usarse entonces en consultas LINQ, y no es necesario que el autor de
las consultas se preocupe de asuntos triviales como conexiones de base de datos y referencias a
claves externas. En realidad, los programadores han estado escribiendo cdigo como ste durante
aos, abstrayendo el modelo de datos fsico en una vista lgica contra la que es ms fcil progra-
mar. Entity Framework simplemente agiliza y facilita la configuracin de este proceso.
El marco conceptual incluye varias herramientas que le ayudan a construir las entidades desde
las estructuras de base de datos de origen. Una herramienta clave es el diseo de modelo de
datos de entidad de ADO.NET (ADO.NET Entity Data Model Designer), una herramienta
visual de arrastrar y colocar que facilita la creacin de entidades como si se tratara de formula-
rios de Visual Basic.
Debido a que ADO.NET Entity Framework sali despus de Visual Studio 2008, no lo estar
demostrando en este libro.

LINQ to DataSet
LINQ es compatible con consultas de registros dentro de tablas de datos de ADO.NET. Los ob-
jetos DataTabla ADO.NET no dan soporte directo a la interfaz IInumerable, y los campos
dentro de estas tablas son, como opcin predeterminada, sin tipo, lo que en realidad enfurece a
LINQ. La nueva funcionalidad LINQ to DataSet supera ambas limitaciones para que funcione
la consulta de conjuntos de datos.
Al principio de este captulo, vimos ejemplos de LINQ que usaban la clase Libro. Mantenga-
mos esos datos de ejemplo, pero pretendamos que los datos aparecen ahora en una instancia
DataTabla de ADO.NET. La tabla tendr cuatro registros (para los cuatro libros de nuestro
ejemplo) y tres columnas: Titulo, IDAutor y Paginas.

LINQ para datos relacionados con ADO.NET | 463

17_PATRICK-CHAPTER_17.indd 463 17/2/10 15:29:28


Class Libro
Public Titulo As String
Public IDAutor As String
Public Paginas As Integer
Ind Class

En lugar de crear una consulta de LINQ to Objects como sta:


Dim opciones = From lb In Biblioteca _
Where lb.Field(Of Integer)!Paginas >= 1000 _
Or (lb.Paginas < 1000 _
And InStr(lb.Titulo, "-") > 0) _
Select lb.Titulo

LINQ to DataSet usa mtodos especficos del objeto de conjunto de datos que fuerzan a los
objetos de ADO.NET en algo con lo que LINQ puede interactuar y en una manera con fuerte
imposicin de tipo.
Dim opciones = _
From lb In libroTabla.AsEnumerable( ) _
Where lb.Field(Of Integer)("Paginas") >= 1000 _
Or (lb.Field(Of Integer)("Paginas") < 1000 _
And InStr(lb.Field(Of String)("Titulo"), "-") > 0) _
Select New With _
{.Titulo = lb.Field(Of String)("Titulo")}

Tiene un aspecto realmente diferente, pero es la misma consulta. La instancia DataTabla de


libroTabla se fuerza primero para que tenga un aspecto como el de una instancia IInume-
rable mediante su mtodo AsInumerable. Luego, a medida que cada campo interviene en la
consulta, su tipo de datos se declara mediante clusulas Of genricas, seguidas por el nombre del
campo entre comillas. Por ltimo, debido a que la consulta no tiene acceso directo a nombres
de campo, el conjunto de resultados se crea empleando la sintaxis de inicializador de objetos. Es
ms un rodeo que LINQ to Objects. Pero si ya tiene datos en objetos de ADO.NET en memo-
ria, LINQ to DataSet es lo que debe usar.
LINQ to DataSet tambin incluye soporte para conjuntos de datos con tipo, conjuntos de
datos que incluyen los metadatos necesarios para describir por completo los tipos de datos
de cada campo. Con los conjuntos de datos con imposicin fuerte de tipo, no necesita tener
constantemente a mano a LINQ mediante clusulas Of tipodatos; LINQ imaginar los cam-
pos por su propia cuenta. Para conocer informacin acerca de la creacin de conjuntos de datos
con tipo, consulte la documentacin de MSDN que se incluye con Visual Studio.

LINQ to SQL
LINQ to SQL es el proveedor que permite que consultas de LINQ interacten con bases de
datos de SQL Server. Debido a que el proyecto Biblioteca usa SQL Server, dedicaremos un poco
ms de tiempo a esta tecnologa. Al igual que con LINQ to Entities, LINQ to SQL funciona
mediante clases intermedias. Aunque podra proporcionar una vista lgica diferente de sus tablas

464 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 464 17/2/10 15:29:28


de datos fsicos usando LINQ to SQL, hay ms de una expectativa de que los objetos de LINQ
to SQL se parecern ms a las tablas de las bases de datos.
LINQ to SQL incluye una herramienta, el diseador relacional de objetos (Object Relational [O/R]
Designer), que le ayudar a crear las clases intermedias. Puede echar un vistazo a la figura 17-2
para ver su aspecto, pero le comento que no es Rembrandt. En realidad, hace un trabajo res-
petable en establecer el vnculo necesario con la base de datos. El diseador O/R es tan simple
como arrastrar y colocar, y es adecuado para bases de datos que no son terriblemente largas. Si
necesita crear las clases de vnculo para un base de datos que tenga, digamos, cientos de tablas,
debe leer sobre la herramienta SqlMetal.exe que se incluye con Visual Studio. Encontrar detalles
completos en la documentacin de MSDN incluida con Visual Studio.
El uso de LINQ to SQL se hace en cinco pasos fciles. Puede seguirlos en un nuevo proyecto de
Windows Forms, si lo desea:
1. Agregue un nuevo archivo dbml. Este archivo (en realidad, unos cuantos archivos que Visual
Studio despliega como uno) describe el contexto de sus datos, la clase maestra que contiene el
cdigo de vnculo para cada tabla de la base de datos que usar en su aplicacin. Para crear este
archivo desde un proyecto de Visual Studio, use el comando de men Proyecto Agregar
nuevo elemento para desplegar el formulario Agregar nuevo elemento. De la categora Datos,
seleccione la plantilla Clases de LINQ to SQL, cambie el nombre del archivo a Biblioteca.dbml
de la opcin predeterminada y haga clic en el botn Agregar (vase la figura 17-1).

Figura 17-1. Adicin de una nueva clase dbml.

Aparece un nuevo elemento Biblioteca.dbml en su proyecto, que abre el diseador O/R,


mostrado en la figura 17-2. Si examina sus propiedades ver que su nombre es BibliotecaDa-
taContext.

LINQ para datos relacionados con ADO.NET | 465

17_PATRICK-CHAPTER_17.indd 465 17/2/10 15:29:29


Figura 17-2. El diseador O/R; no hay mucho que ver por ahora.

2. Agregue tablas al diseador O/R. Abra el Explorador de servidores en Visual Studio.


(Seleccione el comando de men Ver Explorador de servidores para encontrarlo.) Debe
ver ya un vnculo con la base de datos Biblioteca en la parte Conexiones de datos del rbol
Explorador de servidores, porque lo creamos en un captulo anterior. Se llamar algo como
miservidor\sqlexpress.Biblioteca.dbo. Expanda la rama del rbol y luego la rama Tablas debajo
de l. Deben aparecer todas las tablas de la base de datos Biblioteca.
Arrastre y coloque la tabla Actividad del Explorador de servidores en la mitad izquierda
del diseador O/R. Tarde o temprano, una imagen de la tabla debe aparecer en la pantalla
(vase la figura 17-3).

Figura 17-3. La familiar tabla Actividad y sus campos (propiedades).

466 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 466 17/2/10 15:29:30


3. Genere su aplicacin. He encontrado que este paso es necesario en algunas instalaciones
de Visual Studio, pero no en otras. Actualiza la vista de Visual Basic de las nuevas clases
de BibliotecaDataContext. Para generar la aplicacin seleccione el comando de men
Generar Generar WindowsAplicacin1.
4. Abra el contexto de datos personalizados. El cdigo generado por el diseador O/R define la
interaccin entre su programa y la base de datos, pero an debe especificar la conexin de
base de datos cuando ejecute su aplicacin, slo en caso de que algo cambie en el camino.
Agregue un nuevo contol Button a Form1, luego agregue el siguiente cdigo a manejador
de eventos Click a ese botn:
Dim BibliotecaBD As New SqlClient.SqlConnection( _
"Data Source=miservidor\sqlexpress;" & _
"Initial Catalog=Biblioteca;Integrated Security=true")
Dim vinculoBiblioteca = New BibliotecaDataContext(BibliotecaBD)

Reemplace miservidor en el cdigo con el nombre de su propio sistema, y actualice las


configuraciones de seguridad si usa autentificacin de SQL Server.
5. Escriba consultas. Ya est listo para disear sus consultas LINQ. He aqu algn cdigo que
obtiene las primeras cinco actividades de la tabla Actividad y las ordena:
Dim actividades = From act In vinculoBiblioteca.Actividades _
Where act.ID <= 5 _
Order By act.NombreCompleto
For Each unElemento In actividades
MsgBox(unElemento.ID & ": " & unElemento.NombreCompleto)
Next unElemento
' Mensajes --> 2: Administrar tipos de autor y nombre
' 1: Administrar autores y nombres
' 3: Administrar codigos de estado de copia
' 4: Administrar tipos de medios
' 5: Administrar series

Si hace clic en el botn Mostrar todos los archivos en el Explorador de soluciones, puede acceder
al archivo de diseador .dbml, Biblioteca.designer.vb. Este archivo contiene las clases intermedias
generadas usando LINQ to SQL. En cuanto al uso de la tabla Actividad en nuestras consultas
LINQ, he aqu las partes relevantes del cdigo fuente autogenerado:
<System.Datos.Linq.Mapping.DatabaseAttribute(Name:="Biblioteca")> _
Partial Public Class LibraryDataContext
Inherits System.Datos.Linq.DataContext

Public ReadOnly Property Actividades(


) _
As System.Data.Linq.Tabla(Of Actividad)
Get
Return Me.GetTabla(Of Actividad)
End Get
End Property
End Class

LINQ para datos relacionados con ADO.NET | 467

17_PATRICK-CHAPTER_17.indd 467 17/2/10 15:29:30


<Table(Name:="dbo.Actividad")> _
Partial Public Class Actividad
Private _ID As Long
Private _NombreCompleto As String
<Column(Storage:="_ID", DbType:="BigInt NOT NULL", _
IsPrimaryClave:=true)> _
Public Property ID() As Long
Get
Return Me._ID
End Get
End Property

<Column(Storage:="_NombreCompleto", _
DbType:="VarChar(50) NOT NULL", CanBeNull:=false)> _
Public Property NombreCompleto() As String
Get
Return Me._NombreCompleto
End Get
End Property
End Class

La clase BibliotecaDataContext implementa un contexto de datos de LINQ personalizado


que parece, bueno, una miniversin de mi base de datos. Contiene referencias a esas tablas que
eleg incluir en el vnculo; todas las tablas de Biblioteca apareceran en esta clase si las hubiera
seleccionado. De modo que, cuando hago referencia a vinculoBiblioteca.Actividades en
la consulta LINQ de ejemplo, haca referencia al miembro Actividades pblico del contexto
de datos.
La tabla Actividad expone distintas propiedades que coinciden con los campos de la base de
datos. As que en realidad no es una sorpresa que pueda consultar estas clases mediante LINQ,
tal como lo hago con cualquier clase de tipo LINQ to Objects. Pero hay una parte extraa
acerca de la manera en que la clase en realidad obtiene los datos de la base de datos. sa es la
parte oculta de LINQ to SQL, manejado a travs de la clase DataContext base y los atributos
relacionados del espacio de nombres System.Datos.Linq.Mapping.

Tras bambalinas, LINQ to SQL est generando regularmente instrucciones


SQL para consulta y actualizacin de registros en las tablas de la base de datos
reales. Puede examinar estas consultas generados usando la herramienta SQL
Quero Debug Visualizer. No viene con Visual Studio, pero puede descargarla
del sitio Web MSDN de Microsoft.

Ejecucin diferida
Cuando construye una consulta de LINQ, Visual Basic no la procesa de inmediato. En cambio,
difiere la ejecucin, ejecutando la consulta slo cuando solicite un registro de los resultados. Esto
le permite generar una consulta en partes, y no tiene que consumir ciclos de CPU hasta que en
realidad necesita los datos finales.

468 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 468 17/2/10 15:29:30


' CUIDADO: Ejemplo simplista.
Dim algunosLibros = From lb In Biblioteca _
Select lb.Titulo, lb.Paginas
Dim titulosOrdenados = From lb In algunosLibros _
Order By lb.Titulo

En este cdigo, el ordenamiento de los registros no sucede hasta la segunda instruccin. Pero eso
no importa porque nada se procesa en realidad en la primera instruccin. Recuerde que LINQ
slo est en realidad convirtiendo sus consultas en mtodos de extensin y expresiones lambda.
La asignacin de algunosLibros est haciendo algo como esto:
algunosLibros = Biblioteca.Select("Titulo, Paginas")

La asignacin de titulosOrdenados simplemente extiende algunosLibros:


titulosOrdenados = _
Biblioteca.Select("Titulo, Paginas").OrderBy("Titulo")

El procesamiento real ocurre cuando solicita un registro de titulosOrdenados. Por proce-


samiento, me refiero a que cada mtodo de extensin se ejecuta en el origen de datos original
Biblioteca en orden, de izquierda a derecha. Para titulosOrdenados, los datos de Biblio-
teca original se reducen a travs del mtodo Select y luego se modifica an ms mediante el
mtodo OrderBy.
Hacer que los mtodos se procesen de izquierda a derecha explica por qu el orden de clusulas
como Skip y Take es tan importante. La expresin
Biblioteca.Take(2).Skip(2)

es diferente de
Biblioteca.Skip(2).Take(2)

Resumen
Esa fue una revisin general rpida de LINQ con algunas de las permutaciones de su primer lan-
zamiento. Parece mucho, pero slo he cubierto los aspectos bsicos. Adems de consultar datos,
tambin puede actualizar los datos almacenados mediante instrucciones LINQ especialmente
creadas. Y la capacidad de crear su propio proveedor de LINQ significa que los almacenes de
tipos de datos que LINQ puede procesar son ilimitados.
La principal desventaja de LINQ es que, sobre todo para LINQ to SQL, las instrucciones SQL
y el cdigo MSIL que LINQ genera al final de cuentas con base en su consulta tal vez no ser
tan eficiente como el que podra crear por su cuenta. Algunas de sus consultas LINQ pueden
ejecutarse tan lentamente que no tiene otra opcin que reemplazarlas con caractersticas previas
a LINQ. Pero para los propsitos de consulta ms comunes, sobre todo entre orgenes de datos
divergentes, LINQ es un paso gigante hacia delante.

Resumen | 469

17_PATRICK-CHAPTER_17.indd 469 17/2/10 15:29:30


Proyecto
En este captulo finalmente se agrega lo que muchos consideran el corazn de un sistema de
biblioteca, la bsqueda de libros y otros artculos de biblioteca por parte de los clientes.

ACCESO AL PROYECTO
Cargue el proyecto Cap17 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap17 (Final) cdigo.

Bsqueda de artculos de Biblioteca


Cuando construimos el formulario principal Biblioteca en el captulo 7, incluimos campos que
permitan que un cliente buscara elementos de la biblioteca. Pero es todo lo que hicimos; no
habilitamos los campos y no les dimos capacidad de uso. Tampoco incluimos algn lugar para
desplegar una lista de elementos coincidentes. Completaremos estos componentes en este cap-
tulo. Empezaremos con la lista de elementos coincidentes.
He agregado un formulario al proyecto, llamado BusquedaArticulos.vb, que despliega los resul-
tados de una bsqueda de elementos de biblioteca. Incluye unos cuantos botones en la parte
superior del formulario y tres paneles de despliegue principales:
PanelCoincidencias
Contiene un cuadro de lista grande que despliega coincidencias que no son de artculos. Por
ejemplo, despliega una lista de nombres de autor o editor coincidentes mientras un cliente
hace una bsqueda. Cuando aparece este panel, el cliente selecciona una coincidencia de
la lista CoincidenciaGeneral, y hace clic en el botn Buscar para desplegar elementos
unidos a esa entrada de autor, editor o de otro tipo.
PanelArticulos
Contiene un cuadro de lista grande que despliega artculos de la tabla de base de datos Ar-
ticuloConNombre. Es decir, despliega una lista de artculos de la biblioteca que coinciden
con algn criterio. Al seleccionar un artculo de la lista ArticulosCoincidentes y al hacer
clic en el botn Buscar se despliegan los detalles de ese artculo.
PanelUnArticulo
Contiene un control WebBrowser que despliega detalles acerca de un solo elemento de la
biblioteca. El contenido de detalle est construido usando HTML estndar, y puede con-
tener vnculos que regresan al panel PanelArticulos con un nuevo conjunto de artculos
coincidentes desplegado. Por ejemplo, si est viendo los detalles de un libro sobre programa-
cin en Visual Basic 2008 que ha ganado premios (como podra esperarse) y hace clic en el
nombre del editor de ese artculo, aparece el panel PanelArticulos, con una lista de todos
los artculos producidos por ese editor.

470 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 470 17/2/10 15:29:30


El formulario tambin incluye un conjunto de botones Atrs (en la esquina superior izquier-
da) que funcionan como el botn Atrs de su explorador Web, un botn Cerrar que regresa al
formulario principal, y un men (MenuAtras), usado para dar soporte a las caractersticas del
botn Atrs. En la figura 17-4 se muestra el formulario con el panel PanelArticulos al frente,
porque parece un poco ms interesante que los otros dos paneles.

Figura 17-4. El panel de artculos coincidentes, con encabezados de columnas .

El cdigo fuente relacionado tiene alrededor de 1000 lneas, muchas de ellas concentradas en
llenar los dos cuadros de lista y el contenido de detalle de HTML. La bsqueda realizada en el
formulario principal llama a este formulario de bsqueda mediante el mtodo IniciarBusque-
da. La bsqueda real en la base de datos de artculos coincidentes ocurre en el mtodo Reali-
zarBusqueda, que es llamado por IniciarBusqueda. RealizarBusqueda incluye consultas
LINQ que viajan a la base de datos Biblioteca y de regreso mediante el proveedor LINQ to SQL.
Se incluyen consultas para todos los tipos diferentes de bsquedas: ttulo, autor, tema, palabra
clave, editor, serie, cdigo de barras y algunas bsquedas de nmero de ID, principalmente para
uso interno. El tipo de bsqueda realizado determina cul de los tres paneles se despliega (por
medio de la variable tipoResultado). Una bsqueda de autor despliega el PanelCoinciden-
cias con una lista de nombres de autor coincidentes; una bsqueda de ttulo despliega elemen-
tos coincidentes en el panel PanelArticulos.
Antes de que revisemos el cdigo LINQ necesitamos configurar algunas cosas en el resto de la
aplicacin para que d soporte a estas nuevas consultas LINQ. He deshabilitado el archivo Bus-
quedaArticulos.vb de la compilacin por ahora porque slo generara errores al generarse.
Aunque LINQ to SQL es sorprendente, aun requiere el toque humano (es decir, el suyo) para
ayudarle a localizar las tablas de la base de datos de SQL Server. Usaremos el diseo relacional de
objetos con el que jugamos antes en este captulo. Seleccione el comando Proyecto Agregar
nuevo elemento del men de Visual Studio. En el cuadro de dilogo Agregar nuevo elemen-
to, seleccione Datos de la lista Categoras, seleccione Clases de LINQ to SQL del campo Plan-
tillas y escriba Biblioteca.dbmlen el campo Nombre antes de hacer clic en el botn Agregar.
Aparece una ventana de diseador O/R.

Proyecto | 471

17_PATRICK-CHAPTER_17.indd 471 17/2/10 15:29:31


Abra el Explorador de servidores y busque la base de datos Biblioteca. De la rama Tablas, arrastre
y coloque las siguientes tablas en la mitad izquierda de la ventana del diseador O/R:
Autor
CodigoTipoMedio
CodigoSerie
AutorArticulo
CopiaArticulo
ClaveArticulo
TemaArticulo
Clave
ArticuloConNombre
Editor
Tema
Correctamente, el diseador analizar las relaciones entre las tablas y mostrar lneas de vnculos
entre las referencia externas. Puede reorganizar las tablas segn sea necesario para verlas mejor, o
mantenerlas apiladas, si lo desea; no soy su madre. Pero tal vez tenga que hacer algunos pequeos
cambios en los nombres de las tablas. El diseador O/R trata de ser realmente inteligente, cam-
biando cualquier nombre de tabla en plural, si encuentra un singular equivalente. (Por tradicin,
los nombres en singular se prefieren cuando se disean tablas de base de datos.) Por desgracia,
si hubiramos llamado a una tabla, por ejemplo, CodigoSeries, la hubiera cambiado a Codi-
goSerie. Es adecuado, pero no tiene sentido. En ese caso, seleccionara la tabla y cambiara la
propiedad Name a CodigoSeries en el panel Propiedades.
Si se hubiera hecho un cambio, eso restablecera los nombres de tablas a sus races, pero eso tam-
poco sera bueno. El problema es que se usaron algunos de esos nombres de tablas para nombres
de formularios en la aplicacin Biblioteca. Las clases en conflicto se encuentran en espacio de
nombres diferentes, de modo que el cdigo podra compilarse, pero tendramos que escribir
una gran cantidad de espacio de nombres cuando se identifiquen esas clases, y soy un poco pe-
rezoso para ello. Para eliminar cualquier posible conflicto, decid arbitrariamente aadir la letra
Q al principio de cada nombre de tabla LINQ a SQL. En el diseador, seleccione cada tabla
y cambie su nombre, agregando una Q al principio. CodigoSerie se vuelve QCodigoSerie;
AutorArticulo se vuelve QAutorArticulo, etc. Cuando haya terminado debe tener una vista
de diseador parecida a la de la figura 17-5.
A pesar de trabajar duro para asegurar que todos los nombres evitan conflictos y que estn en
singular, cuando usemos el contexto de datos en biblioteca en nuestras consultas LINQ, encon-
traremos que todos los nombres de clase para esas tablas generadas con LINQ a SQL estn de
alguna manera en plural (QEditores en lugar de QEditor). Sorprendente.

472 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 472 17/2/10 15:29:31


Figura 17-5. Las tablas con sus nuevos nombres.

De regreso al cdigo del proyecto del captulo 12 agregamos un mtodo de extensin a la clase Sql-
Client.SqlDataReader que forma un nombre de autor a partir de una consulta de base de datos.
<System.Runtime.CompilerServices.Extension(
)> _
Public Function FormarNombreAutor ( _
ByRef infoBD As SqlClient.SqlDataReader) As String

Proyecto | 473

17_PATRICK-CHAPTER_17.indd 473 17/2/10 15:29:31


Por desgracia, esta rutina slo es til con objetos de SqlDataReader. En la rutina Realizar-
Busqueda que estamos por agregar, necesitamos formar los nombres de autor de una consulta
LINQ de registros de tabla QAutor. Supongo que necesitaremos otro mtodo de extensin para
ese tipo de objeto. Abra el archivo de cdigo fuente General.vb y agregue un nuevo mtodo
FormarNombreAutor al mdulo General. Aqu aparece parte del cdigo.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap17, Elemento 1.

<System.Runtime.CompilerServices.Extension(
)> _
Public Function FormarNombreAutor( _
ByVal autor As QAutor) As String
' ----- Dado el registro de un autor, regresar el nombre formado.
Dim nombreAutor As String

On Error Resume Next

' ----- Formar el nombre.


nombreAutor = CStr(autor.Apellido)
If (autor.Nombre IsNot Nothing) Then
nombreAutor &= ", " & autor.Nombre
If (autor.Inicial IsNot Nothing) Then _
nombreAutor &= " " & autor.Inicial
End If
If (autor.Sufijo IsNot Nothing) Then _
nombreAutor &= ", " & autor.Sufijo

...se ha omitido codigo para ser breve...

' ----- Terminado.


Return nombreAutor
End Function

Si compara este cdigo fuente con la versin SqlDataReader encontrar que esta versin es
mucho ms limpia, porque hace referencia a miembros de clase en lugar de campos de base de
datos mediante un lector. Gracias LINQ!
Esto es todo en cuanto a los cambios en el soporte de LINQ. Habilite el archivo BusquedaArti-
culos.vb al seleccionarlo en el panel Explorador de soluciones y cambiando su propiedad Accin
de compilacin de Ninguna a Compilacin. Ahora regresemos al cdigo en ese archivo.
La rutina RealizarBusqueda consta principalmente de una gigantesca instruccin If, con di-
ferentes condiciones para la mayor parte de los tipos diferentes de bsqueda. La ltima clusula
Else maneja todas las bsquedas que se rellenarn en la lista del panel PanelArticulos del
formulario. sa es la lista que muestra los artculos reales. Tambin contiene una gran cantidad
de instrucciones If. Pero lo realmente estupendo es su consulta LINQ consulta. En lugar de slo
escribir una consulta simple, es una consulta compleja que se construye poco a poco. La consulta
empieza con los fundamentes, solicitando registros coincidentes de la tabla ArticuloConNombre

474 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 474 17/2/10 15:29:32


de la base de datos. (La variable bibliotecaDC es el contexto de datos abierto para la base de
datos Biblioteca.)
Dim consultaArticulo = From ni In bibliotecaDC.QArticuloConNombre

A continuacin, si el usuario solicit artculos de un tipo de medio especfico (slo mustrame


DVD coincidentes, no libros), la consulta se actualiza con la clusula Where apropiada.
If (LimitarPorMedio <> -1) Then
' ----- Limitar a un tipo de medio especifico.
consultaArticulo = From ni In consultaArticulo _
Where ni.TipoMedio = LimitarPorMedio
End If

El tipo de bsqueda tambin ajusta la consulta. Por ejemplo, una bsqueda por palabra clave
agrega palabra claves especificadas por el usuario como criterio.
conjuntoClaves = New Generic.List(Of String)
conjuntoClaves.AddRange(Split(buscarTexto.ToUpper, ","))
consultaArticulo = From ni In consultaArticulo _
Let conjuntoClave = (Aggregate ik In ni.QClaveArticulo _
Into Any(conjuntoClaves.Contains( _
ik.QClave.NombreCompleto.ToUpper))) _
Where conjuntoClave = True _
Select ni

Esa adicin us una subconsulta Aggregate dentro de la consulta principal. La palabra clave
Let, parte de LINQ, asigna una subconsulta u otro tipo de resultado a una variable temporal
dentro de la consulta (conjuntoClave en este caso) de modo que puede hacerse referencia des-
de cualquier lugar de la consulta.
Una vez que se han agregado las clusulas Where se ordena y usa toda la consulta.
consultaArticulo = From ni In consultaArticulo _
Order By ni.Titulo, ni.Subtitulo

Algunas de las consultas LINQ de la rutina RealizarBusqueda son muy sencillas. He aqu el
cdigo que hace una bsqueda del nombre del editor:
' ----- Preparar la consulta para una busqueda de editor.
contenerTexto = Trim(buscarTexto)
If (InStr(contenerTexto, "*") = 0) Then contenerTexto &= "*"
Dim consultaEditor = From pb In bibliotecaDC.QEditor _
Where pb.NombreCompleto Like contenerTexto _
Order By pb.NombreCompleto

No parece muy diferente de lo que esperara de una consulta SQL. Algo agradable es que los
comodines usan el carcter * en lugar del carcter % estndar de SQL.
Despus de procesar esta consulta, los resultados LINQ se rastrean y los registros se mueven a la
lista CoincidenciaGeneral.
For Each articuloPublicado In consultaEditor
CoincidenciaGeneral.Items.Add(New DatosListaElementos ( _
articuloPublicado.NombreCompleto, CInt(articuloPublicado.ID)))

Proyecto | 475

17_PATRICK-CHAPTER_17.indd 475 17/2/10 15:29:32


coincidencias += 1
Next articuloPublicado

Esto es slo ms del mismo cdigo que ha visto en captulos anteriores. Carga el control List-
Box con objetos DatosListaElementos, cada uno con un nombre de despliegue y un nmero
de ID de la base de datos. Eso es adecuado para una lista con requisitos de despliegue simples.
Pero si revisa la figura 17-4, queda claro que queremos algo un poco ms interesante para la lista
de artculos coincidentes. Queremos columnas, y las columnas requieren datos razonables.
Para almacenar estos datos haremos una nueva clase, llamada DatosArticulosCoincidentes,
que funciona como DatosListaElementos, pero con ms campos de datos.
Private Class DatosArticulosCoincidentes
Public IDArticulo As Integer ' ArticuloConNombre.ID
Public Titulo As String
Public Subtitulo As String
Public Autor As String
Public TipoMedio As String
Public NumeroLlamada As String

Public Overrides Function ToString( ) As String


' ----- Generar una cadena de despliegue simple.
If (Subtitulo = "") Then
Return Titulo & ", by " & Autor
Else
Return Titulo & ": " & Subtitulo & ", by " & Autor
End If
End Function
End Class

Como esta clase se usar slo para desplegar artculos coincidentes en este formulario, la he he-
cho subordinada dentro de la clase del formulario ms grande BusquedaArticulos. El mtodo
ToString da salida al texto que aparece en la lista. No generaremos la salida en columna real
hasta el siguiente captulo. Por ahora slo desplegaremos el ttulo y autor.
Los paneles PanelCoincidencias y PanelArticulos incluyen un botn Buscar que inicia
una nueva llamada a RealizarBusqueda con base en el artculo seleccionado en la lista. El
botn Buscar del panel PanelArticulos recupera el objeto DatosArticulosCoincidentes
seleccionado de la lista y realiza la nueva bsqueda.
Private Sub AccBuscarArticulo_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles AccBuscarArticulo.Click
' ----- Buscar el articulo con el ID seleccionado.
Dim idArticulo As Integer

' ----- Ignorar si no se ha seleccionado una coincidencia.


If (ArticulosCoincidentes.SelectedIndex = -1) Then Return
idArticulo = CType(ArticulosCoincidentes.SelectedItem, _
DatosArticulosCoincidentes).IDArticulo

476 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 476 17/2/10 15:29:32


' ----- Realizar la bsqueda.
If (RealizarBusqueda(MetodosBusqueda.PorIDBaseDatos, _
CStr(idArticulo), False) = False) Then Return

' ----- Almacenar la historia.


AgregarHistoriaBusqueda(MetodosBusqueda.PorIDBaseDatos, CStr(idArticulo))
End Sub

La llamada a RealizarBusqueda inicia el proceso de nuevo.

Mantenimiento del historial de bsqueda


Digamos que tiene un cliente con mucho tiempo entre manos y que quiere buscar el libro
Guerra y paz.
Empezando desde IniciarBusqueda y pasando al cdigo RealizarBusqueda, la bsque-
da del ttulo inicial (Guerra y paz) despliega una lista de ttulos coincidentes en el panel
PanelArticulos.
El cliente localiza el libro en la lista, y hace clic en el botn Buscar, que llama al manejador
de eventos AccBuscarArticulo_Click.
Este manejador de eventos, a su vez, llama de nuevo a RealizarBusqueda, esta vez haciendo
una bsqueda precisa con base en el ID de datos dentro de la tabla ArticuloConNombre.
El detalle del artculo aparece en el panel PanelUnArticulo. (Analizar cmo hace esto
ms adelante en este captulo.)
El detalle incluye un vnculo a Tolstoi, Leon, el sufrido autor del libro. Cuando el cliente hace
clic en este vnculo, inicia otra llamada a RealizarBusqueda, esta vez por ID de autor.
Regresamos al panel PanelArticulos, viendo una lista de libros y otros artculos de
Tolstoi, suponiendo que tuviera tiempo de escribir algo ms.
De este modo, ahora el cliente tiene una experiencia con tres paneles de bsqueda: 1) una lista
general de ttulos que coinciden en el nombre Guerra y paz; 2) el despliegue del detalle
para el artculo Guerra y paz seleccionado, y 3) una lista de artculos de libros escritos por
Len Tolstoi. La caracterstica historia incluida en este formulario le permite al cliente regresar a
la pgina de bsqueda previa, al igual que las caractersticas en su explorador Web.
Es posible que algunas de las bsquedas realizadas pudieran regresar cientos de resultados. No
queremos almacenar todo ese contenido en la memoria, porque es posible que el cliente nunca
use el botn Atrs. En cambio, haremos lo que hace su explorador Web: almacenar la informa-
cin mnima necesaria para realizar de nuevo la consulta. Su explorador Web slo mantiene el
nombre y el URL de rutas visitadas en su lista atrs. (Archivos y cach de imagen no son parte
de la caracterstica de historia.) El formulario BusquedaArticulos.vb slo necesita almacenar esos
valores que necesita RealizarBusqueda para realizar de nuevo la bsqueda: el tipo de bsqueda
y los criterios numricos o de texto usados en la bsqueda.

Proyecto | 477

17_PATRICK-CHAPTER_17.indd 477 17/2/10 15:29:32


Se accede a la historia del cliente en una base ltimo en entrar, primero en salir. La pgina
vista ms recientemente es la que el cliente quiere ver cuando usa el botn Atrs. Analizamos la
estructura tipo ltimo en entrar, primero en salir o LIFO en el captulo 16: la pila. Cada vez
que el usuario ve un panel, tomamos nota de ello, obteniendo slo los valores que necesitamos al
final en la pila. Cuando el usuario quiere ver la historia, tomaremos el contenido ms reciente de
la pila y actualizaremos el despliegue.
La clase HistoriaBusquedaArticulos, otra clase subordinada dento de la clase BusquedaAr-
ticulos, almacena los valores que necesitamos para administrar la historia en la pila.
Private Class HistoriaBusquedaArticulos
Public DesplegarHistoria As String
Public TipoBusqueda As Biblioteca.MetodosBusqueda
Public DatosBusqueda As String
End Class

DesplegarHistoria proporciona un nombre de despliegue corto para ayudar al usuario a


rastrear la historia. TipoBusqueda y DatosBusqueda son los valores que se pasaron a Reali-
zarBusqueda. Todo es muy bonito. Para hacer las cosas ms limpias, usaremos una pila para
almacenamiento real. Se declara como un campo de la clase BusquedaArticulos.
Private ConjuntoHistoriaBusqueda As _
Collections.Generic.Stack(Of HistoriaBusquedaArticulos)

A medida que el cliente visita cada panel, las llamadas al mtodo AgregarHistoriaBusqueda
llenan la pila con cada artculo nuevo visitado.
Private Sub AgregarHistoriaBusqueda( _
ByVal tipoBusqueda As Biblioteca.MetodosBusqueda, _
ByVal buscarTexto As String)
' ----- Agregar un articulo a la historia de busqueda.
Dim nuevaHistoria As HistoriaBusquedaArticulos
Dim desplegartexto As String

' ----- Generar el texto para despliegue en el nuevo articulo.


desplegartexto = BuildDisplayText(tipoBusqueda, buscarTexto)

' ----- Generar el nuevo elemento de historia.


nuevaHistoria = New HistoriaBusquedaArticulos
nuevaHistoria.TipoBusqueda = tipoBusqueda
nuevaHistoria.DatosBusqueda = buscarTexto
nuevaHistoria.DesplegarHistoria = desplegartexto
ConjuntoHistoriaBusqueda.Push(nuevaHistoria)

' ----- Actualizar el boton Atras.


ActualizarBotonesAtras()
End Sub

Ms adelante, cuando el cliente haga clic en uno de los botones Atrs, el manejador de eventos
ElementosMenuAtras_Click examina la pila de historia y llama a RealizarBusqueda, se-
gn sea necesario. Y como almacenamos los objetos de HistoriaBusquedaArticulos en una
pila genrica, no tenemos que convertirlos especficamente de System.Object; el programa
slo sabe qu tipo de datos son.

478 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 478 17/2/10 15:29:32


Private Sub ElementosMenuAtras _Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MenuAtras1.Click, ..., MenuAtras10.Click
' ----- Se hizo clic en uno de los elementos del menu atras.
Dim cualElemento As Integer
Dim contador As Integer
Dim buscarHistoria As HistoriaBusquedaArticulos

' ----- Determinar el elemento en que se hizo clic.


cualElemento = CInt(SoloDigitos(CType(sender, _
System.Windows.Forms.ToolStripMenuItem).Name))
If (cualElemento >= ConjuntoHistoriaBusqueda.Count) Then Return

' ----- Deshacerse de los elementos intermedios.


For contador = 1 To cualElemento
ConjuntoHistoriaBusqueda.Pop( )
Next contador

' ----- Realizar una busqueda como se solicito.


buscarHistoria = ConjuntoHistoriaBusqueda.Peek
If (RealizarBusqueda(buscarHistoria.TipoBusqueda, _
buscarHistoria.DatosBusqueda, False) = False) Then Return
ActualizarBotonesAtras()
End Sub

Despliegue de los detalles de un artculo


La funcin GenerarHTMLYVinculos genera el contenido HTML que aparece en el panel
PanelUnArticulo. Este panel incluye DetalleArtSolo, un control WebBrowser inclui-
do con .NET. Es, en esencia, una versin de Internet Explorer que usted incrusta en sus
aplicaciones. Por lo general, usted lo proporciona con un URL para despliegue, pero tam-
bin puede proporcionar contenido personalizado mediante la propiedad DocumentText
del control. Los mtodos de bsqueda PorIDBaseDatos y PorCodigoBarras dentro de la
rutina RealizarBusqueda asigna esta propiedad con contenido devuelto de GenerarHT-
MLYVinculos.
DetalleArtSolo.DocumentText = _
GenerarHTMLYVinculos(CInt(consultaId.ToArray(0)))

El contenido proporcionado por esta rutina es HTML estndar, pero con algunos vnculos
especialmente creados que dejan que el programa de biblioteca realiza bsquedas adicionales
en los detalles del elemento de biblioteca desplegado.
La mayor parte del HTML es un patrn, y parece una vergenza desperdiciar clulas cere-
brales haciendo unin de cadenas slo para incluirlo. En cambio, almacen gran parte del
HTML como un recurso de archivo de texto a travs del panel Recursos de las propiedades
del proyecto. En ese panel, hice clic en el botn Agregar recurso, hice clic en el elemento de
men Agregar nuevo archivo de texto e ingrese CuerpoBusquedaArticulo como nombre del
nuevo archivo de texto (vase la figura 17-6).

Proyecto | 479

17_PATRICK-CHAPTER_17.indd 479 17/2/10 15:29:32


Figura 17-6. Adicin de un nuevo recurso de archivo de texto.

En la ventana del editor de texto que apareci agregu el siguiente contenido:


<html>
<head>
<style type="text/css">
body { font-family: "Arial"; }
h1 { font-family: "Arial"; margin-top: 0px;
margin-bottom: 0px; font-size: 18pt; font-weight: bold; }
h2 { font-family: "Arial"; margin-top: 20px;
margin-bottom: 0px; font-size: 15pt; font-weight: normal; }
h3 { font-family: "Arial"; margin-top: 0px;
margin-bottom: 0px; font-size: 15pt; font-weight: normal;
font-style: italic; }
p { margin-top: 2px; margin-bottom: 2px;
margin-left: 15px; font-family: "Arial"; font-size: 12pt; }
table { border: solid black 1px; margin-left: 15px; }
th { border: solid black 1px; background-color: black;
color: white; white-space: nowrap; text-align: left; }
td { border: solid black 1px; white-space: nowrap; }
a:visited { color: blue; }
</style>
</head>
<body>

Si est familiarizado con HTML, reconocer la mayor parte del contenido como una hoja de
estilos en cascada (CSS, Cascading Style Sheet) incrustada. Sus diversas reglas de formato traern
un aspecto especfico y consistente al contenido de explorador que aparece dentro del formulario
de bsqueda de artculos. Esto no es un libro sobre CSS, pero hay algunos buenos libros en su
librera local que puede llmar a travs de las reglas y sintaxis si est interesado.
Puede encontrar la parte del contenido HTML en el Explorador de soluciones, dentro de la
rama Recursos. Tal vez ya observ que las etiquetas de cierre </body> y </html> no estn in-
cluidas. Adjuntaremos eso en el mtodo GenerarHTMLYVinculos. Debido a que la unin de
cadenas es notoriamente lenta, decid usar la clase StringBuilder, una clase especial parecida
a una cadena con diseo personalizado para hacerlo ms rpido cuando agrega contenido de

480 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 480 17/2/10 15:29:33


manera repetida a una cadena base. Se adjunta contenido al final de StringBuilder empleando
sus mtodos Append y AppendLine, y se recupera toda la cadena a travs del mtodo ToString
estndar.
Empezaremos el contenido con el HTML de plantilla que se present antes. Debido a que lo
agregamos como recurso, ya aparece en el objeto My.Resources bajo el nombre que le dimos.
Dim cuerpoDetalle As New System.Text.StringBuilder
cuerpoDetalle.Append(My.Resources.CuerpoBusquedaArticulo)

La mayor parte del cdigo agrega texto simple al generador de cadenas cuerpoDetalle
empleando su mtodo AppendLine. He aqu el cdigo que agrega el ttulo principal del libro:
textoSql = "SELECT Titulo, Subtitulo FROM ArticuloConNombre " & _
"WHERE ID = " & idArticulo
infoBD = CrearLector(textoSql)
infoBD.Read()
cuerpoDetalle.AppendLine("<h1>" & _
CodigoHTML(CStr(infoBD!Titulo)) & "</h1>")

La funcin CodigoHTML, llamada en este bloque, se incluye en la clase BusquedaArticulos.


Hace cierta modificacin de caracteres especiales como lo necesita HTML. Se le llama de mane-
ra repetida a travs de GenerarHTMLYVinculos.
Bueno, eso es en relacin con el HTML, pero que hay con los vnculos? Si coloco un vnculo
estndar a, digamos, http://www.microsoft.com, el explorador insertado saltar a esa pgina cuan-
do se haga clic en el vnculo. Pero eso no me ayuda a realizar bsquedas en la base de datos. El
control WebBrowser en realidad no expone un evento de vnculo en que se hizo clic, pero
tiene un evento Navigating que se le parece mucho. Este evento se dispara cada vez que el
explorador est por pasar a una nueva pgina. Por fortuna, uno de los valores de datos pasados
al manejador de eventos es el URL de destino. De modo que todo lo que tenemos que hacer es
generar un vnculo que contenga la informacin que necesitamos para realizar la bsqueda en
la base de datos.
Decid almacenar los detalles relevantes de la bsqueda de base de datos como una coleccin
(similar a la pila de historia), y crear vnculos falsos con estilo de URL que indican cul ele-
mento de la coleccin usar. Despus de mucho razonamiento, me decid por el formato de mis
vnculos de URL falsos:
biblioteca://x

donde x es reemplazado por un ndice en la coleccin de vnculos. Es simple, y funciona. La co-


leccin de detalles de bsqueda es un diccionario genrico almacenado como un campo dentro
de la clase del formulario.
Private Class VinculoArticuloUnico
Public TipoVinculo As Biblioteca.MetodosBusqueda
Public IDVinculo As Integer
End Class

Private ConjuntoVinculosArticulos As Collections.Generic.Dictionary( _


Of Integer, VinculoArticuloUnico)

Proyecto | 481

17_PATRICK-CHAPTER_17.indd 481 17/2/10 15:29:33


Luego regreso al cdigo de generacin de HTML, agrego falsos URL y objetos VinculoArticu-
loUnico juntos. He aqu parte del cdigo usado para agregar en vnculos de autor, dado un lector
con campos de nombre de autor. (El valor idEntrada proporciona la x en biblioteca://x.)
Do While infoBD.Read
' ----- Agregar en un nombre de autor.
contenerTexto = FormarNombreAutor(infoBD)
idEntrada += 1
cuerpoDetalle.AppendLine("<p><a href=""biblioteca://" & _
idEntrada & """>" & CodigoHTML(contenerTexto & " [" & _
CStr(infoBD!NombreTipoAutor) & "]") & "</a></p>")

' ----- Agregar en un vnculo de autor.


nuevoVinculo = New VinculoArticuloUnico
nuevoVinculo.TipoVinculo = General.MetodosBusqueda.porIdAutor
nuevoVinculo.IDVinculo = CInt(infoBD!ID)
ConjuntoVinculosArticulos.Add(idEntrada, nuevoVinculo)
Loop

Cuando el usuario hace clic en un vnculo en el explorador Web incrustado, desencadena el


manejador de eventos Navigating.
Private Sub DetalleArtSolo_Navigating( _
ByVal sender As Object, ByVal e As System.Windows. _
Forms.WebBrowserNavigatingEventArgs) _
Handles DetalleArtSolo.Navigating
' ----- Seguir el vinculo en que se hizo clic.
If (e.Url.Scheme = "biblioteca") Then _
SeguirVinculoArticulo(CInt(e.Url.Host( )))
End Sub

La propiedad e.Url.Scheme devuelve la parte del URL antes de los caracteres ://, mientras
e.Url.Host devuelve el primer componente delimitado por diagonales justo despus de estos
caracteres. Es donde almacenamos el ndice en el diccionario ConjuntoVinculosArticulos.
El mtodo SeguirVinculoArticulo extrae los detalles de bsqueda de ConjuntoVinculos
Articulos y llama al mtodo RealizarBusqueda confiable, que da lugar a una nueva bsque-
da que se almacena en la historia de bsqueda.
Private Sub SeguirVinculoArticulo(ByVal idEntrada As Integer)
' ----- Dada la posicion de un caracter en el panel de texto de un
' solo elemento, seguir el vinculo indicado.
Dim buscarVinculo As VinculoArticuloUnico

' ----- Acceder al vnculo.


buscarVinculo = ConjuntoVinculosArticulos.Item(idEntrada)
If (buscarVinculo Is Nothing) Then Return

' ----- Realizar una bsqueda como se solicit.


If (RealizarBusqueda(buscarVinculo.TipoVinculo, _
CStr(buscarVinculo.IDVinculo), False) = False) _
Then Return

' ----- Almacenar la historia.


AgregarHistoriaBusqueda(buscarVinculo.TipoVinculo, CStr(buscarVinculo.
IDVinculo))
End Sub

482 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 482 17/2/10 15:29:33


Habilitacin de las caractersticas de bsqueda
El formulario BusquedaArticulos est listo para usarse. Slo necesitamos llamarlo desde los
campos de bsqueda en el formulario principal. El panel PanelArtsBiblioteca de Formulario-
Principal.vb incluye varios controles de seleccin ComboBox, pero no hay cdigo para rellenarlos.
Agreguemos ahora el cdigo. Acceda el cdigo fuente de FormularioPrincipal.vb y localicemos el
evento FormularioPrincipal_Load evento. Ya hay all algn cdigo que ajusta los elementos
del formulario. Adjunte el nuevo cdigo de relleno de lista al final de esta rutina.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap17, Elemento 2.

He aqu la parte del nuevo cdigo que rellena la lista de mtodos de bsqueda:
' ----- Cargar en la lista de tipos de busqueda.
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por titulo", MetodosBusqueda.PorTitulo))
TipoBusqueda.SelectedIndex = 0
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por autor", MetodosBusqueda.PorAutor))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por tema", MetodosBusqueda.PorTema))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por clave (cualquier coincidencia)", _
MetodosBusqueda.PorPalabraClaveCualq))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por clave (todas las coincidencias)", _
MetodosBusqueda.PorPalabraClaveTodas))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por editor", MetodosBusqueda.PorEditor))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por serie Name", MetodosBusqueda.PorSerie))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por codigo de barras", MetodosBusqueda.PorCodigoBarras))

El botn Limpiar del panel principal restablece todos los campos y los prepara para una nueva
bsqueda. Agregue un nuevo manejador de eventos AccLimpiarBusqueda_Click usando el
mtodo de seleccin de campos arriba de la ventana del editor de campo o haciendo doble clic
en el botn Limpiar en el propio formulario. Luego agregue el siguiente cdigo al manejador.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap17, Elemento 3.

' ----- Limpiar el criterio de busqueda actual.


TipoBusqueda.SelectedIndex = TipoBusqueda.Items.IndexOf( _
CInt(MetodosBusqueda.PorTitulo))
TextoBusqueda.Text = ""
BusquedaTipoMedio.SelectedIndex = _

Proyecto | 483

17_PATRICK-CHAPTER_17.indd 483 17/2/10 15:29:33


BusquedaTipoMedio.Items.IndexOf(-1)
BusquedaUbicacion.SelectedIndex = _
BusquedaUbicacion.Items.IndexOf(-1)

Debido a que la aplicacin Biblioteca tal vez ser usada por muchos clientes distintos en todo
el da, debemos suponer que una persona diferente est usando el programa cada vez que el for-
mulario devuelve el panel de bsqueda. Simulemos un clic en el botn Limpiar cada vez que el
usuario ve el panel de bsqueda. Localice el mtodo TareaArtBiblioteca y agregue el siguien-
te cdigo al final de la rutina, justo antes de la instruccin TextoBusqueda.Focus( ).

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap17, Elemento 4.

AccLimpiarBusqueda.PerformClick()
If (ActSearchLimits.Top = LabelMoreLimitsTop.Top) Then _
ActSearchLimits.PerformClick()

Con la intencin de ser lo ms amigable posible con el usuario, agreguemos algn texto de ayu-
da al panel de bsqueda, que vare dependiendo del tipo de bsqueda seleccionado en la lista
desplegable Tipo de bsqueda. Agregue un nuevo manejador de eventos TipoBusqueda_Se-
lectedIndexChanged y luego agregue su cdigo.

INSERCIN DE FRAGMENTO DE CDIGO


Inserte el fragmento de cdigo Cap17, Elemento 5.

No lo incluir todo aqu porque es ms bien repetitivo. El cdigo simplemente examina la se-
leccin actual en el control TipoBusqueda, y establecer la etiqueta EtqDatosConsejosBqd en
algn texto de ayuda descriptivo.
Estamos llegando al final. Lo nico que queda es realizar la bsqueda cuando el usuario hace clic
en el botn Buscar. Agregue un manejador de eventos para AccBuscar_Click y luego agregue
su cdigo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap17, Elemento 6.

La mayor parte de esta rutina revisa entrada vlida antes de llamar al formulario BusquedaAr-
ticulos mediante su mtodo pblico IniciarBusqueda.
Call (New BusquedaArticulos).IniciarBusqueda( _
CType(searchMethod, Biblioteca.MetodosBusqueda), _
Trim(TextoBusqueda.Text), limiteMedio, limiteUbicacion)

484 | Captulo 17:LINQ

17_PATRICK-CHAPTER_17.indd 484 17/2/10 15:29:33


Ya casi ha terminado, doctor. Ha agregado un corazn al paciente. El programa est listo para
ejecutarse y usarlo para bsqueda de artculos! Si ya ha agregado algunos artculos con nombre,
puede localizarlos usando cualquiera de los mtodos de bsqueda relevantes. Trate de hacer una
bsqueda por ttulo, usando el comodn * para los criterios de bsqueda.
Aunque la caracterstica de bsqueda funciona, encontrar que algunos elementos de despliegue
del formulario BusquedaArticulos no funcionan perfectamente. Nunca obtendremos esas
columnas trabajando en el panel de resultados de artculos. Las mejoras vendrn pronto. Con el
enfoque en el siguiente captulo en las tcnicas de interfaz de usuario, pronto podremos actuali-
zar el despliegue del contenido de nuestro corazn.

Proyecto | 485

17_PATRICK-CHAPTER_17.indd 485 17/2/10 15:29:33


Captulo 18
Interfaz de usuario

Una imagen vale ms que mil palabras (o varios miles de lneas de cdigo fuente, si est generan-
do una imagen de mapa de bits con l). Escribir cdigo para manipular imgenes con varios ni-
veles de color, o para trazar arte vectorial de varias capas, puede ser una pesadilla de contorsiones
geomtricas y lgebra lineal. Lo hacen a uno echar de menos los das de las computadoras previas
a la pantalla. La primera clase de programacin que tom usaba una DECWriter, una terminal
basada en impresora que no tena pantalla, e inclua las capacidades grficas de una medusa.
Era perfecta para m. No poda dibujar una lnea recta, de todos modos, y no necesitaba alguna
bonita terminal de pantalla de video que me lo recordara.
Las imgenes incluidas en los primeros sistemas de pantalla no eran mucho mejores. Terminales
tontas, como la popular VT100, inclua algunas imgenes de caracteres simples que desplegaban
lneas y bloques bsicos. Cada parte grfica era exactamente del tamao de un carcter y cualquier
imagen que quisiera desplegar tena que caber en una cuadrcula incmoda de 80 24.
Por fortuna para los aficionados al arte de todas partes, las computadoras han recorrido mucho
camino en el departamento grfico. GDI+, el sistema de dibujo estndar de .NET, incluye ca-
ractersticas de dibujo complejas que haran llorar a una DECWriter. Construida sobre la vieja
tecnologa de la interfaz de dispositivo grfico (GDI, Graphics Device Interface) de Windows,
GDI+ incluye comandos para dibujar lneas, texto e imgenes en el mundo mejorado de Picasso
de las imgenes 2D.
Ms all de GDI+, .NET tambin proporciona soporte para la nueva base de presentacin
de Windows (WPF, Windows Presentation Foundation), una interfaz de usuario y un sistema
de presentaciones multimedia muy ricos basados en parte en XML. WPF incluye caractersti-
cas de despliegue e interaccin que van ms all de GDI+, aunque hay unas cuantas caracte-
rsticas en GDI+ que estn ausentes en WPF. Aunque har una breve revisin de WPF en este
captulo, la mayor parte de l (y todo el cdigo de la interfaz de usuario del proyecto Biblioteca)
se concentrar en GDI+.

486

18_PATRICK-CHAPTER_18.indd 486 18/2/10 11:16:38


Revisin general de GDI+
Antes de .NET, los programadores en Windows dependan del sistema GDI para dibujar casi
todo en la pantalla, aunque no supieran que exista GDI. Adems de las imgenes en mapa de
bits, todos los controles, etiquetas, bordes de ventana e conos aparecan en pantalla gracias a
GDI. Era un paso gigantesco adelante en relacin con las imgenes de carcter. GDI presentaba
un conjunto bsico de caractersticas de dibujo a partir de las cuales poda dar salida, en teora,
a cualquier tipo de imagen compleja. Pero no era fcil. Las imgenes primitivas eran (bueno)
primitivas, y tena que generar sistemas complejos a partir de sus partes. Casi ningn programa-
dor haca cosas hermosas, de modo que trataban de evitar las complejidades de GDI. Pero en
ocasiones tena que dibujar una lnea o un crculo, y no haba manera de evitarlo.
GDI+, nuevo con .NET, se construye a partir de GDI, proporcionando los primitivos bsicos
GDI, pero tambin algunos agrupamientos de imgenes caractersticas en funciones fciles de
usar. Esta simplicidad ha trado un renacimiento del trabajo grfico iniciado por el programador.
Eche un vistazo a la figura 18-1, que muestra una imagen que se dibuj usando la antigua GDI,
y esa misma imagen generada slo con unos rpidos comandos de GDI+.

GDI GDI+
Figura 18-1. La maravilla que es GDI+.

El sistema GDI+ tiene su hogar en el espacio de nombres System.Drawing, e incluye mul-


titudes de clases que representan los objetos de dibujo, las superficies y las caractersticas de
embellecimiento que habilitan imgenes de despliegue. Pero no se relaciona slo con el des-
pliegue. GDI+ generaliza el dibujo de mapa de bits y vectoriales en superficies de salida dispo-
nibles: mapas de bits o dibujo de lneas en la pantalla (incluidos formularios y superficies de
control), salida de informes en una impresora, graffitis en la pared trasera de su supermercado
local, contenido de imgenes destinadas a archivos JPEG (todo es GDI+). Todos los destinos
usan los mismos mtodos y objetos de dibujo, facilitndole generalizar su cdigo de dibujo.

Revisin general de GDI+ | 487

18_PATRICK-CHAPTER_18.indd 487 18/2/10 11:17:25


Entre las caractersticas de GDI+ se incluyen superficies, tintas de dibujo, elementos de dibujo
y transformaciones.
GDI+ generaliza las superficies de dibujo a travs de la clase System.Drawing.Graphics.
Este objeto representa un lienzo de dibujo, con atributos para cantidad de colores y tamao
(ancho y alto). El lienzo puede vincularse con una regin de la pantalla de la estacin de
trabajo, un rea contenedora interna para salida final a la impresora, o un lienzo de imagen
en general para manipulacin de contenido en memoria antes de darle salida a una pantalla
o un archivo. Otro tipo de superficie, la ruta (System.Drawing.Drawing2D.Graphics
Path), es como una grabadora de macros para imgenes vectoriales (de lnea). El dibujo he-
cho dentro de una ruta puede volverse a reproducir en una superficie de dibujo estndar,
o usarse para proporcionar lmites para otros comandos de dibujo.
Los colores y las tintas aparecen en la forma de colores (valores de color opacos o semitrans-
parentes), pinceles (pseudoplumas basadas en mapa de bits usadas para rellenos y disposicin
en mosaicos) y plumas (objetos para dibujo de lneas a color con un grosor especfico).
Entre los elementos de dibujo se incluyen rectngulos, elipses, lneas y otras formas estndar
o de orilla personalizada. Tambin incluyen fuentes, en versiones de mapa de bits y basadas
en contornos.
Las transformaciones le permiten cambiar el tamao, girar e inclinar dibujos mientras los
genera. Cuando se aplica una transformacin a una superficie, puede dibujar objetos como
si no tuvieran transformaciones aplicadas, y los cambios sucedern en tiempo real.
Los controles de Windows Forms que ve en aplicaciones de escritorio suelen ocuparse de sus propias
caractersticas de despliegue. Sin embargo, algunos controles le permiten tomar algunas o varias
de las responsabilidades de dibujo. Por ejemplo, el control ListBox despliega texto simple de un
solo color para cada elemento de lista. Sin embargo, puede sobrescribir el dibujo de cada elemento
de lista, proporcionando su propio contenido personalizado, que puede incluir texto o imgenes de
varios colores. Esta capacidad de proporcionar parte del cdigo de dibujo a un control es conocido
como dibujo de propietario, y funciona mediante el mismo objeto Graphics generalizado que se
usa para otros dibujos. Incluiremos algn cdigo de dibujo en el proyecto Biblioteca.
Para hacer una descripcin completa, debe saber que en este captulo slo se cubrir tal vez el 1%
de las caractersticas disponibles de GDI+, si acaso. GDI+ es complejo y vasto, y podra dedicar
aos profundizando en cada pequea caracterstica, justo a tiempo para su cambio eventual a
WPF. Le har una breve exposicin del sistema GDI+ para que pueda percibir algunos de los ele-
mentos bsicos. Si necesita manipular imgenes y texto ms all de lo que se enumera aqu (y tal
vez lo har), pruebe la documentacin de MSDN u otro recurso dedicado a descifrar GDI+.

Seleccin de un lienzo
La mayor parte del dibujo en .NET ocurre en el contexto de un objeto Graphics. (Para quienes
estn familiarizados con el desarrollo previo a .NET en Windows, esto es similar a un contexto de
dispositivo.) Los objetos Graphics proporcionan un lienzo en que usted dibuja lneas, formas,
imgenes de mapa de bits y macros de dibujo grabadas previamente. El objetoGraphics no

488 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 488 18/2/10 11:17:25


contiene la propia superficie de dibujo; son simples conductos genricos al lienzo real. Siempre
hay alguna superficie tras el objeto Graphics, sea una parte de la pantalla, un objeto Bitmap o la
superficie simulada de una pgina impresa. Cualquier dibujo hecho en el objeto Graphics tiene
un impacto inmediato en la superficie subyacente.
El objeto Graphics incluye docenas de mtodos que le permiten dibujar formas e imgenes en
la superficie de la imagen, y realizar otras actividades 2D mgicas. Cubriremos muchas de ellas
en este captulo.

Obtencin y creacin de objetos grficos


Para obtener un objeto Graphics para un formulario o control en pantalla basta con llamar al
mtodo CreateGraphics del formulario o control.
Dim todasLasImagenesFormulario As Graphics = _
Me.CreateGraphics()
Dim botonSoloImagenes As Graphics = _
Button1.CreateGraphics()

Algunos eventos, sobre todo Paint para formularios y controles, proporciona acceso a un objeto
Graphics mediante los argumentos del evento.
Private Sub PictureBox1_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles PictureBox1.Paint
Dim pintarLienzo As Graphics = e.Graphics
End Sub

Tambin puede crear un objeto Graphics que no est relacionado con cualquier rea de desplie-
gue existente al asociarla con un mapa de bits.
Dim verdaderoMapaBits As New Bitmap(50, 50)
Dim lienzo = Graphics.FromImage(verdaderoMapaBits)

Recuerde que todos los cambios hechos a la instancia lienzo tendrn impacto en la imagen
verdaderoMapaBits.

Eliminacin apropiada de los objetos grficos


Cuando haya terminado de crear un objeto Graphics, debe deshacerse de l al llamar a su mtodo
Dispose. (Esta regla es vlida para muchos objetos GDI+ diferentes.) No lo conserve para un
da de lluvia, porque no ser vlido ms adelante. Debe, debe, debe deshacerse de l cuando deje
de usarlo. Si no lo hace, podra corromperse la imagen, crear problemas de uso de memoria o,
peor an, generar conflictos armados. De modo que por favor deshgase de manera apropiada
de todos los objetos Graphics.
lienzo.Dispose( )

Si crea un objeto Graphics dentro de un evento, en realidad necesita desecharlo antes de salir
del manejador de eventos. No hay garanta de que el objeto Graphics an ser vlido en un
evento posterior. Adems, es fcil volver a crear otro objeto Graphics en cualquier momento.

Seleccin de un lienzo | 489

18_PATRICK-CHAPTER_18.indd 489 18/2/10 11:17:25


Si usted usa un objeto Graphics que proviene de otra parte del programa (como la referencia
e.Graphics en el manejador de eventos Paint previo), no debe organizarlo. Cada creador es
responsable por la organizacin de sus propios objetos.

Eleccin de plumas y pinceles


Una gran cantidad de trabajo grfico se relaciona con el dibujo de primitivos: uso de lneas, elip-
ses, rectngulos y otras formas regulares e irregulares para generar un despliegue final. Como en
la vida real, usted dibuja primitivos usando un objeto Pen. Para los primitivos que producen una
forma rellenable o semirrellenable, un objeto Brush especifica el color o patrn que se usar en el
rea de relleno. GDI+ incluye muchas plumas y brochas predefinidas, o puede crear las propias.

Plumas
Las plumas son herramientas de dibujo de lneas usadas con los comandos de dibujo de un ob-
jeto Graphics. Una pluma bsica tiene un color y un relleno slidos.
' ----- Una pluma roja de cinco unidades de ancho.
Dim plumaRoja As New Pen(Color.Red, 5)

Al igual que con los objetos Graphics, cualquier Pen puede crearse usando la palabra clave New
y debe desecharse de manera apropiada cuando haya terminado con l.
plumaRoja.Dispose()

Estn disponibles varias plumas predefinidas mediante la clase System.Drawing.Pens, todas


llamadas por su color, como en Pens.Red. Si usa una de estas plumas, no tiene que desecharlas.
Puede crear una gran cantidad de plumas interesantes que varan por estilos de lneas, decoraciones
finales y variaciones de color. El siguiente cdigo genera la imagen desplegada en la figura 18-2:
Private Sub PictureBox1_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles PictureBox1.Paint
' ----- Dibujar algunas lneas bonitas.
Dim usarPluma As Pen

' ----- Limpiar el fondo.


e.Graphics.Clear(Color.White)

' ----- Dibujar una linea basica de 1 pixel usando el color de la barra de titulo.
usarPluma = New Pen(SystemColors.ActiveCaption, 1)
e.Graphics.DrawLine(usarPluma, 10, 10, 200, 10)
usarPluma.Dispose( )

' ----- Dibujar una linea de guiones mas gruesa con extremos de flecha
' y bola. Cada segmento de guion tiene un extremo en triangulo.
usarPluma = New Pen(Color.FromName("Red"), 5)
usarPluma.DashCap = Drawing2D.DashCap.Triangle
usarPluma.StartCap = Drawing2D.LineCap.ArrowAnchor

490 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 490 18/2/10 11:17:25


usarPluma.EndCap = Drawing2D.LineCap.RoundAnchor
usarPluma.DashStyle = Drawing2D.DashStyle.Dash
e.Graphics.DrawLine(usarPluma, 10, 30, 200, 30)
usarPluma.Dispose()

' ----- Una pluma negra semitransparente con tres partes de


' linea, dos delgadas y una gruesa.
usarPluma = New Pen(Color.FromArgb(128, 0, 0, 0), 10)
usarPluma.CompoundArray = _
New Single() {0.0, 0.1, 0.4, 0.5, 0.8, 1.0}
e.Graphics.DrawLine(usarPluma, 10, 55, 200, 55)
usarPluma.Dispose()
End Sub

Figura 18-2. S seor, tres lneas completas.

El cdigo muestra que hay unas cuantas maneras diferentes de especificar un color, ya sea por su
nombre predefinido (Color.White y SystemColors.ActiveCaption), un nombre de cadena
(usando Color.FromName) o su valor en alfa-rojo-verde-azul (Color.FromArgb). La ltima
versin le permite proporcionar diferentes valores para los componentes de la mezcla alfa (que
establece el nivel de transparencia, de 0 para completamente diferente a 255 para completamen-
te opaco) y el rojo, verde y azul de lo que se denomina a todo color.
Casi todas las propiedades especficas de pluma que demostr aqu se explican por s solas, de
alguna manera. Al igual que con casi todo en GDI+, la abrumadora cantidad de caractersticas
disponibles imposibilitan documentarlas por completo en un captulo pequeo, mucho menos
proporcionar una buena noche de sueo para los autores que disean estos captulo. Simple-
mente pedir al lector que revise la documentacin en lnea para la clase Pen para obtener todos
los detalles.

Brochas
Las brochas se usan para rellenar espacios entre lneas dibujadas, aunque haga esas lneas com-
pletamente invisibles. GDI+ incluye varios tipos de brochas, incluidas brochas slidas (de un solo
color bsico), brochas de patrn (que son agradables pero generales), brochas de textura (donde
se utiliza un mapa de bits personalizado) y brochas de degradado (que degradan poco a poco un
color en otro a travs de la brocha). La clase System.Drawing.Brushes incluye algunas bro-
chas slidas predefinidas con base en el nombre de un color. Al igual que con las plumas debe
deshacerse de las brochas que cree, pero no de las brochas slidas definidas por el sistema.

Eleccin de plumas y pinceles | 491

18_PATRICK-CHAPTER_18.indd 491 18/2/10 11:17:25


El siguiente bloque de cdigo dibuja algunos rectngulos simples con una variedad de estilos de
brocha. El resultado aparece en la figura 18-3.
Private Sub PictureBox1_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles PictureBox1.Paint
' ----- Dibujar algunos bonitos rectangulos.
Dim usarBrocha As Brush

e.Graphics.Clear(Color.White)

' ---- Dibujar un rectangulo relleno con un color solido.


e.Graphics.FillRectangle(Brushes.Cyan, 10, 10, 150, 50)

' ----- Dibujar un rectangulo de patron. Use negro como fondo


' y blanco para el fondo del patron.
usarBrocha = New Drawing2D.HatchBrush( _
Drawing2D.HatchStyle.LargeConfetti, _
Color.White, Color.Black)
e.Graphics.FillRectangle(usarBrocha, 10, 70, 150, 50)
usarBrocha.Dispose( )

' ----- Dibujar un rectangulo con degradado lineal de interfaz a


' derecha. El propio degradado del rectangulo determina el
' desplazamiento inicial, con base en la superficie del
' origen de Graphics.
usarBrocha = New Drawing2D.LinearGradientBrush( _
New Rectangle(200, 10, 75, 25), Color.Blue, _
Color.Yellow, Drawing2D.LinearGradientMode.Horizontal)
e.Graphics.FillRectangle(usarBrocha, 200, 10, 150, 50)
usarBrocha.Dispose( )

' ----- Usar una imagen para la brocha. Estoy usando la imagen
' "BuscarArticulo.bmp" usada en el proyecto Biblioteca.
' y que se encuentra en la carpeta Imagenes del codigo
' de este libro.
usarBrocha = New TextureBrush(Image.FromFile( _
"BuscarArticulo.bmp"))
e.Graphics.FillRectangle(usarBrocha, 200, 70, 150, 50)
usarBrocha.Dispose( )
End Sub

Figura 18-3. Algn tipo de cuadrado, si me lo pregunta.

492 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 492 18/2/10 11:17:26


Flujo de texto a partir de la fuente
Los crculos y cuadrados son adecuados, pero no siempre comunican mucho, a menos que sea
Joan Mir. Casi todos usamos el texto para decir lo que queremos. Por fortuna, GDI+ tiene una
gran cantidad de caractersticas que colocan el texto en la superficie de su imagen.
Antes de que las interfaces grficas de usuario estuvieran disponibles, el texto en realidad no era
un problema; o usaba los caracteres integrados en el sistema, o no usaba nada. En la pantalla,
cada letra del alfabeto estaba diseada en el hardware de la computadora o el monitor, y cual-
quier carcter particular poda aparecer slo dentro de cada cuadro de la cuadrcula predefinida
de 80 24. Las impresoras eran un poco mejores, porque poda usar la tecla de retroceso y volver
a escribir todas las posiciones previamente escritas para generar texto en negritas o subrayado.
An as, por lo general estaba limitado a una fuente, o slo un pequeo puado de fuentes bsi-
cas incrustadas en la memoria de la impresora.
Estas limitaciones son cosa del pasado. Todo el texto en Microsoft Windows aparece por cortesa
de las fuentes, descripciones de formas de carcter que pueden cambiar de tamao o estirarse
o hacer nfasis en ellas para satisfacer cualquier necesidad relacionada con el texto. Y debido a
que el usuario puede agregar fuentes al sistema en cualquier momento, y a partir de terceros, la
variedad de estas fuentes es sorprendente. Pero ya sabe todo esto. Pasemos al cdigo
Para obtener acceso a una fuente que use en sus imgenes, cree una instancia de la clase System.
Drawing.Font, pasando por lo menos el nombre de la fuente y su puntaje, y una referencia de
estilo opcional:
Dim fuenteBasica As New Font("Arial", 14, FontStyle.Italic)

Naturalmente, la lista de fuentes disponibles vara de acuerdo con el sistema; si va ms all de


las fuentes bsicas preinstaladas que proporciona Windows, debe confirmar que est disponi-
ble una fuente con nombre, y que tenga una opcin de recuperacin si no la tiene. Puede obte-
ner una lista de todas las fuentes al consultar amablemente a GDI+. Todas las fuentes aparecen
en familias, donde cada familia con nombre puede tener negritas, cursivas y otras variaciones
instaladas como archivos de fuente separados. El siguiente bloque de cdigo agrega una lista de
todas las familias de fuentes instaladas en un control ListBox:
Dim todasLasFuentes As New Drawing.Text.InstalledFontCollection( )
For Each unaFamilia As Drawing.FontFamily In todasLasFuentes.Families
ListBox1.Items.Add(unaFamilia.Name)
Next unaFamilia

Si la fuente que necesita no est disponible y no est seguro de cul usar, deje que GDI+ elija por
usted. Incluya unas cuantas fuentes genricas para caso de emergencia.
Drawing.FontFamily.GenericMonospace
Drawing.FontFamily.GenericSansSerif
Drawing.FontFamily.GenericSerif

Regresando al uso de fuentes en el dibujo actual, el objeto Graphics incluye un mtodo


DrawString que lleva algn texto al lienzo.

Flujo de texto a partir de la fuente | 493

18_PATRICK-CHAPTER_18.indd 493 18/2/10 11:17:26


Private Sub PictureBox1_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles PictureBox1.Paint
Dim fuenteBasica As New Font("Arial", 14, FontStyle.Italic)
e.Graphics.DrawString("Esto es una prueba", fuenteBasica, _
Brushes.Black, 0, 0)
fuenteBasica.Dispose()
End Sub

En la figura 18-4 se muestra la salida de este bloque de cdigo. En casi todo el cdigo de ejemplo
de este captulo, dar salida al contenido de un control PictureBox al que he llamado Pictu
reBox1, que he colocado en el formulario de una nueva aplicacin de Windows Forms. Tam-
bin he establecido la propiedad BorderStyle en FixedSingle y su propiedad BackColor
en White, de modo que pueda visualizar las orillas del lienzo. El dibujo ocurre en el manejador
de eventos Paint, al que se llama cada vez que el cuadro de imagen necesita actualizarse, como
cuando otra ventana la oculta y luego desaparece. En los ejemplos de cdigo restantes, no inclui-
r la definicin del mtodo Sub PictureBox1_Paint, slo el cdigo que va en el interior.

Figura 18-4. Seguro que sta es la prueba.

Por supuesto, puede mezclar y buscar coincidencias en fuentes en un solo lienzo de salida. Este
cdigo incluye texto usando Arial 14 y Arial 18:
Dim fuenteBasica As New Font("Arial", 14)
Dim fuenteDestacada As New Font("Arial", 18, FontStyle.Bold)
Dim desplazamiento As Single = 0.0
Dim mostrarTexto As String
Dim tamanoTexto As Drawing.SizeF

mostrarTexto = "Este es un "


tamanoTexto = e.Graphics.MeasureString(mostrarTexto, fuenteBasica)
e.Graphics.DrawString(mostrarTexto, fuenteBasica, _
Brushes.Black, desplazamiento, 0)
desplazamiento += tamanoTexto.Width

mostrarTexto = "texto"
tamanoTexto = e.Graphics.MeasureString(mostrarTexto, fuenteBasica)
e.Graphics.DrawString(mostrarTexto, fuenteBasica, _
Brushes.Black, desplazamiento, 0)
desplazamiento += tamanoTexto.Width
mostrarTexto = "destacado."

494 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 494 18/2/10 11:17:26


tamanoTexto = e.Graphics.MeasureString(mostrarTexto, fuenteDestacada)
e.Graphics.DrawString(mostrarTexto, fuenteDestacada, _
Brushes.Black, desplazamiento, 0)
desplazamiento += tamanoTexto.Width

fuenteDestacada.Dispose( )
fuenteBasica.Dispose( )

La salida de este cdigo aparece en el cuadro superior de la figura 18-5, y es correcto. Pero quiere que
las orillas inferiores de las partes del cuerpo principal de cada bloque de texto (es decir, la lnea base
de cada bloque) se alinee apropiadamente, como se muestra en el cuadro inferior de la figura 18.5.

Figura 18-5. Lo bueno y lo malo; ambos feos.

Hacer esto de la bonita alineacin de las cosas es como un dolor en el cuello. Tiene que hacer
todo tipo de mediciones con base en el diseo de la fuente original, como se extrapola en el
dispositivo en pantalla basada en pixeles. Luego conecte el hueso de la rodilla con el del muslo,
etc. He aqu el cdigo que us para generar la segunda imagen alineada.
Dim fuenteBasica As New Font("Arial", 14)
Dim fuenteDestacada As New Font("Arial", 18, FontStyle.Bold)
Dim desplazamiento As Single = 0.0
Dim mostrarTexto As String
Dim tamanoTexto As Drawing.SizeF
Dim arribaBasico As Single
Dim arribaDestacado As Single
Dim factorDestacado As Single
Dim factorBasico As Single

' ----- La familia de fuentes usa unidades de diseo, tal vez


' especificadas por el diseador original de la fuente.
' Asignar estas unidades a unidades de despliegue (puntos).
factorDestacado = fuenteDestacada.FontFamily.GetLineSpacing( _
FontStyle.Regular) / fuenteDestacada.Height
factorBasico = fuenteBasica.FontFamily.GetLineSpacing( _
FontStyle.Regular) / fuenteBasica.Height

Flujo de texto a partir de la fuente | 495

18_PATRICK-CHAPTER_18.indd 495 18/2/10 11:17:27


' ----- Determinar la ubicacion de la linea base de cada fuente.
arribaDestacado = (fuenteDestacada.FontFamily.GetLineSpacing( _
FontStyle.Regular) - fuenteDestacada.FontFamily.GetCellDescent( _
FontStyle.Regular)) / factorDestacado
arribaBasico = (fuenteBasica.FontFamily.GetLineSpacing( _
FontStyle.Regular) - fuenteBasica.FontFamily.GetCellDescent( _
FontStyle.Regular)) / factorBasico

' ----- Dibujar una linea que pruebe la alineacion del texto.
e.Graphics.DrawLine(Pens.Red, 0, arribaDestacado, _
e.ClipRectangle.Width, arribaDestacado)

' ----- Mostrar cada parte del texto.


mostrarTexto = "Este es un "
tamanoTexto = e.Graphics.MeasureString(mostrarTexto, fuenteBasica)
e.Graphics.DrawString(mostrarTexto, fuenteBasica, _
Brushes.Black, desplazamiento, arribaDestacado - arribaBasico)
desplazamiento += tamanoTexto.Width

mostrarTexto = "texto"
tamanoTexto = e.Graphics.MeasureString(mostrarTexto, fuenteBasica)
e.Graphics.DrawString(mostrarTexto, fuenteBasica, _
Brushes.Black, desplazamiento, arribaDestacado - arribaBasico)
desplazamiento += tamanoTexto.Width

mostrarTexto = "destacado."
tamanoTexto = e.Graphics.MeasureString(mostrarTexto, fuenteDestacada)
e.Graphics.DrawString(mostrarTexto, fuenteDestacada, _
Brushes.Black, desplazamiento, 0)
desplazamiento += tamanoTexto.Width

fuenteDestacada.Dispose()
fuenteBasica.Dispose()

Hay muchos clculos ms en ese cdigo. Y ni siquiera tratar de abarcar cosas como el interletra-
je, las ligaduras o cualquier otra cosa que tenga que ver con la tipografa. De cualquier manera,
si necesita hacer manipulacin compleja de fuentes, GDI+ expone todos los detalles para que
pueda hacerlo de manera apropiada. Si slo quiere dar salida lnea tras lnea usando la misma
fuente, llame al mtodo GetHeight de la fuente para cada lnea que se despliegue:
desplazamientoVertical += useFont.GetHeight(e.Graphics)

Basta de cosas complejas. Tambin hay cosas fciles y atractivas que hacer con el texto. Observ
que la salida de texto usa brochas y no plumas? Esto significa que puede dibujar texto usando cual-
quier brocha que cree. Este bloque de cdigo usa la brocha con la imagen de mapa de bits Buscar
Articulo.bmp del proyecto Biblioteca para desplegar algn texto basado en mapa de bits.
Dim usarBrocha As Brush = New TextureBrush( _
Image.FromFile("BuscarArticulo.bmp"))
Dim usarFuente As New Font("Arial", 60, FontStyle.Bold)
e.Graphics.DrawString("Guau.", usarFuente, usarBrocha, 0, 0)
usarFuente.Dispose( )
usarBrocha.Dispose( )

La salida aparece en la figura 18-6.

496 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 496 18/2/10 11:17:27


Figura 18-6. La combinacin de texto e imgenes.

Creacin de imgenes
Tal vez ms que cualquier cosa, Internet ha echado combustible a la necesidad de estmulo visual
del usuario promedio de computadora. Los sitios Web estn llenos de GIF, JPG, TIFF y una va-
riedad de otros formatos de imagen. Aunque trate con aplicaciones que no sean Web, es proba-
ble que como programador, entrar en contacto ms frecuente con imgenes. Por fortuna, GDI+
incluye caractersticas que le permiten administrar y manipular esas imgenes con facilidad.
El formato de archivo BMP es el mapa de bits nativo incluido en Microsoft Windows, pero no
es tan comn en el mundo Web. Sin embargo, nada de esto le importa a GDI+. Puede cargar y
administrar archivos usando los siguientes formatos grficos:
Archivos de mapas de bits BMP de Windows de cualquier nmero de colores y tamao.
Archivos del formato de intercambio de imgenes (GIF, Graphics Interchange Format) de
CompuServe, usados por lo general para imgenes que no son fotografas en Internet.
Archivos del grupo comn de expertos en fotografa (JPEG, Joint Photographic Experts
Group), de uso comn en fotografas y otras imgenes en Internet. Los archivos JPEG estn
comprimidos internamente para reducir el tamao del archivo, pero con la posible prdida
de calidad en la imagen.
Archivos de imagen intercambiable (EXIF, Exchangeable Image File), una variacin de
JPEG que almacena fotografas profesionales.
Archivos de imagen porttil de red (PNG, Portable Network Graphics), que son similares a
archivos GIF, pero con algunas caractersticas mejoradas.
Archivos de formato de archivo de imagen con etiqueta (TIFF, Tag Image File Format), que
son una especie de combinacin de todos los dems formatos de archivo. Algunas organiza-
ciones gubernamentales almacenan imgenes digitalizadas utilizando TIFF.
Metaarchivos, que almacenan arte de lnea vectorial en lugar de imgenes de mapa de bits.
Archivos de cono (ICO), que se usan para conos estndar de Microsoft Windows. Puede
cargarlos como mapa de bits, pero tambin hay una clase Icon distintiva que le permite
tratarlos en maneras ms parecidas a conos.
Se usan tres clases primarias para imgenes: Image (una clase de base abstracta para las otras dos
clases), Bitmap y Metafile. Ms adelante analizar la clase Metafile.

Creacin de imgenes | 497

18_PATRICK-CHAPTER_18.indd 497 18/2/10 11:17:27


Los mapas de bits representan una imagen como un dibujo en una cuadrcula de bits. Cuando
un bit en la cuadrcula est activado, la celda de la cuadrcula es visible o est rellena. Cuando est
desactivado, la celda de la cuadrcula es invisible o est vaca. En la figura 18-7 se muestra una
imagen simple usando como una cuadrcula de mapa de bits.

Figura 18-7. Un mapa de bits monocromtico 8 8 que contiene una obra de arte.

Debido a que un bit slo puede dar soporte a dos estados, los archivos de mapa de bits de 1 bit
son monocromos, desplegando imgenes que slo usan blanco y negro. Para incluir ms colores,
los mapas de bits agregan planos adicionales. Los planos estn apilados uno encima de otro de
modo que una celda en un plano coincide con la celda en esa misma posicin en todos los dems
planos. Un conjunto de ocho planos da como resultado una imagen de mapa de bits de 8 bits
y da soporte a 256 colores por celda (porque 2planos = 28 = 256). Algunas imgenes incluyen hasta
32 o incluso 64 bits (planos), aunque algunos de estos bits pueden reservarse para fusin alfa,
que hace posible la percepcin de la transparencia.
A menos que sea un fantico de las imgenes, la manipulacin de todos esos bits es una tarea
excesiva. Por fortuna, no tiene que preocuparse por ella, porque todo lo hace la clase Bitmap.
Slo necesita preocuparse por cargar y guardar mapas de bits (empleando los mtodos simples
de Bitmap, por supuesto), empleando un mapa de bits como una brocha o un objeto de dibujo
(como ya lo hicimos en algn cdigo de ejemplo en este captulo), o escribir en la superficie del
propio mapa de bits al adjuntar un objeto Graphics.
Si tiene un mapa de bits en un archivo puede cargarlo mediante el constructor de la clase Bitmap.
Dim bonitaImagen As New Bitmap("BuscarArticulo.bmp")

Para guardar un objeto de mapa de bits en un objeto use el mtodo Save.


bonitaImagen.Save("BuscarArticulo.jpg", Imaging.ImageFormat.Jpeg)

Otro constructor le permite crear nuevos mapas de bits en diversos formatos.


' ---- Crear un mapa de bits de 50-50 pixeles, usando planos de 32 bits
' (ocho cada uno para cantidades de rojo, verde y azul
' en cada pixel, y ocho bits para el nivel de
' transparencia de cada pixel, de 0 a 255).
Dim bonitaImagen As New Bitmap(50, 50, _
Drawing.Imaging.PixelFormat.Format32bppArgb)

Para dibujar un mapa de bits en una superficie grfica use el mtodo objeto DrawImage de
Graphics.
e.Graphics.DrawImage(bonitaImagen, leftOffset, topOffset)

498 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 498 18/2/10 11:17:28


Esa instruccin dibuja la imagen en la superficie de la imagen como es, pero eso es un poco
aburrido. Puede ampliar y recortar la imagen mientras la dibuja, o incluso generar una miniatu-
ra. Probar todos estos mtodos usando la imagen de bienvenida del formulario principal del
proyecto Biblioteca (ImagenBienvenida.jpg).
Dim ImagenBienvenida As New Bitmap("ImagenBienvenida.jpg")

' ----- Dibujarla a la mitad del ancho y alto.


e.Graphics.DrawImage(ImagenBienvenida, New RectangleF(10, 50, _
ImagenBienvenida.Width / 2, ImagenBienvenida.Height / 2))

' ----- Ampliarla porque es divertida.


e.Graphics.DrawImage(ImagenBienvenida, New RectangleF(200, 10, _
ImagenBienvenida.Width * 1.25, ImagenBienvenida.Height / 4))

' ----- Dibujar la parte media.


e.Graphics.DrawImage(ImagenBienvenida, 200, 100, New RectangleF( _
0, ImagenBienvenida.Height / 3, ImagenBienvenida.Width, _
ImagenBienvenida.Height / 2), GraphicsUnit.Pixel)

En la figura 18-8 se muestra la salida del bloque de cdigo anterior. Pero no es todo el dibujo
que puede hacer. El mtodo DrawImage incluye 30 sobrecargas. Eso me mantendra ocupado
por lo menos por 37 minutos!

Figura 18-8. Tres vistas de un lector; una obra maestra del autor.

Exposicin de su verdadero artista


Muy bien, hemos cubierto la mayor parte de las caractersticas bsicas de GDI+ usadas para
dibujar imgenes. Ahora es cosa de dibujar comandos para formas, imgenes y texto en la su-
perficie de una imagen. Casi todo el tiempo se apegar a los mtodos incluidos en el objeto
Graphics, sus 12 trillones. Tal vez exagero, pero son muchos. He aqu un ejemplo:

Exposicin de su verdadero artista | 499

18_PATRICK-CHAPTER_18.indd 499 18/2/10 11:17:28


Mtodo Clear. Limpia el fondo con un color especfico.
Mtodo CopyFromScreen. Si el botn Imp Pant de su teclado deja de funcionar, este m-
todo es para usted.
Mtodo DrawArc. Dibuja una parte de un arco a lo largo de la orilla de una elipse. Cero
grados empieza en la posicin de las tres, en caso de que sea un reloj. Un arco con valores
positivos mueve los arcos en direccin de las manecillas de un reloj; use valores negativos
para moverlo en sentido contrario.
Mtodos DrawBezier y DrawBeziers. Dibuja una spline de Bzier, una curva basada en
una frmula que usa un conjunto de puntos, adems de direccionales que guan la curva a
travs de los puntos.
Mtodos DrawCurve, DrawClosedCurve y FillClosedCurve. Dibuja curvas cardinales
(donde los puntos definen la ruta de la curva), con un relleno de brocha opcional.
Mtodos DrawEllipse y FillEllipse. Dibuja una elipse o un crculo (que es una varia-
cin de una elipse).
Mtodos DrawIcon, DrawIconUnstretched, DrawImage, DrawImageUnscaled y Draw
ImageUnscaledAndClipped. Diferente manera de dibujar imgenes e conos.
Mtodos DrawLine y DrawLines. Dibuja una o ms lneas con gran cantidad de opciones
para hacer que las lneas sean elegantes.
Mtodos DrawPath y FillPath. Analizar las rutas grficas un poco ms adelante.
Mtodos DrawPie y FillPie. Dibuja una rebanada de pastel a lo largo del eje de una elipse.
Mtodos DrawPolygon y FillPolygon. Dibuja una formar geomtrica regular o irregular
basada en un conjunto de puntos.
Mtodos DrawRectangle, DrawRectangles, FillRectangle y FillRectangles. Dibu-
ja cuadrados y rectngulos.
Mtodo DrawString. Ya usamos esto para dar salida a texto en el lienzo.
Mtodo FillRegion. Analizar las regiones ms adelante en el captulo.
He aqu un cdigo de ejemplo de dibujo:
' ----- Linea de (10, 10) a (40, 40).
e.Graphics.DrawLine(Pens.Black, 10, 10, 40, 40)

' ----- Arco en 90 grados en sentido del reloj para un circulo de 40 pixeles de diametro.
e.Graphics.DrawArc(Pens.Black, 50, 10, 40, 40, 0, -90)

' ----- Rectangulo de 40x40 rellenado con una linea de guionres.


e.Graphics.FillRectangle(Brushes.Honeydew, 120, 10, 40, 40)
Using plumaGuiones As New Pen(Color.Black, 2)
plumaGuiones.DashStyle = Drawing2D.DashStyle.Dash
e.Graphics.DrawRectangle(plumaGuiones, 120, 10, 40, 40)
End Using

500 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 500 18/2/10 11:17:29


' ----- una rebanada de un pastel elptico.
e.Graphics.FillPie(Brushes.BurlyWood, 180, 10, 80, 40, _
180, 120)

Etctera. Ya se dio una idea. En la figura 18-9 se muestra la salida de este cdigo.

Figura 18-9. Algunos dibujos de ejemplo.

Rutas: dibujos en macrovisin


La clase GraphicsPath le permite recolectar varios de los objetos de dibujo primitivos (como
lneas y arcos, y hasta rectngulo) en una sola unidad agrupada. Esta ruta completa puede repro-
ducirse en una superficie de imgenes como una macro.
Using laRuta As New Drawing2D.GraphicsPath
laRuta.AddEllipse(0, 0, 50, 50)
laRuta.AddArc(10, 30, 30, 10, 10, 160)
laRuta.AddRectangle(New Rectangle(15, 15, 5, 5))
laRuta.AddRectangle(New Rectangle(30, 15, 5, 5))

e.Graphics.DrawPath(Pens.Black, laRuta)
End Using

Este bloque de cdigo dibuja una carita sonriente en el lienzo (vase la figura 18-10).

Figura 18-10. Dibujo con el objeto GraphicsPath.

Qu bonito. Por fortuna, hay otros usos para las rutas grficas, algunas de las cuales analizar en
la siguiente seccin.

Rutas: dibujos en macrovisin | 501

18_PATRICK-CHAPTER_18.indd 501 18/2/10 11:17:29


Regiones e imgenes
Por lo general, cuando dibuja imgenes, tiene todo el lienzo visible para trabajar en l. (Puede di-
bujar imgenes y formas hasta la orilla del lienzo, si lo desea, pero si un rbol dibuja una imagen
en el bosque y nadie est all para admirarla, es real?) Pero hay ocasiones en que querr que slo
aparezca una parte de lo que dibuj. Windows usa este mtodo para ahorrar tiempo. Cuando
oculta una ventana con otra, y luego expone la ventana oculta, la aplicacin tiene que redibujar
todo lo que aparece en el formulario o la ventana. Pero si slo una parte de esa ventana de fondo
est oculta y luego la hace visible de nuevo, por qu el programa debe atravesar el problema de
dibujar todo de nuevo? En realidad slo tiene que redibujar la parte que estaba oculta, la que
estaba en la regin oculta.
Una regin especifica un rea que habr de dibujarse en una superficie. Y las regiones estn li-
mitadas a formas rectangulares aburridas. Puede disear una regin basada en formas simples,
o puede combinar regiones existentes para crear otras ms complejas. Por ejemplo, si tiene dos
regiones rectangulares, puede superponerlas y solicitar una regin combinada que contenga
1) las dos regiones originales; 2) las regiones originales, pero sin las partes superpuestas, o 3) slo
las partes superpuestas. En la figura 18-11 se muestran estas combinaciones.

Regiones originales Unin Xor (XOR) Interseccin (AND)


Figura 18-11. Diferentes combinaciones de regiones.

Durante las operaciones de dibujo, a las regiones en ocasiones se les denomina regiones de
recorte, porque cualquier contenido que se dibuja fuera de la regin es recortado y desechado.
El siguiente cdigo dibuja una imagen, pero enmascarada en una elipse en la parte media al usar
(ta-da!) una ruta grfica para establecer una regin de recorte personalizada:
' ----- Cargar la imagen. Se mostrara mas pequena que lo normal.
Dim ImagenBienvenida As New Bitmap("ImagenBienvenida.jpg")
Dim laRuta As New Drawing2D.GraphicsPath( )

' ----- Crear una ruta eliptica que es del tamano de la


' imagen de salida.
laRuta.AddEllipse(20, 20, ImagenBienvenida.Width \ 2, _
ImagenBienvenida.Height \ 2)

' ----- Reemplazar la region de recorte original que cubre


' todo el lienzo solo con la region rectangular.
e.Graphics.SetClip(laRuta, Drawing2D.CombineMode.Replace)
' ----- Dibujar la imagen, que se recortara.

502 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 502 18/2/10 11:17:30


e.Graphics.DrawImage(ImagenBienvenida, 20, 20, _
ImagenBienvenida.Width \ 2, ImagenBienvenida.Height \ 2)

' ----- Limpiar.


laRuta.Dispose()

La salida de este cdigo aparece en la figura 18-12.

Figura 18-12. Listo para colgarlo en su galera de fotografas.

Las regiones tambin son tiles para prueba de golpes. Si dibuja una imagen no rectangular
en un formulario, y quiere saber cuando el usuario hace clic en la imagen, pero no en cual-
quier pxel fuera de sta, puede usar una regin que tenga la forma exacta de la imagen para
probar los clics del ratn.

Modificaciones elaboradas con transformaciones


Por lo general, cualquier cosa que dibuje en el lienzo grfico cae directamente sobre la superficie
del mapa de bits. Es como una cuadrcula gigante, y sus comandos de dibujo, en esencia, estn
coloreados directamente en cada celda de la cuadrcula. El objeto Graphics tambin le da la
capacidad de pasar sus comandos de dibujo a travs de una transformacin geomtrica antes de
que su salida pase a la superficie del lienzo. Por ejemplo, una transformacin de giro girara sus
lneas, formas y texto en la cantidad que especifique (en grados), y luego aplicara el resultado a
la superficie. En la figura 18-13 se despliegan los resultados del cdigo siguiente, que aplica dos
traducciones: 1) mover el origen (0, 0) 100 pixeles a la derecha y 75 abajo, y 2) agregar un giro
de 270 grados en el sentido de las manecillas del reloj.
e.Graphics.DrawString("Normal", _
SystemFonts.DefaultFont, Brushes.Black, 10, 10)
e.Graphics.TranslateTransform(100, 75)
e.Graphics.RotateTransform(270)
e.Graphics.DrawString("Girada", _
SystemFonts.DefaultFont, Brushes.Black, 10, 10)
e.Graphics.ResetTransform( )

Modificaciones elaboradas con transformaciones | 503

18_PATRICK-CHAPTER_18.indd 503 18/2/10 11:17:30


Figura 18-13. Texto normal y girado.

Las transformaciones son acumulativas; si aplica varias transformaciones al lienzo, cualquier


comando de dibujo recorrer todas las transformaciones antes de llegar al lienzo. El orden en
que ocurren las transformaciones es importante. Si el cdigo que acabamos de ejecutar tiene las
instrucciones TranslateTransform y RotateTransform, el giro habra alterado las coordena-
das x, y para todo el mundo del lienzo. La traduccin siguiente de (100, 75) habra movido el
origen hacia arriba 100 pixeles y luego a la derecha 75 pixeles.
La clase Graphics incluye estos mtodos que le permiten aplicar transformaciones a la vista del
mundo del lienzo durante el dibujo:
RotateTransform
Gira la vista del mundo en grados en sentido de las manecillas del reloj, de 0 a 359. El giro
puede ser positivo o negativo.
ScaleTransform
Establece un factor de escala para todo el dibujo. En esencia, esto aumenta o disminuye el
tamao de la cuadrcula del lienzo cuando se dibuja. El cambio en la escala tiene un impacto
en el ancho de las plumas. Si cambia el tamao del mundo en un factor de dos, no slo las
distancias aparecen duplicadas, sino que todas las plumas se dibujan con el doble del grosor
cuando se elimina la escala.
TranslateTransform
Vuelve a colocar el origen basado en un desplazamiento de x y y.
MultiplyTransform
Una especie de mtodo de transformacin maestra que le permite aplicar transformaciones
mediante el objeto Matrix. Tiene ms opciones que las transformaciones estndar incluidas
en el objeto Graphics. Por ejemplo, puede aplicar una transformacin de inclinacin que
cambie un rectngulo en un paralelogramo.
ResetTransform
Elimina todas las transformaciones aplicadas a un lienzo.

504 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 504 18/2/10 11:17:31


Save
Guarda el estado actual de la superficie de imagen transformada (o no) en un objeto para
posterior restauracin. Esto le permite aplicar algunas transformaciones, guardarlas, aplicar
algunas ms y luego restaurar el conjunto guardado, eliminando cualquier transformacin
aplicada desde que se guard el conjunto.
Restore
Restaura un conjunto de transformaciones guardado.

Mejoramiento de controles mediante el dibujo de propietario


En .NET se incluyen muchas caractersticas ms de dibujo de GDI+, pero lo que hemos vis-
to aqu debe ser suficiente para saciar su apetito. Puede hacer muchos dibujos agradables con
GDI+, pero enfrentmoslo: usted y yo somos programadores, no artistas. Si furamos artistas,
estaramos clasificando seis figuras usando polvo del piso para dibujar paisajes italianos cubistas
tradicionales con acentos de Bauhaus.
Por fortuna, puede hacer cosas prcticas y semiartsticas con GDI+. Una caracterstica de dibujo
importante es el dibujo de propietario, una manera de compartir las propiedades de dibujo entre
un control y usted, el programador. (Usted es el propietario.) El control ComboBox da soporte
a dibujo de propietario de los elementos individuales en la parte desplegable de la lista. Creemos
un control ComboBox que despliegue el nombre de un color, incluida una pequea muestra del
color a la izquierda del nombre. Cree una nueva aplicacin de Windows Forms y agregue un
control ComboBox control llamado ComboBox1 a Form1. Haga estos cambios a ComboBox1:
1. Cambie su propiedad DropDownStyle a DropDownList.
2. Cambie su propiedad DrawMode a OwnerDrawFixed.
3. Modifique su propiedad Items, agregando varios nombres de colores, como lneas de texto
distintivas en la ventana Editor de la coleccin Cadena. Agregu los nombres de los colores,
en ingls (Red, Green y Blue), porque el cdigo tomar este nombre para el despliegue del
cuadro de color. Al lector no debe resultarle difcil hacer los cambios para que se usen nom-
bres en espaol.
Ahora, agregue el siguiente cdigo al rea de cdigo fuente de la clase Form1:
Private Sub ComboBox1_DrawItem(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DrawItemEventArgs) _
Handles ComboBox1.DrawItem
' ----- Ignorar el estado no seleccionado.
If (e.Index = -1) Then Return

' ----- Crear una brocha para el color de despliegue, con base
' en el nombre del elemento.
Dim brochaColor As New SolidBrush(Color.FromName( _
CStr(ComboBox1.Items(e.Index))))

Mejoramiento de controles mediante el dibujo de propietario | 505

18_PATRICK-CHAPTER_18.indd 505 18/2/10 11:17:31


' ----- Crear una brocha de texto. El color varia si
' este elemento esta seleccionado o no.
Dim textoBrocha As Brush
If ((e.State And DrawItemState.Selected) = _
DrawItemState.Selected) Or _
((e.State And DrawItemState.HotLight) = _
DrawItemState.HotLight) Then
textoBrocha = New SolidBrush(SystemColors.HighlightText)
Else
textoBrocha = New SolidBrush(SystemColors.ControlText)
End If

' ----- Obtener la forma del area de despliegue de color.


Dim cuadroColor As New Rectangle(e.Bounds.Left + 4, _
e.Bounds.Top + 2, (e.Bounds.Height - 4) * 2, _
e.Bounds.Height - 4)

' ----- Dibujar el fondo seleccionado o no.


e.DrawBackground( )

' ----- Dibujar el area de color personalizada.


e.Graphics.FillRectangle(brochaColor, cuadroColor)
e.Graphics.DrawRectangle(Pens.Black, cuadroColor)

' ----- Dibujar el nombre del color a la derecha de este.


e.Graphics.DrawString(CStr(ComboBox1.Items(e.Index)), _
ComboBox1.Font, textoBrocha, 8 + cuadroColor.Width, _
e.Bounds.Top + ((e.Bounds.Height - _
ComboBox1.Font.Height) / 2))

' ----- Dibujar un rectangulo seleccionado alrededor del elemento,


' si es necesario.
e.DrawFocusRectangle( )

' ----- Limpiar.


textoBrocha.Dispose( )
brochaColor.Dispose( )
End Sub

Ejecute el cdigo y juegue con el cuadro combinado, como se muestra en la figura 18-14.

Figura 18-14. Nuestro cuadro combinado personalizado de colores.

506 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 506 18/2/10 11:17:31


Windows Presentation Foundation
Las interfaces grficas de usuario son un fenmeno relativamente nuevo. Los primeros progra-
madores no tenan todas esas campanitas que adornan las modernas interfaces de usuario. Te-
nan que hacerlo con marcas navales de semforo y cdigo Morse. Aqu en el siglo xxi, habiendo
pasado las pocas de las interfaces de texto y de figuras pegadas, las computadoras finalmente son
capaces de presentar informacin de una manera que confunde totalmente al usuario final, pero
en un estilo hermoso y muy interactivo.
La herramienta ms reciente de Microsoft para la construccin de interfaces de usuario activas,
de la siguiente generacin, es la base de presentacin de Windows (WPF, Windows Presentation
Foundation). Como en LINQ, WPF une muchas tecnologas diferentes en un solo campo unifi-
cado. Algunas de estas tecnologas han estado con nosotros durante muchos aos, como el sistema
Direct3D de Microsoft, que despliega y manipula elementos 3D. WPF condensa todas estas tec-
nologas y las hace disponibles mediante un lenguaje descriptivo basado en XML, conocido como
XAML (eXtensible Application Markup Lenguaje, lenguaje extensible de marcado de aplicacin).
WPF incluye caractersticas y elementos que tratan con muchas reas de presentacin, incluidos
controles en pantalla, dibujos 2D (como GDI+), imgenes 3D (de Direct3D), imgenes estti-
cas (como imgenes JPEG), multimedia interactiva (video y audio), y presentacin de documen-
tos WYSIWYG (similar a documentos PDF). Pueden animarse elementos individuales y todas
las interfaces de usuario automticamente, o como respuestas a interacciones de usuarios.
Cuando se trata de desplegar su contenido WPF puede presentarlo al usuario de unas cuantas
maneras. Los archivos XAML y el cdigo .NET relacionado pueden construirse en una apli-
cacin independiente, como una aplicacin tpica de Windows Forms de .NET, pero con el
asombroso parecido a Cary Grant que suele ser inaccesible para los desarrolladores.
WPF tambin puede usarse para generar aplicaciones Web hospedadas dentro del explorador de
usuario. En realidad, los elementos que disee para uso en aplicaciones estilo escritorio pueden
usarse en Web sin modificaciones. Como es de esperar, las limitaciones de seguridad ponen un
tope a algunas cosas que puede hacer cuando ejecute este tipo de host.
Los programas WPF de explorador requieren que .NET Framework y las bibliotecas de WPF es-
tn instaladas y accesibles en la estacin de trabajo del cliente. Microsoft est integrando mucha
de esa tecnologa y empaquetndola en un producto llamado Silverlight. Diseado para competir
con cosas como la plataforma Flash de Adobe y el nuevo sistema JavaFX de Sun Microsystems,
Silverlight con el tiempo permitir que contenido vinculado de XAML y .NET se ejecuten en
plataformas que no son de Windows, como Macintosh.
Una tercera variacin usa un conjunto de XAML para definir un documento esttico tipo PDF.
A estos documentos se les conoce como XPS (XML Paper Specification, especificacin de papel
de XML), y en realidad son archivos ZIP que contienen todas las pginas XAML, imgenes y
otros elementos de pgina en archivos distintivos dentro del archivado.

Windows Presentation Foundation | 507

18_PATRICK-CHAPTER_18.indd 507 18/2/10 11:17:31


WPF y XAML
Una de las marcas distintivas del diseo de aplicaciones en WPF es la separacin entre la lgica
y la presentacin. Se trata de un objetivo comn expresado en muchas tecnologas ms recien-
tes, incluidos XML y ASP.NET (vase el captulo 23). Toda la lgica de la aplicacin (todos los
manejadores de eventos desencadenados por la entrada del usuario y las acciones del sistema)
estn escritos en cdigo .NET estndar. La interfaz de usuario tambin puede aparecer como
cdigo .NET, con objetos creados a partir del espacio de nombres System.Windows especfico
de WPF. Pero es ms comn disear elementos de interfaz de usuario y controles derivados
mediante XAML, un esquema XML que puede generarse en Visual Studio o el Bloc de notas, o
por herramientas de terceros.
Debido a que el contenido XAML puede generarse fuera de su aplicacin, un especialista en
diseo de interfaces de usuario con conocimientos limitados de programacin pueden generar
los componentes de sta de manera independiente del trabajo del desarrollador en la lgica de la
aplicacin. Microsoft ofrece una herramienta para esos diseadores, llamado Microsoft Expres-
sion Blend, uno de un puado de productos de diseo de Expression. Otros vendedores tambin
ofrecen herramientas para generar contenido rico en XAML.
Visual Studio 2008 le permite crear aplicaciones WPF completas con base en contenido XAML.
Para generar una aplicacin WPF, inicie Visual Studio, cree un nuevo proyecto y, desde el cuadro
de dilogo Nuevo Proyecto, seleccione la plantilla Aplicacin WPF dentro de Tipo de proyecto
Visual Basic. Luego haga clic en Aceptar. De inmediato, Windows crea un nuevo proyecto de
WPF Forms, desplegando el formulario de inicio, Window1 (vase la figura 18-15).

Figura 18-15. No es demasiado diferente de una aplicacin Windows Forms.

508 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 508 18/2/10 11:17:32


La interfaz de usuario est definida por completo por el conjunto XML desplegado en la parte
inferior del formulario. Actualmente, define la propia ventana de la eventual aplicacin.
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com
/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>

</Grid>
</Window>

Este cdigo define la ventana, Window1, que tiene su clase real System.Windows.Window. Los
atributos de la etiqueta Window de XAML, incluidos Title, Height y Width, se asignan a las
propiedades del mismo nombre en la clase Window.
Aadamos un poco de picante a este formulario. Agreguemos un botn que incluye un arcoris
en la superficie de ste, adems de un brillo amarillo alrededor del botn. Agregar un maneja-
dor de eventos que muestre un cuadro de mensaje. Al igual que con una aplicacin estndar de
Windows Forms, se utilizan los controles en el Cuadro de herramientas para generar su formu-
lario. Arrastrar un botn a la superficie del formulario y usar el rea de texto XAML para dar
nueva vida a la ventana.
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="160" Width="411">
<Grid>
<Button Margin="95,26,99,35" Name="Button1">
<Button.Foreground>White</Button.Foreground>
<Button.FontSize>18</Button.FontSize>
<Button.FontWeight>Bold</Button.FontWeight >
<Button.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="Red" Offset="0" />
<GradientStop Color="Orange" Offset="0.1425"/>
<GradientStop Color="Yellow" Offset="0.285"/>
<GradientStop Color="Green" Offset="0.4275"/>
<GradientStop Color="Blue" Offset="0.57"/>
<GradientStop Color="Indigo" Offset="0.7325"/>
<GradientStop Color="Violet" Offset="0.875"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Button.Background>
<Button.BitmapEffect>
<OuterGlowBitmapEffect />
</Button.BitmapEffect> Click Me
</Button>
</Grid>
</Window>

Windows Presentation Foundation | 509

18_PATRICK-CHAPTER_18.indd 509 18/2/10 11:17:32


Tambin agregar un manejador de eventos, empleando la misma simplicidad de sealar y hacer
clic que he usado en los proyecto de Windows Forms.
Private Sub Button1_Click(ByVal sender As Object, _
ByVal e As System.Windows.RoutedEventArgs) _
Handles Button1.Click
MsgBox("Hola, mundo")
End Sub

Al ejecutar este programa con la tecla F5 se nos presenta el formulario y el botn esperados, pero,
oh, qu botn tan complejo (vase la figura 18-16).

Figura 18-16. Haga clic en algn lugar del arcoris.

Aunque el color no aparece en este libro en escala de grises, el formulario tiene un botn con el
arcoris desplegado.

Mejoramiento de clases con atributos


Los atributos que modifican clases son algo que analizamos en el captulo 1, y no tienen relacin con
GDI+. Slo quera actualizar su memoria porque se usarn en el cdigo del proyecto de este captulo.
Los atributos que modifican clases o miembros aparecen justo antes de la definicin de la clase o
miembro, y dentro de parntesis angulares. Este cdigo adjunta el atributo AtributoObsoleto
a la clase SomeOldClass:
<AtributoObsoleto> _
Class AlgunaClaseAntigua
...aqui van los detalles de la clase...
End Class

(La parte del atributo de un nombre no debe entrar en conflicto con alguna palabra clave de
Visual Basic.) Los atributos aparecen como metadatos en el ensamblado compilado final, y son
usados por clases y aplicaciones que, por diseo, extraen significado de atributos especficos. En
el cdigo de este captulo usaremos el control PropertyGrid, el control que implementa el pa-
nel Propiedades dentro del entorno de desarrollo de Visual Studio, y suele usarse para modificar

510 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 510 18/2/10 11:17:33


las propiedades Form y Control. Este control est disponible para que lo use en sus propias apli-
caciones. Para usarlo, asigne una instancia de clase a la propiedad SelectedObject del control.
Luego, mgicamente, todas las propiedades del objeto aparecen en la lista de propiedades del
control.
Aunque es agradable, no siempre es deseable. Su objeto puede tener propiedades que no deben
desplegarse. El control PropertyGrid est diseado para ser genrico; no conoce las necesida-
des de su objeto, de modo que no sabe cules propiedades excluir. Es decir, no lo sabe, hasta que
se lo indique mediante atributos. Al agregar atributos especficos a las propiedades de su clase,
le indica al control PropertyGrid cmo tratar miembros de su objeto. Por ejemplo, el atribu-
to BrowsableAttribute le indica a PropertyGrid que incluya (True) o excluya (False) la
propiedad.
<Browsable(False)> _
Public Property PropiedadSecreta() As String...

Proporcionar detalles adicionales acerca de esto cuando usemos el control PropertyGrid ms


adelante en este captulo.

Resumen
Aunque muchas partes de GDI+ son como envolturas alrededor del viejo sistema GDI, GDI+
an se las arregla para proporcionar poder y simplicidad que rebasa la implementacin original.
En el desarrollo de aplicaciones de negocios, no siempre tiene la necesidad de usar los aspectos
ms interesantes del espacio de nombres System.Drawing. Pero cuando lo hace, encontrar un
sistema simple y coherente para despliegue de imgenes, texto y elementos vectoriales personali-
zados en la pantalla u otro medio de salida.
Y hablando de simplicidad y coherencia, busque WPF en un equipo de cmputo cerca de usted.
A medida que ms programadores se vean seducidos por el nuevo sistema, con el tiempo suplan-
tar a Windows Forms y al sistema de pginas ASP.NET como la capa de presentacin principal
en el escritorio .NET y en aplicaciones Web.

Proyecto
El proyecto Biblioteca ha usado caractersticas de GDI+ desde el momento en que apareci el
primer formulario en el proyecto recin creado, pero lleg gratis mediante cdigo incluido en
el marco conceptual. Ahora es tiempo de que usted, el programador, agregue su propia contribu-
cin de GDI+ a la aplicacin. En el cdigo de proyecto de este captulo utilizaremos GDI+ para
mejorar el despliegue normal de un control mediante caractersticas de diseo de propietario.
Adems, por fin empezaremos a implementar parte de las caractersticas de cdigo de barras con
que lo tent en captulos anteriores. Siento decirle que no usaremos la agradable experiencia de
dibujo XML que es WPF.

Proyecto | 511

18_PATRICK-CHAPTER_18.indd 511 18/2/10 11:17:33


Acceso al proyecto
Cargue el proyecto Cap18 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap18 (Final) cdigo.

Instale la fuente de cdigo de barras


Si an no ha obtenido una fuente de cdigo de barras, es hora de que lo haga. Las caractersticas
incluidas en el cdigo de proyecto de este captulo requerirn que use esa fuente. El sitio Web del
editor de este libro (que aparece en el apndice A) incluye recursos sugeridos para obtener una
fuente a un mdico precio o gratuito para uso personal. Tambin puede comprar una fuente de
cdigo de barras profesional. Asegrese de que la fuente que obtiene sea TrueType.

Uso de dibujo de propietario


En el captulo anterior agregamos el formulario BusquedaArticulo.vb con sus mltiples vistas de
elementos de biblioteca. Una de esas vistas inclua el control ArticulosCoincidentes, un cua-
dro de lista de varias columnas que desplegaba las columnas Autor/Nombre, Llamada Nmero
y Tipo de medio. Aunque almacenamos los datos especficos de la columna dentro de cada
elemento, en realidad no desplegamos las columnas individuales para el usuario.
Lo importante acerca de la listas de varias columnas y otros despliegues de texto limitados es que
parte de ese texto est unido para sobrescribir su rea oficial, si lo permite. Por ejemplo, el texto
de una columna de la lista puede superponerse al de otro. En esos casos, se ha vuelto tradicin
recortar el contenido extendido y reemplazarlo con puntos suspensivos (). Por tanto, nece-
sitamos una rutina que determine si una cadena es demasiado larga para su rea de despliegue,
y que realice el recorte y la inclusin de puntos suspensivos, como sea necesario. Agregue el
mtodo AcomodarTextoAlAncho al cdigo de mdulo del archivo General.vb.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap18, Elemento 1.

Public Function AcomodarTextoAlAncho(ByVal textoOriginal As String, _


ByVal anchoPixeles As Integer, _
ByVal lienzo As System.Drawing.Graphics, _
ByVal usarFuente As System.Drawing.Font) As String
' ----- Dada una cadena de texto, asegurarse de que cabe en el
' ancho especificado de pixeles. Truncar y agregar
' puntos suspensivos, si es necesario.
Dim nuevoTexto As String
nuevoTexto = textoOriginal

512 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 512 18/2/10 11:17:33


If (lienzo.MeasureString(nuevoTexto, usarFuente).Width( ) > _
anchoPixeles) Then
Do While (lienzo.MeasureString(nuevoTexto & "...", _
usarFuente).Width( ) > anchoPixeles)
nuevoTexto = Left(nuevoTexto, nuevoTexto.Length - 1)
If (nuevoTexto = "") Then Exit Do
Loop
If (nuevoTexto <> "") Then nuevoTexto &= "..."
End If
Return nuevoTexto
End Function

El formulario BusquedaArticulo.vb tiene un botn Atrs como en los exploradores Web, con una
lista desplegable de entradas recientes. Los elementos agregados a la lista pueden incluir ttulos
y nombres de autor largos. Usemos el nuevo mtodo AcomodarTextoAlAncho para limitar el
tamao de los elementos de texto en esta lista. Abra el cdigo fuente del formulario Busque
daArticulo y localice el mtodo ActualizarBotonesAtras. Cerca de la mitad de esta rutina
se encuentra esta lnea de cdigo:
cualMenu.Text = buscarHistoria.DesplegarHistoria

Reemplace esta lnea, en cambio, con las siguientes.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap18, Elemento 2.

cualMenu.Text = AcomodarTextoAlAncho(buscarHistoria.DesplegarHistoria, _
Me.Width \ 2, usarLienzo, cualMenu.Font)

Eso limitar cualquier texto de elemento de men a la mitad del ancho del formulario, lo que
parece razonable. Esa variable usarLienzo es nuevo, as que agreguemos una declaracin en la
parte superior del mtodo ActualizarBotonesAtras.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap18, Elemento 3.

Dim usarLienzo As Drawing.Graphics = Me.CreateGraphics(


)

Adems, necesitamos desechar apropiadamente ese lienzo grfico creado al principio del mtodo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap18, Elemento 4.

usarLienzo.Dispose( )

Proyecto | 513

18_PATRICK-CHAPTER_18.indd 513 18/2/10 11:17:33


Ahora tomemos los elementos de la lista de dibujo. Los controles ListBox le permiten usar su
propio cdigo de dibujo para cada elemento visible de la lista. Tiene dos opciones cuando est
administrando usted mismo el dibujo de elementos: puede mantener cada elemento a una altura
consistente y puede hacer que cada elemento de la lista tenga una altura diferente con base en el
contenido de ese elemento. En el cuadro de dilogo ArticulosCoincidentes utilizaremos la
misma altura para cada elemento de la lista.
Para habilitar el modo de dibujo de propietario, abra el editor de diseo de formulario Bus
quedaArticulo, seleccione el cuadro de lista ArticulosCoincidentes en el formulario o
mediante el panel Propiedades, y cambie su propiedad DrawMode a OwnerDrawFixed.
Cada elemento coincidente de la lista incluir dos filas de datos: 1) el ttulo del elemento coinci-
dente, en negritas, y 2) las tres columnas de autor, nmero de llamada y datos de tipo de medio.
Agregue el siguiente cdigo al manejador de eventos Load que determina la altura total de cada
elemento de la lista, y la posicin de la segunda lnea dentro de cada elemento.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap18, Elemento 5.

' ----- Preparar el formulario.


Dim imagenesFormulario As System.Drawing.Graphics

' ----- Establecer la altura predeterminada de elementos


' en el cuadro de lista de elementos coincidentes.
imagenesFormulario = Me.CreateGraphics( )
ArticulosCoincidentes.ItemHeight = CInt(imagenesFormulario.MeasureString( _
"A" & vbCrLf & "g", ArticulosCoincidentes.Font).Height( )) + 3
FilaSegundoArticulo = CInt(imagenesFormulario.MeasureString("Ag", _
ArticulosCoincidentes.Font).Height( )) + 1
imagenesFormulario.Dispose( )

Us el texto Ag para asegurarme de que la altura incluya todos los elementos ascendentes y descen-
dentes de la fuente (las partes que sobresalen arriba y abajo de la mayor parte de las letras). Pienso
que el clculo incluira esos valores aunque usara mm para la cadena, pero como digo siempre, es
mejor prevenir que lamentar. Al establecer la propiedad ArticulosCoincidentes.ItemHeight
aqu, se indica el tamao de todos los elementos de la lista. Si hubiera decidido usar elementos de
altura variable en lugar de fija, habra manejado el evento MeasureItem del control. Con los ele-
mentos fijos podemos ignorar ese evento, y pasar al que hace el dibujo real: DrawItem.
He aqu lo que cdigo va a hacer para cada elemento de la lista: 1) crear las brochas y los objetos
de fuente necesarios que usaremos en el dibujo; 2) dibujar las cadenas de texto en el lienzo de
elementos de lista, y 3) limpiar. Debido a que los elementos de la vista tambin pueden estar selec-
cionados o no, llamaremos a algn mtodo proporcionado por el marco conceptual para dibujar
los elementos apropiados de fondo y primer plano que indican las selecciones de elementos.
Cuando dibujamos las columnas de texto mltiples, es posible que una columna sea demasiado
larga e invada el rea de la siguiente columna. Por esto es por lo que escribimos antes la funcin

514 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 514 18/2/10 11:17:33


AcomodarTextoAlAncho. Pero resulta que GDI+ ya incluye una caracterstica que agrega pun-
tos suspensivos al texto justo a la derecha, cuando no cabe. Se encuentra en una clase llamada
StringFormat, en su propiedad Trimming. Al establecer esta propiedad en EllipsisCharac
ter y usarla cuando se dibuja la cadena, se recortar sta cuando sea apropiado. Cuando dibuje-
mos la cadena en el lienzo proporcionaremos un rectngulo que indique a la cadena cules son
los lmites. He aqu el cdigo bsico usado para dibujar una columna de texto truncado:
Dim textoSuspensivos As New StringFormat
textoSuspensivos.Trimming = StringTrimming.EllipsisCharacter
e.Graphics.DrawString("Algun texto largo ", e.Font, algunaBrocha, _
New Rectangle(left, top, width, height), textoSuspensivos)

El cdigo que usar para dibujar cada elemento de la lista ArticulosCoincidentes usar
cdigo como ste. Agreguemos ahora ese cdigo al manejador de eventos ArticulosCoinci
dentes.DrawItem.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap18, Elemento 6.

' ----- Dibujar los elementos coincidentes en dos lineas.


Dim elementoADibujar As DatosArticulosCoincidentes
Dim usarBrocha As System.Drawing.Brush
Dim fuenteNegritas As System.Drawing.Font
Dim textoSuspensivos As StringFormat

' ----- Dibujar el fondo del elemento.


If (CBool(CInt(e.State) And CInt(DrawItemState.Selected))) _
Then usarBrocha = SystemBrushes.HighlightText _
Else usarBrocha = SystemBrushes.WindowText
e.DrawBackground()

' ----- El titulo usara una version en negritas de cada fuente principal.
fuenteNegritas = New System.Drawing.Font(e.Font, FontStyle.Bold)

' ----- Obtener el elemento que se dibujara.


elementoADibujar = CType(ArticulosCoincidentes.Items(e.Index), _
DatosArticulosCoincidentes)
textoSuspensivos = New StringFormat
textoSuspensivos.Trimming = StringTrimming.EllipsisCharacter

' ----- Dibujar el texto del elemento.


e.Graphics.DrawString(elementoADibujar.Titulo, fuenteNegritas, usarBrocha, _
New Rectangle(0, e.Bounds.Top, _
ElemFinCol.Left - ArticulosCoincidentes.Left, _
fuenteNegritas.Height), textoSuspensivos)
e.Graphics.DrawString(elementoADibujar.Autor, e.Font, usarBrocha, _
New Rectangle(ElemAutorCol.Left, _
e.Bounds.Top + FilaSegundoArticulo, _
ElemLlamadaCol.Left - ElemAutorCol.Left - 8, _
e.Font.Height), textoSuspensivos)

Proyecto | 515

18_PATRICK-CHAPTER_18.indd 515 18/2/10 11:17:33


e.Graphics.DrawString(elementoADibujar.NumeroLlamada, e.Font, _
usarBrocha, New Rectangle(ElemLlamadaCol.Left, _
e.Bounds.Top + FilaSegundoArticulo, _
ElemFinCol.Left - ElemTipoCol.Left, _
e.Font.Height), textoSuspensivos)
e.Graphics.DrawString(elementoADibujar.TipoMedio, e.Font, _
usarBrocha, New Rectangle(ElemTipoCol.Left, _
e.Bounds.Top + FilaSegundoArticulo, _
ElemTipoCol.Left - ElemLlamadaCol.Left - 8, _
e.Font.Height), textoSuspensivos)

' ----- Si el ListBox tiene el enfoque, dibujar un rectangulo de enfoque.


e.DrawFocusRectangle()
fuenteNegritas.Dispose()

Lo ve?, es sorprendentemente fcil dibujar cualquier cosa que quiera en el elemento de cuadro
de lista. En este cdigo, la salida real al lienzo mediante GDI+ fue responsable de las cuatro
instrucciones DrawString. Aunque esta base de datos de biblioteca no le da soporte, pudimos
incluir una imagen de cada elemento en la base de datos y desplegarlo en el cuadro de lista, justo
a la izquierda del ttulo. Adems, las llamadas a e.DrawBackground y e.DrawFocusRectangle
permiten que el control resalte apropiadamente el elemento correcto (aunque tuve que elegir la
brocha de texto). En la figura 18-17 se muestran los resultados de nuestra dura labor.

Figura 18-17. Un libro de ejemplo con dos lneas y tres columnas.

Diseo de cdigo de barras


El proyecto Biblioteca incluye soporte genrico para etiquetas de cdigo de barras. Visit unas
cuantas bibliotecas en mi rea y compar los cdigos de barras agregados a los artculos de su
biblioteca (como libros) y sus tarjetas de ID de cliente. Encontr que la variedad era demasiado
grande como para enmarcarla en una solucin predefinida. Por tanto, la aplicacin de Biblioteca
permite a un administrador o bibliotecario disear hojas de etiquetas de cdigo de barras para
cumplir sus necesidades especficas. (Hay negocios que venden etiquetas y tarjetas de cdigo de
barras preimpresas a bibliotecas que no quieren imprimir las propias. La aplicacin tambin da
soporte a este mtodo, porque la generacin de cdigo de barras y la asignacin de ste a artcu-
los son dos pasos distintos.)
Para dar soporte al diseo de cdigos de barras genricos, agregaremos un conjunto de clases de
diseo y dos formularios a la aplicacin:

516 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 516 18/2/10 11:17:34


ClaseElementoCodigoBarras.vb
Este archivo de clase contiene seis clases distintas, una de las cuales es una clase de base
para las otras cinco clases derivadas. Las clases derivadas disean los elementos de texto
estticos, las imgenes y los nmeros de cdigo de barras, las lneas y los rectngulos que el
usuario agregar a la superficie de una sola etiqueta de cdigo de barras.
PaginaCodigoBarras.vb
Se trata de un formulario de editor derivado de FormularioCodigoBase, el mismo formula-
rio base usado por los diversos editores de cdigo en la aplicacin. Este formulario especifica la
organizacin de las hojas de etiquetas. El usuario probablemente comprar hojas de etiquetas
en su tienda de artculos de oficina. Al ingresar el nmero de filas y columnas de la etiqueta, el
tamao de cada etiqueta y cualquier espacio entre las etiquetas y alrededor de stas, el usuario
puede disear en gran medida muchas de las hojas de etiquetas regulares.
EtiquetaCodigoBarras.vb
Otro editor basado en FormularioCodigoBase; este formulario permite al usuario disear
una etiqueta nica de cdigo de barras al agregar texto, cdigos de barras, lneas y rectngu-
los a un rea de vista previa.
En un captulo futuro agregaremos la impresin de etiquetas, donde las etiquetas y las pginas se
unirn en un glorioso trabajo de impresin.
Debido a que estos tres archivos juntos incluyen casi 2000 lneas de cdigo fuente, slo le mos-
trar las secciones clave de cada uno. Ya he agregado los tres archivos al cdigo de su proyecto,
de modo que empecemos con ClaseElementoCodigoBarras.vb. Define cada tipo de elemento de
despliegue que el usuario agregar a la plantilla de etiqueta en el formulario EtiquetaCodigoBa-
rras.vb. He aqu el cdigo de la clase base abstracta, GenericoArticuloCodigoBarras:
Imports System.ComponentModel
Public MustInherit Class GenericoArticuloCodigoBarras
<Browsable(False)> Public MustOverride ReadOnly _
Property ItemType( ) As String
Public MustOverride Overrides _
Function ToString( ) As String
End Class

No hay mucho aqu. La clase define dos miembros obligatorios: una propiedad String de slo
lectura llamada ItemType, y un requisito de que la clase derivada proporcione su propia imple-
mentacin para ToString. Las otras cinco clases derivadas de este archivo mejoran la clase base
para dar soporte a los distintos tipos de elementos de despliegue incluidos en una etiqueta de c-
digo de barras. Revisemos brevemente una de las clases, RecArticuloCodigoBarras. Permite
que un rectngulo con relleno opcional aparezca en una etiqueta de cdigo de barras, e incluye
miembros privados que rastrean los detalles del rectngulo.
Public Class RecArticuloCodigoBarras
' ----- Incluye un elemento de rectangulo basico en una
' etiqueta de codigo de barras.
Inherits GenericoArticuloCodigoBarras

' ----- Almacen privado de atributos.

Proyecto | 517

18_PATRICK-CHAPTER_18.indd 517 18/2/10 11:17:34


Private RecAlmacenadoIzquierda As Single
Private RecAlmacenadoArriba As Single
Private RecAlmacenadoAncho As Single
Private RecAlmacenadoAlto As Single
Private RecAlmacenadoColor As Drawing.Color
Private RellenoColorAlmacenado As Drawing.Color
Private RecAlmacenadoAngulo As Short

El resto de la clase incluye propiedades que proporcionan la interfaz pblica de esos miembros
privados. He aqu el cdigo para la propiedad RellenarColor:
<Browsable(True), DescriptionAttribute( _
"Establece el color de relleno del rectangulo.")> _
Public Property FillColor() As Drawing.Color
' ----- El color de relleno.
Get
Return RellenoColorAlmacenado
End Get
Set(ByVal Value As Drawing.Color)
RellenoColorAlmacenado = Value
End Set
End Property

Como casi todas las dems propiedades, slo recupera el valor privado relacionado. Su declaracin
incluye dos atributos que sern ledos por el control PropertyGrid ms adelante. La propiedad
Browsable dice: S, incluye esta propiedad en la cuadrcula, y DescriptionAttribute esta-
blece el texto que aparece en la parte inferior del rea de ayuda del control PropertyGrid.
Cuando haya usado el panel Propiedades para editar sus formularios, podr establecer colores
para una propiedad de color empleando una herramienta de seleccin de color especial integrada
en la propiedad. Basta con tener una propiedad definida usando System.Drawing.Color para
habilitar esta misma funcionalidad para su propia clase. Cmo funciona? Igual que la propiedad
RellenarColor tiene atributos reconocidos por el control PropertyGrid, la clase System.
Drawing.Color tambin tiene esas propiedades, una de las cuales define una clase de editor de
propiedades personalizada para colores. Su implementacin est ms all del alcance de este libro,
pero de todos modos es estupenda. Si est interesado en hacer esto para sus propias clases, puede
leer un artculo que escrib acerca de los editores de cuadrcula de propiedades hace unos aos.*
Antes de llegar a los formularios de editor, necesito que conozca cuatro funciones de apoyo que
ya agregu al archivo del mdulo General.vb:
Funcin GenerarEstiloFuente
Estilos de fuente (como negritas e itlicas) se establecen en los objetos Font empleando miem-
bros de la enumeracin System.Drawing.FontStyle. Pero cuando se almacena informa-
cin de fuentes en la base de datos, eleg almacenar esas configuraciones de estilo empleando
letras (como N para negritas). Esta funcin convierte las letras al valor FontStyle.

* Encontrar el artculo de referencia en mi, http://www.timaki.com, en la seccin Articles.

518 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 518 18/2/10 11:17:34


Funcin ConvertirUnidadesPagina
Los editores de pgina le permiten colocar elementos en unos cuantos sistemas de medida
diferentes, incluidas pulgadas y centmetros. Esta funcin convierte medidas entre los dife-
rentes sistemas.
Funcin EstiloFuenteBD
Esto es lo opuesto de la funcin GenerarEstiloFuente, preparando un valor FontStyle
para insercin en un registro de base de datos.
Funcin ObtenerFuenteCodigoBarras
Esto devuelve el nombre de la fuente de cdigo de barras, si est configurado.
El formulario PaginaCodigoBarras permite al usuario definir una hoja de etiquetas completa.
No las propias etiquetas, sino las posiciones de varias etiquetas en la misma pgina impresa. En
la figura 18.18 se muestran los campos de algunos datos de ejemplo.

Figura 18-18. El formulario PaginaCodigoBarras.

De manera colectiva, los campos en el formulario describen el tamao de la pgina y el de cada


etiqueta que aparece en sta. A medida que el usuario ingresa los valores, el rea Vista previa de
pgina se actualiza de manera instantnea con una vista previa del aspecto que tendr la pgina.
Como editor de cdigo derivado de FormularioCodigoBase, la lgica del formulario ya le
debe resultar familiar; administra los datos encontrados en un solo registro de la tabla Hoja
CodigoBarras. Lo que es diferente es el cdigo GDI+ encontrado en el manejador de eventos
AreaVistaPrevia.Paint. Su primer bloque principal de cdigo trata de determinar la manera

Proyecto | 519

18_PATRICK-CHAPTER_18.indd 519 18/2/10 11:17:35


en que se reduce una hoja de papel de 27.2 21.6 centmetros para que aparezca en un pequeo
rectngulo que tiene slo 216 272 pixeles. Es una gran cantidad de clculos sangrientos que,
cuando se completan, determinan la relacin de papel grande a pequeo, y que lleva al dibujo
de una pieza de papel en pantalla con un borde una sombra cada.
e.Graphics.FillRectangle(SystemBrushes.ControlDark, _
pageLeft + 1, pageTop + 1, pageWidth + 2, pageHeight + 2)
e.Graphics.FillRectangle(SystemBrushes.ControlDark, _
pageLeft + 2, pageTop + 2, pageWidth + 2, pageHeight + 2)
e.Graphics.FillRectangle(Brushes.Black, pageLeft - 1, _
pageTop - 1, pageWidth + 2, pageHeight + 2)
e.Graphics.FillRectangle(Brushes.White, pageLeft, _
pageTop, pageWidth, pageHeight)

Luego, antes de dibujar los contornos de la vista previa de cada etiqueta rectangular, reubica el
origen de la cuadrcula en la esquina superior izquierda de la hoja de papel en pantalla, y trans-
forma la escala con base en la relacin de una pieza de papel real a la imagen en pantalla.
e.Graphics.TranslateTransform(izquierdaPagina, arribaPagina)
e.Graphics.ScaleTransform(usarRelacion, usarRelacion)

Hay que hacer unos cuantos clculos ms para el tamao de cada etiqueta, seguidos por un do-
ble bucle (para las filas y columnas de etiquetas) que hacen la impresin real de los lmites de la
etiqueta (el clculo de los detalles se omiti para ser breves).
For rastreoFila = 1 To CInt(BCRows.Text)
For colScan = 1 To CInt(BCColumns.Text)
desplazamientoIzquierda = ...
topOffset = ...
e.Graphics.DrawRectangle(Pens.Cyan, _
desplazamientoIzquierda, desplazamientoArriba, _
unTwipsAncho, unTwipsAlto)
Next rastreoCol
Next rastreoFila

EtiquetaCodigoBarras es, evidentemente, el ms interesante y complejo de los dos formula-


rios de edicin de cdigos de barras. Mientras el formulario PaginaCodigoBarras define una
hoja completa de etiquetas sin algo dentro de cada etiqueta, EtiquetaCodigoBarras define lo
que va dentro de cada una de estas etiquetas. En la figura 18-19 se muestra este formulario con
una etiqueta de ejemplo.
El formulario EtiquetaCodigoBarras se deriva de FormularioCodigoBase, de modo que su
cdigo trata con la carga y el guardado de registros de las tablas de la base de datos Etiqueta
CodigoBarras y ArtEtiquetaCodBarras. Cada etiqueta de cdigo de barras est unida a una
plantilla de pgina especfica (que acabamos de definir mediante el formulario PaginaCodigo
Barras), y almacena su registro principal en la tabla EtiquetaCodigoBarras. Esta tabla define
los fundamentos de la etiqueta, como su nombre y sistema de medicin. Los elementos de texto
y forma colocados en esa etiqueta estn almacenados como registros en la tabla ArtEtiqueta
CodBarras relacionada.

520 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 520 18/2/10 11:17:35


Figura 18-19. El formulario EtiquetaCodigoBarras.

La rutina PrepararCamposFormulario carga registros existentes de la etiqueta de la base de


datos, creando instancias de clases del nuevo archivo ClaseElementoCodigoBarras.vb, y los agrega
al control ListBox ElementosDesplegados control. He aqu la seccin de cdigo que carga
una imagen de cdigo de barras (el cdigo de barras real desplegado) de una entrada en la tabla
ArtEtiquetaCodBarras:

nuevaImagenCodigoBarras = New Biblioteca.ImagenCodigoArticuloCodigo


nuevaImagenCodigoBarras.Alignment = CType(CInt(infoBD!Alineacion), _
System.Drawing.ContentAlignment)
nuevaImagenCodigoBarras.BarcodeColor = _
System.Drawing.Color.FromArgb(CInt(infoBD!Color1))
nuevaImagenCodigoBarras.BarcodeSize = CSng(infoBD!PuntosFuente)
nuevaImagenCodigoBarras.Left = CSng(infoBD!PosIzq)
nuevaImagenCodigoBarras.Top = CSng(infoBD!PosSup)
nuevaImagenCodigoBarras.Width = CSng(infoBD!PosAncho)
nuevaImagenCodigoBarras.Height = CSng(infoBD!PosAltura)
nuevaImagenCodigoBarras.RotationAngle = CShort(infoBD!Giro)
nuevaImagenCodigoBarras.PadDigits = _
CByte(DBGetInteger(infoBD!DigitosRelleno))
ElementosDesplegados.Items.Add(nuevaImagenCodigoBarras)

Proyecto | 521

18_PATRICK-CHAPTER_18.indd 521 18/2/10 11:17:36


El usuario puede agregar nuevas formas, elementos de texto y cdigos de barras a la etiqueta
al hacer clic en uno de los cinco botones Agregar artculos que aparecen debajo del control
ElementosDesplegados. Cada botn agrega un registro predeterminado a la etiqueta, que el
usuario puede modificar. A medida que cada elemento es seleccionado de ElementosDesple
gados, sus propiedades aparecen en el control ElementoPropiedades, una instancia de Pro
pertyGrid. Para modificar un elemento de etiqueta basta con cambiar sus propiedades. En la
figura 18-20 se muestra el cambio de una propiedad de color.

Figura 18-20. Modificacin de una propiedad de elemento de etiqueta.

Al igual que con el formulario PaginaCodigoBarras, la diversin real en el formulario Eti


quetaCodigoBarras viene del evento Paint del control de vista previa, AreaVistaPrevia.
Esta rutina de ms de 300 lneas empieza por dibujar la superficie en blanco de la etiqueta con la
sombra cada. Luego procesa cada elemento en la lista ElementosDesplegados, uno por uno,
transformando y dibujando cada elemento como lo indican sus propiedades. Mientras pasa por
la lista de elementos, el cdigo aplica transformaciones al rea de dibujo, segn se hace necesario.
Para mantener las cosas ordenadas para cada elemento, el estado de la superficie se guarda antes
de cada cambio, y se restaura una vez que los cambios se completan.
For contador = 0 To ElementosDesplegados.Items.Count - 1
' ----- Guardar el estado actual del rea de la imagen.
conservarEstado = e.Graphics.Save()

...aqui va el codigo principal de dibujo, entonces...


' ----- Restaurar el estado trasformado original de

522 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 522 18/2/10 11:17:36


' la superficie de la imagen.
e.Graphics.Restore(conservarEstado)
Next contador

El cdigo de cada tipo de elemento realiza las diversas transformaciones de tamao, posicin y
giro necesarias para desplegar apropiadamente el elemento. Echemos una mirada cercana al c-
digo que despliega elementos de texto estticos (cdigo al que tambin se le llama para desplegar
texto de cdigo de barras). Despus de reducir a escala la vista real al rea de vista previa de la
superficie de la etiqueta, cualquier giro solicitado por el usuario es realizado cerca de la esquina
superior izquierda del rectngulo que contiene el texto impreso.
e.Graphics.TranslateTransform(X1, Y1)
e.Graphics.RotateTransform(anguloTexto)

A continuacin, una lnea de guiones grises se dibuja alrededor del objeto de texto para mostrar
su estado seleccionado.
plumaPixeles = New System.Drawing.Pen(Color.LightGray, _
1 / e.Graphics.DpiX)
plumaPixeles.DashStyle = Drawing2D.DashStyle.Dash
e.Graphics.DrawRectangle(plumaPixeles, X1, Y1, X2, Y2)
plumaPixeles.Dispose( )

Despus de establecer algunas marcas para alinear apropiadamente el texto de manera vertical y
horizontal dentro de su cuadro contenedor, el mtodo estndar DrawString echa el texto sobre
la pantalla.
e.Graphics.DrawString(mensajeTexto, usarFuente, _
New System.Drawing.SolidBrush(colorTexto), _
New Drawing.RectangleF(X1, Y1, X2, Y2), formatoTexto)

De alguna manera duplicaremos el cdigo de dibujo de etiquetas incluido en la clase Etiqueta


CodigoBarras cuando imprimimos etiquetas reales en un captulo posterior.
Lo nico que queda por hacer es vincular estos editores al formulario principal. Como ya nos
hemos divertido mucho con estos formularios, le permitir jugar un rato con el cdigo. Abra el
cdigo de FormularioPrincipal, localice el manejador de eventos para el evento AdminVin
culosEtqCodigoBarras.LinkClicked, y agregue la siguiente etiqueta.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap18, Elemento 7.

' ----- Permitir que el usuario edite la lista de etiquetas de codigo de barras.
If (PerfilSeguridad( _
SeguridadBiblioteca.AdministrarPlantillasCodigoBarras) = False) Then
MsgBox(MensajeNoAutorizado, MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If

Proyecto | 523

18_PATRICK-CHAPTER_18.indd 523 18/2/10 11:17:36


' ----- Editar los registros.
ListaRegistrosEditados.AdministrarRegistros(New Biblioteca.EtiquetaCodigoBarras)
ListaRegistrosEditados = Nothing

Haga lo mismo para el manejador de eventos AdminVinculosPagCodigoBarras.LinkClic


ked. Su cdigo es casi idntico, excepto por la instancia de clase pasada a ListaRegistros
Editados.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap18, Elemento 8.

' ----- Deje que el usuario edite la lista de paginas de codigo de barras.
If (PerfilSeguridad( _
SeguridadBiblioteca.AdministrarPlantillasCodigoBarras) = False) Then
MsgBox(MensajeNoAutorizado, MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If

' ----- Editar los registros.


ListaRegistrosEditados.AdministrarRegistros(New Biblioteca.PaginaCodigoBarras)
ListaRegistrosEditados = Nothing

Diversin con imgenes


GDI+ no slo es una herramienta de dibujo seria; tambin puede tener algo de diversin. Ha-
gamos un cambio al formulario ProgramaAcercaDe.vb para que se desvanezca cuando el usuario
haga clic en el botn Cerrar. Esto incluye la alteracin de la propiedad Opacity del formulario,
para aumentar la transparencia del formulario. Desde el punto de vista de nuestro cdigo, no
interviene GDI+. Pero an participa mediante el cdigo oculto que responde a la propiedad
Opacity.
Abra el cdigo fuente del archivo ProgramaAcercaDe.vb y agregue el cdigo siguiente al final del
manejador de eventos ProgramaAcercaDe.Load.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap18, Elemento 9.

' ----- Preparar el formulario para posterior desvanecimiento.


Me.Opacity = 0.99

Aunque esta instruccin no es realmente necesaria, encontr que el formulario tenda a pestaear
un poco en algunos sistemas cuando la opacidad iba de 100% (1.0) a cualquier cosa (99%, o
0.99, en este caso). Este parpadeo era menos notorio cuando hice la transicin durante el pro-
ceso de carga.
En el manejador de eventos de AccCerrar.Click incluya este cdigo.

524 | Captulo 18: Interfaz de usuario

18_PATRICK-CHAPTER_18.indd 524 18/2/10 11:17:36


Insercin de fragmento de cdigo
Inserte el fragmento de cdigo Cap18, Elemento 10.

' ----- Desvanecer el formulario.


Dim contador As Integer

For contador = 90 To 10 Step -20


Me.Opacity = contador / 100
Me.Refresh( )
Threading.Thread.Sleep(50)
Next contador
Me.DialogResult = Windows.Forms.DialogResult.Cancel

Este cdigo desvanece lentamente el formulario en el curso de 250 milisegundos, en cinco pasos
distintos. Para que el formulario no se cierre abruptamente antes del bonito desvanecimiento,
abra el diseador del formulario, seleccione el botn AccCerrar y cambie su propiedad Dia
logResult a None.
Otra cosa que nunca hicimos fue establecer el cono primario para la aplicacin. Aunque esto
no es estrictamente GDI+, incluye el despliegue grfico, que tiene impacto en la percepcin del
usuario de la calidad del programa. He incluido un cono llamado Libro.ico en el conjunto de
archivos del proyecto. Abra las propiedades del proyecto, seleccione la ficha Aplicacin y use el
campo Icono para buscar el archivo Libro.ico.
Mientras proba el cono, observe que la pantalla de bienvenida apareca (con el cono prede-
terminado de Visual Studio) en la barra de tareas de Windows. En realidad, cada formulario
abierto apareca en la barra de tareas, junto con la entrada del formulario principal. Esto no es el
estndar, y se debe al valor de la propiedad ShowInTaskbar incluida en cada formulario. Me he
tomado la libertad de recorrer todos los formularios (excepto FormularioPrincipal) y estable-
cer esta propiedad en False. La mayor parte de los formularios estaban listos para establecerse
apropiadamente, de modo que alter la docena que no lo estaba.
La aplicacin Biblioteca est realmente empezando a llenarse de caractersticas. En realidad, para
el siguiente captulo, habremos agregado ms de 95% de su cdigo total. Puedo ver la excitacin
en su casa. Siga adelante, d vuelta a la pgina y aada algo al disfrute de su cdigo.

Proyecto | 525

18_PATRICK-CHAPTER_18.indd 525 18/2/10 11:17:36


Captulo 19
Localizacin y globalizacin

Bienvenue chapitre dix-neuf! Mis disculpas a todos aquellos que no hablan francs (y tambin a
quienes en realidad lo hablan). Me llev cuatro aos completos de idiomas en preparatoria, pero
por alguna razn, no aprend. An puedo recordar algunas frases importantes, como Je suis un
garon y O est le crayon?, pero eso es todo. Incluso leamos Candide y Le Petit Prince en clase,
pero eso no ayuda gran cosa. Tom japons en la universidad, y lo encontr mucho ms fcil de
digerir que el francs, de modo que tal vez deba decir, en cambio .
Como un intento por expandir este libro ms all de las playas de las naciones que hablan ingls
localic el prrafo anterior. En un intento por expandir el atractivo de sus aplicaciones ms all
del mundo de habla inglesa, .NET proporciona caractersticas que le permiten localizar su pro-
yecto en otro idioma, aun despus de que su software se ha compilado y liberado.
La cobertura de todas las caractersticas de localizacin en .NET incluira calendarios basados
en los reinos lunares y del emperador, y sistemas de escritura de derecha a izquierda. En este
captulo slo se cubren algunas de las caractersticas de localizacin de interfaces ms comunes.
Tengo la esperanza de despertar su inters en que rebase los lmites del lenguaje de sus aplica-
ciones, llegando a les toiles.

Definicin de globalizacin y localizacin


Microsoft tiene cientos de aplicaciones de software para venta y gratuitas, y la compaa
obtiene mucho dinero en todo el mundo proporcionando estos productos de software a los
consumidores. Casi todos sus productos son desarrollados en Estados Unidos, escritos por
programadores que hablan principalmente ingls, dirigidos por lderes tcnicos y administra-
dores de producto, que toman decisiones en ingls, comercializados por un equipo de ventas
que planean campaas en ingls, y combatidos por competidores y detractores que gritan sus

526

19_PATRICK-CHAPTER_19.indd 526 18/2/10 11:18:24


motivos y prcticas de negocios detrs de cada producto en ingls. Entonces, cmo es posible
que Microsoft pueda vender software a personas que no hablan ingls en todo el mundo?
La clave est en la globalizacin y localizacin de sus productos. Seguro, Microsoft o cualquier otra
compaa podra desarrollar productos distintos pero idnticos, cada uno en un idioma distinto,
y venderlos en mercados apropiados. Pero eso sera caro y consumira tiempo. En cambio, escribe
un solo programa, y luego lo mejora con sus caractersticas especficas de idioma y cultura.
La globalizacin es el proceso de preparar software para que pueda ajustarse fcilmente a cada
idioma y mercado. No se agregan trminos extranjeros durante el proceso de globalizacin. En
cambio, los desarrolladores disean la aplicacin de modo que todos los trminos relevantes
en ingls, y los elementos culturales estadounidenses (como la moneda desplegada en dlares
estadounidenses) puede reemplazarse rpida y fcilmente con elementos extranjeros, sin tener
impacto en los elementos esenciales del software.
Las aplicaciones de Windows han usado, de manera tradicional, recursos para mantener aplica-
ciones globalmente genricas. Los recursos contienen cadenas de texto, imgenes, y otros ele-
mentos que no pertenecen al cdigo que son reemplazados en tiempo de ejecucin con base en el
lenguaje y la cultura activos del sistema operativo. En un sistema de habla alemana, la aplicacin
carga los recursos del idioma alemn (si estn disponibles) y los despliega en lugar de los recursos
predeterminados. .NET Framework sigue usando recursos para este fin, aunque mejora el desa-
rrollo de recursos a travs de archivos y herramientas basadas en XML.
La localizacin agrega los elementos de lenguaje y culturales no nativos reales a una aplicacin.
Es en este paso que, digamos, las etiquetas en ingls se traducen al swahili, o algn otro idioma
de destino. Visual Studio le permite localizar una aplicacin dentro del propio entorno de desa-
rrollo, o mediante herramientas que pueden ser usadas por traductores que no tienen acceso al
cdigo fuente de la aplicacin.
Las buenas noticias para los desarrolladores .NET es que Microsoft se ocupa de la parte de la
globalizacin. Usted slo necesita concentrarse en localizar su aplicacin. Su universidad estatal
ofrece clases en ms o menos una docena de idiomas extranjeros, as que le permitir elegir su
primer destino de localizacin.

Archivos de recursos
Los archivos de recursos son clave para la localizacin del idioma en programas .NET. Visual
Studio escribir los archivos por usted, pero es bueno saber algo acerca de la manera en que
trabajan, porque tal vez quiera crear sus propios archivos de recursos (si tiene mucho tiempo
en sus manos). La vida de un recurso recorre tres fases, como lo determina el tipo de archivo en
que aparece:

Archivos de recursos | 527

19_PATRICK-CHAPTER_19.indd 527 18/2/10 11:18:24


Fuente
Los recursos de una aplicacin empiezan su vida en un archivo fuente. Antes, los recursos
.NET aparecieron en archivos de secuencias de comandos de recursos, que combinaban lo
mejor del desarrollo en lenguaje C y COMANDOS DE SECUENCIAS EN MAYSCU-
LAS, y usaban una extensin de archivo .rc. En Visual Basic 2008 se usan los archivos .resx
de XML. Toda nueva aplicacin de Windows Forms ya incluye un archivo Resources.resx que
slo espera a ser gloriosamente llenado con sus recursos de aplicacin.
Ms all de los archivos fuente de recursos, otros tipos de archivo pueden incluirse como re-
cursos, aunque an se hace referencia a ellas mediante el contenido de archivo .resx. Los ar-
chivos comunes de recursos externos incluyen archivos de imagen (como archivos .gif y .jpg)
y de texto simple (.txt). El proyecto Biblioteca usa un archivo llamado ImagenBienvenida.
jpg como recurso para la pantalla de bienvenida, y otro archivo llamado CuerpoBusquedaAr-
ticulo.txt que incluye contenido HTML usado cuando se despliegan elementos mediante el
formulario BusquedaArticulos.vb.
Intermedio
Una vez que tiene listos sus recursos, se convierten en un formulario intermedio, y se al-
macena con una extensin de archivo .resources, mediante un proceso llamado generacin de
recursos. Por lo general, Visual Studio hace este paso tras bambalinas, pero usted tambin
puede usar una herramienta proporcionada con el SDK de .NET (llamado resgen.exe) para
generar esos archivos. Los archivos de recursos intermedios slo incluyen contenido binario,
y no estn diseados para revisarse en el Bloc de notas.
Compilado
Los archivos de recursos intermedios no son muy tiles para su aplicacin desplegada. El
trmino intermedio revela un poco el secreto, o no? Antes de emplear los recursos en su
programa, necesitan compilarse en un archivo DLL o EXE. Tal vez ya sabe que estos archi-
vos contenan varias secciones, incluidas secciones distintivas de cdigo y datos. Un archivo
de recursos compilado slo contiene una seccin de datos con recursos; no hay cdigo en
un archivo de recursos compilados, aunque los archivos de cdigo compilados estndar
tambin pueden incluir recursos compilados.
En .NET, los archivos de recursos compilados son ensamblados satlite. Dan soporte al ensam-
blado primario de la aplicacin, y por lo general slo son tiles partes del ensamblado maestro.
En la figura 19-1 se muestra el tiempo de vida de un recurso mediante estas tres etapas.
Algunos tipos de recursos estndar estn almacenados en archivos de recursos .NET (.resx):
Cadenas
Todos nos concentramos principalmente en recursos de cadena en este captulo. Cada recur-
so de cadena incluye un nombre y un valor de cadena.
Imgenes
Las aplicaciones de Visual Basic pueden incluir archivos de imagen JPEG, GIF, TIFF, PNG
y BMP. Cada imagen, al igual que todos los recursos, incluye un nombre asociado, que
puede diferir del nombre original del archivo de imagen.

528 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 528 18/2/10 11:18:24


Generacin Compilacin

Recursos Recursos Recursos


originales intermedios compilados
Figura 19-1. La vida comestible de un recurso.

conos
Los conos de programa usados con formularios y la propia aplicacin aparecen como recur-
sos estndar. Los conos tienen una extensin de archivo .ico.
Audio
Recursos que pueden incluir archivos de audio con nombre, con base en contenido de audio
WAV.
Archivos
Si los tipos de archivo de la lista hasta ahora no cumplen sus necesidades, puede incluir
archivos completos de cualquier tipo como un recurso con nombre.
Otros
Ms all de los archivos puede almacenar el contenido de cualquier tipo de datos .NET
vlido como un recurso. Los recursos en un archivo .resx tienen tipos .NET, de modo que
en realidad no hay lmite al tipo de datos que puede colocar all. Tambin puede modificar
el archivo .resx para incluir recursos no estndar. stos se encuentran ms all del alcance
de este captulo.
La ventana de propiedades del proyecto incluye un administrador para recursos de toda la apli-
cacin (vase la figura 19-2). La IDE tambin incluye editores especiales que le permiten editar
tipos de recursos estndar y algunos pocos no estndar.

El objeto My.Resources
Analizamos esto en captulos anteriores, pero como recordatorio puede acceder a los recursos
de una aplicacin mediante el objeto My.Resources. Si tiene un recurso de cadena llamado
LeyendaFormularioPrincipal, la siguiente referencia devuelve su valor:
My.Resources.LeyendaFormularioPrincipal

Todos los recursos tienen fuerte imposicin de tipo. En este caso, LeyendaFormularioPrin-
cipal es de tipo System.Cadena. El recurso de imagen ImagenBienvenida incluido en el

El objeto My.Resources | 529

19_PATRICK-CHAPTER_19.indd 529 18/2/10 11:18:25


Figura 19-2. El administrador de recursos para el proyecto.

proyecto Biblioteca es declarado como tipo System.Drawing.Bitmap. Debido a que cada re-
curso es de tipo impuesto, puede usar la referencia My.Resources en su cdigo justo como
cualquier dato del tipo de recurso.
En nuevas aplicaciones de Windows Forms, todos los recursos de toda la aplicacin aparecen en
el archivo Resources.resx, encontrados en el directorio My Project dentro del directorio de cdigo
fuente de la aplicacin. Puede verlo en el Bloc de notas, si lo desea. Es un archivo XML muy
grande que no me interesa por el momento, excepto que funciona! He aqu la parte del archivo
Resources.resx del proyecto Biblioteca que especifica nuestros dos recursos existentes. (He dividi-
do algunas de las lneas para que quepa en la pgina.) He resaltado el nombre de cada recurso, y
sus tipos de datos impuestos.
<data name="CuerpoBusquedaArticulo"
type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CuerpoBusquedaArticulo.txt;System.String,
mscorlib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>

<data name="ImagenBienvenida"
type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\recursos\imagenbienvenida.jpg;System.Drawing.Bitmap,
System.Drawing, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a</value>
</data>

Cada formulario que agregue a su proyecto tambin tiene su propio archivo de recursos privado.
El que corresponde a Form1 es denominado Form1.resx. Estos archivos terminan siendo una
gran adicin para la localizacin de aplicaciones Windows Forms.
Tras bambalinas, su aplicacin est tomando un mtodo orientado a objetos a la adminis-
tracin de recursos. Se est usando la clase System.Resources.ResourceManager para
localizar y devolver instancias de cada recurso cuando sea necesario. Y esta misma clase toma
decisiones acerca de cules recursos especficos del idioma o la cultura (de las docenas que
estoy seguro que ha agregado a su aplicacin) ser visible para el usuario.

530 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 530 18/2/10 11:18:25


Localizacin de formularios dentro de Visual Studio
No tiene sentido posponer la introduccin de las caractersticas de localizacin de Visual Studio,
porque son muy fciles de usar. Ya conoce el editor de recursos de las propiedades del proyecto
de toda la aplicacin. En cambio, revisemos la parte asombrosa: formularios y controles de loca-
lizacin justo en el editor de formularios de Visual Studio. Tambin podra iniciar Visual Studio
y probarlo conmigo, slo por diversin.
He aqu una bonita pero relativamente inofensiva aplicacin de Windows Forms que escribe
su nombre de cabeza. Agregu unos controles Label, uno TextBox y uno PictureBox a un
formulario, como se muestra en la figura 19-3.

Figura 19-3. Una aplicacin tpica de Windows Forms.

Luego agregu el siguiente cdigo fuente al formulario:


Private Sub TextBox1_TextChanged( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles TextBox1.TextChanged
' ----- Forzar un redibujo.
PictureBox1.Invalidate()
End Sub

Private Sub PictureBox1_Paint(ByVal sender As Object, _


ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles PictureBox1.Paint
' ----- Dibuja el fondo en blanco.
e.Graphics.Clear(SystemColors.Window)
e.Graphics.DrawRectangle(SystemPens.InactiveCaption, _
0, 0, PictureBox1.Width - 1, PictureBox1.Height - 1)

' ----- Cambia la orientacion del despliegue.


Dim guardarEstado As Drawing2D.GraphicsState = _
e.Graphics.Save()
Dim matrizEspejo As New Drawing2D.Matrix( _
1, 0, 0, -1, 0, PictureBox1.Height)
e.Graphics.Transform = matrizEspejo
' ----- Dibujar el texto.
e.Graphics.DrawString(TextBox1.Text, TextBox1.Font, _
SystemBrushes.WindowText, 1, 4)

' ----- Regresar todo.

Localizacin de formularios dentro de Visual Studio | 531

19_PATRICK-CHAPTER_19.indd 531 18/2/10 11:18:26


e.Graphics.Restore(guardarEstado)
End Sub

Cuando ejecute el programa, crear una imagen de espejo de cualquier cosa que escriba en el
control TextBox empleando caractersticas GDI+. En la figura 19-4 se me muestra jugando con
el programa en lugar de cumplir la fecha lmite de entrega de este captulo.

Figura 19-4. Mira mam, estoy de cabeza.

Aunque este programa parece interesante, no est completamente globalizado ni localizado. Est
casi globalizado. Todo lo que necesitamos para globalizarlo por completo es jalar el switch en
el formulario que habilita la posterior localizacin. Hacemos esto mediante la propiedad Loca-
lizable. Cambie este propiedad de False a True. Ta-da! Su formulario est globalizado!
Ahora, para la parte 2: localizacin. He aqu los pasos para localizar el formulario:
1. Determine cul idioma o combinacin idioma-cultura desea localizar.
2. Seleccione ese idioma o idioma-cultura de la propiedad Language del formulario. Cuando
abra esta lista de propiedades, incluir slo el idioma, como Francs e idiomas combina-
dos con una cultura o pas, como Francs (Canad). A las solas entradas del idioma se les
conoce como de idioma neutral. Puede usar cualquier tipo de localizacin. Si selecciona,
por ejemplo, francs, los usuarios de su aplicacin en Francia o la parte de Canad que ha-
bla francs usar los recursos en francs. Si localiza usando Francs (Canad), los usuarios
canadienses del francs accedern a los recursos localizados, pero no los usuarios en francs
de Francia.
3. Modifique cualquiera de las propiedades del formulario o sus controles.
Eso es todo. Cada vez que se cambie la propiedad Language a algo diferente de (Default),
Visual Studio empieza a grabar todos los cambios en el formulario y el control en un archivo de
recursos separado especficos del formulario y especficos del idioma o la combinacin idioma-
cultura.
Puede localizar el formulario con varios idiomas. Cada vez que cambie la propiedad Language
a otra seleccin de idioma o idioma-cultura, los cambios al formulario o los controles slo se
aplican a esa seleccin. Cada vez que su cambio se guarde en un archivo de recursos separado.

532 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 532 18/2/10 11:18:26


Probemos con el ejemplo del programa de ejemplo. Voy a elegir japons como idioma de lo-
calizacin. En primer lugar, establec la propiedad Language del formulario en Japons. El
formulario parpadea por un momento, pero no hay un cambio notable. Tiene el aspecto de la
imagen de la figura 19-3.
A continuacin, cambi las propiedades Text del formulario y de cada control de etiqueta a sus
equivalentes en japons (vase la figura 19-5).

Figura 19-5. El programa de reflejo del nombre en japons.

Observa cmo las etiquetas del idioma japons estn ms alejadas de los campos de texto y espe-
jo? Le preocupa tanto como a m? Para sacarlo de mi mente, cambiar el tamao de dos campos
y los har un poco ms largos al jalarlos a la izquierda, como hice en la figura 19-6.

Figura 19-6. La versin japonesa con campos ajustados.

La parte asombrosa es que si establece de nuevo la propiedad Language del formulario a (De-
fault), no slo las etiquetas regresarn al ingls, sino que los campos de texto y espejo regre-
sarn a sus tamaos naturales. Aunque no he revisado cada propiedad, la caracterstica de
localizacin parece tener impacto en todos los elementos de despliegue de cada control.
Ahora el programa est totalmente localizado para el ingls (el idioma predeterminado) y el ja-
pons. Por lo general, el recurso en japons sera usado slo en un sistema que ejecute la versin
japonesa de Microsoft Windows. Pero podemos forzar al programa para que use el japons al
cambiar la cultura de la interfaz de usuario. En el cdigo de inicio de la aplicacin (la rutina
MyAplicacion_Startup en el archivo ApplicationEvents.vb), agregu el siguiente cdigo:
Private Sub MyAplicacin_Startup(ByVal sender As Object, _
ByVal e As Microsoft.VisualBasic.ApplicationServices. _
StartupEventArgs) Handles Me.Startup
If (MsgBox("Confirme que desee cambiar de ingles a japones.", _

Localizacin de formularios dentro de Visual Studio | 533

19_PATRICK-CHAPTER_19.indd 533 18/2/10 11:18:27


MsgBoxStyle.Question Or MsgBoxStyle.YesNo) = _
MsgBoxResult.Yes) Then
My.Application.ChangeUICulture("ja-JP")
End If
End Sub

Y es seguro que al ejecutar el programa y decir S al indicador Cambiar a japons se presenta


un formulario en japons, como se muestra en la figura 19-7. (Si responde No a la pregunta,
aparece el idioma predeterminado, ingls.)

Figura 19-7. Mira mam, soy japons.


Revisemos los archivos creados en este proyecto. (Busque en el directorio de instalacin del cdi-
go de este libro el directorio Nombres extranjeros. He colocado una copia de este proyecto de tex-
to de espejo all para usted.) El subdirectorio de cdigo fuente incluye un archivo Form1.resx file,
agregado como opcin predeterminada a todas las nuevas aplicaciones de Windows Forms. Pero
tambin hay un archivo Form1.ja.resx, el archivo de recursos de Form1 para el idioma japons.
Visual Studio compilar el archivo en un recurso especfico del idioma cuando genera el proyec-
to. En ese momento, el subdirectorio bin\Release del cdigo contendr un subdirectorio adicio-
nal con un archivo llamado NombresExtranjeros.resources.dll. Se trata del ensamblado satlite que
contiene todos los recursos en idioma japons. Si la aplicacin ha incluido varios formularios,
todos los recursos japoneses para todos los formularios apareceran en un solo archivo DLL.

Adicin de recursos fuera de Visual Studio


Visual Studio facilita la localizacin. Pero es raro que el desarrollador de una aplicacin impor-
tante tambin sepa hablar varios idiomas de destino. Y usted ciertamente no quiere que quienes
no sean programadores obtengan acceso a sus formularios y su cdigo en Visual Studio, donde
pueden hacer quin sabe qu a su lgica.
Para mantener en su lugar los ojos y dedos en el idioma extranjero, Microsoft escribi el Edi-
tor de recursos para localizacin de Windows, incluido con el kit de desarrollo de software
proporcionado con .NET. (En mi sistema est localizado en Inicio [Todos los] Programas
Microsoft Windows SDK v6.0A Tools Editor de recursos para localizacin de Win-
dows. Su nombre de lnea de comandos es winres.exe.) Cuando est listo para que un traductor
convierta un formulario a un idioma especfico, slo necesita proporcionarle este programa, y el
archivo .resx del formulario (como Form1.resx). El programa simula el despliegue del formulario
como aparece en Visual Studio, y permite que el traductor modifique cualquier propiedad de
formulario o control relevante para un idioma especfico. En la figura 19-8 se muestra Form1
de NombresExtranjeros en el Editor de localizacin.

534 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 534 18/2/10 11:18:27


Figura 19-8. Un parecido asombroso con Form1, listo para traduccin.

El programa le pregunta el idioma o la combinacin idioma-cultura de destino cuando trate de


guardar los cambios. Da salida a un archivo .resx especfico del idioma (como Form1.ja.resx para el
japons) que puede usarse en su aplicacin. Una vez que obtiene de nuevo los archivos de recursos
extranjeros de los traductores, almacnelos (los archivos, no los traductores) en el directorio fuen-
te del proyecto, y reconstruya el proyecto para generar los ensamblados satlite correctos.

Compilacin manual de recursos


Es posible generar los ensamblados satlite manualmente a partir de los archivos .resx fuente
sin volver a generar todo el proyecto en Visual Studio. Tendr que usar la lnea de comandos de
Windows (cmd.exe), y necesitar agregar acceso al archivo EXE o DLL del ensamblado princi-
pal. No es para dbiles de corazn y un solo carcter mal escrito puede costarle millones a los
contribuyentes.
En la figura 19-1 se present un resumen de los pasos necesarios para mover un archivo .resx
en un ensamblado satlite. Los pasos para generar y compilar pueden hacerse usando dos
utileras de lnea de comandos: resgen.exe y al.exe. No suena muy divertido?
Al igual que con otras herramientas .NET de lnea de comandos, stas necesitan el entorno
de lnea de comandos para su configuracin, o se enojarn y se rehusarn a ejecutarse. Para
asegurar que tiene el entorno correcto, necesita abrir la versin .NET especial de lnea de
comandos. El SDK de .NET se instal junto con el marco conceptual, de modo que debe
tener la capacidad de encontrar una entrada en el men Inicio para l en Inicio [Todos los]
Programas Microsoft Visual Studio 2008 Visual Studio Tools Smbolo del sistema
de Visual Studio 2008.

Compilacin manual de recursos | 535

19_PATRICK-CHAPTER_19.indd 535 18/2/10 11:18:28


Generacin de un archivo de recursos
Una vez que tenga disponible un archivo .resx, al crearlo manualmente o al usar el Editor de
recursos para localizacin de Windows, se genera un archivo .resources empleando resgen.exe, la
utilera de lnea de comandos Generador de recursos, parte del juego de herramientas de SDK.
Acepta un nombre de entrada y uno de salida como argumentos.
resgen.exe Form1.ja.resx Form1.ja.resources

Si omite el nombre de archivo de salida, resgen simplemente reemplazar la extensin .resx con
.resources.
Si tiene varios ensamblados de idioma extranjero (para varios formularios, por ejemplo) genere
archivos de recursos para todos ellos. Luego estar listo para compilar el ensamblado satlite.

Compilacin de ensamblados satlite


.NET utiliza al.exe, el programa para vincular ensamblados, para compilar todas sus aplica-
ciones .NET en sus archivos de ensamblado final. Usaremos este mismo programa para generar
los ensamblados satlite. Sus argumentos de lnea de comandos fueron diseados por una socie-
dad secreta, de modo que costar un poco de trabajo hacer que funcionen bien. Echemos primero
un vistazo al comando, y luego lo explicar.
al.exe /target:lib
/embed:Form1.ja.resources,ForeignNames.Form1.ja.resources
/culture:ja
/out:ForeignNames.resources.dll
/template:bin\Release\ForeignNames.exe

Debe ingresar estas lneas como una sola lnea larga. Tengo que dividirla en el libro porque el
editor no quiso hacer uno de esos libros tridimensionales que se publican para nios. No les
gust mi idea del entorno de Visual Studio desplegable interactivo, tampoco (algo relacionado
con mantener el libro a un precio accesible).
Las opciones proporcionadas para al.exe hacen magia:
/target:lib
La parte lib dice: Da salida a un archivo estilo DLL.
/embed
Esta opcin indica cules archivos fuente quiere incluir en el ensamblado de salida. La
primera parte delimitada por comas indica el nombre de archivo fuente. La segunda,
el nombre por el cual ser conocido este recurso en la aplicacin. El nombre debe estar en el
formato nombrebase.nombreCultura.recursos, donde nombrebase es el nombre de la
aplicacin (en el caso de recursos para toda la aplicacin) o el nombre de la clase (calificado
con su espacio de nombres) para una clase especfica, como Form1. Debido a que mi apli-
cacin y su espacio de nombres predeterminado de nivel superior es NombresExtranjeros,
lo he incluido en el componente del nombre. Puede agregar tantas opciones /embed como
archivos de recursos tenga que incluir.

536 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 536 18/2/10 11:18:28


/culture
Aunque con el tiempo pondr el ensamblado satlite en una carpeta con el nombre de la cul-
tura de destino, Visual Basic no confa en usted. En cambio, quiere un registro de la cultura
incrustado en el propio ensamblado. Eso se hace con esta opcin de lnea de comandos.
/out
Esta opcin especifica el nombre de salida del archivo satlite. Realmente necesita usar el
nombre aplicacion.resources.dll para el archivo, donde aplicacion es el nombre de su
aplicacin antes de la parte .exe. Si no hace esto, no funcionar. Bueno, an podra hacer
que funcionar al ajustar el archivo app.config de la aplicacin, pero ese archivo es atemori-
zante, de modo que no querr meterse con l.
/template
sta es la opcin que dice: Estoy haciendo un ensamblado satlite, y el ensamblado prima-
rio relacionado es x.
Para usar el ensamblado satlite, localice el directorio que contiene el ensamblado EXE prin-
cipal. Cree un nuevo subdirectorio justo all, dndole el nombre del idioma o la clave idioma-
cultura usada para crear el ensamblado [ja en mi caso; ja-JP hubiera sido una opcin si creara
el ensamblado usando Japons (Japn)]. Luego coloque el nuevo ensamblado satlite en ese
subdirectorio.

Otras caractersticas de localizacin


La localizacin es ms que slo palabras en pantalla. Tambin es aplicable al despliegue de ho-
ras, fechas y valores monetarios para el usuario. Las buenas noticias son que estas caractersticas
funcionarn automticamente si globaliza su programa de manera adecuada. As como cada pro-
grama .NET mantiene una cultura de interfaz de usuario (con la que jugamos en el programa
de ejemplo anterior), tambin tiene una cultura general usada para manipulacin de cadena de
horas, fechas, valores financieros y otras cosas dependientes de la cultura.
Si usa mtodos centrales como CDate para extraer valores de fecha, en lugar de rastrear una
cadena de fecha ingresada por el usuario a mano, obtiene de manera gratuita procesamiento
de fechas especfico de la cultura. Adems, para salida, si usa los formatos predefinidos para el
mtodo Format (y otros mtodos similares de salida de cadenas), obtiene el formato correcto
especfico de la cultura sin esfuerzo adicional de su parte. Probemos un ejemplo rpido que des-
pliega dinero usando la moneda local.
Estoy creando una nueva aplicacin de Windows Forms. Agregar el cdigo siguiente al archivo
ApplicationEvents.vb file:
Private Sub MyApplication_Startup(ByVal sender As Object, _
ByVal e As Microsoft.VisualBasic.ApplicationServices. _
StartupEventArgs) Handles Me.Startup
If (MsgBox("Confirme que quiere cambiar de ingles a japones", _
MsgBoxStyle.Question Or MsgBoxStyle.YesNo) = _
MsgBoxResult.Yes) Then

Otras caractersticas de localizacin | 537

19_PATRICK-CHAPTER_19.indd 537 18/2/10 11:18:28


My.Application.ChangeCulture("ja-JP")
End If
End Sub

Este bloque de cdigo es casi idntico al usado en el ejemplo anterior, pero estoy llamado a
My.Application.ChangeCulture en lugar de My.Application.ChangeUICulture (la par-
te UI est faltando). Esto cambia la cultura de manipulacin de cadenas en lugar de la de interfaz
de usuario.
Ahora, agregar el siguiente cdigo a la clase Form1:
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
MsgBox(Format("500", "Currency"))
End Sub

En la figura 19-9 se muestran los resultados de este cdigo cuando se ejecuta en los modos de
ingls y japons.

Figura 19-9. Gasto de dinero en dos lugares a la vez.

Las bibliotecas de clase del marco conceptual (FCL, Framework Class Libraries) incluyen an
ms caractersticas de administracin de cultura en el espacio de nombres System.Globali-
zation. Las clases en este espacio de nombres le permiten ajustar manualmente la salida de ca-
denas sensibles a la cultura para satisfacer sus necesidades. Casi todas son muy esotricas y estn
orientadas a grupos culturales especficos, de modo que no los analizar aqu.

Resumen
Despus de todo, el mundo es pequeo. Y las caractersticas especficas de la cultura en .NET
han ayudado a que sea de esa manera, por lo menos en su software. An estoy sorprendido de
que sea capaz de usar japons en mi versin en ingls de Microsoft Windows. (Primero tengo que
habilitar el soporte para idiomas del este de Asia en la applet Configuracin regional y de idioma
del Panel de control.) Y ahora no slo es Windows o Microsoft Office el que puede cambiar au-
tomticamente con la cultura actual. Los polticos pueden hacerlo, tambin. Perdn, quiero de-
cir que sus propias aplicaciones pueden hacerlo, tambin. Al aprovechar los recursos especficos
de la cultura y las caractersticas de formato automtico y manual incluidas con .NET, pronto
estar vendiendo sus inteligentes aplicaciones de negocios en seis de los siete continentes.

538 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 538 18/2/10 11:18:29


Proyecto
S que est esperando que localice todos los formularios del proyecto Biblioteca en griego, y es
una idea tentadora. Pero para mayor brevedad (y para preservar mi salud), dejar eso como un
ejercicio para el lector. (Risas disimuladas.)
Lo que haremos en el cdigo del proyecto de este captulo es habilitar el resto de las caractersticas
de administracin y rastreo especificas del cliente. Esas caractersticas incluyen la administra-
cin de multas para clientes malos que no devuelven a tiempo los libros a la biblioteca. Usa-
remos las caractersticas genricas de formato de moneda analizadas en este captulo para que la
aplicacin sea accesible lo ms globalmente posible.

Acceso al proyecto
Cargue el proyecto Cap19 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap19 (Final) cdigo.

Rastreo de pagos de clientes


Creemos una clase que expone las caractersticas importantes de cada conjunto de pagos aplica-
do a un archivo prestado especfico. Por supuesto, todas estarn almacenadas en la base de datos
Biblioteca. Pero mantener un resumen de pagos temporalmente en cach simplifica en algo el
procesamiento.
Agregue un nuevo elemento de clase al proyecto Biblioteca, dndole el nombre de PagoArticulo.
vb. Defnalo usando el siguiente cdigo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 1.

Public Class PagoArticulo


' ----- Usado para rastrear e imprimir las boletas de pago.
Public tituloArticulo As String
Public IDCopiaCliente As Integer
Public CuotasPagadas As Decimal
Public SaldoAdeudo As Decimal
End Class

Cada instancia de esta clase identifica las multas cobradas y los pagos por un artculo especfico
de la biblioteca (tituloArticulo) y para el cliente que entreg tarde el artculo (IDCopia-
Cliente).

Proyecto | 539

19_PATRICK-CHAPTER_19.indd 539 18/2/10 11:18:29


Clculo de multas
Tambin necesitamos conocer las multas totales que adeuda un cliente por todos los artculos,
aunque no se muestren los detalles. Agregue la funcin CalcularMultasCliente al mdulo
General.vb.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 2.

Public Function CalcularMultasCliente( _


ByVal idCliente As Integer) As Decimal
' ----- Dado un ID de cliente, calcule las multas adeudadas.
Dim textoSql As String

On Error GoTo ErrorHandler

' ----- Recuperar los registros de multas para el cliente.


textoSql = "SELECT SUM(Multa - Pagado) FROM CopiaCliente " & _
"WHERE Cliente = " & idCliente
Return ObtenerDecimalBD(EjecutarSQLRegresar(textoSql))

ErrorHandler:
ErrorGeneral("CalcularMultasCliente", Err.GetException(
))
Return 0@
End Function

Es cdigo muy bsico, en realidad, porque la base de datos hace todo el trabajo de sumar los va-
lores. Revis la documentacin de la base de datos y confirm que Multa y Pagado son campos
obligatorios, y nunca sern NULL. Esto mantiene bien el cdigo SQL.

Acceso a registros de clientes


Antes de revisar el registro de un cliente, el usuario debe identificarlo. Esto se hace mediante
el formulario de acceso de registros de cliente, una especie de formulario de inicio de sesin
para clientes. A cada cliente se le asigna una contrasea, que debe proporcionarse antes de que
el cliente pueda acceder a su registro. Los administradores pueden acceder al registro de un clien-
te son proporcionar la contrasea.
Ya he agregado el formulario AccesoCliente.vb a su proyecto; aparece en la figura 19-10.
El cdigo de este formulario es muy parecido al del formulario CambiarUsuario.vb, un formu-
lario que proporciona acceso administrativo al programa y que se agreg en el captulo 11. El
formulario acceso a clientes se comporta de manera diferente para los administradores y para los
clientes regulares.
Los clientes regulares deben proporcionar su cdigo de barras o su nombre (apellidos, co-
modines opcionales en el nombre) y su contrasea. Si usan un nombre parcial en lugar de
un cdigo de barras, y una bsqueda de ese nombre da como resultado varias coincidencias,

540 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 540 18/2/10 11:18:29


Figura 19-10. El formulario de acceso de clientes, AccesoCliente.vb.

tendrn que proporcionar una entrada ms correcta de su nombre. (Si dos clientes tienen el
mismo nombre tendrn que depender de cdigos de barras; pero este programa es para una
pequea biblioteca, de modo que los nombres en conflicto deben ser raros.)
Los administradores ingresan el nombre del cliente o el cdigo de barras, pero no necesitan
contrasea. Si hay varias coincidencias, el formulario presenta todos los nombres coinciden-
tes en una lista, y el administrador puede seleccionar la entrada correcta de la lista. Esto le
da a un administrador acceso completo a todos los registros del cliente. Obviamente, resulta
importante para un administrador cerrar una sesin cuando termine de usar una estacin
de trabajo que est disponible para clientes.
El mtodo SeleccionarCliente del formulario AccesoCliente proporciona la interfaz al
formulario para administradores y clientes comunes. La funcin devuelve el ID del cliente selec-
cionado, o -1 si el usuario no tuvo acceso correcto al registro de un cliente.

Modificacin de la contrasea del cliente


Aunque los administradores pueden cambiar la contrasea de cada cliente mediante el formu-
lario Cliente.vb, no queremos dar a los clientes comunes acceso a ese formulario y todo su
poder simple y no adulterado. Pero an queremos que los clientes puedan cambiar sus propias
contraseas, porque es algo agradable y seguro. He agregado el formulario ClaveCliente.vb a su
proyecto para satisfacer este propsito (vase la figura 19-11).

Figura 19-11. El formulario de contrasea del cliente, ClaveCliente.vb.

Proyecto | 541

19_PATRICK-CHAPTER_19.indd 541 18/2/10 11:18:30


En esencia, el formulario es un subconjunto reducido del formulario Cliente.vb completo. De-
bido a que necesita tratar slo con clientes activos, no tiene mucho cdigo en Cliente.vb que
se diferencie entre los registros de clientes nuevos y existentes. El enfoque del formulario para
contrasea de clientes es la instruccin de actualizacin que establece la contrasea del cliente,
en el mtodo SaveFormData.
textoSql = "UPDATE Cliente SET Clave = " & _
TextoBD(CifrarClave("cliente", _
Trim(RecordPassword.Text))) & _
" WHERE ID = " & IDActivo
ExecutarSQL(textoSql)

Cobro de pagos de cliente


En un mundo perfecto, los clientes nunca dejaran que los libros y otros artculos de biblioteca
alcanzarn el estado de vencido. Por supuesto, en un mundo perfecto, las bibliotecas le dejaran
mantener los libros para siempre. Y djeme terminar con estas incesantes noticias vencidas. Qu
hay con eso?
Pero para el caso de las pequeas bibliotecas que insisten en cobrar multas por artculos venci-
dos, el proyecto Biblioteca incluye caractersticas para evaluar y dar seguimiento a multas. En
un captulo posterior, agregar el cdigo que calcula automticamente las multas para artculos
vencidos. Por ahora, implementaremos el formulario que le permite documentar los pagos del
cliente y otros ajustes financieros a artculos en el registro del cliente.
He agregado el formulario PagoCliente a la coleccin de archivos de proyecto, pero an no est
integrado en el proyecto. Seleccione el archivo PagoCliente.vb en el Explorador de soluciones,
y luego cambie la propiedad Accin de compilacin (en el panel Propiedades) de Ninguna a
Compilacin. En la figura 19-12 se muestran los controles de este formulario.
Las multas que se agregan automticamente a un artculo vencido aparecen en el campo de la
base de datos CopiaCliente.Multa. Aunque ese valor se despliega en el formulario de pago
de clientes, no es el enfoque primario de ese formulario. En cambio, el formulario existe para
permitir a un bibliotecario que ingrese cobros y pagos para un artculo previamente prestado,
almacenando esas actualizaciones en la tabla PagoCliente de la base de datos. Esta tabla registra
cuatro tipos de eventos financieros para cada artculo prestado a un cliente:
Multas adicionales impuestas por un bibliotecario o administrador. Por ejemplo, un biblio-
tecario puede agregar el valor de un artculo como una multa si resulta que el cliente ha
perdido el artculo. Entradas de multas adicionales usan la letra F en el campo de la base de
datos PagoCliente.TipoEntrada.
Pagos hechos por el cliente para un artculo vencido. P es el tipo de entrada.
Se desechan una o todas las multas pendientes para un artculo vencido, indicado por un
tipo de entrada D.
Si el tipo de entrada es R, el registro indica un pago reembolsado al cliente por la biblioteca.

542 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 542 18/2/10 11:18:30


Figura 19-12. El formulario de pago del cliente, PagoCliente.vb.

Cada registro de la tabla PagoCliente incluye una fecha de transaccin, la cantidad de sta,
comentarios adicionales y la identidad del usuario administrativo que registra la entrada. Para
aclarar un poco ms el cdigo, los cdigos de letras en la tabla de datos se conviertan a valores
numricos a partir de la enumeracin EventEntryType.
Private Enum TipoEntradaEvento
NoDefinido
PagoCliente
MultaAgregada
MultaDesechada
ReembolsoACliente
MultasAdeudadas
End Enum

La entrada MultasAdeudadas permite que el valor CopiaCliente.Multas sea parte del histo-
rial financiero desplegado en el formulario.
El bibliotecario usa los campos en la seccin Nuevo evento de pago del formulario PagoClien-
te para agregar registros de cobro y pago. Todos los registros agregados previamente aparecen en
la lista HistoriaEventos, en la seccin Historia de eventos de pago.
El formulario que llama (agregado ms adelante en este captulo) necesita pasarse en el valor
CopiaCliente.ID para identificar el registro apropiado. Pero el plan es hacer que los pagos
agregados en este formulario fluyan de regreso al formulario principal. Los dos formularios
compartirn un conjunto de objetos de PagoArticulo empleando la clase que agregamos hace
unas cuantas secciones en este captulo. Las almacenaremos en una variable de miembro local
como un conjunto genrico.

Proyecto | 543

19_PATRICK-CHAPTER_19.indd 543 18/2/10 11:18:31


Private SoloPagos As Generic.List(Of PagoArticulo)

El punto de entrada en el formulario ser un mtodo pblico llamado AdministrarPagos.


Agregue ese cdigo ahora a la clase PagoCliente.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 3.

Public Sub AdministrarPagos(ByVal idCopiaCliente As Integer, _


ByVal pagosSesion As Generic.List(Of PagoArticulo))
' ----- Administrar los pagos de un articulo.
IDCopiaClienteActivo = idCopiaCliente
SoloPagos = pagosSesion
Me.ShowDialog( )
End Sub

Este mtodo registra el nmero de ID de la copia del cliente y el cobro de pagos para el artculo
prestado. Entonces el procesamiento pasa al manejador de eventos Load. Es en esta rutina donde
agregamos nuestro cdigo de administracin financiera localizada. En la rutina PagoClien-
te_Load recorra hacia abajo hasta la tercera parte del mtodo, al cdigo que carga los detalles
de resumen de la base de datos. Justo despus de la lnea:
RegistroArticulo.Text = CStr(infoBD!Titulo)

Agregue las instrucciones que formarn globalmente los valores de moneda para las etiquetas de
resumen Multas, Pagos y Saldo que aparecen cerca de la parte superior del formulario.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 4.

multaOriginal = CDec(infoBD!Multa)
RegistroMulta.Text = Format(multaOriginal, "Currency")
RegistroPagos.Text = Format(CDec(infoBD!Paid), "Currency")
saldoAdeudado = multaOriginal - CDec(infoBD!Paid)
RegistroSaldo.Text = Format(saldoAdeudado, "Currency")

El resto del cdigo del manejador de eventos Load carga registros existentes de la tabla Pago-
Cliente, adems de la multa adeudada original, si la hay, del campo de la base de datos Co-
piaCliente.Multa.
Ms adelante, cuando el usuario hace clic en el botn Agregar para agregar un nuevo evento fi-
nanciero a la entrada de cliente y copia de artculo, la rutina GuardarDatosEvento (equivalente
al mtodo GuardarDatosFormulario en casi todos los dems formularios que hemos desarro-
llado hasta ahora) guarda la informacin actualizada en la base de datos. Esta rutina debe guardar
el nuevo cobro o pago en la tabla PagoCliente, adems de actualizar el resumen de cobro y pago
en el registro CopiaCliente. Agregue el cdigo que escribe esos registros, justo despus de los
clculos para las variables montoMulta y montoPagado en el mtodo GuardarDatosEvento.

544 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 544 18/2/10 11:18:31


Insercin de fragmento de cdigo
Inserte el fragmento de cdigo Cap19, Elemento 5.

' ----- Agregar la entrada a la base de datos.


EmpezarTransac()
sqlText = "INSERT INTO PagoCliente (CopiaCliente, " & _
"FechaEntrada, TipoEntrada, Monto, Comentario, IDUsuario) " & _
"OUTPUT INSERTED.ID VALUES (" & IDCopiaClienteActivo & _
", GETDATE(), " & TextoBD(codigoEntrada) & ", " & _
RegistroMonto.Text & ", " & _
TextoBD(Trim(RegistroComentario.Text)) & _
", " & IdUsuarioInicio & ")"
nuevoID = CInt(EjecutarSQLRegresar(sqlText))

textoSql = "UPDATE CopiaCliente SET Multa = " & montoMulta & _


", Pagado = " & montoPagado & " WHERE ID = " & _
IDCopiaClienteActivo
EjecutarSQL(sqlText)
ConfirmarTransac()

He dividido ambas instrucciones de base de datos en una transaccin para ayudarle a asegurar
la integridad de los datos. Una vez que se haya actualizado, es hora de actualizar la pantalla. La
lista en pantalla de cobros y pagos requiere este nuevo registro. La lista usa la clase local Histo-
riaEventosArticulos, una variacin de la clase DatosListaElementos que suele usar con-
troles ListBox. HistoriaEventosArticulos tiene campos que son especficos para desplegar
informacin financiera en el cuadro de lista HistoriaEventos. Agregue el cdigo que genera
un registro HistoriaEventosArticulos y agrguelo a la lista HistoriaEventos, inmediata-
mente despus del cdigo que actualiza la base de datos que acabamos de agregar.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 6.

' ----- Agregar un elemento a la lista de entrada.


articuloHistoria = New HistoriaEventosArticulos
articuloHistoria.IDPago = nuevoID
articuloHistoria.FechaEntrada = Today
articuloHistoria.MontoPago = CDec(RegistroMonto.Text)
articuloHistoria.Comentarios = Trim(RegistroComentario.Text)
articuloHistoria.TipoEntrada = tipoEntrada
HistoriaEventos.Items.Add(articuloHistoria)

Este cdigo es seguido por cdigo similar que actualiza la lista SoloPagos, la Generic.List(Of
PagoArticulo) que fue pasada del formulario que llama. El cdigo actualiza el registro de re-
sumen del pago existente o agrega un nuevo registro a la lista genrica.

Proyecto | 545

19_PATRICK-CHAPTER_19.indd 545 18/2/10 11:18:31


' ----- Agregar un nuevo pago.
rastreoPago = New PagoArticulo
rastreoPago.IDCopiaCliente = IDCopiaClienteActivo
rastreoPago.tituloArticulo = RegistroArticulo.Text
rastreoPago.CuotasPagadas = montoPagado
rastreoPago.SaldoAdeudo = montoMulta - montoPagado
SoloPagos.Add(rastreoPago)

Antes de dejar esta funcin, necesitamos actualizar los tres valores de resumen financieros cerca
de la parte superior del formulario, los que establecimos cuando se carg por primera vez el for-
mulario. Agregue este cdigo justo despus de la lista actualizada PaymentSolo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 7.

' ----- Actualizar los valores en pantalla.


RegistroMulta.Text = Format(montoMulta, "Currency")
RegistroPagos.Text = Format(montoPagado, "Currency")
RegistroSaldo.Text = Format(montoMulta - montoPagado, _
"Currency")

La lista HistoriaEventos es un control de dibujo de propietario de altura de lnea variable,


similar al que diseamos en el captulo 18. Su manejador de eventos MedidaArticulo establece
la altura de cada elemento de la lista (los comentarios aparecen en una segunda lnea, cuando
estn disponibles), y su manejador de eventos DibujarArticulo hace el dibujo real de cada
columna de datos y de los comentarios.

Administracin de todas las multas y los pagos


El formulario Pago del cliente le permite al bibliotecario ingresar multas y pagos individuales,
pero el programa an necesita administrar todas las multas y pagos para un solo cliente, un
formulario que llama al Pago del cliente cuando lo necesitamos. El nuevo formulario Registros-
Cliente.vb satisface esta necesidad. He agregado este formulario a su proyecto, aunque necesita
habilitarlo. Seleccinelo en el Explorador de soluciones y cambie su propiedad Accin de com-
pilacin (en el panel Propiedades) de Ninguna a Compilacin. En la figura 19-13 se muestran
los controles de este formulario.
Este formulario est disponible para administradores y clientes, aunque algunos de los clientes
estn ocultos de la vista del cliente.
El botn Contrasea lleva al formulario Cambio de contrasea del cliente que agregamos al
principio de este captulo. El botn Editar, slo disponible para los administradores, propor-
ciona acceso al formulario Cliente.vb completo. La principal seccin del formulario Registro del
cliente despliega una lista de todos los artculos que el cliente ha pedido prestados actualmente.
Incluye un botn Renovar que le permite a un cliente extender la fecha de vencimiento para el
artculo prestado. Agregaremos el cdigo para esa caracterstica en un captulo posterior.
El formulario tambin despliega un resumen de todas las multas y pagos pendientes. En la figura
19-14 se muestra la ficha Multas y sus campos.

546 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 546 18/2/10 11:18:31


Figura 19-13. El formulario de registros del cliente, RegistrosCliente.vb.

Figura 19-14. El panel Multas en el formulario Registros del cliente.

El botn Imprimir boleta de saldo genera un recibo impreso de todas las multas y pagos del
cliente. Agregaremos su cdigo en un captulo posterior.
Casi todo el cdigo de este formulario existe para administrar multas y pagos. Para agregar un
cobro o pago, el bibliotecario selecciona un artculo de la lista Multas y luego hace clic en el
botn Multas y pagos. Esto despliega el formulario Pago del cliente que acabamos de agregar.
Las dos listas principales del formulario Registros del cliente aprovecharn la clase estndar Datos-
ListaElementos y usarn una clase ms rica en propiedades para dar soporte a las necesidades de

Proyecto | 547

19_PATRICK-CHAPTER_19.indd 547 18/2/10 11:18:32


despliegue de cada lista. Agregaremos este ArticuloDetalleCliente como una clase separada
porque (como veremos en un captulo posterior) se usar en otros lugares del proyecto Biblioteca.
Cree una nueva clase llamada ArticuloDetalleCliente.vb y use el siguiente cdigo para su contenido.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 8.

Public Class ArticuloDetalleCliente


Public IDDetalle As Integer
Public TextoTitulo As String
Public FechaVencimiento As Date
Public MontoMulta As Decimal
Public MontoPagado As Decimal
Public SaldoAdeudo As Decimal
End Class

Ahora, regrese al formulario RegistrosCliente. Como puede saber al revisarlo, la lista Multas
despliega varias columnas de valores monetarios. Agreguemos el cdigo que forma correctamen-
te la moneda de acuerdo con los parmetros monetarios regionales. En primer lugar, localice el
mtodo ActualizarMultasClientes. Esta rutina agrega todas las multas y pagos, y despliega
el resultado a travs del control Label SaldoAdeudo.
Cerca de la parte superior de esta rutina hay un comentario que establece Limpiar la lista ac-
tual. Agregue el cdigo siguiente justo despus del comentario.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 9.

Multas.Items.Clear()
saldoTotal = 0@
SaldoVencido.Text = Format(0@, "Currency")
Me.Cursor = Windows.Forms.Cursors.WaitCursor

Pudimos establecer el campo SaldoAdeudo en $0.00, pero esto no estara globalizado de


manera apropiada. Empleando la funcin Format con Currency como regla de formato an
da como resultado $0.00 cuando se usa en Estados Unidos, pero tambin se ajusta adecuada-
mente a otras culturas.
El mtodo ActualizarMultasCliente requiere una gran cantidad de clculos, y termina con
el saldo de cliente restante en la variable local saldoTotal. Localice el comentario que dice
Mostrar el saldo total y agregue el siguiente cdigo justo despus de l.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 10.

SaldoAdeudo.Text = Format(saldoTotal, "Currency")

548 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 548 18/2/10 11:18:32


La lista Multas, una implementacin de ListBox de dibujo de propietario, tambin desplie-
ga valores de moneda. sta es otra lista que utiliza la clase estndar DatosListaElementos,
empleando en cambio la clase local ArticuloDetalleCliente para la administracin de sus
artculos. Localice el manejador de eventos Multas_DrawItem, y el comentario Extraer los
detalles de los elementos de lista dentro de ese manejador. Agregue el cdigo siguiente despus
del comentario.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 11.

detalleArticulo = CType(Multas.Items(e.Index), ArticuloDetalleCliente)


textoTitulo = detalleArticulo.TextoTitulo
textoMulta = Format(detalleArticulo.montoMulta, "Currency")
textoPagado = Format(detalleArticulo.MontoPagado, "Currency")
textoSaldo = Format(detalleArticulo.SaldoAdeudo, "Currency")
If (detalleArticulo.SaldoAdeudo = 0@) Then usarNoticia = usarBrocha

Este bloque forma de manera apropiada cada valor de moneda. Como opcin predeterminada,
todos los montos adeudados aparecen en rojo en la lista. La ltima lnea de este bloque de cdigo
restablece el color a uno del elemento de lista si no hay saldo adeudado.

Conexin de caractersticas de patrn al formulario principal


Esto lo hace para los nuevos formularios especficos del cliente. Habilitemos el acceso a ellos me-
diante el formulario Biblioteca principal. Guau! Ha pasado mucho tiempo desde que realmente
revis este formulario. He olvidado su aspecto. Ah, s. Uno de los conos principales accede a un
registro de cliente (vase la figura 19-15).

Figura 19-15. Acceso a los registros de cliente del formulario principal.

Todo lo que necesitamos hacer es agregar un manejador de eventos para el botn Cliente. Ubi-
que el manejador de eventos AccClienteAcceso_Click en el cdigo del formulario. Luego
agregue el siguiente cdigo a ese manejador.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 12.

Proyecto | 549

19_PATRICK-CHAPTER_19.indd 549 18/2/10 11:18:32


' ----- Buscar el registro de un cliente activo.
Dim idCliente As Integer

' ----- Obtener el ID del cliente.


idCliente = (New AccesoCliente).SelecionarCliente()
If (idCliente = -1) Then Return

' ----- Mostrar el registro de cliente.


Call (New RegistrosCliente).VerRegistroCliente(idCliente, True)

Este cdigo hace llamadas directas a dos de los formularios que agregamos en este captulo:
AccesoCliente y RegistrosCliente. Primero pide al usuario que seleccione un registro de
cliente y luego despliega sus detalles mediante el formulario Registros del cliente.

Duelo por los formularios de administracin de clientes


Hagamos un cambio ms relacionado con los registros de cliente. En un captulo anterior, in-
cluimos un botn Administrar artculos de cliente en el formulario Cliente.vb. Este botn exista
para proporcionar acceso al futuro formulario RegistrosCliente.vb form, pero haba estado muer-
to hasta ahora. Pero con el formulario RegistrosCliente.vb ya incluido, estamos listos para hacer
historia en la administracin de clientes.
Abra el cdigo fuente del formulario Cliente.vb y localice el manejador de eventos AccArticu-
los_Click. Luego agrguele el siguiente cdigo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap19, Elemento 13.

Call (New RegistrosCliente).VerRegistroCliente(IDActivo, False)

Esto es correcto y est bien, pero tal vez est pensando Ahora el formulario Cliente le per-
mite abrir el formulario Registros del cliente. Y ese formulario tiene un botn Editar que le
permite una vez ms abrir el formulario Cliente. Si fuera un falso bibliotecario, puede haber
millones de formularios de administracin de clientes en pantalla a la vez. Y es cierto. As que
tenemos que agregar algn cdigo para evitar que eso suceda. El segundo argumento False de
RegistrosCliente.ViewRegistrosCliente es una marca que dice: No muestres el botn
Editar en el formulario Registros del cliente. Existe cdigo similar en el formulario Registros del
cliente que detiene la recursin.
Private Sub AccEditarCliente_Click...
If ((New Cliente).EditarRegistroLimitado( _
ActivePatronID) <> -1) Then...

El mtodo EditarRegistroLimitado oculta el botn Administrar artculos de cliente en el


formulario Cliente.vb. No importa con cul formulario empiece, puede acceder al otro formula-
rio, pero no podr generar una nueva copia del formulario inicial.

550 | Captulo 19:Localizacin y globalizacin

19_PATRICK-CHAPTER_19.indd 550 18/2/10 11:18:33


Hay mucho cdigo nuevo en este captulo, pero todo ha sido pedestre. Podramos tener in-
cluso cambios culturalmente sensibles. Por ejemplo, la columna Fecha vencimiento en la lista
de artculos prestados de RegistrosCliente.vb usa un formato de fecha codificado para su des-
pliegue.
fechaVencimiento = Format(detalleArticulo.FechaVencimiento, "d, MMM, yyyy")

Podra cambiar esto a Short Date o cualquier otra configuracin de cultura neutral. El mtodo
que elija en realidad depender de su audiencia de destino. Y si a esa audiencia le gusta lo escrito
en el papel, el siguiente sobre impresin es para usted.

Proyecto | 551

19_PATRICK-CHAPTER_19.indd 551 18/2/10 11:18:33


Captulo 20
Impresin

Cuando Microsoft lanz su versin original de MS-DOS, incluy caractersticas de impresin


que daban soporte a las impresoras disponibles: cincel y piedra. Por fortuna, la impresin ha
recorrido un largo camino desde entonces. Ahora, las impresoras a color avanzadas y los sistemas
de impresin sin papel (como Adobe Acrobat y XPS) dan soporte a impresoras que rivalizan
con las imprentas offset a todo color profesionales.
Aunque .NET Framework no reemplaza el sistema de cola de impresin integrado en cada copia
de Windows, lo hace accesible. Al momento de leer este captulo, una impresora es ahora tratada
como cualquier superficie de dibujo de .NET. Las instrucciones que use para dibujar un formu-
lario o control pueden copiarse y pegarse directamente en su cdigo de impresin.
Como mencion en el captulo 18, la base de presentacin de Windows (WPF, Windows Pre-
sentation Foundation) incluye caractersticas que permiten generar archivos XPS, diseados para
impresin WYSIWYG. No analizaremos esa tecnologa en este captulo, porque los archivos
XPS son un intermedio entre su cdigo de impresin y la impresora fsica. Las tcnicas de im-
presin basadas en GDI+ mostradas en este captulo proporcionan integracin ms directa entre
cdigo e impresora.
En este captulo se proporciona un anlisis general del soporte a impresin en .NET. Un anlisis
de la impresin de informes aparece en el siguiente captulo. Si est leyendo este captulo en su
formato electrnico mediante el sistema de publicacin de Safari, an puede salir corriendo aho-
ra y hacerse de los medios para comprar una versin impresa de este libro. Al tener esa respuesta
tctil de la superficie de la pgina debe estar de humor para el anlisis de la tcnica y el papel de
este captulo.

552

20_PATRICK-CHAPTER_20.indd 552 17/2/10 15:31:46


Impresin en Windows
Las impresoras son como personas. Oh!, no quiero decir que sean renuentes o que se queden
rpidamente sin tinta. Como las personas del mundo, las impresoras hablan muchos idiomas
diferentes. En el extremo bsico de la escala de lenguaje, algunas impresoras simplemente dan
salida a los caracteres que reciben. Otras agregan secuencias de escape, combinaciones espe-
ciales de caracteres que habilitan caractersticas mejoradas como seleccin de fuente y texto de
doble ancho. En el extremo complejo de la escala estn PostScript y XPS, lenguajes de impresora
completamente escalables, con comandos que son un poco similares a los de GDI+.
Sera la peor pesadilla de todo programador ajustar el cdigo de la aplicacin de modo que se
oriente a todas las posibles impresoras que un usuario pudiera tener. Cada nuevo lenguaje de im-
presora significara otra oleada de desarrollo y pruebas. Y los fabricantes de impresoras son lo sufi-
cientemente activos como para salir con nuevas variaciones del lenguaje en cuestin de meses.
Por fortuna, Windows implementa un sistema de controladores especficos de la impresora que
protege al desarrollador de la mayor parte de las variaciones en las impresoras. Todos estos con-
troladores hablan un lenguaje comn (llammosle impreol) que el controlador traduce a la
lengua nativa de la impresora. Como desarrolladores, slo necesitamos disear software que
hable impreol.
El sistema de impresin de .NET Framework agrega un nivel adicional de traduccin del lengua-
je. Los programas .NET no se comunican directamente con los controladores de impresora. En
cambio, usan comandos GDI+ (los mismos que se utilizan para actualizaciones de pantalla) para
dar salida al contenido en un lienzo de impresora en memoria. El marco conceptual convierte
entonces estos comandos a impreol y enva la salida al controlador de impresora apropiado, y
por ltimo a la impresora. En la figura 20-1 se muestra un resumen de los pasos que intervienen
en la impresin en .NET.

.NET/GDI+

Aplicacin Impresin Controlador Impresora


Figura 20-1. Del programador al lienzo: impresin con .NET.

Impresin en Windows | 553

20_PATRICK-CHAPTER_20.indd 553 17/2/10 15:31:46


Impresin en .NET
El hecho de que la salida a la pantalla y la impresora se generan mediante comandos GDI+ idn-
ticos, significa que este captulo puede ser realmente corto; tome como referencia su captulo 18
para conocer los detalles. Pero tambin significa que es necesario que haya un lienzo (un objeto
System.Drawing.Graphics) de donde tomen su salida los comandos GDI+ especficos de la
impresora. La clase System.Drawing.Impresin.PrintDocument le proporciona el lienzo
de salida que necesita para impresin y salida de vista preliminar comn. Hay tres maneras de
usar la clase PrintDocument:
Agregar un control PrintDocument a un formulario del cuadro de herramientas de Win-
dows Forms. Este control aparece como opcin predeterminada en la seccin Impresin del
cuadro de herramientas. Asigne sus propiedades y responda a sus eventos como con cualquier
otro control.
Crear una instancia de nivel de campo de la clase PrintDocument. Incluya la clusula With
Events en la definicin para ovtener administracin de evento.
Crear una instancia local de PrintDocument y conectar cualquier evento empleando Add-
Handler.
stos son mtodos estndar en .NET, pero tener una variacin de control hace que la clase re-
sulte mucho ms conveniente. Entraremos un poco ms adelante en el cdigo de impresin un
poco ms adelante.
Estn disponibles otros cuatro controles especficos de la impresora en los proyectos de Windows
Forms:
PageSetupDialog
Este control presenta un cuadro de dilogo de configuracin de impresora de Windows que
permite al usuario configurar un trabajo de impresin especfico, o todos los trabajos de im-
presin para la aplicacin. El mtodo ShowDialog del control despliega el formulario que
se muestra en la figura 20-2. El control tambin expone propiedades relacionadas con la se-
leccin del usuario. Su miembro PageSettings expone preferencias de usuario especficas
como se definen en el formulario, y el miembro PrinterSettings identifica a la impresora
seleccionada y sus propiedades. Puede retener estos miembros y asignar ms adelante a otras
clases especficas de la impresora que incluyen miembros similares.
PrintDialog
En la figura 20-3 se muestra el cuadro de dilogo de este control, el cuadro estndar que
aparece en casi todos los programas cuando el usuario selecciona el comando de men Ar-
chivo Impresora. Este control tambin expone un Microsoft PrinterSettings usado
para asignar o recuperar la impresora seleccionada y las opciones relacionadas.
PrintPreviewDialog
El cuadro de dilogo de este control despliega una vista previa de su documento impreso
para el usuario. Incluye caractersticas de presentacin de vista previa, incluidos nivel de
acercamiento y un control de pginas que se vern a la vez. El botn Imprimir enva el
contenido de vista previa a la impresora predeterminada (sin pedir seleccin de impresora).

554 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 554 17/2/10 15:31:46


Figura 20-2. El cuadro de dilogo Configurar pgina.
Este control interacta directamente con la instancia de su PrintDocument, que dirige el
contenido del despliegue real. En la figura 20-4 se muestra el cuadro de dilogo Vista previa
de impresin, aunque sin contenido especfico de una pgina.
PrintPreviewControl
El control PrintPreviewDialog incluye caractersticas de administracin bsicas de vista
previa (como la de acercamiento) que satisfacen las necesidades de la mayor parte de las apli-
caciones. Por desgracia, ese control es una caja negra sellada, y no puede agregarle fcilmente
sus caractersticas personalizadas, o eliminar caractersticas que no le gusten. El control
PrintPreviewControl proporciona una interfaz alterna que le permite personalizar por
completo la experiencia de vista previa. En lugar de un cdigo completo, implemente slo
la parte de despliegue de pgina del formulario. Debe implementar todas las barras de he-
rramientas y otras caractersticas, y vincular su funcionalidad con el control de vista previa.
No analizar este control en este captulo. Si est interesado en usar este control avanzado,
puede leer un artculo que escrib hace unos aos acerca de la vista previa de impresin.*
Antes de imprimir, necesita saber cul impresora desea utilizar para la salida. Tal vez tambin
necesite saber sobre las caractersticas disponibles de la impresora, como si da soporte a color. Si
sola ser un desarrollador en Visual Basic 6.0, estar acostumbrado a la conveniente coleccin
Printers. Su ausencia en Visual Basic 2008 significa que debemos usar medios ms indirectos
para acceder a las impresoras.

* Encontrar el archivo de referencia en mi sitio Web, http://www.timaki.com, en la seccin Articles.

Impresin en .NET | 555

20_PATRICK-CHAPTER_20.indd 555 17/2/10 15:31:47


Figura 20-3. El cuadro de dilogo Imprimir.

Figura 20-4. El cuadro de dilogo Vista previa de impresin.

556 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 556 17/2/10 15:31:48


La clase System.Drawing.Printing.PrinterSettings incluye una coleccin de cadena
InstalledPrinters que presenta una lista de la ruta a cada impresora configurada. Puede
asignar cualquiera de estas cadenas al miembro PrinterName de PrinterSettings, haciendo
disponible la impresora especfica dentro de la aplicacin. El siguiente fragmento de cdigo deja
que el usuario seleccione de la lista de impresoras, y despliega alguna informacin bsica acerca
de la impresora seleccionada:
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
' ----- Desplegar la lista de impresoras.
Dim buscarImpresora As String

For Each buscarImpresora In Drawing.Printing. _


PrinterSettings.InstalledPrinters
ListBox1.Items.Add(buscarImpresora)
Next buscarImpresora
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles Button1.Click
' ----- Desplegar informacion acerca de la impresora seleccionada.
Dim impresoraSeleccionada As Drawing.Printing.PrinterSettings

If (ListBox1.SelectedIndex = -1) Then Return


impresoraSeleccionada = New Drawing.Printing.PrinterSettings( )
impresoraSeleccionada.PrinterName = ListBox1.Text
MsgBox(impresoraSeleccionada.ToString)
End Sub

Impresin de un documento
Ya vimos que muchos componentes de Windows funcionan juntos para generar su salida im-
presa. Dentro de su cdigo .NET, tambin usar muchos componentes (clases) para orientar el
proceso de impresin. Cuatro pasos principales intervienen en la impresin de un documento
(al menos de manera directa) a partir de su cdigo:
1. Crear una instancia de una clase PrintDocument (o agrguela como un control a su formu-
lario).
2. Establecer los diversos parmetros de impresora de PrintDocument, ya sea mediante una
clase o control PrintDialog (o relacionado), o usando las configuraciones manual o pre-
determinada.
3. Agregar un manejador de eventos para el evento PrintPage de PrintDocument. A este
evento se le llama una vez por cada pgina, y recibe un objeto System.Drawing.Graphics
para el lienzo de la impresora. Su cdigo de manejador de eventos imprime una sola pgina
y actualiza una marca que le indica al documento si habr ms pginas.
4. Llamar al mtodo Print de PrintDocument para que la rueda empiece a girar.

Impresin de un documento | 557

20_PATRICK-CHAPTER_20.indd 557 17/2/10 15:31:48


Probemos un poco de cdigo para ver cmo come esta bestia de la impresin. O cmo imprime.
O qu hace. Qu le parece un programa simple que imprima un documento de cinco pginas
en la impresora seleccionada por el usuario? La salida ser varias pginas grandes con un dgito en
cada una, perfecto para el set de Plaza Ssamo. En primer lugar, creemos una nueva aplicacin de
Windows Forms, y agreguemos un solo botn a Form1 llamado AccImprimir. Tambin agrega-
remos un control PrintDocument (llamado DocCuenta) y un control PrintDialog (llamado
ImpresoraUsuario). En la figura 20-5 se muestra el formulario y sus controles de soporte.

Figura 20-5. Un programa que slo tiene la impresin en mente.

Estos controles implementan los dos primeros pasos del proceso de impresin de cuatro pasos.
A continuacin agregaremos el cdigo fuente.
Public Class Form1
Private CualPagina As Integer

Private Sub AccImprimir_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles AccImprimir.Click
' ----- Preguntar al usuario la configuracion de impresora
' y empezar la impresion.
ImpresoraUsuario.Document = DocCuenta
If (ImpresoraUsuario.ShowDialog( ) = _
Windows.Forms.DialogResult.OK) Then _
DocCuenta.Print( )
End Sub

Private Sub DocCuenta_BeginPrint(ByVal sender As Object, _


ByVal e As System.Drawing.Printing.PrintEventArgs) _
Handles DocCuenta.BeginPrint
' ----- Iniciar el conteo.
CualPagina = 1
End Sub

Private Sub DocCuenta_PrintPage(ByVal sender As Object, _


ByVal e As System.Drawing.Printing. _
PrintPageEventArgs) Handles DocCuenta.PrintPage
' ----- Imprimir una sola pagina.
Dim fuenteEnorme As Font
Dim textoCentrado As StringFormat

558 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 558 17/2/10 15:31:48


' ----- Desbordmonos con la fuente: 256 puntos!
fuenteEnorme = New Font("Arial", 256)

' ----- Centrar el texto en la pagina.


textoCentrado = New StringFormat( )
textoCentrado.Alignment = StringAlignment.Center
textoCentrado.LineAlignment = StringAlignment.Center

' ----- Imprimir el numero.


e.Graphics.DrawString(CStr(CualPagina), fuenteEnorme, _
Brushes.Black, e.MarginBounds, textoCentrado)

' ----- Dibujar los margenes de la pagina para aclarar


' donde estan.
e.Graphics.DrawRectangle(Pens.Blue, e.MarginBounds)

' ----- Limitar la salida a cinco paginas.


CualPagina += 1
If (CualPagina <= 5) Then e.HasMorePages = True _
Else e.HasMorePages = False
End Sub
End Class

Este cdigo implementa los pasos 3 (AccImprimir_Click) y 4 (DocCuenta_PrintPage). El


manejador de eventos Click del botn AccImprimir vincula el documento y el cuadro de di-
logo Imprimir para que hagan referencia a los mismos parmetros. Luego pide al usuario que se-
leccione una impresora y varias opciones a travs de la llamada a ShowDialog. Si el usuario hace
clic en el botn Aceptar de ese cuadro de dilogo, desencadena una llamada al mtodo Print.
La accin pasa entonces a los eventos de la instancia PrintDocument. He implementado dos
de los eventos: un manejador de eventos BeginPrint que realiza alguna inicializacin, y uno
PrintPage que hace el trabajo duro. (Otros eventos incluyen EndPrint, usado para limpiar
cuando la impresin est completa, y QueryPageSettings, donde puede cambiar la orientacin
y configuracin de cada pgina del documento.) En realidad no es tan difcil, sobre todo cuando
vemos cdigo similar en el captulo 18. La mayor diferencia es la cantidad de espacio disponible
en la pgina impresa, permitindonos jugar con fuentes cuyo tamao es de varios cientos.
En la figura 20-6 se muestra la pgina de la salida de este programa. Imprim en la pseudoim-
presora instalada para capturar trabajos de impresin como documentos XPS. Puede ver en la
esquina inferior izquierda que registra de manera apropiada cinco pginas de salida.

Vista previa de impresin


La adicin de una interfaz de vista previa de impresin es fcil, de modo que tal vez le deba
pedir a su jefe primero un proyecto difcil, y luego regresar cuando se haya cansado. Generemos
nuestra aplicacin simple de impresin de nmeros, agregando un control Button llamado
AccVistaPrevia. Tambin agregaremos un control PrintPreviewDialog llamado Vista-
PreviaUsuario. Una vez que estn en su lugar, agregue el siguiente manejador de eventos
Click al botn de vista previa:

Vista previa de impresin | 559

20_PATRICK-CHAPTER_20.indd 559 17/2/10 15:31:49


Figura 20-6. Esta pgina es trada por el nmero 2.

Private Sub AccVistaPrevia_Click(ByVal sender As System.Object, _


ByVal e As System.EventArgs) Handles AccVistaPrevia.Click
' ----- Desplegar una vista previa del documento.
VistaPreviaUsuario.Document = DocCuenta
VistaPreviaUsuario.ShowDialog( )
End Sub

Hey!, eso es ms simple que el cdigo que inicia la impresin para la impresora real, aunque
la tecnologa de vista previa pare ser ms compleja que la simple impresin. Incluso debe
haber una ley contra esta simplicidad. Por fortuna, no la hay. En la figura 20-7 se muestra la
ventana de vista previa, despus de usar el botn de la barras de herramientas de dos pginas
a la vez.
Profundicemos un poco ms en lo simple que es este cdigo. Puedo aceptar que la clase
PrintPreviewDialog incluya mucho cdigo sorprendente para salida impresa de la vista
previa. Pero la parte notable del cdigo es que no tuvimos que reescribir la lgica personali-
zada de dibujo de GDI+ que ahora dirige el despliegue de vista previa y la salida real. Todo
lo que necesitbamos hacer era asignar el objeto PrintDocument al control de cuadro de
dilogo correcto.

560 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 560 17/2/10 15:31:49


Figura 20-7. La vista previa despliega varias pginas a la vez sin esfuerzo adicional de su parte.

Conteo y numeracin de pginas


Durante el proceso de impresin (o vista previa), el manejador de eventos PrintPage de Print-
Document obtiene llamadas para cada pgina de salida. Pero he aqu el truco: cuando se llam
por primera vez al manejador PrintPage, no fue para imprimir la pgina 1 del documento,
sino para imprimir la pgina que se necesite imprimir, sin importar su nmero de pgina.
Busque todo lo que quiera mediante las propiedades de la clase PrintDocument, pero nunca
encontrar una propiedad PageNumber. La clase PrintDocument no sabe nada acerca de los
nmeros de pgina en su documento y (a pesar de todo lo agradable que hace) no le importa.
Todo lo que sabe es que tiene que imprimir muchas pginas, y llamar a su manejador de eventos
PrintPage hasta que diga basta!
Si regresa a la figura 20-3, ver que el cuadro de dilogo Imprimir incluye la seccin Rango de
pginas, aunque la mayor parte de sus controles estn deshabilitados, como opcin predeter-
minada. El control PrintDialog incluye tres propiedades booleanas que le permiten habilitar
controles en esa seccin: AllowCurrentPage, AllowSomePages y AllowSelection. Al asignar
True a estas propiedades se habilita el control de la opcin coincidente. Ms adelante, despus
de que el usuario ha hecho una seleccin, puede consultar la propiedad PrinterSettings.
PrintRange del objeto PrintDocument para determinar cul opcin es.

Conteo y numeracin de pginas | 561

20_PATRICK-CHAPTER_20.indd 561 17/2/10 15:31:50


Agreguemos cdigo que habilita la seleccin de rangos de pgina. An limitaremos las pginas
permitidas a las numeradas del uno al cinco, pero el usuario podr elegir un rango dentro de ese
conjunto. Regresemos al manejado de eventos Click para el botn AccImprimir, e insertemos
unas cuantas lneas de cdigo (las que se encuentran en negritas):
Private Sub AccImprimir_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles AccImprimir.Click
' ----- Preguntar al usuario las configuraciones de impresora
' e iniciar la impresion.
ImpresoraUsuario.Document = DocCuenta

ImpresoraUsuario.AllowSomePages = True
DocCuenta.PrinterSettings.MinimumPage = 1
DocCuenta.PrinterSettings.MaximumPage = 5
DocCuenta.PrinterSettings.FromPage = 1
DocCuenta.PrinterSettings.ToPage = 5

If (ImpresoraUsuario.ShowDialog() = _
Windows.Forms.DialogResult.OK) Then _
DocCuenta.Print()
End Sub

Cuando esta vez el usuario haga clic en el botn Imprimir, la seccin Imprimir rango del cuadro
de dilogo tiene habilitado el campo Pginas, y se han llenado ya los campos de pginas mximas
y mnimas en el rango 1-5 (vase la figura 20-8).

Figura 20-8. Soporte a rangos de pgina.

Si el usuario ajusta este campo a 1-6, ocurre un error que establece que el rango vlido slo se
encuentra entre 1-5. Pero si selecciona Todas las pginas o 1-5 o 1-4 o 2-3 o Pgina actual o
Seleccin, el manejador de eventos PrintPage ser llamado exactamente de la misma manera.
En realidad, el manejador ser llamado docenas, incluso cientos de veces hasta que le diga que se
detenga. La seleccin del usuario tiene impacto en la propiedad PrinterSettings.PrintRan-
ge y algunas otras propiedades, pero no tiene un impacto directo en el proceso de impresin.
Depende de usted modificar el comportamiento de impresin de estos parmetros.
Imaginemos que el usuario ingres un rango de impresin 2-3. No podemos dejar que Print-
Document dispare el evento PrintPage para las cinco pginas porque, aunque generemos la
salida slo para las pginas 2 y 3, aun tendremos tres pginas en blanco fuera de la impresora. Lo
que queremos es hacer que el evento slo se dispare una vez para la pgina 2 y otra para la pgina
3. Necesitaremos ajustar el uso de la variable de rastreo en el nivel de la clase CualPagina para

562 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 562 17/2/10 15:31:50


compensar el rango indicado. En primer lugar, cambiemos el manejador BeginPrint para que
use el nmero de pgina de inicio correcto.
Private Sub DocCuenta_BeginPrint(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintEventArgs) _
Handles DocCuenta.BeginPrint
' ----- Iniciar de nuevo el conteo.
CualPagina = DocCuenta.PrinterSettings.FromPage
End Sub

En el manejador de eventos PrintPage, debemos modificar el cdigo que determina cundo


salir del proceso de impresin.
CualPagina += 1
If (CualPagina <= DocCuenta.PrinterSettings.ToPage) _
Then e.HasMorePages = True Else e.HasMorePages = False

Debido a que el cdigo de vista previa de impresin comparte la misma configuracin de documen-
to, necesitamos ajustar el cdigo de vista previa para forzarlo a imprimir siempre todas las pginas.
Private Sub AccVistaPrevia_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles AccVistaPrevia.Click
' ----- Desplegar una vista previa del documento.
VistaPreviaUsuario.Document = DocCuenta
DocCuenta.PrinterSettings.PrintRange = _
Printing.PrintRange.AllPages
VistaPreviaUsuario.ShowDialog( )
End Sub

Si ejecuta el programa y ajusta el rango de impresin, debe ajustar las pginas que solicit. He
colocado una copia de este programa en el directorio de instalacin del libro. Lo encontrar en
el subdirectorio Prueba de vista previa de impresin.

Impresin en modo simple


Emplear GDI+ para generar pginas impresas es muy sencillo. En el caso de pginas complejas,
tal vez tenga que hacer una gran cantidad de posicionamiento y mediciones de cadenas de texto
y muchas cosas ms, pero todo se reduce a dibuja este texto o esta forma en esta posicin.
Por tristeza, no todas las impresoras dan soporte a la manera de impresin de la aplicacin a la
impresora va GDI e impreol. Esto resulta especialmente cierto para las impresoras usadas para
imprimir recibos de tarjeta de crdito en papel trmico en su pizzera favorita. Aunque algunas
de estas impresoras pueden tener controladores de Windows, en realidad estn diseadas para
comunicacin directa con una aplicacin mediante su lenguaje de secuencia de escape especial.
Para esas impresoras, necesita escribir directamente en la impresora en modo simple, donde
controla exactamente cules caracteres se envan a la impresora. (En realidad, no tiene que ir
directamente a la impresora. An puede escribir en la cola de la impresora y dejar que Windows
administre la programacin del trabajo de impresin.)

Impresin en modo simple | 563

20_PATRICK-CHAPTER_20.indd 563 17/2/10 15:31:50


Aun es ms triste que deba informarle que .NET carece de soporte a la impresora. Aunque se
incluye un DLL con Windows que habilita este mtodo de impresin directo, no se incluye una
envoltura de .NET administrada para esto con el marco conceptual. Usted y otros programado-
res sobrecargados de trabajo en todos lados deben ocuparse de ello.
Bueno, no todo es malo. Microsoft y otros desarrolladores han publicado cdigo que asigna las
llamadas no administradas a sus equivalentes administrados. Estaremos usando una variacin de
parte de este cdigo en el Proyecto Biblioteca de este captulo para dar soporte a la impresin
de boletas, recibos impresos que le hacen saber a un cliente cules artculos sac y cundo debe
devolverlos.

Resumen
Le recomiendo que estudie con cuidado las clases y controles especficos de la impresora y que
los analice en este captulo. Se incluyen muchas propiedades que le permiten afinar la salida de
su pgina impresa con base en los parmetros especificados por el usuario. Por ejemplo, le pro-
met al principio de este captulo que podra descubrir si una impresora era a color. La propie-
dad PrinterSettings.SupportsColor le da una respuesta simple de s o no a esta pregunta
caracterstica. Si sabe que una impresora no soporta color, puede ajustar su cdigo PrintPage
para presentar el contenido de pgina en un formato ligeramente diferente.

Proyecto
Como se anunci, el proyecto de este captulo se concentra en los recibos de salida y pago de
multa. Pero tambin agregaremos todo el cdigo que permite a los clientes y bibliotecarios dar
entrada y salida a libros y otros artculos de la biblioteca.

Acceso al proyecto
Cargue el proyecto Cap20 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap20 (Final) cdigo.

Soporte a impresin simple


Para que la exposicin sea franca y honesta, debo decirle que yo no cre el cdigo bsico para
impresin simple de esta seccin. Oh!, parte del cdigo es mo, tanto en los aspectos estilsti-
cos como de imaginacin. Pero no revise todos los vnculos entre la aplicacin y el archivo
winspool.drv. Este cdigo viene originalmente del artculo de la base de conocimiento de Micro-
soft nmero 322090, que describe el soporte a la impresin simple en aplicaciones .NET. Usa
una caracterstica de .NET conocida como interop que permite que el cdigo .NET interope-
re con componentes y aplicaciones COM no administradas. (Para facilitar el seguimiento de ese
artculo, en caso de que desee revisarlo, se ha dejado gran parte del cdigo como est el original,
y slo se traducen comentarios y variables y comandos necesarios.)

564 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 564 17/2/10 15:31:50


Muchacho, estoy contento de sacar esto de mi ronco pecho. Quiero decir, si alguien pensara que
yo fui quien cre el cdigo que est a punto de ver, habra furiosas multitudes agolpadas afuera de
mi casa por la noche, y agitacin general en las calles. El cdigo contenido en la clase Auxiliar
ImpresoraSimple, es un poco horrible. Bueno, no tiene sentido posponerlo ms. Cree una
nueva clase llamada AuxiliarImpresoraSimple.vb, y use el siguiente cdigo para su definicin.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 1.

Imports System.Runtime.InteropServices

Public Class AuxiliarImpresoraSimple


' ----- El codigo de esta clase se basa en el articulo de
' la base de conocimiento de Microsoft numero 322090.
' Web: http://support.microsoft.com/?id=322090

' ----- Estructura y declaraciones de API.


<StructLayout(LayoutKind.Sequential, _
CharSet:=CharSet.Unicode)> _
Private Structure DOCINFOW
<MarshalAs(UnmanagedType.LPWStr)> _
Public pDocName As String
<MarshalAs(UnmanagedType.LPWStr)> _
Public pOutputFile As String
<MarshalAs(UnmanagedType.LPWStr)> _
Public pDataType As String
End Structure

<DllImport("winspool.Drv", EntryPoint:="OpenPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function OpenPrinter(ByVal src As String, _
ByRef hPrinter As IntPtr, ByVal pd As Long) As Boolean
End Function

<DllImport("winspool.Drv", EntryPoint:="ClosePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function ClosePrinter( _
ByVal hPrinter As IntPtr) As Boolean
End Function

<DllImport("winspool.Drv", EntryPoint:="StartDocPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _

Proyecto | 565

20_PATRICK-CHAPTER_20.indd 565 17/2/10 15:31:51


Private Shared Function StartDocPrinter( _
ByVal hPrinter As IntPtr, ByVal level As Int32, _
ByRef pDI As DOCINFOW) As Boolean
End Function

<DllImport("winspool.Drv", EntryPoint:="EndDocPrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function EndDocPrinter( _
ByVal hPrinter As IntPtr) As Boolean
End Function

<DllImport("winspool.Drv", EntryPoint:="StartPagePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function StartPagePrinter( _
ByVal hPrinter As IntPtr) As Boolean
End Function

<DllImport("winspool.Drv", EntryPoint:="EndPagePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function EndPagePrinter( _
ByVal hPrinter As IntPtr) As Boolean
End Function

<DllImport("winspool.Drv", EntryPoint:="WritePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function WritePrinter( _
ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, _
ByVal dwCount As Int32, ByRef dwWritten As Int32) _
As Boolean
End Function

Public Shared Function EnviarCadenaAImpresora(


_
ByVal impresoraDestino As String, _
ByVal contenidoCadena As String, _
ByVal tituloDocumento As String) As Boolean
' ----- Enviar como una matriz de bytes a una cola de impresion.
' Regresar True si es correcta.
Dim manejoImpresora As IntPtr
Dim codigoError As Int32
Dim detalleDoc As DOCINFOW = Nothing
Dim bytesEscritos As Int32
Dim impresionCorrecta As Boolean
Dim contenidoBytes As IntPtr

566 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 566 17/2/10 15:31:51


Dim tamanoContenido As Int32
On Error Resume Next

' ----- Configurar la identidad de este documento.


With detalleDoc
.pDocName = tituloDocumento
.pDataType = "RAW"
End With

' ----- Convertir la cadena a texto ANSI.


tamanoContenido = contenidoCadena.Length()
contenidoBytes = Marshal.StringToCoTaskMemAnsi(
_
contenidoCadena)

' ----- Abrir la impresora e imprimir el documento.


impresionCorrecta = False
If OpenPrinter(impresoraDestino, manejoImpresora, 0) Then
If StartDocPrinter(manejoImpresora, 1, detalleDoc) Then
If StartPagePrinter(manejoImpresora) Then
' ----- Enviar el contenido a la impresora.
impresionCorrecta = WritePrinter(manejoImpresora, _
contenidoBytes, tamanoContenido, bytesEscritos)
EndPagePrinter(manejoImpresora)
End If
EndDocPrinter(manejoImpresora)
End If
ClosePrinter(manejoImpresora)
End If

' ----- ObtenerUltimoError puede proporcionar informacion sobre


' el ultimo error. Por ahora, solo ignorelo.
If (impresionCorrecta = False) Then codigoError = _
Marshal.GetLastWin32Error()

' ----- Liberar la memoria no usada.


Marshal.FreeCoTaskMem(contenidoBytes)

' ----- Completo.


Return impresionCorrecta
End Function
End Class

Aunque horrible, el cdigo es relativamente claro. El mtodo EnviarCadenaAImpresora pre-


para una cadena para impresin al forzarla a un formato ANSI estndar. Luego usa las funciones
de la biblioteca winspool.drv para abrir un nuevo trabajo de impresin, y le enva el contenido
preparado. Hay una gran cantidad de trabajo de polica en el cdigo mediante los miembros de
la clase Marshal. Porque winspool.drv es una biblioteca no administrada, todos los datos deben
barajarse indirectamente entre la aplicacin Biblioteca administrada y la biblioteca winspool.drv
no administrada.

Proyecto | 567

20_PATRICK-CHAPTER_20.indd 567 17/2/10 15:31:51


Impresin de boletas
Ahora que tenemos una clase conveniente que enviar cualquier contenido simple a una impre-
sora especfica, agreguemos algo de cdigo para usarla. En primer lugar, necesitamos una clase
auxiliar para una parte de la impresin de la boleta. Cree un nuevo archivo de clase llamado
ArticuloPrestado.vb y reemplace su plantilla de clase vaca con el siguiente cdigo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 2.

Public Class ArticuloPrestado


' ----- Usado para alamacenar los detalles de cada articulo
' prestado en el formulario principal, aunque tambien
' da soporte a la impresion de recibos.
Public tituloArticulo As String
Public CopiaNmero As Integer
Public CodigoBarras As String
Public FechaVencimiento As Date
End Class

Usaremos esta clase para comunicar los detalles que se imprimirn en el recibo cuando se presten
artculos. Hablando de la impresin de la boleta, agreguemos la clase que hace la impresin real.
Cree un nuevo archivo de mdulo (no una clase) llamado ImpresionBoleta.vb. Reemplace su
definicin de mdulo vaca con el fragmento de cdigo siguiente.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 3.

El cdigo incluye tres mtodos para imprimir: ImprimirBoletaPrestamo, PrintBalance-


Ticket y PrintPaymentTicket. Estos mtodos se llaman desde otras partes de la aplicacin
cuando es momento de presentar un ticket de impresin al usuario. El mdulo TicketPrin-
ting tambin incluye algunos mtodos para apoyar los primarios. Debido a su similitud estruc-
tural, slo veremos ImprimirBoletaPrestamo.
Public Sub ImprimirBoletaPrestamo(ByVal idCliente As Integer, _
ByVal articulosPrestados As ListBox)
' ----- Imprimir una boleta de lo que se presto al cliente. El control
' ListBox proporcionado contiene objetos del tipo ArticuloPrestado.
Dim anchoBoleta As Integer
Dim textoBoleta As System.Text.StringBuilder
Dim contador As Integer
Dim multasCliente As Decimal
Dim detalleArticulo As ArticuloPrestado

On Error GoTo ErrorHandler


' ----- Ignorar si no hay nada que imprimir.

568 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 568 17/2/10 15:31:51


If (idCliente = -1) Or (articulosPrestados.Items.Count = 0) _
Then Return

' ----- Obtener el ancho de la boleta.


anchoBoleta = My.Settings.AnchoRecibo
If (anchoBoleta <= 0) Then anchoBoleta = 40

' ----- Generar el encabezado.


textoBoleta = GetTicketHeader(idCliente, anchoBoleta)
If (textoBoleta Is Nothing) Then Return

' ----- Procesar cada elemento prestado.


For contador = 0 To articulosPrestados.Items.Count - 1
' ----- Extraer el detalle de la lista.
detalleArticulo = CType(articulosPrestados.Items(contador), _
ArticuloPrestado)

' ----- Agregar el nombre del articulo.


textoBoleta.AppendLine(Left(detalleArticulo.tituloArticulo, _
anchoBoleta))

' ----- Agregar el numero de codigo de barras y la fecha de vencimiento.


textoBoleta.AppendLine(TextoIzquierdaYDerecha( _
detalleArticulo.CodigoBarras, "Vencimiento: " & _
Format(detalleArticulo.FechaVencimiento, "d, MMM, yyyy"), _
anchoBoleta))
textoBoleta.AppendLine()
Next contador

' ----- Si se adeudan multas, incluirlas aqui.


multasCliente = CalcularMultasCliente(idCliente)
If (multasCliente > 0@) Then
textoBoleta.AppendLine("Multas vencidas: " & _
Format(multasCliente, "Currency"))
textoBoleta.AppendLine()
End If

' ----- Agregar el texto de despliegue inferior.


textoBoleta.Append(GetTicketFooter(anchoBoleta))

' ----- Enviar la boleta a la impresora.


AuxiliarImpresoraSimple.EnviarCadenaAImpresora( _
My.Settings.ImpresoraRecibo, _
textoBoleta.ToString(), "Recibo de prestamo")
Return

ErrorHandler:
ErrorGeneral("ImpresionBoleta.ImprimirBoletaPrestamo", _
Err.GetException())
Return
End Sub

Proyecto | 569

20_PATRICK-CHAPTER_20.indd 569 17/2/10 15:31:51


El cdigo genera una cadena (en realidad un StringBuilder) de contenido de despliegue, la
adicin de detalles acerca de cada artculo prestado a un bfer de cadena. Luego llama a En-
viarCadenaAImpresora para enviar el contenido a la impresora de recibo configurada (My.
Settings.ImpresoraRecibo).
Ms adelante, agregaremos el cdigo que llama a ImprimirBoletaPrestamo. Por ahora, agre-
guemos cdigo que llame a los otros dos mtodos. Cuando el formulario Registro de pago
se cierre, queremos imprimir automticamente un recibo de todos los pagos hechos mientras se
abre el formulario. Agregue el cdigo siguiente al manejador de eventos RegistrosCliente.
AccCerrar_Click, justo antes del cdigo que ya se encuentra en ese manejador.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 4.

' ----- Imprimir una boleta, si es necesario.


If (PagosSesion.Count > 0) Then _
PrintPaymentTicket(IDClienteActivo, PagosSesion)
PagosSesion.Clear()
PagosSesion = Nothing

Luego, agregue algn cdigo al manejador de eventos AccBoletaSaldo_Click, tambin en la


clase RegistrosCliente, que imprima una boleta de saldo cuando el usuario la solicite.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 5.

' ----- Imprimir una boleta de todos los saldos.


ImprimirBoletaSaldo(IDClienteActivo, Multas)

Impresin de cdigos de barras


El Proyecto Biblioteca imprime tres tipos de cdigos de barras: 1) cdigos de barras de artcu-
lo que puede pegar en los libros, CD y cualquier otra cosa que preste o administre el sistema;
2) cdigos de barras de cliente que pueden incluirse en tarjetas de identificacin de cliente, y
3) cdigos de barras diversos que una biblioteca puede usar para cualquier otro fin. Los tres
tipos de cdigo de barras se imprimen mediante el nuevo formulario ImprimirCodigo
Barras. En la figura 20-9 se muestran los controles incluidos en este formulario.
Ya he agregado este formulario al proyecto, incluido su cdigo. He aqu el cdigo del botn Vista
previa, que debe serle familiar despus de que le mostr los conceptos en este captulo.
Private Sub AccVistaPrevia_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles AccVistaPrevia.Click
' ----- El usuario quiere una vista previa de las etiquetas
On Error Resume Next

' ----- Asegurar que el usuario proporcione datos validos.


If (VerifyFields() = False) Then Return

570 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 570 17/2/10 15:31:51


Figura 20-9. Un formulario, tres tipos de cdigo de barras, muchas etiquetas felices.

' ----- Cargar todos los detalles especificos de la pagina que se


' usaran en la impresion.
If (CargarDetallesPagina() = False) Then Return

' ----- Crear el cuadro de dialogo de vista previa.


Me.Cursor = Windows.Forms.Cursors.WaitCursor
PaginashastaAhora = 0
ModoVistaPrevia = True
DocCodigobarras = New System.Drawing.Printing.PrintDocument

' ----- Desplegar la vista previa.


VistaPreviaCodigobarras.Document = DocCodigobarras
VistaPreviaCodigobarras.ShowDialog()
DocCodigobarras = Nothing
Me.Cursor = Windows.Forms.Cursors.Default
End Sub

El cdigo del botn Imprimir es casi exactamente el mismo, pero usa una instancia de PrintDia-
log en lugar de una de PrintPreviewDialog. Tambin lleva registro del nmero de cdigo de
barras impreso, de modo que puede ayudar a evitar la sobrecarga la prxima vez que se imprimen.
El manejador de eventos DocumentoCodigoBarras_PrintPage hace la impresin real del
cdigo de barras. Su cdigo combina los manejadores de eventos EtiquetaCodigoBarras.
PreviewArea_Paint y PaginaCodigoBarras.PreviewArea_Paint en una gloriosa m-
quina de impresin.
Para habilitar el uso del formulario de impresin de cdigo de barras, agregue las siguientes
instrucciones al manejador de eventos AccCodigoBarrasInformes_Click en la clase Formu-
larioPrincipal.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 6.

Proyecto | 571

20_PATRICK-CHAPTER_20.indd 571 17/2/10 15:31:52


' ----- Asegurar que el usuario tiene permitido hacer esto.
If (PerfilSeguridad(SeguridadBiblioteca. _
AdministrarPlantillasCodigoBarras) = False) Then
MsgBox(MensajeNoAutorizado, MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If

' ----- Mostrar el formulario de impresion de codigo de barras.


Call (New ImprimirCodigoBarras).ShowDialog()

Renovacin de los archivos prestados al cliente


Para el cliente de una biblioteca, lo nico ms importante que pedir prestados libros es tener la
capacidad de leerlos. El Proyecto Biblioteca no le ayudar con eso, pero permitir las acciones
de entrega y prstamo con el cdigo que agregamos en este captulo. Empecemos por agregar el
cdigo de renovacin para los artculos prestados. El botn Renovar en el formulario Registros
del cliente, incia el proceso. Agregue el cdigo al manejador de eventos RegistrosCliente.
AccRenovarArtsPrestados_Click que hace la renovacin.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 7.

El cdigo hace algunos clculos para determinar la nueva fecha de vencimiento (evitando los das
festivos), y luego actualiza la base de datos en una transaccin.
EmpezarTransac()

' ----- Actualizar el registro.


textoSql = "UPDATE CopiaCliente SET FechaVencimiento = " & _
FechaBD(FechaVencimiento) & ", Renovacion = " & RenovacionesHastaAhora & _
" WHERE ID = " & detalleArticulo.IDDetalle
EjecutarSQL(textoSql)

' ----- Actualizar el registro del cliente.


textoSql = "UPDATE Cliente SET UltimaActividad = GETDATE( ) " & _
"WHERE ID = " & IDClienteActivo
EjecutarSQL(textoSql)

ConfirmarTransac()

Soporte para devolucin y prstamo


Si una biblioteca agrega etiquetas de cdigo de barras a todos sus elementos, la devolucin y el
prstamo se harn mediante un lector de cdigo de barras. Pero una biblioteca muy pequea
que emplea el programa tal vez no tenga el tiempo disponible del personal para incluir cdigo de
barras en todo lo que tiene en los estantes. Por tanto, el Proyecto Biblioteca necesita dar soporte a
la devolucin y el prstamo por ttulo. Durante el prstamo o la devolucin, el usuario ingresar
un cdigo de barras o un ttulo (parcial o completo). Se supone que las entradas no numricas

572 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 572 17/2/10 15:31:52


Figura 20-10. Un formulario de coincidencia de ttulos para devolucin y prstamo.

son ttulos y se inicia una bsqueda de ttulo. El nuevo formulario BuscarEntregaPrestamo.vb,


que se muestra en la figura 20-10, despliega todas las coincidencias para el ttulo ingresado.
Aunque los campos del formulario al principio indican que slo son para prstamo, el formula-
rio tiene dos tareas, alterando sus funciones para fines de devolucin. Adems, los listados para
devolucin estn limitados slo a los artculos ya prestados.
Ya agregu este formulario al proyecto, junto con su cdigo fuente. Casi todo el cdigo consulta
elementos de biblioteca coincidentes en la base de datos, y despliega los resultados utilizando el
cuadro de lista de dibujo de propietario. Es un subconjunto del cdigo encontrado en el formu-
lario BusquedaArticulo.vb. La nica diferencia real entre la devolucin y el prstamo ocurre en el
mtodo RealizarBusqueda. Este bloque de cdigo empieza por construir el comando SQL de
seleccin de elementos, y luego termina con estas instrucciones:
If (asCheckIn) Then textoSql &= " AND IC.ID IN" _
Else textoSql &= " AND IC.ID NOT IN"
textoSql &= " (SELECT CopiaArticulo FROM CopiaCliente " & _
WHERE Regresado = 0)"

As, la diferencia est en IN en comparacin con NOT IN.


La funcin RevisarArticulosPorTitulo es la interfaz principal de la forma lgica.
Public Function RevisarArticulosPorTitulo(ByVal Devolver As Boolean, _
ByVal buscarTexto As String) As Integer

Usted pasa esta funcin al ttulo proporcionado por el usuario (buscarTexto) y una marca
indicando devolucin o prstamo, y devuelve el campo CopiaArticulo.ID de la base de datos
para el artculo seleccionado de la biblioteca.
Todos los cambios restantes en este captulo ocurren en la clase FormularioPrincipal, as que
pasemos all ahora. El mtodo ActualizarDespliegueParaUsuario ajusta las caractersticas
del formulario principal cuando un administrador inicia o termina sesin. Una caracterstica
que no tomamos en cuenta antes es la capacidad definida del administrador para que los clientes
pidan prestados los artculos sin ayuda del bibliotecario. Para dar soporte a esa caracterstica, ne-
cesitamos cambiar parte del cdigo en el mtodo ActualizarDespliegueParaUsuario. Unas
diez lneas de cdigo abajo, en la seccin condicional que configura el despliegue para cliente,
encontrar estas cuatro lneas:

Proyecto | 573

20_PATRICK-CHAPTER_20.indd 573 17/2/10 15:31:52


EtqTareas.Visible = False
LineaTareas.Visible = False
ImgSalida.Visible = False
AccSalida.Visible = False

Reemplace estas cuatro lneas con el cdigo siguiente.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 8.

' ----- Ver si los clientes pueden prestarse los articulos.


Dim usuarioPuedePrestarse As Boolean = _
CBool(Val(ObtenerValorSistema("SalidaCliente")))

EtqTareas.Visible = usuarioPuedePrestarse
LineaTareas.Visible = usuarioPuedePrestarse
ImgSalida.Visible = usuarioPuedePrestarse
AccSalida.Visible = usuarioPuedePrestarse

Tambin necesitamos agregar cdigo relacionado con seguridad similar al mtodo TareaSali-
da. He aqu las primeras lneas del cdigo de ese mtodo:
' ----- Actualizar el despliegue.
AllPanelsInvisible()
If (PerfilSeguridad(SeguridadBiblioteca.ArticulosPrestados)) Then _
PanelSalida.Visible = True

Reemplace estas lneas con el siguiente cdigo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 9.

' ----- ModoSalida.


Dim usuarioPuedePrestarse As Boolean

' ----- Ver si los patrones pueden sacar elementos por si solos.
usuarioPuedePrestarse = CBool(Val(ObtenerValorSistema ("SalidaCliente")))

' ----- Actualizar el despliegue.


AllPanelsInvisible()
If (usuarioPuedePrestarse Or _
PerfilSeguridad(SeguridadBiblioteca.ArticulosPrestados)) Then _
PanelSalida.Visible = True

El prstamo real de artculos ocurre en el propio formulario principal. En primer lugar, se iden-
tifica un cliente, y se procesan los artculos que se prestarn. Agreguemos una variable en el nivel
de la clase a FormularioPrincipal para llevar registro del cliente. Y siempre y cuando estemos
agregando definiciones, tambin agregaremos dos constantes que hagan referencia a las imge-
nes almacenadas en el control FormularioPrincipal.ImagenesEstatus. Estas constantes se

574 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 574 17/2/10 15:31:52


usarn en algn cdigo relacionado con la devolucin o el prstamo agregado un poco despus.
Agregue el siguiente cdigo al principio de la definicin de clase.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 10.

Private ClientePrestamoActivo As Integer = -1

Private Const ImagenEstatusMalo As Integer = 0


Private Const ImagenEstatusBueno As Integer = 1

Cuando el usuario identifica al cliente al que se har el prstamo, y luego inicia el prstamo
de artculos, el ltimo paso es hacer clic en el botn Finalizar, indicando el final del proceso de
prstamo para ese cliente. (Vaya a la figura 20-11, si quiere ver ahora el botn Finalizar.) Sin
embargo, no hay nada para evitar que el usuario salte a otra parte del programa, o que salga del
programa por completo, sin hacer primero clic en el botn Finalizar. Debemos anticipar este
comportamiento descorts tan tpico de los usuarios de software. Para asegurar que el proceso de
salida se complete de manera apropiada, agregaremos algn cdigo a tres lugares de Formula-
rioPrincipal que debe capturar cualquier accin descorts del usuario. Agregue el siguiente
cdigo al principio de estos tres mtodos: 1) El manejador de eventos FormularioPrinci-
pal_FormClosing; 2) el mtodo MostrarFormularioInicio, y 3) el mtodo AllPanels
Invisible.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 11, tres veces.

' ----- Finalizar el proceso de prestamo, si es necesario.


If (ClientePrestamoActivo <> -1) Then _
AccFinalizarPrestamo.PerformClick( )

Prstamo de artculos
Todo el cdigo de prstamo (excepto el del formulario BuscarEntregaPrestamo.vb) aparece en la
clase del formulario principal. La salida o prstamo es uno de los ocho paneles principales de
despliegue a los que se accede a travs de este formulario (vase la figura 20-11).
He aqu el proceso para pedir prestados libros del panel de prstamo:
1. El usuario hace clic en el botn Cliente e identifica al cliente que quiere pedir prestados los
artculos.
2. El usuario ingresa el ttulo o el cdigo de barras de cada elemento que se llevar y hace clic
en el botn Salida de cada uno.
3. El usuario hace clic en el botn Finalizar cuando est completado el proceso de salida.

Proyecto | 575

20_PATRICK-CHAPTER_20.indd 575 17/2/10 15:31:52


Figura 20-11. El panel de salida en el formulario principal.

Agreguemos el cdigo para cada uno de estos tres botones. Primero, agregue el cdigo al mane-
jador de eventos AccClienteSalida_Click.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 12.

Este cdigo pide la seleccin del usuario y despliega los campos restantes, si tiene xito. He aqu
la parte del cdigo que hace la peticin:
' ----- Obtener el ID del cliente.
idCliente = (New AccesoCliente).SeleccionarCliente()
If (idCliente = -1) Then Return

' ----- Obtener el nombre del cliente.


textoSql = "SELECT Nombre + ' ' + Apellido FROM Cliente " & _
"WHERE ID = " & idCliente
nombreCliente = CStr(EjecutarSQLRegresar(textoSql))

' ----- Buscar si el cliente esta activo.


textoSql = "SELECT Activo FROM Cliente WHERE ID = " & idCliente
If (CBool(EjecutarSQLRegresar(textoSql)) = False) Then
MsgBox("Cliente '" & nombreCliente & _
"' esta marcado como inactivo.", _ MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If

576 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 576 17/2/10 15:31:53


Agregue el cdigo al manejador de eventos AccHacerPrestamo_Click, que procesa cada archi-
vo mediante el botn Salida.
Insercin de fragmento de cdigo
Inserte el fragmento de cdigo Cap20, Elemento 13.

Como mencion antes, este cdigo diferencia entre entrada numrica (cdigos de barras) y otras
entradas (ttulos).
If (IsNumeric(Trim(CodigoBarrasSalida.Text))) Then
' ----- Tal vez hay un codigo de barras proporcionado. Obtener el ID
relacionado.
textoSql = "SELECT ID FROM CopiarArticulo WHERE CodigoBarras = " & _
TextoBD(Trim(CodigoBarrasSalida.Text))
idCopia = ObtenerEnteroBD(EjecutarSQLRegresar(textoSql))
If (idCopia = 0) Then
' ----- Codigo de barras no valido.
MsgBox("No se encuentra el codigo de barras.", MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
CodigoBarrasSalida.Focus()
CodigoBarrasSalida.SelectAll()
Return
End If
Else
' ----- Buscar por titulo.
idCopia = (New BuscarEntregaPrestamo).RevisarArticulosPorTitulo(False, _
Trim(CodigoBarrasSalida.Text))
If (idCopia = -1) Then Return
End If

Con el tiempo, despus de verificar que el archivo est disponible para uso del cliente, el cdigo
da la salida al artculo al actualizar los registros relevantes en la base de datos.
EmpezarTransac()

' ----- Actualizar regisro de copia del cliente.


textoSql = "INSERT INTO CopiaCliente (Cliente, CopiaArticulo, " & _
"Prestado, Renovado, FechaVencimiento, Regresado, Faltante, " & _
"Multa, Pagado) VALUES (" & ClientePrestamoActivo & ", " & _
idCopia & ", " & FechaBD(Today) & ", 0, " & _
FechaBD(hastaFecha) & ", 0, 0, 0, 0)"
EjecutarSQL(textoSql)

' ----- Actualizar el registro del cliente.


textoSql = "UPDATE Patron SET LastActivity = GETDATE()" & _
"WHERE ID = " & ClientePrestamoActivo
EjecutarSQL(textoSql)

ConfirmarTransac()

El ltimo de los tres botones es Finalizar. Agregue el cdigo al manejador de eventos AccFi-
nalizarSalida_Click.

Proyecto | 577

20_PATRICK-CHAPTER_20.indd 577 17/2/10 15:31:53


Insercin de fragmento de cdigo
Inserte el fragmento de cdigo Cap20, Elemento 14.

Este cdigo simplemente restablece los campos de despliegue en preparacin del siguiente prs-
tamo del cliente.
El cuadro de lista del panel de salida necesita desplegar dos columnas de datos: 1) la fecha de
vencimiento, y 2) detalles del archivo, como ttulo y cdigo de barras. Estos valores se agregaron
a la lista empleando la clase ArticuloPrestado que agregamos un poco antes en el captulo.
Agregue cdigo al manejador de eventos ArticulosPrestados_DrawItem.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 15.

Devolucin de artculos
Devolver los artculos es mucho ms simple porque no necesitamos identificar primero al cliente.
El cdigo de barras o el ttulo del artculo devuelto bastan para completar todo el procesamiento.
En la figura 20-12 se muestra el panel Entrada que muestra el panel para devolucin de libros.

Figura 20-12. El panel Entrada en el formulario principal.

578 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 578 17/2/10 15:31:54


Este panel incluye una fecha que indica cundo se devolver el artculo. Por lo general, es hoy,
pero si los artculos de la biblioteca se devuelven en un depsito nocturno despus de las horas
laborales, tal vez el bibliotecario quiera ajustar la fecha a Ayer, slo en caso de que alguno de
los artculos se devuelva antes de la medianoche. Agreguemos algn cdigo para que el panel
indique Hoy o Ayer o algn otro da cuando la fecha cambia. Agregue el siguiente cdigo al
manejador de eventos FechaEntrada_ValueChanged.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 16.

' ----- Ajustar el dia en el despliegue.


Select Case DateDiff(DateInterval.Day, _
FechaEntrada.Value, Today)
Case 0 ' ----- Hoy
DiaEntrada.Text = "Hoy"
DiaEntrada.BackColor = SystemColors.Control
DiaEntrada.ForeColor = SystemColors.ControlText
Case 1 ' ----- Ayer
DiaEntrada.Text = "Ayer"
DiaEntrada.BackColor = Color.Red
DiaEntrada.ForeColor = Color.White
Case Else ' ----- X dias atras
DiaEntrada.Text = DateDiff(DateInterval.Day, _
FechaEntrada.Value, Today) & " dias atras."
DiaEntrada.BackColor = Color.Red
DiaEntrada.ForeColor = Color.White
End Select

La entrada real ocurre cuando el usuario ingresa un cdigo de barras o ttulo en el campo de texto y
hace clic en el botn Entrada. Agregue el cdigo al manejador de eventos AccEntrada_Click.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap20, Elemento 17.

Despus de realizar algunas bsquedas y revisiones de confirmacin, el cdigo da entrada al


artculo mediante actualizaciones de la base de datos.
' ----- Hacer la entrada en una transaccion
EmpezarTransac()

' ----- Actualizar el registro de la copia del cliente.


textoSql = "UPDATE CopiaCliente SET Entrada = " & _
FechaBD(FechaEntrada.Value) & _
", Regresado = 1 WHERE ID = " & idCopiaCliente
EjecutarSQL(textoSql)

Proyecto | 579

20_PATRICK-CHAPTER_20.indd 579 17/2/10 15:31:54


' ----- Actualizar el registro del cliente.
textoSql = "UPDATE Cliente SET UltimaActividad = " & _
"GETDATE() WHERE ID = " & idCliente
EjecutarSQL(textoSql)

ConfirmarTransac()

Esto es todo sobre los procedimientos de devolucin y prstamo, y la impresin de la boleta.


Es muy buen cdigo, pero no perfecto. Lo que an no hemos agregado es cdigo para procesar
apropiadamente las multas sobre artculos antes de devolverlos, o mientras se ajustan de otras
maneras. Pospondremos esa lgica hasta el captulo 22. Mientras tanto, echemos un vistazo a
otra caracterstica de impresin de aplicacin: informes.

580 | Captulo 20: Impresin

20_PATRICK-CHAPTER_20.indd 580 17/2/10 15:31:54


Captulo 21
Creacin de informes

Para el desarrollador de aplicaciones de negocios, los informes son inevitables. Tal vez quiera
dedicar su tiempo a desarrollar agradables interfaces de usuario o a imaginar los algoritmos
centrales usados por lo general en los principios aceptados de contabilidad. En cambio, invierte
muchas aburridas horas de cada semana a crear informe tras informe. Y estos informes toman un
nmero importante de vctimas en la comunidad de la programacin. Slo en Estados Unidos,
los Centros para el Control y la Prevencin de Enfermedades estiman en casi 850 las muertes
al ao relacionadas con los informes, y ni siquiera toman en cuenta a quienes los leen. Una vez
tuve un cliente que imprima 20 copias de un informe de 600 pginas al mes para sus admi-
nistradores de nivel superior. Claramente estupefacto por la cantidad de pulpa de rboles usada
para generar este informe, la persona fue incapaz de salir con un nombre ms interesante que
informe mensual.
De modo que si usted es un programador de negocios, los informes son su futuro. Pero mientras
sus predecesores tenan que lidiar con lenguajes como RPG III, usted acostumbra usar .NET.
Hey!, despus de todo no es necesario que los informes sean tan malos. Y aun sin depender
de herramientas de creacin de informes de terceros, Visual Studio y .NET incluyen varias
caractersticas y herramientas concentradas en los informes que puede usar en cuanto instala el
programa.
En este captulo se analizan algunos de los recursos de creacin de informes, y se profundiza un
poco en los controles para informes usados en el Proyecto Biblioteca.

Opciones de informe en .NET


La creacin de informes incluye el despliegue y la impresin de datos bsicos o de resumen que
el usuario requiere para fines de negocios especficos. Visual Basic 2008 Professional Edition
incluye seis mtodos principales para lograr este objetivo. Otras ediciones agregan o reducen este
conjunto de opciones, y siempre puede mejorar esta lista empleando herramientas de terceros.

581

21_PATRICK-CHAPTER_21.indd 581 17/2/10 15:32:20


Impresin con PrintDocument
Como aprendimos en el captulo anterior, .NET Framework incluye un sistema de impre-
sin de objetos completo que usa comandos de GDI+ para dibujar imgenes en cada pgina
impresa. Como puede poner cualquier cosa que quiera en cada pgina, podra desarrollar
sus propios informes personalizados empleando este mtodo. La responsabilidad de la colo-
cacin de cada etiqueta y campo calculado en la pgina, y la determinacin de cundo pasar
a una nueva pgina, descansar por completo en sus espaldas. An as, los comandos GDI+
son sencillos, y el desarrollo de algunos informes bsicos empleando este mtodo no resulta
abrumador.
Si quiere tomar esta ruta para sus informes, consulte el captulo 20 y los conceptos bsicos de
impresin presentados all.

HTML y pgina Web


Adems de ser una herramienta eficaz para gastar el tiempo, Internet (y su lenguaje de descrip-
cin de pginas basado en HTML) es un medio estupendo para la comunicacin de informes de
datos. Las etiquetas de formato de tablas en HTML (como <td>) le permiten organizar salida
tabular sin mucho esfuerzo. Seguro, es una tarea exigente tratar con todas esas cadenas de
texto del tamao de un nio para generar la pgina, pero tambin hay manera de sortearlas.
En el captulo 13 analic XSLT (transformacin XSL, XSL Transformations), una manera de to-
mar datos XML y darle cualquier formato que desee (incluidos estupendos trabajos de arte crea-
dos por Miguel ngel, o HTML bellamente ensamblado). Aunque obtiene HTML, tambin
cuenta con una opcin de desplegar mtodos. El mtodo ms directo incluye el almacenamiento
de HTML generado en un archivo de disco, y el lanzamiento del explorador predeterminado del
usuario para desplegarlo usando un comando como:
Process.Start("c:\temp\MiInforme.htm")

Si quiere que el informe tenga un aspecto ms integrado en su aplicacin, puede desplegar el


contenido HTML en un control del explorador. Hicimos esto en el cdigo del proyecto para
el captulo 17, cuando desplegamos los detalles de un elemento de biblioteca como HTML.

Documentos XPS
La base de presentacin de Windows (WPF, Windows Presentation Foundation) se usa prin-
cipalmente para que su interfaz de usuario baile con color y accin. Pero una parte de esa tec-
nologa existe para generar documentos estticos tipo XML conocidos como XPS (XML Paper
Specification, especificacin XML para el papel). De la misma manera en que puede generar
informes con HTML, puede hacerlo con el estndar XPS.
En el captulo 18 se incluye un breve anlisis de WPF y XPS. Si la generacin de informes en
XPS le parece interesante, revise la documentacin incluida con Visual Studio.

582 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 582 17/2/10 15:32:20


Servicios y controles de informes
Visual Studio incluye un conjunto de clases en el espacio de nombres Microsoft.Reporting
que estn especficamente diseados para crear informes de datos. La clase clave en este espacio de
nombres es ReportViewer (identificada como MicrosoftReportViewer en su otro control).
En realidad, es dos controles: uno para Windows Forms y otro para Web Forms. Estos controles
estn basados, en parte, en la tecnologa encontrada en Microsoft SQL Server Reporting Services,
aunque puede usar los controles sin SQL Server.
El Proyecto Biblioteca usar el control WinForms.ReportViewer para sus informes integrados.
Dedicaremos la mayor parte de este captulo a analizar el control y su uso en aplicaciones de
Windows Forms. No analizar la versin de Web Forms del control aqu, aunque su uso es muy
similar al de la versin de Windows Forms.
Ver lo simple que es agregar el control MicrosoftReportViewer a un proyecto existente. Pero
Visual Studio tambin incluye una nueva plantilla de proyecto que se concentra en el control
MicrosoftReportViewer. La creacin de un nuevo proyecto Aplicacin de informes usa un
asistente para proyectos que le ayuda a configurar un informe personalizado. El resultado final
puede ser su aplicacin de informe completo o puede usarla como base para mayor personali-
zacin.

Crystal Reports
Si tiene por lo menos la Professional Edition de Visual Studio 2008, recibi una copia de gracia
de Crystal Reports. La versin incluida es un subconjunto funcional de la versin oficial de
Crystal Reports 2008. Si es nuevo en Visual Basic, tal vez se haya saltado las versiones anteriores
de Crystal Reports que se han incluido con el lenguaje desde sus primeras versiones. Debido a
esta relacin de largo tiempo con Visual Basic, Crystal Reports se ha vuelto uno de los paquetes
de creacin de informes de uso ms amplio en el mercado.
Crystal Reports es un producto de terceros, que es propiedad de una empresa llamada Business
Objects. El producto ha cambiado de propietario varias veces desde que se asoci con Visual
Basic, pero al parecer Business Objects se est ocupando de ello por el momento. No analizar
ms Crystal Reports en este libro.

Integracin con Microsoft Office


Visual Basic ha sido el lenguaje principal de macros para la suite de aplicaciones Microsoft Offi-
ce desde la muerte final de WordBasic. Pero estoy hablando de los tiempos anteriores a .NET
Visual Basic, que era no administrado. Por fortuna, tambin puede usar el mundo administrado
de Visual Basic 2008 para interactuar con aplicaciones de Microsoft Office. La manera en que
interacta con Office depende de si el documento de Office o la aplicacin de Visual Basic es el
eje principal para el usuario.

Opciones de informe en .NET | 583

21_PATRICK-CHAPTER_21.indd 583 17/2/10 15:32:20


Si su objetivo es mejorar una aplicacin de lnea de negocios empleando aplicaciones de Office
como portal (por ejemplo, mostrando las ltimas cifras de ventas dentro de Microsoft Outlook)
considere la generacin de una aplicacin de negocios de Office (OBA, Office Business Appli-
cation). Las OBA representan una nueva manera de disear programas integrados empleando
Visual Studio, Microsoft Office, Microsoft SharePoint Services y otros sistemas relacionados.
Desde el mundo de Visual Studio, su trabajo de desarrollo sucede mediante las herramientas
para Office de Visual Studio (Visual Studio Tool for Office, VSTO), incluidas con las ediciones
Professional y Team System de Visual Studio.
Si su objetivo es crear sus propios complementos de barra de tareas dentro de aplicaciones de
Office, use las nuevas plantillas de proyecto integradas de Office incluidas con Visual Studio. Se
trata de extensiones fciles de desarrollar que le permiten personalizar la experiencia de usuario
al personalizar el conjunto de caractersticas de Office. Los complementos tambin se conside-
ran parte de VSTO y slo estn disponibles con las ediciones Visual Studio 2008 Professional y
Team System.
Si el usuario slo acceder indirectamente a las caractersticas de Office mediante su aplicacin
de Visual Basic (por ejemplo, si quiere que su programa inicie una combinacin de correspon-
dencia de Microsoft Word), use los ensamblados primarios de interoperacin (Primary Interop
Assemblies, PIA) de Microsoft Office proporcionados por Microsoft. Estas bibliotecas propor-
cionan acceso a las caractersticas especficas de la aplicacin de Office mediante el espacio de
nombres Microsoft.Office. Como VSTO, estas bibliotecas vinculan su cdigo .NET con
Microsoft Office, pero con el enfoque en su cdigo en lugar del documento de Office.

Uso de controles de informe en .NET


Dedicaremos el resto de este captulo a analizar las herramientas de informes estndar proporcio-
nadas en Visual Studio. Como ya se mencion, hay dos clases ReportViewer en Visual Studio:
una para el desarrollo de escritorio y otra para el desarrollo Web. Hablar slo de la variante
de escritorio en este captulo. El diseador acostumbrado al desarrollo de estos informes no
diferenciar entre el destino del informe (escritorio o explorador). Hay algunas diferencias en la
implementacin, pero tendr que dejar la Web para un futuro libro de programacin de altas
ventas, o para que usted haga su propia investigacin.
El control MicrosoftReportViewer se integra directamente con Microsoft SQL Server Re-
porting Services, desplegando pginas completas generadas por ese sistema basado en servidor.
Como estamos suponiendo que usted est empleando SQL Server Express Edition para su de-
sarrollo (que no incluye Reporting Services), me concentrar en cambio en la presentacin del
modo local del control. Esto le permite desplegar cualquier dato desde cualquier fuente que
elija en cada pgina de despliegue de informes, incluido SQL Server.
En la lnea de Quienes sepan, hganlo; quienes no puedan, enseen, recorreremos los pa-
sos necesarios para disear visualmente un informe simple empleando la clase ReportViewer.
Crearemos un informe que presente listas de los registros en la tabla Actividad del Proyecto
Biblioteca, una tabla que tendr datos, en caso de que an no haya usado el programa Biblioteca.
Esto funciona mejor si lo sigue frente al equipo de cmputo, porque leer acerca del diseo de

584 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 584 17/2/10 15:32:20


informes es como leer sobre ciruga cerebral: es ms interesante si la practica. Empiece por crear
una nueva aplicacin de Windows Forms.

Y ahora, las malas noticias


El control MicrosoftReportViewer no es el control ms fcil de usar del mundo, pero es an
ms difcil de usar cuando ni siquiera viene con su copia de Visual Studio. Si est usando Visual
Basic 2008 Express Edition, no encontrar el control MicrosoftReportViewer en su cuadro
de herramientas. Microsoft lo pone a su disposicin como una descarga separada (acceda al rea
de descargas de Microsoft, http://www.microsoft.com/downloads, y revise Microsoft Report Viewer
Redistributable 2005 SP1), pero eso slo lo dejar a la mitad del camino. Estar analizando un
diseador de informes visual que tampoco es parte de la Express Edition. Aunque an pueda crear
manualmente el contenido XML que suele generarse en el diseador visual, no es nada divertido.
Si est usando la Express Edition, an puede utilizar el cdigo de proyecto de este libro. No podr
disear visualmente nuevos informes. Pero s podr ejecutar los informes prescritos que ya inclu,
porque slo tienen contenido XML.
Si, despus de todo eso, an es un usuario de la Express Edition, por favor descargue e instale el
archivo Microsoft Report Viewer Redistributable 2005 SP1 del sitio Web de Microsoft.

Adicin de un origen de datos


Agregue un origen de datos al proyecto que hace referencia a la tabla Actividad de la base de da-
tos. Ya hicimos esto en el captulo 10, en la seccin Creacin de un origen de datos. Seleccione el
comando de men Datos Agregar nuevo origen de datos, y use el Asistente para la configuracin
de orgenes de datos para localizar su base de datos Biblioteca. Cuando alcance la lista de objetos de
base de datos, revise el cuadro junto a la tabla Actividad y haga clic en el botn Finalizar. Ahora
debe tener un origen de datos llamado BibliotecaDataSet. En la figura 21-1 se muestran los
elementos agregados al Explorador de soluciones y el panel Orgenes de datos para esta accin.

Figura 21-1. El BibliotecaDataSet como un origen de datos, y como un archivo XML .xsd.

Uso de controles de informe en .NET | 585

21_PATRICK-CHAPTER_21.indd 585 17/2/10 15:32:21


Adicin de una superficie de diseo de informes
Use el comando de men Proyecto Agregar nuevo elemento, para agregar un nuevo elemento
Informe. En la figura 21-2 se muestra el elemento de informe en el cuadro de dilogo Agregar
nuevo elemento. Asegrese de elegir Informe y no Crystal Report de la lista.

Figura 21-2. Adicin de un nuevo informe al proyecto.

Haga clic en el botn Agregar para insertar el informe en el proyecto. Aparece un nuevo archivo
Report1.rdlc en su proyecto, y su diseador se abre automticamente. RDLC es la abreviatura de
lenguaje de definicin de informes de cliente (Report Definition Lenguaje Client) y los archivos
de este tipo contienen XML que describe el diseo de un informe diseado en el equipo local. En
la figura 21-3 se muestra el diseador para el archivo Report1.rdlc agregado, adems de los contro-
les en la barra de herramientas que puede agregar a la superficie del informe. Har referencia a los
informes creados mediante este diseador como informes RDLC en el resto de este captulo.

Figura 21-3. El diseador de informes y la barra de herramientas relacionada.

586 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 586 17/2/10 15:32:22


Diseo de la superficie del informe
Si ha escrito informes en Microsoft Access o en alguna otra herramienta comn de creacin
de informes, tal vez ya est familiarizado con los informes en bandas. Estos informes tienen
bandas o tiras separadas que representan una parte de la pgina impresa. Las bandas incluyen
encabezados y pies de pgina, encabezados y pies de informe, la seccin de detalle del registro
y encabezados y pies de grupo usados para agrupar de manera visual y lgica las entradas de
detalle. Mientras se ejecutan los informes, una lnea imaginaria horizontal a lo largo de la pgina
corre de la parte superior a la inferior de la pgina. Cuando la lnea llega a cada banda, el informe
procesa los campos en esa banda hasta que ya no hay ms registro que procesar.
Los RDLC son un poco diferentes de los informes en bandas. Slo tienen tres bandas: encabeza-
do de pgina, pie de pgina y todo lo dems (una banda llamada Cuerpo). En lugar de agregar
bandas para registros y grupos, se agregan regiones de datos. Estos controles especiales procesan
los registros vinculados con el informe de acuerdo con la forma de la regin de datos. Hay cuatro
controles de regin de datos en el cuadro de herramientas.
Table
Esta regin presenta un nmero ilimitado de filas, pero con un conjunto predefinido de
columnas de datos. Est diseada para presentacin tabular de registros de datos, y cada
columna suele desplegar un solo campo de datos de origen o calculados. Cada fila de la tabla
representa un registro de datos de origen.
Matrix
Este control es similar a la regin Table, pero permite un nmero flexible de columnas de
datos, no slo filas.
List
La regin List proporciona una seccin de despliegue de forma libre para cada registro
entrante. Puede agregar cualquier nmero de campos o controles de despliegue a la seccin
de registro.
Chart
Chart usa los datos recolectados del informe para presentar grficas de lnea, barras y pastel
al usuario.
Los registros de los conjuntos de datos estn siempre unidos a regiones de datos. Si su informe
incluye datos de varios orgenes de datos distintos, cada origen se vincular exactamente con una
regin de informe, y todas las regiones aparecern en la banda Cuerpo. Usaremos una regin de
datos Lista para este informe de ejemplo. Siga adelante y agregue un control Lista a la banda
Cuerpo de la superficie del informe. Ahora puede agregar otros elementos a la propia banda o
a la superficie del control Lista. Los elementos agregados al control Lista se reprocesan para
cada registro en el origen de datos entrante. Estos elementos pueden ser controles del cuadro de
herramientas o campos de la base de datos desplegados en el panel Orgenes de datos. Mediante
el uso de la tabla Actividad en el panel Orgenes de datos, arrastre el campo NombreCompleto
a la superficie del control Lista. En la figura 21-4 se muestra el despliegue justo despus de
realizar esta operacin de arrastre.

Uso de controles de informe en .NET | 587

21_PATRICK-CHAPTER_21.indd 587 17/2/10 15:32:22


Figura 21-4. Un control Lista con un campo de un conjunto de datos.

Cuando arrastramos el campo del origen de datos al control Lista, Visual Studio establece un
vnculo entre ellos. El campo DataSetName del control list1 ahora hace referencia a Biblio-
tecaDataSet_Actividad, el nombre del origen de datos. Tambin se agrega un control Text-
Box a la superficie de la lista, y se agrega una expresin (=Fields!NombreCompleto.Value)
que despliega el contenido del campo de la base de datos para cada registro procesado.
Voy a cambiar el tamao del control Lista, el cuadro de texto y la banda Cuerpo para que el campo
del cuadro de texto NombreCompleto sea casi todo lo que hay en informe (vase la figura 21-5).

Figura 21-5. Una versin con un nuevo tamao del informe.

El informe est listo para usarse. Mientras disebamos la superficie del informe, Visual Studio
estaba ocupado generando XML y almacenando en el archivo Report1.rdlc.

Uso de un control de informe


El archivo RDLC es slo una definicin XML de un informe, no tiene la capacidad de desple-
garse a s mismo. Para ver el informe, debemos agregar un control de informe a un formulario
o una pgina Web que sepa cmo combinar apropiadamente el contenido de diseo XML con
los datos del origen de datos especificado. Regrese a Form1 y agregue un control MicrosoftRe-
portViewer a su superficie a partir del cuadro de herramientas (est en la seccin Informe del
cuadro de herramientas en mi sistema).
El control agregado incluye un pequeo botn de etiqueta inteligente en su esquina superior
derecha. Al hacer clic en este botn se despliega la ventana lateral tareas de ReportViewer Tasks,
que aparece en la figura 21-6.
El control MicrosoftReportViewer presenta una experiencia basada en formulario para des-
pliegue de informes. La mayor parte del control es un rea en blanco donde aparece el informe.
Tambin incluye una barra de herramientas usada para navegar por las pginas del informe. El
usuario tambin pude iniciar una exportacin o la impresin de un informe mediante estos con-
troles. Si no necesita la barra de herramientas o uno de sus controladores, use las diversas propie-
dades Show... del control MicrosoftReportViewer para ocultar los elementos innecesarios.

588 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 588 17/2/10 15:32:23


Figura 21-6. El control MicrosoftReportViewer en la superficie del formulario.

El visor de informes es genrico e independiente del informe. Si tiene archivos RDLC en su


proyecto, puede desplegar cualquiera de ellos (uno a la vez) mediante el mismo visor de infor-
mes. Slo tenemos un informe en nuestro proyecto, de modo que conectmoslo (InformeSim-
ple.Report1.rdlc) al visor usando la tarea Elegir informe, del botn de etiqueta inteligente del
visor. Adems, haga clic en la tarea Anclar en contenedor principal en la ventana lateral, para
expandir el informe al tamao del formulario.
El informe RDLC, los datos del origen y el control MicrosoftReportViewer estn todos
unidos en un glorioso despliegue de informe por la magia de la unin de datos. Cuando vincul
el informe al control del visor, aparecieron tres controles ms en el formulario: Biblioteca-
DataSet, ActividadBindingSource y ActividadTableAdapter. BibliotecaDataSet
es una referencia al origen real de datos que agregamos antes. Los otros dos controles envuelven
esos datos en un formulario que puede unirse al visor de informes. Aunque no puede verlo en el
diseador, el cdigo del formulario oculto conecta estos controles y el informe XML al visor.
ReportDataSource1.Name = "BibliotecaDataSet_Actividad"
ReportDataSource1.Value = Me.ActividadBindingSource
Me.ReportViewer1.LocalReport.DataSources.Add( _
ReportDataSource1)
Me.ReportViewer1.LocalReport.ReportEmbeddedResource = _
"InformeSimple.Report1.rdlc"

S, tal vez no comprendo bien. Pero es correcto. Visual Studio conect todo.

Ejecucin del informe


Oprima F5 y vea los resultados de sus esfuerzos. En la figura 21-7 ajust la vista al hacer clic
en el botn de la barras de herramientas Configurar pgina y establec el nivel de acercamien-
to en Ancho de pgina.
Bueno, ese informe es adecuado, en lo que se refiere a la tabla Actividad, pero lo podemos
aderezar un poco ms.

Uso de controles de informe en .NET | 589

21_PATRICK-CHAPTER_21.indd 589 17/2/10 15:32:23


Figura 21-7. Informe del contenido esencial de la tabla Actividad.

Adicin de un encabezado y un pie de pgina


Creo que el informe necesita un ttulo que signifique algo en la parte superior de cada pgina,
adems de un nmero en la esquina inferior derecha. Regresemos al diseador de informes
RDLC y agregumoslos. Una vez all, haga clic con el botn derecho en el fondo del informe (no
en el cuerpo, que es la cuadrcula con marcas) como se muestra en la figura 21-8.

Figura 21-8. Adicin de encabezados y pies de pgina.

Desde este men, seleccione Encabezado de pgina, luego despliegue el men de nuevo y selec-
cione Pie de pgina. Cada nueva banda aparece en la superficie del informe.
Si es texto esttico, sin cambio, o texto que se genere dinmicamente a partir de un origen de da-
tos, el control Cuadro de texto es el que debe elegir para mostrar el contenido de texto. Agre-
gue un control Cuadro de texto del cuadro de herramientas para las secciones de encabezado
y pie de pgina. Haga clic dentro del cuadro de texto del encabezado y escriba lo siguiente:
="El informe de la tabla Actividad"

Puede usar el panel Propiedades para ajustar el aspecto de este control, incluida su fuente de
despliegue.
En el cuadro de texto del pie, agregue este texto:
="Page " & Globals!PageNumber

590 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 590 17/2/10 15:32:24


El seudoobjeto Globals incluye unos cuantos miembros que puede usar en el informe. Cmo
supe que debo usar Globals!PageNumber? Constru la expresin visualmente empleando el
Editor de expresiones. Para accederlo, haga clic con el botn derecho en el control Cuadro de
texto y seleccione Expresin, del men contextual. El editor, que se muestra en la figura 21-9,
le permite generar una expresin usando listas de funciones y nombres de campo. Las funciones
reales slo son (hurra!) funciones de Visual Basic.

Figura 21-9. El editor de expresiones.

Soporte para agrupacin y ordenamiento


La agrupacin de datos es comn en informes impresos. Para agregar agrupaciones a nuestro
informe, necesitamos incrustar nuestro control Lista existente (del registro de detalle) dentro
de otro control Lista (del grupo) y establecer varias propiedades en el control Lista del gru-
po para determinar el mtodo de agrupacin de datos.
Probmoslo. Agregue otro control Lista (llamado list2) al cuerpo del informe y dle el doble
del alto del control Lista existente (llamado list1). Luego, arrastre list1 (el registro de de-
talle) a list2 (el nuevo grupo), colocndolo hacia la parte inferior. Su informe debe parecerse
al de la figura 21-10.
Para configurar el grupo, haga clic con el botn derecho en l y seleccione Propiedades del men
contextual. Aparece el formulario Propiedades de la lista. En su ficha General, haga clic en el botn
Editar grupo de detalles, que establece la agrupacin. En el formulario Propiedades de agrupacin
y ordenacin, que aparece, ingrese el siguiente texto en la primera fila del campo Agrupar por:
=Left(Fields!NombreCompleto.Value, 1)

Uso de controles de informe en .NET | 591

21_PATRICK-CHAPTER_21.indd 591 17/2/10 15:32:25


Figura 21-10. Una lista de agrupacin agregada al informe.

Esta expresin le indica al control list2 que agrupe sus resultados de detalle por el primer ca-
rcter del campo de nombre.
En este mismo formulario, agregue el siguiente texto al campo Etiqueta de mapa de documento:
="Letter: " & Left(Fields!NombreCompleto.Value, 1)

El mapa de documento habilita una lista de hipervnculo en que se puede hacer clic en los dife-
rentes grupos del informe. Cuando ejecutemos el informe un poco despus, veremos este mapa
a la izquierda de la superficie de despliegue del informe.
Los registros de la tabla Actividad estn ordenados para conveniencia del programador (yo). Pero el
usuario del informe tal vez quiera verlos ordenados en la misma manera razonable. Haga clic en la fi-
cha Ordenacin y agregue el siguiente texto en el campo Ordenar por, en la columna Expresion:
=Fields!NombreCompleto.Value

Como es de esperar, esto ordenar los datos por el campo NombreCompleto. Haga clic en los bo-
tones Aceptar hasta salir de todos los cuadros de dilogo y regresar a la superficie del informe.
An necesitamos agregar algo que har que cada grupo se destaque. Agregue un control Cuadro
de texto al control de agrupacin list2. Pngalo en la esquina superior izquierda de ese con-
trol principal, y escriba el siguiente texto en l (o en su propiedad Value):
=Left(Fields!NombreCompleto.Value, 1)

Tambin establec su propiedad BackgroundColor en Black, su propiedad Color en White


y su propiedad Font en Normal, Arial, 12pt, Bold para mejorar el aspecto.
Al ejecutar el informe se presentan los resultados de la figura 21-11. Observe el mapa del do-
cumento a lo largo de la orilla izquierda de la ventana, y los ttulos agrupados de una sola letra
antes de cada seccin agrupada.

Formato de estilo mejorado


Tal vez la caracterstica ms agradable de los informes RDLC es que muchas de las propiedades
para elementos colocadas en la superficie del informe pueden incluir expresiones condicionales.
Esto significa que puede alterar condicionalmente, digamos, las propiedades visuales de un con-
trol Cuadro de texto con base en el valor de un campo en el registro actual.

592 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 592 17/2/10 15:32:25


Figura 21-11. El informe completo, con agrupacin y ordenamiento habilitados.

En la seccin Proyecto de este captulo escribiremos un informe que usa fechas de vencimiento
para artculos prestados. Si el artculo se encuentra vencido, quiero mostrar la fecha de venci-
miento en rojo. Por lo general, la propiedad Color del control Cuadro de texto (que controla
el color de fuente) es Black. Para que el campo responda a los artculos vencidos, reemplazar
Black con la siguiente expresin:
=IIf(Fields!FechaVencimiento.Value < Today, "Red", "Black")

Uso de datos personalizados


Aunque es muy comn generar informes a partir de bases de datos, en realidad puede usar datos
de casi cualquier origen. Cuando usa el control MicrosoftReportViewer, cualquier origen
de datos que implemente la interfaz IEnumerable es buena. Eso incluye todas las colecciones,
matrices y resultados de consulta LINQ. El informe no es tan exigente, siempre y cuando los
datos estn formados como lo espera. Para el informe que acabamos de hacer, podemos hacer a
un lado los datos reales y proporcionar nuestros propios datos falsos. Esta intercepcin y susti-
tucin de datos es algo sacado de una novela de espas. Pero debemos seguir unas cuantas reglas
para que funcione:
Cuando arrastramos el campo Actividad.NombreCompleto del origen de datos a la super-
ficie del informe, ste (en realidad, el control list1) tiene esta idea divertida de que todos
los datos tienen que venir de un origen de datos llamado BibliotecaDataSet_Activi-
dad. Cualquier origen de datos que usemos en lugar del real debe tener este nombre.
El origen de los datos falsos debe incluir el campo NombreCompleto, porque es lo que espe-
ran los campos del informe.
Esas reglas no estn mal. As que esto es lo que necesitamos hacer: crear un origen de datos falso,
interceptar el informe justo antes de que trate de obtener los datos de la base de datos Biblioteca
e insertar, en cambio, nuestros propios datos.

Uso de controles de informe en .NET | 593

21_PATRICK-CHAPTER_21.indd 593 17/2/10 15:32:26


Para un origen de datos falso, necesitaremos una clase que incluya por lo menos el campo
NombreCompleto.
Public Class RegistroActividadFalso
Private IDAlmacenado As Long
Private NombreCompletoAlmacenado As String

Public Sub New(ByVal cualID As Long, _


ByVal cualNombreCompleto As String)
IDAlmacenado = cualID
NombreCompletoAlmacenado = cualNombreCompleto
End Sub

Public Property ID() As Long


Get
Return IDAlmacenado
End Get
Set(ByVal valor As Long)
IDAlmacenado = valor
End Set
End Property

Public Property NombreCompleto() As String


Get
Return NombreCompletoAlmacenado
End Get
Set(ByVal valor As String)
NombreCompletoAlmacenado = valor
End Set
End Property
End Class

Los campos expuestos deben ser propiedades, y no slo campos pblicos; el visor de informes no
reconoce campos de miembro estndar.
Si revisa el cdigo fuente de Form1, encontrar que el cdigo siguiente se agreg al manejador de
eventos Form_Load cuando vinculamos el visor del informe con el informe RDLC:
Me.ActivityTableAdapter.Fill(Me.BibliotecaDataSet.Actividad)
Me.ReportViewer1.RefreshReport()

Es la primera lnea que carga los datos de la tabla Actividad de la base de datos Biblioteca, y lo
vincula con el informe. Necesitamos reemplazar estas dos lneas generadas por el asistente con
cdigo que corte los datos reales a cada paso.
' ----- Crear una tabla falsa de registros falsos.
Dim origenFalso As New Collections.Generic.List( _
Of RegistroActividadFalso)

' ----- Agregar cada uno de los registros falsos.


origenFalso.Add(New RegistroActividadFalso(1, "Ponte a trabajar"))
origenFalso.Add(New RegistroActividadFalso(2, "Toma una siesta"))
origenFalso.Add(New RegistroActividadFalso(3, "Escribe un programa"))
' ----- El informe esta listo para unirse al origen de datos

594 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 594 17/2/10 15:32:26


' real. Eliminarlo.
Me.ReportViewer1.LocalReport.DataSources.Clear(
)

' ----- Generar un nuevo origen de datos. Recuerdese que debe


' tener el mismo nombre.
Dim origenInformeFalso As New _
Microsoft.Reporting.WinForms.ReportDataSource
origenInformeFalso.Name = "BibliotecaDataSet_Actividad"
origenInformeFalso.Value = origenFalso

' ----- Conectar el origen de datos al informe y es todo.


Me.ReportViewer1.LocalReport.DataSources.Add(origenInformeFalso)
Me.ReportViewer1.RefreshReport()

En la figura 21-12 se muestra el informe con los datos falsos en el despliegue.

Figura 21-12. Estos datos falsos no se autodestruirn en cinco segundos.

Suministro de orgenes de datos personalizados


La sustitucin de datos en el ltimo segundo es buena, pero qu pasa si quiere disear un in-
forme que no dependa en absoluto de la base de datos? Tambin puede hacerlo, al proporcionar
un origen de datos completamente personalizado. Los informes RDLC requieren una especie
de esquema de origen de datos en tiempo de diseo; slo que no puede suministrar datos com-
pletamente personalizados al vuelo cuando se ejecute el informe. Pero s puede proporcionar un
esquema basado en una clase en su aplicacin.
En el caso de la clase, nos apegaremos al RegistroActividadFalso que creamos en la seccin
anterior. Luego disearemos un origen de datos de esta clase. Seleccione el comando de men
Datos Agregar nuevo origen de datos. Cuando ha aparecido el Asistente para la configuracin
de orgenes de datos en el pasado, siempre ha seleccionado Base de datos como origen de los
datos. Esta vez, seleccione Objeto, como se muestra en la figura 21-13.
Cuando haga clic en el botn Siguiente, aparecer una jerarqua de todas las clases de su aplica-
cin. Expanda las clases, luego localice y seleccione RegistroActividadFalso. Haga clic en
el botn Finalizar. Ahora RegistroActividadFalso aparece como un origen de datos en el
panel Orgenes de datos.

Uso de controles de informe en .NET | 595

21_PATRICK-CHAPTER_21.indd 595 17/2/10 15:32:26


Figura 21-13. Creacin de un origen de datos basada en un objeto personalizado.

Ahora puede arrastrar y colocar este campo NombreCompleto del origen de datos en la superficie
de diseo del informe RDLC. Agregue un nuevo informe a su proyecto y siga los mismos pasos
que usamos antes para disear el primer informe. Esta vez, use el origen de datos RegistroAc-
tividadFalso en lugar de BibliotecaDataSet.
Para probar este nuevo informe, elimin el Form1 original del proyecto y agregu un nuevo
Form1. Tambin agregu un control MicrosoftReportViewer a su superficie y lo ancl, pero
no lo vincul con el informe RDLC. Esto mantiene las cosas un poco ms limpias mientras que
no hay controles de origen de unin y cosas por el estilo de qu preocuparse. Luego agregu este
cdigo al manejador de eventos Load:
' ----- Vincular con el diseo del informe RDLC.
Me.ReportViewer1.LocalReport.ReportEmbeddedResource = _
"InformeSimple.Report2.rdlc"

' ----- Crear una tabla falsa de registros falsos.


Dim origenFalso As New Collections.Generic.List( _
De RegistroActividadFalso)

' ----- Agregar cada uno de los registros falsos.


origenFalso.Add(New RegistroActividadFalso(1, "Desayuno"))
origenFalso.Add(New RegistroActividadFalso(2, "Comida"))
origenFalso.Add(New RegistroActividadFalso(3, "Cena"))

' ----- Generar un nuevo origen de datos. Recuerde que debe tener
' el mismo nombre.
Dim origenInformeFalso As New _
Microsoft.Reporting.WinForms.ReportDataSource
origenInformeFalso.Name = "InformeSimple_RegistroActividadFalso"
origenInformeFalso.Value = origenFalso

596 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 596 17/2/10 15:32:27


' ----- Conectar el origen de datos al informe y es todo.
Me.ReportViewer1.LocalReport.DataSources.Add(origenInformeFalso)
Me.ReportViewer1.RefreshReport()

Es muy similar al cdigo personalizado anterior, aunque el nombre del origen de datos es ahora
InformeSimple_RegistroActividadFalso, el nombre que este nuevo informe espera (lo que
encontr al ejecutar el informe y leer el mensaje de error).
He guardado una copia de ambos informes personalizados en el directorio de instalacin de los
ejemplos de cdigo fuente del libro. Bsquela en el subdirectorio llamado InformeSimple.

Resumen
Aunque este captulo incluy muchas bonitas imgenes y una gran cantidad de instrucciones,
slo rascamos la superficie de las caractersticas disponibles en los controles de informes in-
cluidos con .NET. Pienso que me rasp el cerebro cuando trat de estudiar cada caracterstica
disponible, pero tal vez su cerebro est mejor preparado para la tarea. An as, si no lo encuentra
exactamente a su gusto, puede usar una de las dems caractersticas de creacin de informes que
present al principio del captulo, o an optar por una solucin de terceros.
Los informes son una parte importante de la vida diaria del desarrollador de negocios. Encon-
trar la herramienta correcta de informes y sentirse cmodo con sus caractersticas no slo es
una buena sugerencia, es necesario en el mundo de los usuarios de software hambrientos de
informes.

Proyecto
Cuando dejamos por ltima vez el documento Kit de recursos tcnicos para el Proyecto Biblio-
teca, inclua cinco informes integrados:
Informe #1: Informe de artculos prestados
Informe #2: Informe de artculos vencidos
Informe #3: Informe de artculos faltantes
Informe #4: Informe de multas adeudadas por clientes
Informe #5: Informe de estadsticas de la base de datos de biblioteca
En este captulo agregaremos estos cinco informes al proyecto. Antes de escribir cualquier cdi-
go, necesitamos imaginar cmo vamos a obtener los datos. Debido a que stos provienen de la
base de datos Biblioteca, slo necesitamos generar la instruccin SQL para cada informe que se
vincular con el informe diseado.
El quinto informe, estadsticas, informar cosas como el nmero de artculos, el nmero de
clientes y valores estadsticos similares de la base de datos Biblioteca. Como estos datos en rea-
lidad no pueden venir de una sola instruccin SQL, extraeremos los datos de la base de datos y
generaremos un origen de datos personalizado que los alimente al informe.

Proyecto | 597

21_PATRICK-CHAPTER_21.indd 597 17/2/10 15:32:27


Armado de las instrucciones SQL
El primer informe, artculos prestados, presenta una lista del nombre del cliente y el ttulo
del artculo para cada archivo que ha pedido prestado el cliente. Incluye la tabla Cliente (para
obtener el nombre del cliente), la tabla CopiaCliente (el evento de prstamo o salida), la tabla
CopiaArticulo (el elemento real prestado) y la tabla ArticuloConNombre (donde aparece el
ttulo del elemento). Tambin incluiremos la tabla CodigoTipoMedio, que nos indica si el ele-
mento es un libro, un CD o algn otro tipo de medio.
Microsoft SQL Server Management Studio Express incluye un diseador de consulta que po-
demos usar para disear la consulta. En la figura 21-14 se muestran las cinco tablas necesarias
como las vincul el diseador.

Figura 21-14. Las cinco tablas en la consulta de artculos prestados.

Si utiliza el diseador de consultas o construye la instruccin SQL a mano, con el tiempo saldr
con algo similar a lo siguiente, que usaremos dentro de la aplicacin Biblioteca:
/* ----- Informe #1: Informe de articulos prestados. */
SELECT PA.Apellido + ', ' + PA.Nombre AS NombreCliente,
PA.CodigoBarras AS CodigoBarrasCliente,
PC.FechaVencimiento, IC.CopiaNmero, IC.CodigoBarras AS CodigoBarrasArticulo,
NI.Title, CMT.NombreCompleto AS NombreMedio
FROM Cliente AS PA
INNER JOIN CopiaCliente AS PC ON PA.ID = PC.Cliente
INNER JOIN CopiaArticulo AS IC ON PC.CopiaArticulo = IC.ID
INNER JOIN ArticuloConNombre AS NI ON IC.IDArticulo = NI.ID
INNER JOIN CodigoTipoMedio AS CMT ON NI.TipoMedio = CMT.ID
WHERE PC.Regresado = 0
AND PC.Faltante = 0
AND IC.Faltante = 0
ORDER BY NI.Titulo, IC.CopiaNmero, PA.Apellido, PA.Nombre

Esta consulta vincula todas las tablas, y luego solicita cada registro que no se ha regresado (PC.
Regresado = 0). Ignora cualquier artculo marcado como faltante (PC.Faltante = 0 AND
IC.Faltante = 0). Esta consulta con el tiempo orienta el informe. Pero por ahora, tenga en

598 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 598 17/2/10 15:32:27


mente que los informes RDLC en realidad no necesitan una instruccin SQL real o una tabla de
base de datos para el esquema del informe. Tambin podemos construir un esquema compatible
a mano usando una clase. Esto resulta que es un poco ms limpio porque no tenemos muchos
archivos relacionados con conjuntos de datos dispersos en todo el cdigo fuente del proyecto.
(El origen de datos BibliotecaDataSet que creamos en el informe de ejemplo en este captulo
agreg cuatro archivos y casi 50 KB de cdigo fuente al proyecto, sin contar el informe RDLC!
El origen de datos basado en la clase no agreg otro cdigo que la propia definicin de clase, y
un poco de XML al archivo RDLC.)
En cuanto al esquema de origen de datos, podemos extrapolarlo a partir de la clusula SELECT
de la consulta SQL. Si furamos a disear una clase con un esquema coincidente, tendra un
aspecto como ste (sin el cdigo de detalle de propiedades):
Class EsquemaInforme1
Public Property NombreCliente As String
Public Property CodigoBarrasCliente As String
Public Property FechaVencimiento As Date
Public Property CopiaNumero As Integer
Public Property CodigoBarrasArticulo As String
Public Property Titulo As String
Public Property NombreMedio As String
End Class

Los dos informes siguientes son para artculos vencidos y artculos faltantes. Para m, el es-
quema del informe #1 es exactamente lo que quiero ver en estos otros dos informes, as que slo
usemos la misma instruccin SQL. Todo lo que necesitamos hacer es cambiar la clusula WHERE.
Para el informe de artculos vencidos, use esta clusula WHERE:
WHERE PC.Regresado = 0
AND PC.Faltante = 0
AND IC.Faltante = 0
AND PC.FechaVencimiento < GETDATE()

Los artculos faltantes usarn esta clusula WHERE:


WHERE PC.Faltante = 1
Or IC.Faltante = 1

El cuarto informe despliega el monto de multas que an deben los clientes, de modo que ne-
cesitar un esquema diferente. He aqu su instruccin SQL, que usa algunas caractersticas de
agrupacin agregados:
/* ----- Informe #4: Informe de multas adeudadas por clientes. */
SELECT PA.Apellido + ', ' + PA.Nombre AS NombreCliente,
PA.CodigoBarras AS CodigoBarrasCliente,
SUM(PC.Multa - PC.Pagado) AS MultasVencidas
FROM Cliente AS PA
INNER JOIN CopiaCliente AS PC ON PA.ID = PC.Cliente
GROUP BY PA.Apellido + ', ' + PA.Nombre, PA.CodigoBarras
HAVING SUM(PC.Multa - PC.Pagado) > 0
ORDER BY NombreCliente

Proyecto | 599

21_PATRICK-CHAPTER_21.indd 599 17/2/10 15:32:28


He aqu el esquema que va en el informe #4:
Class EsquemaInforme4
Public Property NombreCliente As String
Public Property CodigoBarrasCliente As String
Public Property MultasVencidas As Decimal
End Class

Para el informe final, slo usaremos un esquema con dos valores de cadena: un nombre esttico
y su valor relacionado. He aqu su esquema:
Class EsquemaInforme5
Public Property NombreEntrada As String
Public Property ValorEntrada As String
End Class

Bueno, eso es suficiente preparacin. Empecemos la codificacin.

Acceso al proyecto
Cargue el proyecto Cap21 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap21 (Final) cdigo.

Adicin de esquemas de informe


El archivo EsquemasInformes.vb, ya agregado al proyecto, incluye los tres esquemas usados para
los cinco informes integrados. Slo para recordar los miembros, he aqu las definiciones de
propiedades pblicas incluidas en cada clase, menos Get y Set, y menos los miembros de clase
privados:
Public Class EsquemaInformeArticulosCliente
' ----- Usado por los siguientes informes:
' Informe #1: Informe de articulos prestados
' Informe #2: Informe de articulos vencidos
' Informe #3: Informe de articulos faltantes
Public Property NombreCliente() As String
Public Property CodigoBarrasCliente( ) As String
Public Property FechaVencimiento() As Date
Public Property NumeroCopias() As Integer
Public Property CodigoBarrasArticulo( ) As String
Public Property Titulo() As String
Public Property NombreMedio() As String
End Class

Public Class EsquemaInformeMultasCliente


' ----- Usado por los siguientes reportes:
' Informe #4: Informe de multas adeudadas por cliente
Public Property NombreCliente() As String
Public Property CodigoBarrasCliente() As String
Public Property MultasVencidas() As Decimal
End Class

600 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 600 17/2/10 15:32:28


Public Class EsquemaInformeEstadistica
' ----- Usado para los siguientes reportes:
' Informe #5: Informe de estadisticas de la base de datos de biblioteca
Public Property NombreEntrada() As String
Public Property ValorEntrada() As String
End Class

Una vez que las clases de esquema estn en el proyecto, necesitar generar el proyecto antes de
que esas clases puedan usarse en informes RDLC como orgenes de datos. En el proyecto Biblio-
teca, genere el proyecto ahora con el comando de men Generar Generar Biblioteca. Los tres
esquemas deben entonces aparecer como orgenes en el panel Orgenes de datos (vase la figura
21-15). Si el panel Orgenes de datos est cerrado, bralo usando el comando de men Datos
Mostrar orgenes de datos.

Figura 21-15. Los tres esquemas de origen de datos.

Adicin de informes
Como ya creamos juntos un informe RDLC al principio del captulo, segu adelante y agregu
los cinco informes integrados:
InformePrestados.rdlc
Este archivo implementa el informe #1, el informe artculos prestados. Usa el esquema
de clase EsquemaInformeArticulosCliente, e incluye tres columnas en los datos princi-
pales: nombre de cliente/cdigo de barras, nombre de artculo/cdigo de barras/detalles, y
fecha de vencimiento. Para el campo de nombre de artculo, quera presentar informacin
adicional cuando est disponible. El nombre del artculo, el nmero de copias y el tipo de
medios son valores obligatorios, pero el cdigo de barras de artculo es opcional. He aqu el
formato que deseaba:
Nombre articulo (#CopiaNumero, TipoMedio, CodigoBarras)

Proyecto | 601

21_PATRICK-CHAPTER_21.indd 601 17/2/10 15:32:28


Para obtener este resultado, tuve que unir los diversos campos de origen, y us una funcin
condicional (IIf) para incluir de manera opcional el cdigo de barras y su coma:
=Fields!Titulo.Value & " (#" &
CStr(Fields!CopiaNumero.Value) & ", " &
Fields!NombreMedio.Value &
IIf(IsNothing(Fields!CodigoBarrasArticulo.Value), "",
", " & Fields! CodigoBarrasArticulo.Value) & ")"

Como ya lo mencion, el campo de fecha de vencimiento tiene una expresin en su propie-


dad Color que vuelve el texto rojo cuando el artculo se vence.
InformeVencidos.rdlc
Este informe muestra una lista de todos los artculos vencidos en el sistema. Como todo
estar vencido, establec que el campo de fecha de vencimiento use siempre rojo como
fuente de color. Aparte de eso y el ttulo, el informe es bsicamente idntico al informe de
artculos prestados.
InformeFaltantes.rdlc
Este informe muestra una lista de todos los artculos marcados como faltantes. Aunque el
esquema incluye un campo de fecha de vencimiento, no lo uso en este informe. El resto del
informe es bsicamente idntico al informe de artculos vencidos.
InformeMultasClientes.rdlc
Este informe muestra una lista de todos los clientes que an deben multas, y la cantidad de
la multa adeudada. Usa el esquema de clase EsquemaInformeArticulosCliente. El cam-
po que despliega la multa tiene una C en su propiedad Formato. Esta configuracin de
formato fuerza el valor decimal para que se despliegue como moneda usando los parmetros
culturales del sistema local. Esta propiedad Format usa los mismos cdigos reconocidos por
el mtodo String.Format.
InformeEstadisticas.rdlc
El informe #5 despliega la cuenta de registros a partir de las tablas en la base de datos Biblio-
teca. ste es el nico informe que usa el esquema de clase EsquemaInformeEstadisticas.
El propio informe slo despliega dos cadenas por registro: un nombre y un valor. Depende
del cdigo de llamada para formar de manera apropiada esos campos.

Adicin de un visor de informes


Es hora de agregar un control MicrosoftReportViewer. Como un solo control Microsoft
ReportViewer puede desplegar cualquier tipo de informe RDLC, slo agregaremos un solo
formulario para manejar los cinco informes integrados.
Agregue un nuevo formulario llamado InformeVisorIntegrado.vb al proyecto. Establezca su pro-
piedad Text en Informe de Biblioteca y su propiedad WindowState en Maximized. Ade-
ms, cargue el cono proyecto (Libro.ico) en la propiedad Icon. Encontrar una copia de este
archivo en el directorio de instalacin del proyecto. Si quiere, puede cambiar el tamao del
formulario a un punto de partida razonable para el informe (us 680, 400), pero cada informe
empezar maximizado cuando se use.

602 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 602 17/2/10 15:32:28


Agregue un control MicrosoftReportViewer llamado InformeContenido al formulario,
y establezca su propiedad Dock en Fill. Asigne False a las propiedades ShowBackButton y
ShowDocumentMapButton.
El cdigo que agregaremos a este formulario es una variacin del cdigo que escribimos antes en
este captulo. El cdigo que empieza cada informe pasar a este formulario el nombre del archivo
de informe RDLC, el nombre del esquema de datos usado y los datos reales. Debido a que estos
informes son sin modo (puede mantenerlos abiertos mientras an usa otras partes del programa
Biblioteca), no podemos permitir que el cdigo de llamada espere a que el usuario cierre el in-
forme antes de que descartemos los datos de informe. Dejemos que el informe deseche los datos.
Para esto, necesitamos mantener una referencia a esos datos. Agregue la siguiente instruccin a
la clase del formulario InformeVisorIntegrado.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 1.

Private AlmacenarTablaDatos As Object

Recuerde que los informes pueden usar diversos formatos de origen de datos, incluidas conexio-
nes de base de datos, matrices y colecciones. De informe #1 a #4 usarn una instancia System.
Data.DataTable y el informe #5 pasar una coleccin genrica Lista.
El mejor momento para desechar los datos es cuando se cierra el informe. Agregue el siguiente
manejador de eventos al formulario, que confirma que los datos dan soporte al proceso de dese-
cho antes de llamar al mtodo Dispose.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 2.

Private Sub InformeVisorIntegrado_FormClosing( _


ByVal sender As Object, ByVal e As _
System.Windows.Forms.FormClosingEventArgs) _
Handles Me.FormClosing
' ----- Deshacerse de los datos.
If (TypeOf AlmacenarTablaDatos Is IDisposable) Then
CType(AlmacenarTablaDatos, IDisposable).Dispose( )
End If
End Sub

El cdigo que abre este formulario de despliegue pasar en los valores de informe esenciales me-
diante un mtodo pblico llamado IniciarInforme. Agregue su cdigo ahora.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 3.

Proyecto | 603

21_PATRICK-CHAPTER_21.indd 603 17/2/10 15:32:28


Public Sub IniciarInforme(ByVal cualInforme As String, _
ByVal cualEsquemaDatos As String, _
ByVal cualesDatos As Object)
' ----- Ejecutar uno de los informes integrados. cualInforme es
' el nombre del archivo de informe RDLC, en el formato
' "Biblioteca.xxx.rdlc." cualEsquemaDatos proporciona el
' nombre del esquema a usar, en el formato "Biblioteca_xxx".
' cualConjntoDatos son los datos reales que se vinculan
' con el informe, que debe coincidir con el esquema.
Dim origenDatosPersonalizados As New _
Microsoft.Reporting.WinForms.ReportDataSource

' ----- Conectar el visor, el informe y los datos.


ReportContent.LocalReport.ReportEmbeddedResource = _
cualInforme
origenDatosPersonalizados.Name = cualEsquemaDatos
origenDatosPersonalizados.Value = cualesDatos
ReportContent.LocalReport.DataSources.Add( _
origenDatosPersonalizados)

' ----- Desplegar el informe.


AlmacenarTablaDatos = cualesDatos
Me.Show()
End Sub

Este cdigo le indica al visor cul informe usar como un recurso incrustado y luego adjunta los
datos como un origen de datos personalizado. Local en estos nombres de propiedades indica un
informe local (cliente) en lugar de un informe de servidor que se ejecute dentro de SQL Server.
Cuando estbamos jugando antes con los informes, vimos que el modo de despliegue prede-
terminado era rellenar toda la pantalla con contenido de pgina. De manera personal, me
gusta ver estos lmites de pgina falsos. El control MicrosoftReportViewer no incluye una
propiedad que nos permita cambiar esta vista predeterminada (por qu no?), pero an podemos
ajustar el estilo de despliegue inicial mediante mtodos en el control. Cuando agregamos el visor
de informe al formulario, Visual Studio tambin agreg la siguiente instruccin al manejador de
eventos Load formulario:
InformeContenido.RefreshReport()

Agregue el siguiente cdigo justo antes de esa instruccin.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 4.

' ----- Generar y desplegar el informe.


InformeContenido.SetDisplayMode( _
Microsoft.Reporting.WinForms.DisplayMode.PrintLayout)
InformeContenido.ZoomMode = _
Microsoft.Reporting.WinForms.ZoomMode.Percent
InformeContenido.ZoomPercent = 100

604 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 604 17/2/10 15:32:28


Adicin de informes integrados
Ya olvid hace cunto agregu el formulario SeleccionarInforme.vb que dirige la creacin de in-
formes, pero ya est en el proyecto. En caso de que olvide su aspecto (yo lo hice), la figura 21-6
nos la recuerda.

Figura 21-16. El formulario de seleccin de informes.

Ya antes agregamos soporte para nuestros cuatro informes integrados en este cdigo de formula-
rio. En un tributo a la interminable realidad de olvidos para finalizar todo el cdigo, necesitamos
agregar algn cdigo que subestimamos antes. Si utiliza un archivo de configuracin de informe
XML para rellenar la lista del informe, y proporciona una descripcin para cada informe en XML,
cada entrada despliega esa descripcin en la mitad inferior del formulario de seleccin de infor-
mes. Pero si no utiliza un archivo de configuracin, y slo depende del formulario para agregar los
cinco informes integrados como opcin predeterminada (que lo hace), el formulario no desplega-
r descripciones asociadas, porque olvidamos agregarlos. Agregue una funcin a la clase Selec-
cionarInforme que devuelve una descripcin corta para cada uno de los cinco informes.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 5.

Private Function ObtenerDescripcionInformeIntegrado( _


ByVal cualInforme As ElementoInformeEnum) As String
' ----- Regresar una descripcion predefinida para los
' informes integrados.
Select Case cualInforme
Case ElementoInformeEnum.PrestadoIntegrado
Return "Despliega todos los articulos prestados " & _
"ordenados por nombre."
Case ElementoInformeEnum.VencidoIntegrado
Return "Displiga todos los articulos vencidos, ordenados por nombre."
Case ElementoInformeEnum.FaltanteIntegrado
Return "Despliega todos los articulos faltantes, ordenados por nombre."

Proyecto | 605

21_PATRICK-CHAPTER_21.indd 605 17/2/10 15:32:29


Case ElementoInformeEnum.MultasDebidasIntegrado
Return "Despliega todas las multas no pagadas adeudadas por " & _
"clientes, ordenados por nombre de cliente."
Case ElementoInformeEnum.estadisticasIntegrado
Return "Despliega algunas cuentas de registros de la " & _
"base de datos Biblioteca."
Case Else
Return "No hay descripcion de este informe."
End Select
End Function

Llamaremos a este cdigo desde dos lugares. El primero es el mtodo CargarGrupoInformes.


Este cdigo carga el archivo de configuracin del informe XML. Si ese archivo incluye uno de los
informes integrados, pero no proporciona una descripcin con l, nosotros proporcionaremos la
descripcin. En la parte media de ese cdigo encontrar estas lneas:
' ----- Entonces que tipo de entrada es?
If (nodoRastreo.Attributes("type").Value = "integrado") Then

En unas cinco lneas abajo se encuentra la siguiente instruccin:


entradaInforme.TipoElemento = CType(CInt( _
entradaInforme.RutaInforme), ElementoInformeEnum)

Agregue el siguiente cdigo justo despus de esa instruccin.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 6.

If (entradaInforme.Descripcion = "") Then _


entradaInforme.Descripcion = _
ObtenerDescripcionInformeIntegrado(entradaInforme.TipoElemento)

La segunda descripcin integrada necesaria aparece en el mtodo ActualizarListaInformes.


Este mtodo hace que la llamada a CargarGrupoInformes recupere la configuracin en XML.
Pero si despus de eso la lista de informes an est vaca, ActualizarListaInformes agrega los
cinco informes predeterminados, cada uno de los cuales requiere una descripcin. Cerca del final
del mtodo, dentro de un bucle For...Next, encontrar esta instruccin de cierre:
' ----- Agregar la entrada del informe a la lista.
TodosLosInformes.Items.Add(entradaInforme)

Agregue el siguiente cdigo justo despus de esa instruccin.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 7.

EntradaInforme.Descripcion = ObtenerDescripcionInformeIntegrado( _
EntradaInforme.TipoElemento)

606 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 606 17/2/10 15:32:29


Muy bien, se es todo el cdigo de correccin. Ahora regresemos a escribir los informes reales.
El cdigo para empezar cada uno de los cinco informes ya existe en el manejador de eventos
AccEjecutar_Click del formulario SeleccionarInforme. Casi todo ese cdigo incluye una
instruccin Select Case que acta como tablero de seleccin para el informe seleccionado. He
aqu la parte que llama a los cinco informes integrados:
Case ElementoInformeEnum.PrestadoIntegrado
' ----- Articulos prestados
' TODO: Escribir InformeBasicoPrestado()
Case ElementoInformeEnum.VencidoIntegrado
' ----- Articulos vencidos
' TODO: Escribir InformeBasicoVencido()
Case ElementoInformeEnum.FaltanteIntegrado
' ----- Articulos faltantes
' TODO: Escribir InformeBasicoFaltante()
Case ElementoInformeEnum.MultasDebidasIntegrado
' ----- Multas debidas por los clientes
' TODO: Escribir InformeBasicoMultas(
)
Case ElementoInformeEnum.estadisticasIntegrado
' ----- Biblioteca de estadisticas de base de datos
' TODO: Escribir InformeBasicoEstadisticas(
)

Evidentemente, este cdigo no hace mucho. Cambie cada una de las lneas TODO, eliminando la
parte TODO: Escribir de la instruccin. De modo que la lnea que dice:
' TODO: Escribir InformeBasicoPrestado(
)

cambie el cdigo a:
InformeBasicoPrestado()

Haga esto con cada una de las cinco lneas TODO.


La exposicin de estas cinco llamadas a mtodo significa que tenemos que escribir esos mtodos,
caray. Estos mtodos recuperarn los datos para el informe, y enve esos datos al visor de infor-
mes, junto con el nombre del archivo RDLC. En realidad es muy corto y simple, considerando
los hermosos informes que obtendr con ellos. Empecemos por agregar el mtodo InformeBa-
sicoPrestado a la clase SeleccionarInforme.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 8.

Private Sub InformeBasicoPrestado()


' ----- Ejecutar el informe #1 integrado: informe de articulos prestados.
Dim textoSql As String
Dim datosInforme As Data.DataTable
Dim formularioInforme As InformeVisorIntegrado

On Error GoTo ErrorHandler

' ----- Recuperar los datos como un conjunto de datos.


textoSql = "SELECT PA.Apellido + ', ' + " & _

Proyecto | 607

21_PATRICK-CHAPTER_21.indd 607 17/2/10 15:32:29


"PA.Nombre AS NombreCliente, " & _
"PA.CodigoBarras AS CodigoBarrasCliente, " & _
"PC.FechaVencimiento, IC.CopiaNumero, " & _
"IC.CodigoBarras AS CodigoBarrasArticulo, " & _
"NI.Title, CMT.NombreCompleto AS NombreMedio " & _
"FROM Cliente AS PA " & _
"INNER JOIN CopiaCliente AS PC ON PA.ID = PC.Cliente " & _
"INNER JOIN CopiaArticulo AS IC ON PC.CopiaArticulo = IC.ID " & _
"INNER JOIN ArticuloConNombre AS NI ON IC.IDArticulo = NI.ID " & _
"INNER JOIN CodigoTipoMedio AS CMT ON " & _
"NI.TipoMedio = CMT.ID " & _
"WHERE PC.Regresado = 0 " & _
"AND PC.Faltante = 0 " & _
"AND IC.Faltante = 0 " & _
"ORDER BY NI.Titulo, IC.CopiaNumero, " & _
"PA.Apellido, PA.Nombre"
datosInforme = CrearTablaDatos(textoSql)

' ----- Revisar que no hay datos.


If (datosInforme.Rows.Count = 0) Then
datosInforme.Dispose()
MsgBox("No hay articulos prestados.", MsgBoxStyle.OkOnly _
Or MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If

' ----- Enviar los datos al informe.


formularioInforme = New InformeVisorIntegrado
formularioInforme.IniciarInforme("Biblioteca.InformePrestado.rdlc", _
"Biblioteca_EsquemaInformeArticulosCliente", datosInforme)
Return

ErrorHandler:
ErrorGeneral("SeleccionarInforme.InformeBasicoPrestado", _
Err.GetException())
Return
End Sub

El cdigo recupera los registros especficos del informe de la base de datos y se asegura de que
se incluy por lo menos un registro. (Pudimos agregar la instruccin SQL a la base de datos
Biblioteca como procedimiento almacenado o una vista y llamarlo, en cambio. Para los fines de
este tutorial, era ms simple almacenar la instruccin directamente en cdigo.) Luego llama al
visor del informe, pasando el nombre del archivo RDLC, el nombre del esquema (en el formato
NombreProyecto_NombreClase) y la tabla de datos.
A continuacin, agregue los mtodos informeBasicoVencido e InformeBasicoFaltante.
No mostrar el cdigo aqu porque, excepto por el nombre del archivo RDLC y la clusula WHE-
RE en la instruccin SQL, son idnticas a InformeBasicoPrestado.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 9.

608 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 608 17/2/10 15:32:29


Agregue el mtodo InformeBasicoMultas, que maneja el informe integrado #4.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 10.

Tambin es muy similar al mtodo InformeBasicoPrestado, pero usa la instruccin SQL que
diseamos antes para la recuperacin de multas del cliente. Tambin usa un esquema diferente
y un nombre de informe.
formularioInforme.IniciarInforme("Biblioteca.InformeMultasCliente.rdlc", _
"Biblioteca_EsquemaInformeMultasCliente", datosInforme)

El ltimo mtodo que se agrega a SeleccionarInforme.vb es InformeBasicoEstadisticas, que


maneja el informe #5 integrado. Es un poco diferente de los otros cuatro porque rene datos de
seis tablas diferentes, de uno en uno. En cada caso, recupera una cuenta del nmero de registros
en una tabla de base de datos. Los resultados son luego almacenados en una coleccin genrica
(System.Collections.Generic.List), donde cada entrada de la lista es una instancia de In-
formeBasicoEstadisticas, la clase que usamos para el esquema de datos del quinto informe.
Qu coincidencia!
He aqu el cdigo de InformeBasicoEstadisticas para que lo agregue ahora a la clase de
formulario SeleccionarInforme.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap21, Elemento 11.

Private Sub InformeBasicoEstadisticas(


)
' ----- Ejecutar el informe #5integrado: informe de estadisticas
' de la base de datos Biblioteca.
Dim textoSql As String
Dim datosInforme As Collections.Generic.List( _
Of EsquemaInformeEstadistica)
Dim unaEntrada As EsquemaInformeEstadistica
Dim formularioInforme As InformeVisorIntegrado
Dim valorResultado As Integer
Dim contador As Integer
Const conjuntosTablas As String = "Autor,Editor," & _
"Tema,ArticuloConNombre,CopiaArticulo,Cliente"
Const titulosTabla As String = "Autores,Editores," & _
"Encabezados de tema,Articulos,Copias de articulos,Clientes"

On Error GoTo ErrorHandler

' ----- Generar los datos del informe. Todo cuenta a partir de las
' diferentes tablas.
datosInforme = New Collections.Generic.List( _
Of EsquemaInformeEstadistica)
For contador = 1 To ContarSubCadena(conjuntosTablas, ",") + 1

Proyecto | 609

21_PATRICK-CHAPTER_21.indd 609 17/2/10 15:32:29


' ----- Procesar una tabla.
textoSql = "SELECT COUNT(*) FROM " & _
ObtenerSubCadena(conjuntosTablas, ",", contador)
valorResultado = ObtenerEnteroBD (EjecutarSQLRegresar(textoSql))

' ----- Agregarlo a los datos del informe.


unaEntrada = New EsquemaInformeEstadistica
unaEntrada.NombreEntrada = _
ObtenerSubCadena (titulosTabla, ",", contador)
unaEntrada.ValorEntrada = CStr(valorResultado)
datosInforme.Add(unaEntrada)
Next contador

' ----- Enviar los datos al informe.


formularioInforme = New InformeVisorIntegrado
formularioInforme.IniciarInforme("Biblioteca.InformeEstadisticas.rdlc", _
"Biblioteca_EsquemaInformeEstadistica", datosInforme)
Return

ErrorHandler:
ErrorGeneral("SeleccionarInforme.InformeBasicoEstadistica", _
Err.GetException())
Return
End Sub

Debido a que realmente necesitamos obtener la misma informacin (COUNT(*)) para cada una
de las seis tablas afectadas, acabo de implementar el cdigo como un bucle, y genere la instruc-
cin SQL para cada una a medida que recorremos el bucle. Un nombre de tabla amigable y la
cuenta de registros son almacenados entonces en la lista genrica, que se termina enviando al
informe.
Ahora puede ejecutar la aplicacin y usar los cinco informes integrados. Debe iniciar sesin
como bibliotecario o administrador, y luego acceder al panel Imprimir informes en el formulario
principal.
Aunque usted no lo crea, hemos terminado casi con la aplicacin. Lo nico importante que
queda por hacer es procesar los artculos vencidos de cliente para ver si se necesitan las multas.
Agregaremos este cdigo en el siguiente captulo, y tambin echaremos un vistazo a la asignacin
de licencias.

610 | Captulo 21: Creacin de informes

21_PATRICK-CHAPTER_21.indd 610 17/2/10 15:32:30


Captulo 22
Otorgue licencia a su aplicacin

El licenciamiento de contenido .NET apropiado puede hacer la diferencia entre el dominio de mer-
cado y la bancarrota financiera. Y slo estoy hablando acerca de entender los acuerdos de licencia
incluidos con Visual Studio. Todava tiene que descubrir un mtodo apropiado para el licencia-
miento de su propia aplicacin antes de mandarla a sus clientes.
El licenciamiento y los acuerdos de licencia son medios esenciales para proteger la propiedad
intelectual que tanto trabajo le ha costado desarrollar. Cmo funciona el licenciamiento? La
clave se encuentra en la raz de la palabra: licencia viene de li- (decir una mentira) y -cence
(de centavos). Juntas, significan decir mentiras acerca de pequeas unidades monetarias. La
confusin creada al tratar de descubrir lo que esto significa mantiene a los malos perplejos y lo
suficientemente ocupados como para que no roben su aplicacin.
Si este mtodo no funciona, existen algunas soluciones, algunas de las cuales revisar en este
captulo. Parte del anlisis se enfoca en disear un sistema de licenciamiento que aparecer en el
proyecto Biblioteca. .NET Framework incluye clases de licenciamiento de componentes pero se
usan, sobre todo, para diseadores de controles usados por otros programadores dentro de Visual
Studio IDE, y no para aplicaciones de usuario. No cubriremos estas caractersticas de licencia-
miento en este captulo. Si tiene curiosidad acerca de esas caractersticas, empiece por leer acerca
de License Compiler (lc.exe) en la ayuda en lnea de Visual Studio.

Opciones de licenciamiento de software


En los primeros aos del software, el licenciamiento no era un problema: si podas llegar a la
computadora, era porque estabas autorizado. Toda la interaccin de usuario con el sistema era
a travs de los programadores y tcnicos. Si algn usuario quera robar algo, era en forma de 20
toneladas de acero, cables y bulbos. Divertido? S. Fcil? No.

611

22_PATRICK-CHAPTER_22.indd 611 18/2/10 11:20:02


Hoy en da, es una historia diferente. La mayora de los usuarios no son tcnicos, y algunos no
son ticos. Entonces, ahora tenemos acuerdos de licencia y equipos de abogados para respaldarlo.
Pero tambin tenemos software, que puede imponer delicadamente algunas de las reglas. Para
una pieza de software particular, existe todava la pregunta: Cunto cdigo de implementacin
de licenciamiento agrego a mi aplicacin? La cantidad de control de software que incluya caer
en alguna parte del continuo Libertad-Seguridad que se muestra en la figura 22-1.

Probablemente aqu?

Libertad Seguridad

Figura 22-1. El continuo de implementacin de licenciamiento: Dnde est usted?

Si va a la parte de Libertad del espectro (conveniente para los usuarios y hackers), tendr que
ir por la confiabilidad de los usuarios, y cualquier guardia armado que mande a sus oficinas,
para que se siga cumpliendo con el programa. En la parte de Seguridad de la escala (seguro
para los programadores y despachos de abogados con honorarios altos), el software imple-
menta prcticas y polticas que aseguran que slo los usuarios con licencia de la aplicacin lo
usen o lo instalen; no se necesitan guardias armados.
En el resto de esta seccin se analizan las posibles opiniones que puede seleccionar dentro del
rango Libertad-Seguridad.

Slo acuerdo de licencia


El mtodo de slo acuerdo de licencia opta claramente por libertad en vez de la seguridad. Cuan-
do le proporciona al usuario el software, viene con un acuerdo de licencia redactado con todo
cuidado y que describe los trminos de uso para el usuario y el proveedor de software. Por lo ge-
neral, le da al usuario ciertos derechos como la instalacin, el uso y la distribucin del software.
Cuando escribe una aplicacin para uso slo dentro de una organizacin especfica o por par-
te de un grupo pequeo de usuarios con los que tendr contacto regular, el mtodo de slo
acuerdo de licencia puede ser lo que necesite. En realidad, apostara que la mayor parte de las
aplicaciones de Visual Basic se orientan en este sentido. Microsoft ha anunciado a travs de los
aos que la mayora de los programadores de Visual Basic orientan sus aplicaciones para uso
en una organizacin de negocios especfica, unida a una base de datos personalizada especfica.
Esos sistemas a menudo requieren muy poco en la forma de imposicin de la licencia, porque
la aplicacin no sirve cuando se lleva fuera del edificio en que debe residir.
Aunque su software logre una distribucin amplia, este esquema de licenciamiento puede toda-
va ser el camino a seguir. Muchas aplicaciones de fuente abierta, incluido un sistema operativo
importante que rima con Plinux, usa la licencia GNU General Public License de Free Software
Foundation (http://www.fsf.org/licensing/licenses/gpl.html) como su licenciamiento principal y su
poltica de distribucin.

612 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 612 18/2/10 11:20:03


Clave de licencia generada general
Si necesita un poco ms de control sobre la distribucin, instalacin y uso de una aplicacin, pue-
de imponer una clave de licencia generada general (en esencia, una contrasea que permite que la
aplicacin se instale o use). Estas claves a menudo se insertan al inicio del proceso de instalacin,
donde se pide al usuario una clave especfica. Sin la clave, se le dice adis a la instalacin.
El vendedor de software necesitar una forma de generar un buen conjunto de claves de instala-
cin nicas. Existen un par de opciones:
Slo generar un nmero de serie secuencial y combinarlo con un ID de producto y un n-
mero de versin. Lo grandioso acerca de esa clave es que resulta fcil generarlo. El programa
de instalacin no necesita realizar ninguna lgica de verificacin compleja en la clave. Slo
necesita asegurarse de que el formato general es correcto. Uno de los productos que utilic
para desarrollar documentacin de ayuda en lnea para mis antiguas aplicaciones de Visual
Basic 6.0 utilizaba esa clave de licencia. En una forma, no es ms seguro que usar slo un
acuerdo de licencia, porque cualquiera que conoce el formato general puede inventar su
propia clave.
Usar una clave con hash o revuelta, basada en algn nmero de serie original o una frmula
que pueda verificar el programa de instalacin. Un algoritmo de hash bien hecho puede
generar un amplio rango de claves, pero dificulta que otros que no saben la frmula generen
sus propias claves falsas. Aunque no conozco los secretos de los procesos internos de Micro-
soft, ste parece el mtodo que usa para sus Claves de CD de 25 caracteres, incluido el
que se proporciona con Visual Studio. Aunque es difcil que se inventen claves sin bases, la
naturaleza pblica hace que estn sujetas a ser compartidas. Para algunos de sus productos,
Microsoft combina una clave de CD con un registro en lnea o telefnico para mejorar la
seguridad.
Proporcionar una clave de hash o cifrada basada en un nmero de serie que (secretamente)
se proporciona con el programa de instalacin o medio de distribucin. Cuando el usuario
inserta la clave, se descifra o se prepara de otra forma, y despus se compara con el nmero
de serie. Slo si coincide, la instalacin del software se completar apropiadamente.

Clave de licencia generada personalizada


Una clave de licencia generada personalizada es similar a una clave general generada, pero usa
informacin personal proporcionada por el usuario como parte del proceso de generacin. Esa
clave es ms interactiva, y requiere que el usuario se comunique especficamente con el vendedor
de software (o una aplicacin en su sitio Web) para completar el proceso de instalacin.
Durante la compra o el proceso de instalacin, el usuario hace disponible informacin especfica
(como el nombre del dueo y la fecha de compra) al vendedor de software. El vendedor entonces
usa cifrado de clave pblica-pblica (criptografa asimtrica) para cifrar por completo o firmar
digitalmente la informacin relevante. La firma cifrada entonces se regresa al usuario para la
instalacin. El proceso de instalacin usa la porcin pblica del par de clave para asegurar que
la firma es vlida.

Opciones de licenciamiento de software | 613

22_PATRICK-CHAPTER_22.indd 613 18/2/10 11:20:03


Usaremos este mtodo de clave de licencia en el Proyecto Biblioteca, de modo que tendr ms
qu decir en el futuro.

Clave de licencia con identidad o candado de hardware


Para los vendedores de software paranoicos, o para quienes tienen una necesidad legtima de
mantener las riendas en su base de instalacin, existen soluciones que incluyen acceso regular a
hardware o servicios para confirmar que el software previamente instalado es legal y vlido. Un
mtodo popular usa un dongle, que suele ser un dispositivo basado en puerto USB al que el
software debe acceder cada vez que se ejecuta. El vendedor de software proporciona un dongle
con el software que tiene licencia, y puede codificarlo con lmites basados en fecha o basados en
uso.
Con el predominio de Internet, los vendedores de software tambin tienen la opcin de verifi-
cacin en tiempo real mediante Web. Cada vez que un programa se ejecuta, puede acceder a un
sitio de vendedor conocido para activar un proceso de verificacin de uso. Este sistema permite
el monitoreo continuo del software por parte de vendedores que pueden tener un negocio o
razn gubernamental para limitar el uso de software.
Para el proyecto de uno de mis clientes debo acceder a un sitio Web de terceros cada mes y
descargar datos de propietario para usarlo con el software de ese vendedor. ste requiere que
siempre acceda a su sitio Web desde una mquina especfica con una direccin IP especfica.
Se rehusar a proporcionar los datos si intento conectarme desde cualquier otra computado-
ra. Si tengo una necesidad real de usar una direccin IP nueva (si, por ejemplo, cambio de
proveedor de servicio de Internet), debo mandar un escrito al vendedor informndole de mi
nueva direccin IP. Parece molesto, y es una irritacin. Pero los datos que proporcionan son
nicos y valiosos, y sienten que tienen una necesidad de negocios para proteger esa inversin.
Como mi cliente requiere los datos, no tengo otra opcin ms que aceptar los procedimientos
de verificacin mensuales.

Acceso controlado
El nivel ms alto de seguridad requiere una falta de confianza evidente del usuario, aunque pue-
de haber muy buenas razones para esto. En el caso de aplicaciones demasiado confidenciales, el
vendedor de software puede poner su producto a disposicin de un nmero limitado de clientes,
y despus slo en una base de arrendamiento. Como parte de este acuerdo de arrendamiento, el
cliente accede a tener un miembro de personal entrenado del vendedor de software en el sitio,
ejecutando y manteniendo la aplicacin para el cliente. Como mnimo, el vendedor requerir
que uno de sus empleados est disponible de manera inmediata al cliente cuando la aplicacin
se usa.
En un mundo de aplicaciones de software comerciales, parece inconcebible que ese sistema
pueda existir. Pero en situaciones de alto riesgo, las preocupaciones de seguridad se elevan a tal

614 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 614 18/2/10 11:20:03


nivel que ninguna parte est dispuesta a asumir completamente el riesgo de instalar y usar la
aplicacin, sin el otro.
Aunque estuve tentado a usar este sistema para el proyecto Biblioteca, creo que nos quedaremos
con nuestro plan original de emplear una clave de licencia personalizada generada.

Acuerdos de licencia
Un acuerdo de licencia es un documento en que la parte denominada primera parte a partir
de aqu presta amigablemente a la parte denominada segunda parte ciertos derechos, por una
remuneracin, bonos del tesoro y otros beneficios; a cambio, la denominada segunda parte
har lo mismo para la denominada primera parte sin respeto por ninguna otra parte, partida
o entera.
Intentemos eso de nuevo. Un acuerdo de licencia le dice a un usuario Contina, instala y usa
el software, pero tienes que seguir estas reglas. Aunque a menudo estn escritas en condiciones
legales, tambin pueden aparecer en un lenguaje real, como el espaol. Tambin tienen un rango
en derechos otorgados, que va desde Puede usar esto, pero cuando termine, debe destruir todas
las copias hasta selo, y sintase libre de pasar una copia del programa y su cdigo fuente a
sus amigos y conocidos.
El software Biblioteca proporcionado con este libro incluye un acuerdo de licencia. (Lo inclu
en el apndice B.) Cuando instal el cdigo de ejemplo, accedi a los trminos del acuerdo de
licencia, incluida la parte acerca de mantener bien a mi familia, financieramente en mis aos
de retiro. Pero ya es suficiente sobre m; hablemos acerca de los acuerdos de licencia que tal vez
quiera usar para sus aplicaciones.
Si est desarrollando un programa de catlogo de DVD para su primo Fernando, tal vez se
salte la parte del acuerdo de licencia. Pero cualquier software que haga en las instalaciones de
un trabajo para uso fuera de su propia compaa, debe incluir algn tipo de acuerdo entre
usted (o su compaa) y el usuario del software. Este acuerdo debe definirse como parte del
contrato que estableci el proyecto de desarrollo de software (esto es tpico para consulta de
software), o puede incluir el acuerdo como un componente del software (comn para progra-
mas comerciales).
Cualquiera que sea el mtodo que seleccione, es importante que lo ponga por escrito, porque
puede ahorrarle dolores en el camino. Una vez tuve un cliente que insisti que yo le pasara una
copia del cdigo fuente para una aplicacin que le escrib, para que pudieran mejorarlo y vender
la nueva versin a otro negocio (que descaro!). Por fortuna, tenamos un contrato escrito que
deca las reglas de compromiso. Tenan derecho a una copia del cdigo fuente para propsitos de
archivado, pero no podan usarlo o derivar productos de ste sin consentimiento mo por escrito.
Esto les dio un nivel de seguridad mientras todava proporcionaban los medios para que yo le
diera el mejor soporte posible para su organizacin. Por fortuna, todo lleg a una conclusin
feliz, y como ese cdigo de Visual Basic 3.0 ya no corre, es un punto debatible.

Acuerdos de licencia | 615

22_PATRICK-CHAPTER_22.indd 615 18/2/10 11:20:03


Un acuerdo de licencia suele existir para proteger los derechos del vendedor de software, pero
sera intil si tampoco tuviera derechos significativos para el usuario (y algunos de los derechos
pueden ser generosos). Saba que el estndar del acuerdo de licencia de consumidor para Mi-
crosoft Office le permite instalar el producto en dos diferentes sistemas usando una sola copia
de licencia del programa? No es un completo festival de instalacin. Las computadoras deben
pertenecer a la misma persona, y una debe ser de escritorio mientras la otra tiene que ser un
dispositivo porttil (una computadora porttil). Pero es todava un beneficio significativo para
el usuario tpico.
El departamento legal en OReilly Media quiere recordarle que Tim Patrick no tiene una com-
prensin suficiente de la ley, y no puede darle consejos sobre el contenido de ningn acuerdo de
licencia que quiera crear para sus proyectos.

Ofuscacin
Alud un poco a las caractersticas de ofuscacin en Visual Studio 2008 en los captulos 1 y 5,
pero es buen momento para que echemos un vistazo a las caractersticas. Visual Studio incluye
una versin reducida de Dotfuscator, de una compaa llamada PreEmptive Solutions (no es
parte de Microsoft, todava). Para acceder al programa, use el comando de men Tools Dot
fuscator Community Edition en Visual Studio. La interfaz principal aparece en la figura 22-2.

Figura 22-2. Es tiempo de ofuscar!

Al momento de escribir este libro, Dotfuscator Community Edition no se in-


clua con Visual Basic 2008 Express Edition.

616 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 616 18/2/10 11:20:04


Aunque sta es la versin bsica del producto, puede ver que tiene una cantidad enorme de
opciones. Si quiere profundizar en estas caractersticas mejoradas para su proyecto, es grandioso.
Cubrir el uso bsico aqu.
Recordemos rpidamente por qu querra ofuscar su cdigo, o incluso usar la palabra ofuscar en
mala compaa. Aqu se muestra parte del cdigo del Proyecto Biblioteca:
Public Function CentrarTexto(ByVal textoOriginal As String, _
ByVal anchoTexto As Integer) As String
' ----- Centrar una pieza de texto en un ancho de campo. Si el
' texto es demasiado ancho, truncarlo.
Dim textoResultado As String

textoResultado = Trim(textoOriginal)
If (Len(textoResultado) >= anchoTexto) Then
' ----- Truncar lo necesario.
Return Trim(Left(textoOriginal, anchoTexto))
Else
' ----- Empezar con espacios adicionales.
Return Space((anchoTexto - Len(textoOriginal)) \ 2) & _
textoResultado
End If
End Function

Este cdigo es muy sencillo de entender, sobre todo con los comentarios y el mtodo signifi-
cativo y los nombres de variables. Aunque la ofuscacin de .NET funciona en el nivel MSIL,
pretendamos que el ofuscador funcion directamente en el cdigo de Visual Basic. La ofuscacin
de este cdigo puede producir resultados similares al siguiente:
Public Function A(ByVal AA As String, _
ByVal AAA As Integer) As String
Dim AAAA As String
AAAA = Trim(AA)
If (Len(AAAA) >= AAA) Then
Return Trim(Left(AA, AAA))
Else
Return Space((AAA - Len(AA)) \ 2) & AAAA
End If
End Function

En una rutina tan simple, an podemos descubrir la lgica, pero con ms esfuerzo que en la
versin original. Naturalmente, la ofuscacin real va mucho ms all de esto, revolviendo la legi-
bilidad del cdigo en el nivel IL, y confundiendo a los lectores de cdigo y hackers.
Para ofuscar un ensamblado:
1. Genere su proyecto en Visual Studio usando el comando de men Generar Generar
[nombre de proyecto].
2. Inicie Dotfuscator al usar el comando de men Tools Dotfuscator Community Edition,
en Visual Studio.

Ofuscacin | 617

22_PATRICK-CHAPTER_22.indd 617 18/2/10 11:20:04


3. Cuando se le pida un tipo de proyecto, seleccione Crear nuevo proyecto, y haga clic en el
botn Aceptar.
4. En la ficha Entrada de la ventana de aplicacin Dotfuscator, haga clic en el botn de la
barra de herramientas Examinar y agregar ensamblado a la lista. Es el botn del extremo
izquierdo (que parece un archivo de carpeta con una pequea flecha encima) en el panel que
se muestra en la figura 22-2.
5. Cuando se le pida un nombre de ensamblado, explore su aplicacin compilada, y haga clic
en el botn Aceptar. El ensamblado que habr de usarse estar en el subdirectorio bin\Relea-
se del directorio de cdigo fuente del proyecto.
6. Seleccione el comando de men Archivo Generar para generar el ensamblado ofuscado.
Se le pedir que guarde el archivo de proyecto Dotfuscator (un archivo XML) antes de que
la generacin comience. Guarde este archivo en un nuevo directorio. Cuando ocurra la
generacin, guardar la salida del ensamblado en un subdirectorio Dotfuscated en el mismo
directorio que contiene el archivo de proyecto XML.
7. La generacin se completa, y aparece un resumen, como se muestra en la figura 22-3.
Su archivo ofuscado ya est en uso. El proceso tambin genera un archivo Map.xml, que
documenta todos los cambios de nombre hechos a los tipos y miembros dentro de su
aplicacin. Sera malo distribuir este archivo con el ensamblado. Es slo para usarlo en la
depuracin.
Para probar que la ofuscacin tuvo lugar, use la herramienta IL Disassembler que se incluye
con Visual Studio para examinar cada ensamblado. (En mi sistema, este programa se accede
por medio de Inicio [Todos los] Programas Microsoft Windows SDK v6.0A Tools
IL Disassembler.) En la figura 22-4 se muestran las variables globales incluidas en el archivo
General.vb del proyecto Biblioteca. La versin ofuscada de estas mismas variables aparece en la
figura 22-5.
No realizar ofuscacin en el proyecto Biblioteca en estas secciones de tutorial del libro. Sintase
en la libertad de probarlo por s mismo.

El sistema de licenciamiento de biblioteca


Las herramientas y los procedimientos que usaremos para disear el sistema de licenciamiento
del proyecto Biblioteca pueden generarse a partir de caractersticas que ya se analizaron en los
captulos anteriores:

El archivo de licencia contiene XML. (Captulo 13.)


La licencia aparece como un archivo separado en el mismo directorio que el ensamblado
Biblioteca.exe. El software Biblioteca lee contenido del archivo de licencia. (Captulo 15.)
La licencia incluir una firma digital, que est basada en cifrado de clave pblica-privada.
(Captulo 11.)

618 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 618 18/2/10 11:20:04


Figura 22-3. Resumen de la ofuscacin, con algo de publicidad.

Figura 22-4. Variables globales antes de la ofuscacin.

El sistema de licenciamiento de biblioteca | 619

22_PATRICK-CHAPTER_22.indd 619 18/2/10 11:20:05


Figura 22-5. Variables globales despus de la ofuscacin.

Cada vez que se ejecuta la aplicacin Biblioteca, intenta leer el archivo de licencia. Si no existe,
o si contiene datos o una firma no vlidos, el programa degrada las caractersticas disponibles,
deshabilitando las caractersticas para las que se considera que no tienen licencia.

Diseo del archivo de licencia


El archivo de licencia del Proyecto de biblioteca contiene informacin bsica de propiedad y de-
rechos relacionados al usuario que compr derechos del software. Aqu se muestra el contenido
XML que se me ocurri:
<?xml version="1.0" encoding="utf-8"?>
<License>
<Product>Library Project</Product>
<FechaLicencia>1/1/2000</FechaLicencia>
<FechaExpiracion>12/31/2999</FechaExpiracion>
<VersionCubierta>1.*</VersionCubierta>
<Licenciatario>Juan Q. Publico</Licenciatario>
<NumeroSerie>LIB-123456789</NumeroSerie>
</License>

Eso parece suficiente. El proceso que genera la firma digital tambin almacena una firma cifrada
dentro del contenido XML.

Generacin del archivo de licencia


En el Proyecto de este captulo, generaremos una nueva aplicacin que slo existe para generar
archivos de licencia para la aplicacin Biblioteca. Tendr tres componentes principales:
1. Generar y administrar las claves pblica y privada utilizadas en su proceso de firma.

620 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 620 18/2/10 11:20:05


2. Pedir al usuario la fecha de licencia, fecha de expiracin, versin cubierta, nombre del pro-
pietario de la licencia y nmero de serie para una sola licencia. stos son los valores que
aparecen en el contenido XML del archivo de licencia.
3. Dar salida al archivo XML de licencia y firmarlo digitalmente mediante la clave privada.

Instalacin del archivo de licencia


En la seccin Proyecto de este captulo se mostrar cmo generar un archivo genrico de licen-
cia. Este archivo XML se distribuir e instalar con la aplicacin Biblioteca al usar un programa
de instalacin que generaremos en el captulo 25. El archivo se denominar LicenciaBiblioteca.
lic (como opcin predeterminada) y siempre aparecer en el mismo directorio que el archivo de
aplicacin Biblioteca.exe.
Si estuviera desarrollando una aplicacin real para pagar a los clientes, y tuviera un sitio Web que
soportara un servicio Web (del que hablar en el captulo 23), aqu se muestra un diseo para
instalar el archivo de licencia que podra usar:
1. Ejecute el programa de instalacin para instalar la aplicacin en la estacin de trabajo del
usuario.
2. Durante la instalacin, el programa de instalacin pide al usuario los detalles de licencia que
aparecern en el archivo de licencia XML.
3. El programa de instalacin se pone en contacto con el servicio Web en mi sitio de vendedor
y pasa los valores proporcionados por el usuario al servicio de registro.
4. El servicio de registro regresa un archivo XML firmado digitalmente que contiene el conte-
nido de licencia.
5. El programa de instalacin instala este archivo junto con la aplicacin.
6. Si por cualquier razn el licenciamiento no puede completarse con xito durante la instala-
cin, la aplicacin principal contiene cdigo de licenciamiento idntico, y puede comuni-
carse con el propio servicio de registro.

Uso del archivo de licencia


Cada vez que la aplicacin Biblioteca se ejecute, sta lee el archivo de licencia XML y realiza
muchas revisiones para asegurarse de que la licencia sea vlida para la aplicacin de instalacin
actual. Si la licencia no es vlida por cualquier razn, la aplicacin bloquea el acceso a las carac-
tersticas administrativas mejoradas incluidas en el sistema Biblioteca.

Resumen
Ya que a menudo pasar decenas o centenas de horas diseando y desarrollando una aplicacin
de Visual Basic con calidad, es importante usar el licenciamiento apropiado y la tecnologa de

Resumen | 621

22_PATRICK-CHAPTER_22.indd 621 18/2/10 11:20:05


ofuscamiento para proteger su trabajo duro. Otorgar licencias es otra de esas tareas de progra-
macin comunes que no se agregaron a .NET Framework como una clase fcil de usar (a menos
que est generando y distribuyendo controles en tiempo de diseo). Para el resto de nosotros, es
tiempo de hacerlo mientras contina. Por fortuna, .NET tiene herramientas de soporte grandio-
sas, as que agregar soporte de licenciamiento no es muy difcil.

Proyecto
En el cdigo de proyecto de este captulo seguiremos dos de los cuatro pasos de licenciamiento
analizados en la seccin El sistema de licenciamiento de biblioteca, en pginas anteriores de
este captulo: generar y usar el archivo de licencia. El diseo que creamos antes es suficientemente
bueno para nuestras necesidades, aunque todava necesitamos registrarlo en la documentacin
tcnica del proyecto. No instalaremos formalmente el archivo de licencia hasta que creemos el
programa de configuracin, en el captulo 25.

Actualizacin de documentacin tcnica


Ya que estaremos agregando un nuevo archivo externo que ser procesado por el proyecto Biblio-
teca, necesitamos documentar su estructura en el kit de recursos tcnicos del proyecto. Agregue-
mos la siguiente nueva seccin a ese documento.

Archivo de licencia
El proyecto Biblioteca lee un archivo de licencia especfico de cliente generado por la apli-
cacin de soporte Library License Generation. Este programa genera un archivo de licencia
XML firmado digitalmente que incluye informacin de licencia. Aqu se muestra un ejem-
plo de contenido de archivo de licencia:
<?xml version="1.0"?>
<License>
<Product>Proyecto Biblioteca</Product>
<FechaLicencia>1/1/2000</FechaLicencia>
<FechaExpiracion>12/31/2999</FechaExpiracion>
<VersionCubierta>1.*</VersionCubierta>
<Licenciatario>Juan Q. Publico</Licenciatario>
<NumeroSerie>LIB-123456789</NumeroSerie>
<Signature>
Aqui aparece la firma digital (no mostrada)
</Signature>
</License>

Las etiquetas <FechaLicencia> y <FechaExpiracion> indican el primero y ltimo dato


vlido de la licencia. <Licenciatario> indica el nombre del propietario de licencia. <Nu-
meroSerie> incluye el nmero de serie definido por el vendedor asociado con esta licencia.
La etiqueta <VersionCubierta> contiene datos similares al nmero de versin de ensam-
blado en aplicaciones .NET. Tiene hasta cuatro partes delimitadas por puntos:
<major>.<minor>.<build>.<revision>

622 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 622 18/2/10 11:20:05


Cada componente puede incluir un nmero de 0 a 9999, o el caracter *, que indica todos
los valores vlidos para esa posicin.
La seccin <Signature> contiene la firma generada digitalmente. Su formato es depen-
diente en las herramientas XML Cryptography de .NET, que genera esta seccin. Para ase-
gurarse de que una firma digital es apropiada, siempre use la aplicacin de soporte Library
License Generation para generar archivos de licencia.
Esa aplicacin de soporte genera una clave pblica y una privada para uso en la firma digital.
La porcin pblica de esta clave (como un archivo XML) debe agregarse como un recurso
denominado LicensePublicKey a la aplicacin Biblioteca. La porcin privada debe man-
tenerse privada. Para consistencia, el mismo par de claves debe usarse en todo el tiempo de
vida de la disponibilidad del proyecto Biblioteca.
Tambin almacenaremos la ubicacin del archivo de licencia como una configuracin de aplica-
cin en el programa principal. Necesitamos registrar esa opcin con las otras configuraciones de
aplicacin ya agregadas a la seccin User Settings de Resource Kit.
LicenseFileLocation
La ruta del archivo Library License en esta estacin de trabajo. Si no se proporciona, el
programa buscar un archivo denominado LibraryLicense.lic en la misma carpeta que la
aplicacin.

Aplicacin auxiliar de Library License


Generar archivos de licencia y firmas digitales a mano con el Bloc de notas sera..., bueno, ni
siquiera pensemos en eso. En cambio, dependeremos de una aplicacin personalizada para crear
los archivos y firmas. Ya he desarrollado esa herramienta personalizada. La encontrar en el di-
rectorio de instalacin del cdigo de este libro, en el subdirectorio LicenciaBiblioteca.
Esta aplicacin de soporte incluye dos formularios principales. La primera (FormularioUbica-
cionClave.vb, mostrada en la figura 22-6) ubica o crea los archivos de clave pblica-privada
usados en el proceso de firma digital.

Figura 22-6. Forma de soporte para firmas digitales.

Proyecto | 623

22_PATRICK-CHAPTER_22.indd 623 18/2/10 11:20:06


La mayor parte de la forma del cdigo ayuda a ubicar y verificar la carpeta que contendr los
dos archivos de clave (uno privado, uno pblico). Algo del cdigo en el manejador de eventos
AccGenerar_Click crea los archivos reales.
Dim claveDosPartes As RSA
Dim archivoPublico As String
Dim ArchivoPrinvado As String

...algun codigo omitido aqui, entonces...

' ----- Generar las claves.


claveDosPartes = New RSACryptoServiceProvider
claveDosPartes = RSA.Create()

' ----- Guardar la clave publica.


My.Computer.FileSystem.WriteAllText(archivoPublico, _
claveDosPartes.ToXmlString(False), False)

' ----- Guardar la clave privada.


My.Computer.FileSystem.WriteAllText(ArchivoPrivado, _
claveDosPartes.ToXmlString(True), False)

Eso es realmente simple! La clase System.Security.Cryptography.RSA y la clase relacionada


RSACryptoServiceProvider hacen todo el trabajo. Lo nico que tiene que hacer es llamar al
mtodo RSA.Create, y despus generar las claves XML relevantes al usar el mtodo ToXml
String, pasando un argumento False para la clave pblica y True para la clave privada. Si
quiere ver algunas de las claves de ejemplo, abra el subdirectorio LicenseFiles en el directorio
origen de instalacin del libro. Encontrar dos archivos, uno es la clave pblica y otro es la clave
privada. Imprimira uno de stos aqu, pero todo parece caracteres aleatorios.
La otra forma de soporte es FormularioPrincipal.vb, que genera el archivo de licencia de usuario
real, y aparece en la figura 22-7.

Figura 22-7. Formulario de soporte para la generacin de archivo de licencia.

624 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 624 18/2/10 11:20:06


Al igual que el primer formulario, casi todo este cdigo fuente simplemente asegura que los ar-
chivos de clave privada y pblica estn intactos, y que el usuario insert datos vlidos antes de la
generacin. El manejador de eventos AccGenerar_Click es donde est la verdadera diversin.
Primero, necesitamos algo de contenido XML, que generamos en el mtodo GenerarConteni-
doLicenciaXml. Crea el contenido elemento por elemento, al usar mtodos que aprendimos en
el captulo 13. Por ejemplo, aqu est la parte de cdigo que agrega el nmero de serie.
elementoDatos = result.CreateElement("NumeroSerie")
elementoDatos.InnerText = Trim(NumeroSerie.Text)
elementoRaiz.AppendChild(elementoDatos)

Despus viene la firma digital, por medio de la funcin FirmaContenidoLicenciaXml, que


principalmente aparece aqu:
Private Function FirmaContenidoLicenciaXml( _
ByVal origenXml As XmlDocument) As Boolean
' ----- Agregar una firma digital para un documento XML.
Dim archivoClavePrivada As String
Dim clavePrivada As RSA
Dim firma As SignedXml
Dim metodoReferencia As Reference

' ----- Cargar la clave privada.


archivoClavePrivada = My.Computer.FileSystem.CombinePath( _
UbicacionClave.Text, NombreArchivoClavePrivada)
clavePrivada = RSA.Create()
clavePrivada.FromXmlString( _
My.Computer.FileSystem.ReadAllText(archivoClavePrivada))

' ----- Crear el objeto que genera la firma.


firma = New SignedXml(origenXml)
firma.SignedInfo.CanonicalizationMethod = _
SignedXml.XmlDsigCanonicalizationUrl
firma.SigningKey = clavePrivada

' ----- La firma aparecera como un elemento


' <reference> en el XML.
metodoReferencia = New Reference("")
metodoReferencia.AddTransform(New _
XmlDsigEnvelopedSignatureTransform(False))
firma.AddReference(metodoReferencia)

' ----- Y la firma al contenido XML.


firma.ComputeSignature()
origenXml.DocumentElement.AppendChild(firma.GetXml(
))

' ----- Terminado.


Return True
End Function

La firma digital ocurre por medio de la clase SignedXml (en el espacio de nombre System.
Security.Cryptography.Xml). Esta clase usa unos cuantos mtodos de firma diferentes. El
que seleccion (XmlDsigCanonicalizationUrl) se usa para XML tpico e ignora los comen-
tarios incrustados.

Proyecto | 625

22_PATRICK-CHAPTER_22.indd 625 18/2/10 11:20:06


Esta firma aparece como etiquetas y valores en la salida XML, agregada a travs de la instruccin
AppendChild al final de la rutina. Ya que no queremos que la firma en s se considere cuando
volvamos a revisar el archivo XML en busca de contenido vlido, la clase SignedXml agrega la
firma como una etiqueta <reference>. Esto ocurre en cdigo al agregar el objeto Reference
que est programado para ese propsito. Se agrega a travs de la llamada de mtodo firma.
AddReference.
Una vez que tenemos la firma en el contenido XML, la escribimos en un archivo especificado
por el usuario por medio del mtodo estndar XmlDocument.Save (en el manejador de eventos
AccGenerar_Click).
xmlLicencia.Save(LicenseSaveLocation.FileName)

Aqu se muestra un ejemplo de archivo de licencia XML que incluye una firma digital. sta es
la que he incluido en el directorio LicenseFiles en la instalacin de origen del libro (con algunas
lneas ajustadas para que quepan en esta pgina).
<?xml version="1.0"?>
<Licencia>
<Producto>Proyecto Biblioteca</Producto>
<FechaLicencia>11/30/2009</FechaLicencia>
<FechaExpiracion>12/31/2999</FechaExpiracion>
<VersionCubierta>1.*</VersionCubierta>
<Licenciatario>Juan Q. Publico</Licenciatario>
<NumeroSerie>LIB 123456789</NumeroSerie>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm=
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm=
"http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/
xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/
xmldsig#sha1" />
<DigestValue>CezlqVmSO97b/0rwtQi2c31mqaE=
</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>s+B3s392uePWsbGX4Jpl1p3A/AwSIJtsI
Hq79sgsinUx280358x8mNgwRx/vytlitdRaCgX7aqMD4xz
gvKxejsgqhZ0/cQRu6zY6T9rLYSkcVyuvt5RtleT6rNwz/
6TnHI7KEqemBJM3eDErdzWhVfgrsNjfDZvc2Piav3ddSdI=
</SignatureValue>
</Signature>
</Licencia>

La firma digital aparece como contenido desordenado dentro de la etiqueta <SignatureValue>.


Ahora, si alguien intenta modificar cualquiera de estos valores de licencia, la licencia ya no coinci-
dira con la firma, y toda la licencia dejara de ser vlida.

626 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 626 18/2/10 11:20:07


En vez de usar una firma digital, pudimos slo haber cifrado el archivo de licencia completo con
la clave privada, y despus utilizar la clave pblica para descifrarlo y examinar su contenido. Pero
me gusta ms la firma digital, porque permite a cualquiera abrir el archivo de licencia y revisar
los parmetros de licencia por s mismo mientras previene todava cualquier cambio.

Adicin de la licencia al programa Biblioteca


Regresemos a la aplicacin Biblioteca ya en progreso.

Acceso al proyecto
Cargue el proyecto Cap22 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap22 (Final) cdigo.

El programa ajustar su comportamiento dependiendo de si est licenciado o no. Pero para ha-
cer tal determinacin, necesita asegurarse de que el contenido del archivo de licenciamiento es
vlido y no ha sido saboteado. Para hacer esto, necesita una forma de volver a ordenar la firma
y compararla con el resto de la licencia para asegurarse de que coincide. Generamos la firma al
usar la clave privada; debemos volverla a ordenar mediante la clave pblica.
Podemos almacenar la clave pblica en su propio archivo fuera del programa, pero entonces tal
vez se pierda (al igual que mis claves reales). En vez de eso, almacenaremos la clave pblica como
un recurso de aplicacin, encontrada de manera externa en el cdigo fuente de la carpeta Recur-
sos. Ya he agregado el recurso a su copia del programa, y la he denominado ClavePublicaLi-
cencia. Con esta clave incrustada en la aplicacin, cualquier regeneracin de las claves pblica o
privada requerir modificacin de su recurso. En el cdigo, nos referimos al contenido XML de la
clave pblica al usar su nombre de recurso:
My.Resources.ClavePublicaLicencia

Algunas de las caractersticas de seguridad usan clases encontradas en el espacio de nombre


System.Security.Cryptography.Xml. Esto no es uno de los nombres de espacio incluidos
como opcin predeterminada en las nuevas aplicaciones de Visual Basic, as que tenemos que
agregarla nosotros mismos. Abra la ventana de propiedades de proyecto y seleccione la pestaa
Referencias. Justo debajo de la lista Referencias, haga clic en el botn Agregar, y despus seleccio-
ne System.Security de la pestaa .NET de la ventana Agregar referencia que aparece.
Mientras tenemos todava la ventana de propiedades del proyecto abierta, haga clic sobre la pes-
taa Configuracin. Agregue una nueva configuracin String y use UbicacionArchivoLicencia
como nombre. Usaremos esta configuracin para agregar la ruta al archivo de licencia. Guarde y
cierre la ventana de propiedades del proyecto.
Nuestras necesidades generales de licencia a travs de la aplicacin son muy simples. Slo nece-
sitamos saber el estado actual del archivo de licencia, y tener acceso a algunos de los valores para
que podamos desplegar un mensaje corto acerca de la licencia. Tal vez necesitemos hacer esto en
varias partes del programa, as que agreguemos algo de cdigo genrico al mdulo General.vb.
Abra ese mdulo ahora.

Proyecto | 627

22_PATRICK-CHAPTER_22.indd 627 18/2/10 11:20:07


Justo en la parte superior de ese archivo, el cdigo ya incluye referencia al nombre de espacio
System.Security.Cryptography, desde que incluimos esa contrasea de cifrado de usuario.
Pero esto no cubre las cosas XML estndar o seguras. As que tambin agregamos dos nuevas
instrucciones Import.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 1.

Imports System.Xml
Imports System.Security.Cryptography.Xml

Usaremos una enumeracin para indicar el estado de la licencia. Agrguelo ahora al mdulo
General.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 2.

Public Enum EstatusLicencia


LicenciaValida
ArchivoLicenciaFaltante
ArchivoLicenciaCorrupto
FirmaNoValida
AunNoLicenciada
LicenciaExpirada
VersionNoCoincidente
End Enum

Tambin agreguemos una estructura simple que comunique los valores extrados del archivo de
licencia. Agregue este cdigo al mdulo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 3.

Public Structure DetalleArchivoLicencia


Public Estatus As EstatusLicencia
Public Licenciatario As String
Public FechaLicencia As Date
Public FechaExpiracion As Date
Public VersionCubierta As String
Public NumeroSerie As String
End Structure

628 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 628 18/2/10 11:20:07


Como opcin predeterminada, el archivo de licencia aparece en el mismo directorio que la apli-
cacin, al usar el nombre LicenciaBiblioteca.lic. Agregue la constante global al mdulo General
que identifica este nombre predeterminado.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 4.

Public Const ArchivoLicenciaPredeterminado _


As String = "LicenciaBiblioteca.lic"

Todo lo que necesitamos ahora es algo de cdigo para llenar en la estructura ArchivoLicen-
ciaPredeterminado. Agregue la funcin ExaminarLicencia al mdulo General.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 5.

Public Function ExaminarLicencia() As DetalleArchivoLicencia


' ----- Examinar el archivo de licencia de la aplicacion y
' reportar lo que hay dentro.
Dim resultado As New DetalleArchivoLicencia
Dim usarRuta As String
Dim ContenidoLicencia As XmlDocument
Dim clavePublica As RSA
Dim documentoFirmado As SignedXml
Dim nodosCoincidentes As XmlNodeList
Dim partesVersion() As String
Dim contador As Integer
Dim parteComparar As String

' ----- Ver si existe el archivo de licencia.


resultado.Estatus = EstatusLicencia.ArchivoLicenciaFaltante
usarRuta = My.Settings.LicenseFileLocation
If (usarRuta = "") Then usarRuta = _
My.Computer.FileSystem.CombinePath( _
My.Application.Info.DirectoryPath, ArchivoLicenciaPredeterminado)
If (My.Computer.FileSystem.FileExists(usarRuta) = False) _
Then Return resultado

' ----- Tratar de leer el archivo.


resultado.Estatus = EstatusLicencia.ArchivoLicenciaCorrupto
Try
ContenidoLicencia = New XmlDocument( )
ContenidoLicencia.Load(usarRuta)
Catch ex As Exception
' ----- Error silencioso.
Return resultado
End Try

Proyecto | 629

22_PATRICK-CHAPTER_22.indd 629 18/2/10 11:20:07


' ----- Preparar el recurso de clave publica para uso.
clavePublica = RSA.Create()
clavePublica.FromXmlString(My.Resources.LicensePublicKey)

' ----- Confirmar la firma digital.


Try
documentoFirmado = New SignedXml(ContenidoLicencia)
nodosCoincidentes = ContenidoLicencia.GetElementsByTagName( _
"Firma")
documentoFirmado.LoadXml(CType(nodosCoincidentes(0), _
XmlElement))
Catch ex As Exception
' ----- Todavia un documento corrupto.
Return resultado
End Try
If (documentoFirmado.FirmaRevisada(clavePublica) = False) Then
resultado.Estatus = EstatusLicencia.FirmaNoValida
Return resultado
End If

' ----- El archivo licencia es valido. Extraer sus miembros.


Try
' ----- Obtener el nombre del licenciatario.
nodosCoincidentes = ContenidoLicencia.GetElementsByTagName( _
"Licenciatario")
resultado.Licenciatario = nodosCoincidentes(0).InnerText

' ----- Obtener la fecha de licencia.


nodosCoincidentes = ContenidoLicencia.GetElementsByTagName( _
"FechaLicencia")
resultado.FechaLicencia = CDate(nodosCoincidentes(0).InnerText)

' ----- Obtener la fecha de expiracion.


nodosCoincidentes = ContenidoLicencia.GetElementsByTagName( _
"FechaExpiracion")
resultado.FechaExpiracion = CDate(nodosCoincidentes(0).InnerText)

' ----- Obtener el numero de version.


nodosCoincidentes = ContenidoLicencia.GetElementsByTagName( _
"VersionCubierta")
resultado.VersionCubierta = nodosCoincidentes(0).InnerText

' ----- Obtener el numero de serie.


nodosCoincidentes = ContenidoLicencia.GetElementsByTagName( _
"NumeroSerie")
resultado.NumeroSerie = nodosCoincidentes(0).InnerText
Catch ex As Exception
' ----- Todavia un documento corrupto.
Return resultado
End Try

' ----- revisar fechas fuera de rango.


If (resultado.FechaLicencia > Today) Then

630 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 630 18/2/10 11:20:07


resultado.Estatus = EstatusLicencia.AunNoLicenciada
Return resultado
End If
If (resultado.FechaExpiracion < Today) Then
resultado.Estatus = EstatusLicencia.LicenciaExpirada
Return resultado
End If

' ----- Revisar la version.


partesVersion = Split(resultado.VersionCubierta, ".")
For contador = 0 To UBound(partesVersion)
If (IsNumeric(partesVersion(contador)) = True) Then
' ----- The version format is
' major.minor.build.revision.
Select Case contador
Case 0 : parteComparar = _
CStr(My.Application.Info.Version.Major)
Case 1 : parteComparar = _
CStr(My.Application.Info.Version.Minor)
Case 2 : parteComparar = _
CStr(My.Application.Info.Version.Build)
Case 3 : parteComparar = _
CStr(My.Application.Info.Version.Revision)
Case Else
' ----- Corromper numero version.
Return resultado
End Select
If (Val(parteComparar) <> _
Val(partesVersion(contador))) Then
resultado.Estatus = EstatusLicencia.VersionNoCoincidente
Return resultado
End If
End If
Next contador

' ----- Todo parece en orden.


resultado.Estatus = EstatusLicencia.LicenciaValida
Return resultado
End Function

Es mucho cdigo, pero la mayor parte slo carga y extrae valores del archivo de licencia XML.
La parte de revisin de firma es relativamente corta.

clavePublica = RSA.Create()
clavePublica.FromXmlString(My.Resources.LicenciaClavePublica)
documentoFirmado = New SignedXml(ContenidoLicencia)
nodosCoincidentes = ContenidoLicencia.GetElementsByTagName( _
"Firma")
documentoFirmado.LoadXml(CType(nodosCoincidentes(0), XmlElement))
If (documentoFirmado.FirmaRevisada(clavePublica) = False) Then
' ----- No valido
End If

Proyecto | 631

22_PATRICK-CHAPTER_22.indd 631 18/2/10 11:20:07


El objeto SignedXml (que tambin se usa para generar el archivo de licencia original) necesita
saber exactamente qu etiqueta XML de su contenido representa la firma digital. Pensara que
tener un elemento denominado <Signature> sera una gran ventaja, pero tal vez no. De cual-
quier forma, una vez que ha asignado ese nodo al usar el mtodo SignedXml.LoadXml, se llama
al mtodo FirmaRevisada, pasndolo a la clave pblica. Si regresa True, est bien. Quiero
decir, no en un sentido moral; el cdigo no sabe nada acerca de usted. Pero la firma est bien.

Despliegue la licencia en el formulario Acerca de


Cuando agregamos el formulario Acerca de al proyecto hace unos cientos de pginas, incluimos
un control Label denominado InfoLicencia. Actualmente despliega siempre Sin licencia,
pero ahora tenemos las herramientas para desplegar una licencia apropiada, si est disponible.
Abra el cdigo fuente para el formulario ProgramaAcercaDe.vb, y agregue el siguiente cdigo
para iniciar el manejador de eventos ProgramaAcercaDe_Load.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 6.

' ----- Preparar el formulario.


Dim detallesLicencia As DetalleArchivoLicencia

' ----- Desplegar el licenciatario.


detallesLicencia = ExaminarLicencia()
If (detallesLicencia.Estatus = EstatusLicencia.LicenciaValida) Then
InfoLicencia.Text = _
"Licenciado a " & detallesLicencia.Licenciatario & vbCrLf & _
"Serial number " & detallesLicencia.NumeroSerie
End If

En la figura 22-8 se muestra el formulario AcercaDe en uso con detalles desplegados desde el
archivo de licencia.
Slo por diversin, cambie el nmero de versin en mi archivo de licencia de 1.* a 2.* sin
actualizar la firma digital. Seguramente, cuando despliegue el formulario AcercaDe nuevamen-
te, desplegar Sin licencia, porque la revisin de la firma fall. Cmo prob el cdigo tan
temprano? Copi el archivo LicenciaBiblioteca.lic del subdirectorio ArchivosLicencia instalado
del libro y coloqu esa copia en el subdirectorio bin\Debug del cdigo fuente del proyecto. Ms
adelante podr colocar el archivo en cualquier lugar que quiera y explorarlo, pero estamos ade-
lantndonos.

Imposicin de la licencia
En algn momento, una licencia faltante o no vlida debe tener un impacto negativo en el uso
de la aplicacin. Cuando eso pasa, debemos darle al usuario una oportunidad de corregir el
problema al localizar un archivo de licencia vlido. Haremos esto a travs del nuevo formulario
LocalizarLicencia.vb. Ya he agregado ese formulario a su proyecto. Aparece en la figura 22-9.

632 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 632 18/2/10 11:20:07


Figura 22-8. Despliegue de una licencia vlida.

Figura 22-9. La forma gentil de implementar una licencia de producto.

Este formulario inicia con una llamada a su funcin CambiarLicencia, que regresa True si el
usuario cambia la licencia. Casi todo este cdigo de formulario administra el despliegue, presen-
tando razones detalladas de por qu la licencia es vlida o no al usar los resultados de la funcin
ExaminarLicencia. Si por cualquier razn la licencia no es vlida, un clic en el botn Localizar
permite al usuario explorar una versin mejor.
Private Sub ProgramaAcercaDe_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
' ----- Actualiza el numero de version.

Proyecto | 633

22_PATRICK-CHAPTER_22.indd 633 18/2/10 11:20:08


With My.Application.Info.Version
VersionPrograma.Text = "Version " & .Major & "." & _
.Minor & " Revision " & .Revision
End With
' ----- Preparar el formulario para posterior desvanecimiento.
Me.Opacity = 0.99
' ----- Preparar el formulario.
Dim detallesLicencia As DetalleArchivoLicencia

' ----- Desplegar el licenciatario.


detallesLicencia = ExaminarLicencia(
)
If (detallesLicencia.Estatus = EstatusLicencia.LicenciaValida) Then
InfoLicencia.Text = _
"Licenciado a " & detallesLicencia.Licenciatario & vbCrLf & _
"Serial number " & detallesLicencia.NumeroSerie
End If
End Sub

La variable de nivel de formulario UbicacionModificada se vuelve a enviar al que llama como


un desencadenante para actualizar el estado de la licencia.
Para el Proyecto Biblioteca en particular, no vi ninguna razn para implementar la licencia al
inicio, ya que no es culpa del cliente que la biblioteca robe este trabajo de software importante.
En cambio, regreso el proceso de verificacin hasta que un administrador o bibliotecario intente
acceder a las caractersticas mejoradas de la aplicacin. Despus, si la revisin de licencia falla, el
usuario debe ser capaz de explorar el disco en busca de un archivo de licencia vlido.
Pienso que el mejor lugar para agregar la revisin de licencia es justo despus de que el adminis-
trador proporciona de manera correcta una contrasea. Si revisamos antes de ese punto, dara
a los clientes ordinarios la capacidad de explorar el disco, que es tal vez un no no, ya que cual-
quiera y su to pueden entrar y usar la estacin de trabajo del cliente. Abra el cdigo fuente del
formulario CambiarUsuario.vb, localice el manejador de eventos AccAceptar_Click y ubique
el comentario Inicio de sesin correcto.
' ----- Inicio de sesion correcto.
IdUsuarioInicio = CInt(infoBD!ID)
NombreUsuarioInicio = CStr(infoBD!IdInicio)
...

Justo antes de este bloque de cdigo, agregue el siguiente cdigo de revisin de licencia.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 7.

' ----- No permitir el inicio de sesion si el programa no tiene licencia.


Do While (ExaminarLicencia().Estatus <> _
EstatusLicencia.LicenciaValida)
' ----- Ask the user what to do.
If (MsgBox("Esta aplicacion no tiene una licencia apropiada " & _
"para uso administrativo. Si tiene acceso a " & _
"un archivo de licencia valido, puede verificarlo ahora. " & _

634 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 634 18/2/10 11:20:08


"Confirme si le gustaria localizar un archivo de licencia valido " & _
"en este momento.", MsgBoxStyle.YesNo Or _
MsgBoxStyle.Question, TituloPrograma) <> _
MsgBoxResult.Yes) Then
infoBD.Close()
infoBD = Nothing
Return
End If

' ----- Pedir una licencia actualizada.


Call LocalizarLicencia.CambiarLicencia()
LocalizarLicencia = Nothing
Loop

Este cdigo le da al usuario un nmero ilimitado de posibilidades de ubicar un archivo de licen-


cia vlido. Una vez que la licencia sea vlida, el cdigo se mueve hacia adelante y permite acceso
administrativo.

Procesamiento del elemento Daily


El ltimo conjunto importante de cdigo que habr de agregarse al proyecto Biblioteca no est
relacionado con el licenciamiento, pero es importante: el procesamiento de multas para elemen-
tos no pagados. Agregaremos un mtodo comn que realizar el procesamiento, y despus lo
llamaremos cuando se necesite a travs de la aplicacin.
Agregue el nuevo mtodo ProcesamientoDiarioPorCopiaCliente al mdulo General.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 8.

Public Sub ProcesamientoDiarioPorCopiaCliente( _


ByVal idCopiaCliente As Integer, ByVal hastaFecha As Date)
' ----- Esta rutina hace la mayor parte del trabajo basico de
' procesamiento de multas vencidas. Todas las otras
' rutinas de procesamiento diario llaman a esta rutina.
Dim textoSql As String
Dim infoBD As SqlClient.SqlDataReader
Dim DiasDeMulta As Integer
Dim ultimoProceso As Date
Dim multasHastaAhora As Decimal

On Error GoTo ErrorHandler

' ----- Obtener todos los valores basicos necesarios para


' procesar esta entrada.
textoSql = "SELECT PC.FechaVencimiento, PC.FechaProceso, " & _
"PC.Multa, CMT.MultaDiaria FROM CopiaCliente AS PC " & _
"INNER JOIN CopiaArticulo AS IC ON PC.CopiaArticulo = IC.ID " & _
"INNER JOIN ArticuloConNombre AS NI ON IC.IdArticulo = NI.ID " & _
"INNER JOIN CodigoTipoMedio AS CMT ON & _
"NI.TipoMedio = CMT.ID " & _

Proyecto | 635

22_PATRICK-CHAPTER_22.indd 635 18/2/10 11:20:08


"WHERE PC.ID = " & idCopiaCliente & _
" AND PC.FechaVencimiento <= " & FechaBD(Today) & _
" AND PC.Regresado = 0 AND PC.Faltante = 0 " & _
"AND IC. Faltante = 0"
infoBD = CrearLector(textoSql)
If (infoBD.Read = False) Then
' ----- Falta el registro de copia del cliente. Oh bueno.
' tal vez sea porque este articulo no estaba
' vencido, o faltaba, o algo valido como
' que las multas no deben incrementarse.
infoBD.Close()
infoBD = Nothing
Return
End If

' ----- Si ya hemos procesado este registro para hoy,


' no hacerlo de nuevo.
If (IsDBNull(infoBD!FechaProceso) = False) Then
If (CDate(infoBD!FechaProceso) >= hastaFecha) Then
infoBD.Close()
infoBD = Nothing
Return
End If
ultimoProceso = CDate(infoBD!FechaProceso)
Else
ultimoProceso = CDate(infoBD!FechaVencimiento)
End If

' ----- Las multas estan vencidas en este registro. Idear cuanto.
DiasDeMulta = CInt(DateDiff(DateInterval.Day, _
CDate(infoBD!FechaVencimiento), hastaFecha) - _
DateDiff(DateInterval.Day, CDate(infoBD!FechaVencimiento), _
ultimoProceso) - FineGraceDays)
If (DiasDeMulta < 0) Then DiasDeMulta = 0
multasHastaAhora = 0@
If (IsDBNull(infoBD!Multa) = False) Then _
multasHastaAhora = CDec(infoBD!Multa)
multasHastaAhora += CDec(infoBD!MultaDiaria) * CDec(DiasDeMulta)
infoBD.Close()
infoBD = Nothing

' ----- Actualizar el registro con la ultima multa y


' la informacion de procesamiento.
textoSql = "UPDATE CopiaCliente SET " & _
"FechaProceso = " & FechaBD(hastaFecha) & _
", Multa = " & Format(multasHastaAhora, "0.00") & _
" WHERE ID = " & IDCopiaCliente
EjecutarSQL(textoSql)
Return

ErrorHandler:
GeneralError("ProcesamientoDiarioPorCopiaCliente", Err.GetException( ))
Resume Next
End Sub

636 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 636 18/2/10 11:20:08


Este cdigo examina un registro CopiaCliente (el registro que marca la revisin de un solo
elemento por un cliente) para ver si no se ha pagado, y si es as, qu multas se necesitan agregar
al registro. Cada registro incluye un campo FechaProceso. No queremos cobrar el cliente dos
veces en el mismo da por un solo artculo sin pagar (no, no queremos), as que usamos Fecha-
Proceso para confirmar qu das no se cobran.
Hay algunos lugares de la aplicacin donde queremos llamar esta rutina de procesamiento sin
molestar al usuario. El primero es el formulario RegistrosCliente, el formulario que desplie-
ga las multas que un cliente todava debe. Justo antes de mostrar esa lista, debemos actualizar
cada elemento revisado por el cliente para asegurarnos de desplegar la informacin de multa
ms reciente. Abra el cdigo fuente del formulario, ubique el manejador de eventos Regis-
trosCliente_Load y agregue el cdigo siguiente, justo antes de llamar a ActualizarMultas-
Cliente (-1) que aparece a mitad de la rutina.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 9.

' ----- Asegurarse de que cada articulo esta actualizado.


For contador = 0 To ArticulosPrestados.Items.Count - 1
nuevaEntrada = CType(ArticulosPrestados.Items(contador), ArticuloDetalleCliente)
ProcesamientoDiarioPorCopiaCliente(nuevaEntrada.IDDetalle, Today)
Next contador

El estado sin pagar de un elemento tambin debe actualizarse justo antes de que se revise. Abra el
cdigo fuente del formulario FormularioPrincipal y ubique el manejador de eventos AccEn-
trada_Click. Cerca de la mitad del camino a travs de este cdigo, encontrar un comentario que
inicia con Manejar artculos faltantes. Justo antes de tal comentario, inserte el siguiente cdigo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 10.

' ----- Traer el estatus del articulo actualizado.


ProcesamientoDiarioPorCopiaCliente(idCopiaCliente, FechaEntrada.Value)

La revisin tiene que actualizar las multas del cliente tambin, justo antes de permitir que el
cliente sepa si hay, en realidad, alguna multa vencida. Muvase al manejador de eventos Formu-
larioPrincipal.AccClienteSalida_Click y agregue las siguientes instrucciones en la parte
superior de la rutina.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 11.

Dim tablaBD As Data.DataTable


Dim filaBD As Data.DataRow

Proyecto | 637

22_PATRICK-CHAPTER_22.indd 637 18/2/10 11:20:08


En este mismo mtodo encuentre un comentario que inicia con Mostrar el cliente si hay multas
adeudadas. Como es usual, est cerca de la mitad de la rutina. Inserte el siguiente cdigo justo
antes de ese comentario.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 12.

' ----- Actualizar el registro del cliente.


textoSql = "SELECT ID FROM CopiaCliente WHERE Regresado = 0 " & _
"AND Faltante = 0 AND FechaVencimiento < " & FechaBD(Today) & _
" AND (FechaProceso IS NULL OR FechaProceso < " & _
FechaBD(Today) & ") AND Cliente = " & idCliente
tablaBD = CrearTablaDatos (textoSql)
For Each filaBD In dbTable.Rows
ProcesamientoDiarioPorCopiaCliente(CInt(filaBD!ID), Today)
Next filaBD
tablaBD.Dispose()
tablaBD = Nothing

Adems del procesamiento de multas automtico, el proyecto Biblioteca tambin permite a un


administrador o bibliotecario realizar procesamiento diario de todos los artculos de cliente a
voluntad. Esto ocurre mediante el panel Procesamiento diario en el formulario principal (vase
la figura 22-10).

Figura 22-10. Procesamiento administrativo diario.

Actualmente, el panel no hace mucho, as que cambiemos eso. La primera tarea es actualizar la
etiqueta de estado que aparece en la parte superior del panel. Agregue un nuevo mtodo deno-
minado ActualizarUbicacionProceso a la clase FormularioPrincipal del formulario.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 13.

638 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 638 18/2/10 11:20:09


No mostrar su cdigo aqu, pero bsicamente revisa el campo de la base de datos CodigoLu-
gar.UltimoProcesamiento para todas las ubicaciones, o para la ubicacin seleccionada por el
usuario, y actualiza el estado de despliegue de acuerdo con esto.
El usuario selecciona una ubicacin para procesamiento dentro de la lista desplegable Pro-
cesarUbicacion, pero no hemos agregado todava ningn cdigo para rellenar esa lista. En-
cuentre el mtodo TareaProceso en el cdigo fuente del formulario principal, y agregue estas
instrucciones a la parte superior de este cdigo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 14.

Dim textoSql As String


Dim infoBD As SqlClient.SqlDataReader

On Error GoTo ErrorHandler

Despus agregue estas instrucciones al final del mtodo.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 15.

' ----- Actualizar la lista de ubicaciones.


ProcesarUbicacion.Items.Clear()
ProcesarUbicacion.Items.Add(New ListItemData( _
"<Todas las ubicaciones>", -1))
ProcesarUbicacion.SelectedIndex = 0
textoSql = "SELECT ID, NombreCompleto FROM CodigoLugar " & _
"ORDER BY NombreCompleto"
infoBD = CrearLector(textoSql)
Do While infoBD.Read
ProcesarUbicacion.Items.Add(New DatosListaElementos( _
CStr(infoBD!NombreCompleto), CInt(infoBD!ID)))
Loop
infoBD.Close()
infoBD = Nothing
ActualizarProcesarUbicacion()
Return

ErrorHandler:
GeneralError("FormularioPrincipal.TareaProceso", Err.GetException(
))
Resume Next

Proyecto | 639

22_PATRICK-CHAPTER_22.indd 639 18/2/10 11:20:09


Cada vez que el usuario selecciona una ubicacin diferente de la lista, necesitamos actualizar el
despliegue del estado. Agregue el siguiente cdigo al manejador de eventos ProcesarUbica-
cion_SelectedIndexChanged.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 16.

' ----- Actualizar el estatus con base en la ubicacion actual.


ActualizarProcesarUbicacion()

El procesamiento diario ocurre cuando el usuario hace clic en el botn Procesar. Agregue el
siguiente cdigo al manejador de eventos AccProcesar_Click.

Insercin de fragmento de cdigo


Inserte el fragmento de cdigo Cap22, Elemento 17.

' ----- Procesar todos los libros prestados.


Dim textoSql As String
Dim tablaBD As Data.DataTable
Dim filaBD As Data.DataRow
Dim idUbicacion As Integer

On Error GoTo ErrorHandler


Me.Cursor = Cursors.WaitCursor

' ----- Obtener la lista de todos los articulos que probablemente necesiten procesamiento.
textoSql = "SELECT PC.ID FROM CopiaCliente AS PC " & _
"INNER JOIN CopiarArticulo AS IC ON PC.CopiaArticulo = IC.ID "& _
"WHERE PC.Regresado = 0 AND PC.Faltante = 0 " & _
"AND IC.Faltante = 0 AND PC.FechaVencimiento < " & FechaBD(Today) & _
" AND (PC.FechaProceso IS NULL OR PC.FechaProceso < " & _
FechaBD(Today) & ")"
If (ProcesarUbicacion.SelectedIndex <> -1) Then
idUbicacion = CInt(CType(ProcesarUbicacion.SelectedItem, _
DatosListaElementos))
If (idUbicacion <> -1) Then textoSql &= _
" AND IC.Location = " & idUbicacion
Else
idUbicacion = -1
End If
tablaBD = CrearTablaDatos(textoSql)
For Each filaBD In tablaBD.Rows
ProcesamientoDiarioPorCopiaCliente(CInt(filaBD!ID), Today)
Next filaBD
tablaBD.Dispose()
tablaBD = Nothing
Me.Cursor = Cursors.Default

640 | Captulo 22:Otorgue licencia a su aplicacin

22_PATRICK-CHAPTER_22.indd 640 18/2/10 11:20:09


MsgBox("Procesamiento completo.", MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Information, TituloPrograma)
' ----- Actualizar la fecha de procesamiento.
textoSql = "UPDATE CodigoLugar SET UltimoProcesamiento = " & _
FechaBD(Today)
If (idUbicacion <> -1) Then textoSql &= _
" WHERE ID = " & idUbicacion
EjecutarSQL(textoSql)

' ----- Actualizar el despliegue de estatus.


ProcesarEstatus.Text = " El procesamiento esta actualizado."
ProcesarEstatus.ImageIndex = ImagenEstatusBueno
Return

ErrorHandler:
GeneralError("FormularioPrincipal.AccProcesar_Click", Err.GetException(
))
Resume Next

Pruebe el cdigo, ejectelo, localice un archivo de licencia vlido y pruebe las diferentes carac-
tersticas administrativas.
Esto marca el final de la colocacin de cdigo principal en el proyecto Biblioteca. Felicidades!
Pero todava hay algo mucho que hacer, como puede ver por la presencia de cuatro captulos
ms. Ahora no sera el momento de cerrar el libro y dar por terminado el da. Pero sera un buen
momento para aprender acerca de ASP.NET, el tema del siguiente captulo.

Proyecto | 641

22_PATRICK-CHAPTER_22.indd 641 18/2/10 11:20:09


Captulo 23
Desarrollo Web

Cuando sir Tim Berners-Lee (recibi el ttulo de caballero en 2004) invent World Wide Web
en 1989, realmente no era muy importante. Como el diseador principal de HTTP y HTML,
ciertamente no fue perezoso. Pero la mayor parte de las tecnologas para estructuracin y trans-
porte de pginas Web exista desde aos antes, incluso dcadas. SGML (la base de HTML) y
los sistemas de hipervinculacin han existido desde la dcada de 1960, y la transmisin de datos
basada en Internet entre clientes y servidores ya era comn entre campus de universidades y
algunos negocios. An as, aqu estamos en el siglo xxi, y World Wide Web es el centro de tanta
tecnologa computacional que hace que mi cabeza gire. Gracias, Sr. B-L.
Microsoft promueve .NET como el sistema para desarrollar pginas Web y software relacionado.
Y realmente es un buen sistema. Conforme nos adentremos en el cdigo, descubrir que cerca
de 90% de lo que hace para escribir aplicaciones Web en Visual Studio es idntico a lo que hace
cuando escribe aplicaciones de escritorio. Es fcil de hacer, y muy divertido, as que tal vez querr
escribir algunos programas. Y eso es lo que haremos en este captulo. Pero primero, revisemos
brevemente lo que pasa en el mundo de la comunicacin de World Wide Web.

Cmo funciona Internet


Antes de .NET, desarrollar aplicaciones para Web era difcil y aburrido. Y por buenas ra-
zones: World Wide Web no fue diseado como una plataforma de programacin o procesa-
miento lgico. Se orient originalmente por completo a enviar archivos de texto con formato
especializado de una computadora a otra. No haba ningn lenguaje de programacin que
aprender, ninguna lgica personalizada; slo texto simple, y tal vez una o dos imgenes grfi-
cas binarias.
Los primeros exploradores en realidad slo eran programas glorificados de copia de archivos.
Cuando iniciaba el explorador Mosaic (casi todo lo que haba en ese entonces) y peda una p-
gina Web de otra computadora, aqu se muestra lo que poda pasar:

642

23_PATRICK-CHAPTER_23.indd 642 17/2/10 15:33:39


1. El explorador Web determinaba la direccin IP del sistema remoto.
2. El explorador Web se pona en contacto con el sistema remoto por medio del nmero de
puerto 80 TCP/IP.
3. El sistema remoto aceptaba la conexin.
4. El explorador Web deca: Oye, estoy buscando un archivo llamado index.html. Me lo
podras enviar?
5. El sistema remoto deca: Lo tengo, y lo mandaba de inmediato.
6. El sistema remoto cerraba la conexin.
Mucho de este proceso est oculto de la vista, pero realmente puede ver cmo pasa. Si est inte-
resado, abra el indicador de comandos de Windows y escriba el siguiente comando:
telnet www.google.com 80

Esto ejecuta el programa Telnet, un programa de emulacin de terminal que permite conectarse
a sistemas remotos a travs de una interfaz de texto. (Telnet est instalado en Windows XP como
opcin predeterminada, pero es opcional en Windows Vista. Puede agregarlo a Windows Vista
mediante la applet Programas y caractersticas del Panel de control.) Telnet suele conectarse al
puerto 23 TCP/IP, pero puede especificarse el puerto que desee, como lo hicimos aqu con el
puerto WWW predeterminado de 80.
Es posible que su pantalla se quede en blanco, o que se quede as, como si estuviera muerta. Si
tiene suerte, ver un mensaje connected, pero tal vez no. Y est bien. Su sistema est conectado
al servidor Web de Google. Escriba el siguiente comando:
GET / HTTP/1.0

No olvide los espacios que rodean la primera diagonal. Despus de este comando oprima dos
veces la tecla Enter. Este comando pide al sistema remoto enviar la pgina Web predeterminada
en la parte superior de la jerarqua Web del servidor. Y porque lo pidi, lo har.
HTTP/1.0 200 OK
Cache-Control: private
Content-Type: text/html; charset=ISO-8859-1
Set-Cookie: PREF=ID=1c1dd342e463f3f1:TM=1199325226
:LM=1199325226:S=Pl-4f1fg4yh8Mvw7;
expires=Sat, 02-Jan-2010 01:53:46 GMT;
path=/; domain=.google.com
Server: gws
Date: Tue, 01 Jan 2008 01:30:00 GMT
Connection: Close

<html><head>
...resto del contenido de la pagina Web HTML aqui...
</body></html>

Connection to host lost.

Cmo funciona Internet | 643

23_PATRICK-CHAPTER_23.indd 643 17/2/10 15:33:39


Por supuesto, normalmente no ve todo esto. El explorador Web lleva a cabo este dilogo, y
amablemente forma la respuesta como una pgina Web. Esto es en realidad todo lo que hay
de World Wide Web. Ha experimentado las caractersticas principales: la trasferencia bsica de
datos a travs del puerto TCP/IP. Entonces, dnde entra la programacin?

Programacin de Internet
Las pginas estticas estuvieron bien por un tiempo, pero despus Internet se volvi montono.
Finalmente, alguien tuvo una brillante idea: Tenemos un programa en ejecucin en nuestro
servidor Web que est respondiendo a clientes, y alimentndolo de pginas pedidas. Qu pasa-
ra si pudiramos mejorarlo para que, en ciertas pginas, llamara a un programa o una secuencia
de comandos que generara el contenido HTML al vuelo y enviara de regreso el contenido al
cliente? Entonces cambiaron el proceso de servidor. Ahora, cuando el cliente peda una pgina
Web que terminaba con una extensin .cgi, el proceso de servidor Web ejecutaba la secuencia de
comandos que generaba el contenido. El sistema tambin proporcionaba los medios para con-
tenido proporcionado por el cliente para abrirse paso hasta la secuencia de comandos, haciendo
posible la personalizacin de caractersticas.
De ah, el paso era corto a la obtencin de una solucin genrica. En la plataforma de Microsoft,
el servicio de informacin de Internet (IIS, Internet Information Server) dio soporte a comple-
mentos a los que poda llamarse con base en la extensin del archivo solicitado. Esto llev, a las
pginas activas de servidor (ASP, Active Server Pages), una solucin que permiti a los desarro-
lladores incrustar secuencias de comandos del lado del servidor (a menudo utilizando VBScript,
una variacin de Visual Basic) en el contenido HTML, y que haca que ajustara el contenido
antes de enviarse al cliente.
Alguien ms dijo: Si podemos escribir secuencia de comandos en el lado del servidor, no po-
dramos tambin incluir una secuencia de comandos del lado del cliente justo en el contenido
HTML que un explorador Web inteligente pudiera procesar? Al poco tiempo, los desarrolladores
del lado del cliente y servidor estaban combatiendo en las calles, pero la batalla no lleg muy lejos,
porque todos los programadores estaban cansados. La causa? Programar en secuencia de coman-
dos! Ya sea incrustar secuencias de comandos en HTML (el lado del cliente) o generar HTML
desde una secuencia de comandos (el lado del servidor), la programacin de secuencia de coman-
dos es difcil, lenta, alta en colesterol malo y casi imposible de depurar interactivamente.
Algunos programadores de secuencias de comandos Web no haban usado un compilador de
lenguaje por aos, y estaban al borde del colapso debido a comas fatales inducidos por secuencia
de comandos. Se poda compilar lgica del lado del servidor en una DLL y usarlo para procesar
pginas Web, pero estaba lejos de ser sencillo, y estas DLL todava estaban a menudo vinculadas
en el contenido HTML por medio de secuencias de comandos cortas.
Despus lleg .NET y su soporte para desarrollo de aplicacin compilada del lado de servidor.
Los programadores de secuencias de comandos lanzaron un suspiro colectivo de alivio desde
sus camas de hospital; ahora podan usar el poder completo de los lenguajes Visual Studio y
.NET para generar contenido HTML. Y este nuevo sistema, ASP.NET, fue diseado para que se

644 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 644 17/2/10 15:33:39


pudiera disear una aplicacin Web completa sin ver siquiera una simple etiqueta HTML. La meta
de diseo: hacer desarrollo Web casi idntico al desarrollo de aplicaciones de escritorio. Y Micro-
soft tuvo mucho xito. No resolvi el problema de la secuencia de comandos de cliente (tal vez
pronto!), pero algunas de las caractersticas nuevas del lado del servidor incluidas en ASP.NET
redujeron en mucho la necesidad de secuencias de comandos personalizadas del lado del cliente.
Las pginas que se generan en ASP.NET se denominan Web Forms, y debido a que estn tan
unidas, algunas veces uso ASP.NET y Web Forms de forma intercambiable. Pero no son exacta-
mente la misma cosa: ASP.NET incluye Web Forms.

Caractersticas de ASP.NET
ASP.NET incluye muchos nuevos avances en tecnologa de desarrollo Web. Aqu se muestran
algunos de los ms famosos:
Cdigo compilado
Todo el cdigo que escriba para aplicaciones ASP.NET est totalmente compilado en ensam-
blados estndar DLL de .NET. Cuando el cliente pide un archivo con extensin .aspx, Internet
Information Server ubica este archivo (que contiene HTML o una combinacin de HTML/
ASP.NET) y la DLL compilada asociada, y los usa juntos para procesar el contenido de la p-
gina. Puede precompilar la DLL antes del despliegue, o permitir que ASP.NET lo compile al
vuelo la primera vez que se llama al archivo .aspx (aunque esto afecta un poco el rendimiento).
Soporte .NET
Las aplicaciones ASP.NET pueden acceder a .NET Framework Class Libraries (FCL, bi-
bliotecas de clase de .NET Framework) completas, excepto las que tienen como objetivo
especfico el desarrollo de escritorio. Cualquiera de las caractersticas y clases grandiosas que
tiene en aplicaciones .NET de escritorio estn en las aplicaciones Web tambin.
Basado en objeto
Las etiquetas HTML, como <textarea>, slo son en realidad cadenas de texto dentro de
un archivo de texto HTML ms grande. La creacin de secuencias de comandos del lado
de servidor antes de .NET fue un ejercicio de unin de cadenas, generando un archivo ms
grande de cadenas de contenido ms pequeas. ASP.NET trata a todos los elementos de
pgina Web como objetos verdaderos, junto con propiedades y eventos. Algunos de estos
objetos implementan controles complejos del lado del cliente, respaldados por cientos de
lneas de secuencia de comandos del lado del cliente que obtiene de manera gratuita.
Simplicidad de implementacin
Administrar secuencias de comandos del lado del servidor y personalizar DLL antes de
.NET no era muy divertido. Ciertos tipos de cabios requeran que se apagara por completo
Internet Information Server, o al menos que se deshiciera de la porcin que controlaba la
aplicacin que cambiaba. ASP.NET le permite hacer cambios en un sistema de produccin,
sin impactar a los usuarios activos. Si reemplaza una DLL compilada, ASP.NET empezar a
usarlo de inmediato, pero todava mantendr la versin antigua hasta que todos los clientes
existentes se hayan desconectado de sta.

Caractersticas de ASP.NET | 645

23_PATRICK-CHAPTER_23.indd 645 17/2/10 15:33:39


Independencia de explorador
Los objetos de pgina Web que se usan en ASP.NET tienen la responsabilidad de generar su
propio contenido HTML y sus secuencias de comandos del lado del cliente. Muchos de s-
tos toman el tipo y la versin del explorador del cliente en cuenta, mejorando o reduciendo
caractersticas de manera automtica, cuando sea necesario. Como desarrollador ASP.NET,
ni siquiera tiene que saber qu explorador se est usando.
Extensibilidad
Si quiere mejorar un elemento de pgina Web, puede derivarlo de su clase y agregar nuevas
caractersticas mejoradas, como lo hara con cualquier otra clase .NET.
Por supuesto, hay ms caractersticas grandiosas que las que se mostraron aqu. Pero tal vez ya
est listo para ver a ASP.NET en accin. Iniciemos.

Prueba de ASP.NET
Generemos una aplicacin ASP.NET muy simple, y examinmosla y examinemos sus partes para
descubrir de qu se trata.

Si est usando Visual Basic 2008 Express Edition, no podr seguir por com-
pleto estas instrucciones directamente porque ese producto no incluye ninguna
caracterstica ASP.NET o de desarrollo Web. En cambio, necesita descargar Vi-
sual Web Developer 2008 Express Edition del sitio Web de Microsoft MSDN
(http://msdn.microsoft.com/express). Su interfaz de usuario, aunque est muy
simplificada, ofrece mucha de la misma funcionalidad que el producto com-
pleto de Visual Studio. El tuturial incluido aqu fue escrito con Visual Studio
2008 Professional Edition.

Inicie Visual Studio y seleccione el comando de men Archivo Nuevo sitio Web. Aparece el
formulario Nuevo sitio Web (vase la figura 23-1). A diferencia de las aplicaciones de escritorio,
debe indicar de inmediato a Visual Studio dnde almacenar los archivos. Seleccionaremos una
ubicacin en el sistema de archivos local, pero este formulario tambin le permite trabajar en
un sitio Web remoto por medio de FTP o HTTP. Seleccione la plantilla Sitio Web ASP.NET,
inserte una ruta de directorio donde quiera almacenar los archivos y haga clic en el botn OK.
En la figura 23-2 se muestra Visual Studio listo para iniciar su nueva aplicacin Web (las barras
de herramientas desplegadas corresponden a mis preferencias).
El panel Explorador de soluciones ya muestra tres archivos y una carpeta incluida en el proyecto.
Si explora el directorio del proyecto (la ubicacin predeterminada en Windows Vista es C:\Users\
nombreusuario\Documents\Visual Studio 2008\WebSites\WebSite1) ver los mismos archivos. El
archivo web.config es un archivo XML que contiene configuraciones especficas de aplicacin;
est relacionado con el archivo app.config utilizado en aplicaciones de escritorio. Default.aspx es
la pgina Web, que contendr una mezcla de etiquetas y directivas HTML y ASP.NET especia-
les. El archivo Default.aspx.vb relacionado contiene el cdigo fuente tras el cdigo de Visual
Basic que en algn momento se compilar en un DLL.

646 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 646 17/2/10 15:33:39


Figura 23-1. Creacin de una nueva aplicacin ASP.NET.

Figura 23-2. Un formulario en blanco es algunas veces un buen signo.

Visual Studio tambin crea otra carpeta en C:\Users\nombreusuario\Documents\Visual Studio


2008\Projects\WebSite1. Esta carpeta contiene los archivos de solucin creados normalmente
con cualquier proyecto de Visual Studio. Se hacen a un lado para que no se incluyan con el sitio
Web desplegado.

Prueba de ASP.NET | 647

23_PATRICK-CHAPTER_23.indd 647 17/2/10 15:33:40


El rea en blanco que ve en Visual Studio es una pgina Web, en espera de texto y contenido
de control. Si quiere pruebas, haga clic en el botn de seccin Cdigo, en la esquina inferior
izquierda de la pantalla, o use el comando de men Ver Marcas. La ventana cambia a cdigo
HTML.
<%@ Page Language="VB" AutoEventWireup="false"
CodeFile="Default.aspx.vb" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Pgina sin ttulo</title>
</head>
<body>
<form id="form1" runat="server">
<div>

</div>
</form>
</body>
</html>

Bueno, casi todo es HTML. Hay una lnea en la parte superior que inicia con <%@ que no se ve
como HTML real (y no lo es). sta es una directiva de pgina ASP.NET. Incluye propiedades que
ayudan a guiar a ASP.NET en el procesamiento de la pgina. Tomando prestado un estndar de
su predecesor ASP, ASP.NET usa el par de parntesis angulares <%...%> para marcar comandos
y cdigo especfico de ASP.NET. (Tambin es posible que reconozca estos marcadores del cap-
tulo 13, porque se usan en literales XML.)
Ya basta de HTML. Quin quera verlo de todas formas? Haga clic en el botn de seccin Di-
seo, o use el comando de men Ver Diseador para regresar a la pgina en blanco.
Creemos una aplicacin que multiplique dos nmeros proporcionados por el usuario y desplie-
gue el resultado. Para esta caracterstica simple, podemos escribir algo de JavaScript e incluirlo
como una secuencia de comandos del lado del cliente, pero estamos tratando de evitar hacer
cosas como sas. Escriba lo siguiente en la pgina Web:
Para multiplicar dos valores, ingrselos en los
campos de texto y haga clic en el botn Multiplicar.

Hice que Multiplicar apareciera en negritas al usar la secuencia de teclas Ctrl-B, como lo hara
en un procesador de palabras. Oprima Enter una vez. Como opcin predeterminada, la pgina
Web coloca todos los elementos como un documento de procesamiento de palabras, un mtodo
denominado modo de diseo de flujo. Tambin puede usar posicionamiento absoluto de elementos
individuales para colocarlos en una ubicacin especfica de la pgina.
Existe otra forma de organizar elementos en la pgina: a travs de una tabla HTML. Agreguemos
una ahora. Use el men de comando Tabla Insertar tabla. Cuando aparezca el cuadro de dilo-
go Insertar tabla, especifique una tabla personalizada que sea de tres filas y dos columnas. Despus
haga clic en Aceptar. La tabla debe aparecer inmediatamente en el cuerpo de la pgina Web.

648 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 648 17/2/10 15:33:41


Escriba Operando 1: en la celda superior izquierda y escriba Operando 2: en la celda de abajo.
Su pgina debe verse como la de la figura 23-3.

Figura 23-3. Apenas iniciando en esta aplicacin.

No hay mucho que ver, pero se pondr mejor. Hasta ahora, no hemos hecho mucho ms de lo
que podramos hacer en el Bloc de notas. Pero ahora estamos listos para agregar algunos con-
troles. Si abre el cuadro de herramientas, ver controles muy parecidos a los que se encuentran
en una aplicacin Windows Forms (vase la figura 23-4).

Figura 23-4. Algunos de los cuadros de herramienta de Web Forms.

Los controles se agrupan por funcionalidad:


Estndar
Por lo general, usar los controles de esta seccin para generar la interfaz de usuario de su
pgina Web. Muchos de estos controles representan controles estndar de ventanas, con
paralelos directos en el mundo de Windows Forms. Por ejemplo, la entrada ListBox im-
plementa un control estndar ListBox de Windows dentro de la pgina Web. Para usted,
el programador, estos controles se ven como clases de control .NET estndar, con pro-
piedades, mtodos y eventos. Para el usuario final, se ven como controles de pgina Web
estndar, entregados mediante HTML comn. Algunos de estos controles compuestos:
controles sencillos generados a partir de varios controles HTML que funcionan juntos,
mientras algunas secuencias de comandos del lado del cliente hacen algo del trabajo.

Prueba de ASP.NET | 649

23_PATRICK-CHAPTER_23.indd 649 17/2/10 15:33:42


Datos
Los controles de datos manejan interacciones de unin de base de datos. Como recordar de
captulos anteriores, no soy muy fantico de los controles de unin en aplicaciones estndar.
Pero cuando se estn comunicando datos estticos a travs de la pgina Web, en realidad
ahorran mucho tiempo. Algunos de estos controles realizan la unin de datos, mientras
otros realizan la presentacin de datos real.
Validacin
Los usuarios son muy divertidos, sobre todo cuando insertan datos absurdos en su programa
con calidad. Verificar los datos que insertan es difcil en aplicaciones de escritorio, pero es
an ms difcil cuando el sistema cliente habla a la aplicacin host a slo unas cuantas doce-
nas de segundos por hora. Los controles de validacin eliminan algo de la carga. Prueban los
tipos ms comunes de errores de insercin de datos y notifican al usuario los problemas, sin
cdigo adicional de su parte. Cuando s necesita realizar alguna validacin lgica personali-
zada, el control CustomValidator permite agregar esta lgica como manejador de eventos
o secuencia de comandos del lado del cliente.
Navegacin
Este grupo incluye unos cuantos controles diseados para ayudar al usuario a ir de una
pgina a otra, o de una seccin a otra dentro de su sitio Web.
Inicio de sesin
Estos controles encapsulan las caractersticas de administracin de inicio de sesin y con-
trasea para que el usuario pueda crear una nueva cuenta de usuario, proporcione una
contrasea autenticada o realice otras acciones relacionadas a seguridad.
WebParts
WebParts son contenedores de controles que el usuario reordena mediante arrastre y coloca-
cin dentro de la pgina Web. Esta reorganizacin de la pantalla permite al usuario personali-
zar la pantalla para satisfacer sus deseos egostas que nublan su mente. Puede registrar el estado
de WebParts para volverlo a desplegar la siguiente vez que el usuario regrese al sitio o pgina.
Extensiones AJAX
El puado de controles de esta seccin ayuda a dar soporte a la funcionalidad Ajax de ASP.
NET. Ajax (Asynchronous JavaScript and XML, JavaScript y XML asincrnicos) es un
conjunto de tecnologas basadas en Web que ayuda a hacer que las pginas Web sean ms
sensibles, sobre todo mediante actualizacin parcial de pginas. Ajax est ms all del alcan-
ce de este libro.
Informe
Aqu encontrar el control ReportViewer, la versin Web de la tecnologa de informes que
analizamos en el captulo 21. Despliega informes al usar los mismos archivos RDLC que
gener para su aplicacin de escritorio.
HTML
stos son los controles estndar HTML, como <textarea>, que los desarrolladores de p-
ginas Web han usado por aos. Visual Studio proporciona algo de IntelliSense y validacin

650 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 650 17/2/10 15:33:42


de propiedad, pero usar estos controles es idntico a escribir la etiqueta HTML que coincide
directamente en el marcado de pgina.
Agreguemos unos cuantos controles de la seccin Estndar del cuadro de herramientas a la pgina
Web. En la celda inferior izquierda de la tabla que agregamos antes, agregue un control Button,
asgnele el nombre AccMultiplicar y establezca su propiedad Text en Multiplicar.
Agregue dos controles TextBox en las dos celdas superiores, en la columna de tabla que se encuen-
tra a la derecha. D a uno de stos el nombre PrimerOperando y al otro SegundoOperando.
Agregue un control Label a la celda de la esquina inferior derecha de la tabla. Asgnele el nom-
bre Producto, y establezca su propiedad Text en 0 (cero).
Observ que establecer cada propiedad para estos controles no fue diferente de lo que hizo en
la aplicacin principal Biblioteca? Simple! Por ahora, su pgina Web debe verse como la de la
figura 23-5.

Figura 23-5. La interfaz de usuario completa.

Regrese brevemente al marcado HTML para esta pgina al hacer clic en el botn de seccin
Cdigo, en la parte inferior de la pgina. Si est familiarizado con HTML, puede observar la
etiqueta <table> de la tabla que agregamos. Pero tambin encontrar algo poco familiar dentro
de la primera fila de la tabla.
<table class="style1">
<tr>
<td>
Operand 1:
</td>
<td>
<asp:TextBox ID="PrimerOperando"
runat="server"></asp:TextBox>
</td>
</tr>

Es esa etiqueta </asp:TextBox>. Se parece un poco a otras etiquetas HTML, pero no hay eti-
quetas HTML que inicien con asp. sta es una etiqueta ASP.NET especial que representa una
clase de control Web Forms. Estos controles, y los atributos runat="server" que se distribuyen
a travs del marcado, son lo que hace que las pginas ASP.NET sean lo que son. Conforme ASP.
NET procesa la pgina .aspx, quita estas etiquetas de control personalizadas y llama a los contro-
les relacionados para generar su propio explorador neutral HTML.

Prueba de ASP.NET | 651

23_PATRICK-CHAPTER_23.indd 651 17/2/10 15:33:42


La interfaz de usuario est lista; agreguemos la lgica. Queremos que el programa multiplique
dos operadores cuando hacemos clic en el botn Multiplicar. Regrese al diseo de la pgina Web
y haga doble clic en el botn Multiplicar. Salta a la plantilla de cdigo para un evento Click del
botn, como era de esperar que lo hiciera.
Partial Class _Default
Inherits System.Web.UI.Page

Protected Sub AccMultiplicar_Click(ByVal sender As Object, _


ByVal e As System.EventArgs) Handles AccMultiplicar.Click

End Sub
End Class

La meta de diseo de ASP.NET fue tener cdigo que fuera lo ms cercano posible al cdigo de la
aplicacin de escritorio, y as es. Agregue la siguiente lgica al manejador de eventos:
' ----- Multiplicar los dos numeros.
Producto.Text = Val(PrimerOperando.Text) * _
Val(SegundoOperando.Text)
If (Val(Producto.Text) < 0) Then
Producto.ForeColor = Drawing.Color.Red
Else
Producto.ForeColor = Drawing.Color.Black
End If

A medida que escriba, observ todo el IntelliSense respondiendo a cada teclazo que daba? No
poda indicar que fuera una aplicacin basada en Web, y eso es grandioso.
Oprima la tecla F5 para iniciar la aplicacin. Se le pedir que active la depuracin, que es lo
que quiere hacer. Esto modificar el archivo web.config de la aplicacin para dar soporte a de-
puracin. Ms adelante, querr deshabilitar esa caracterstica para que sus usuarios no puedan
depurar la aplicacin. Si abre el archivo web.config, ver esta lnea:
<compilation debug="true" strict="false" explicit="true"/>

Slo cambie el atributo debug a false para desactivar la depuracin.


ASP.NET es una aplicacin de servidor; requiere un servidor Web vivo y respirando antes de que
las pginas puedan procesarse. Tal vez tenga o no instalado Internet Information Server en su
sistema, pero est bien. Visual Studio 2008 incluye su propio ASP.NET Development Server
que slo existe para que pueda probar sus aplicaciones ASP.NET. En la figura 23-6 se muestra
brotando en la bandeja del sistema.

Figura 23-6. Su servidor Web integrado intenta dar buen servicio.

652 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 652 17/2/10 15:33:43


En la figura 23-7 se muestra la aplicacin ejecutndose en mi explorador Web predeterminado,
Internet Explorer. (Queridas compaas de exploradores Web, para informacin sobre coloca-
cin de producto en esta pgina, contctenme directamente.)

Figura 23-7. Guau!, una aplicacin Web completa en menos de 10 lneas de cdigo.

Si no le gusta cmo se expande la tabla por la pgina, puede ajustarla con el panel CSS Proper-
ties. De regreso a Visual Studio, seleccione el comando de men Ver Propiedades de CSS. El
panel se abre y se ajusta a s mismo dependiendo del elemento de pgina que tenga seleccionado.
Para eliminar el romance de la tabla con el borde derecho, seleccione la tabla, desplcese a la
propiedad ubicacin/width y elimine el valor 100% de esa entrada de propiedad.

Ms acerca de eventos
Hasta ahora, nuestra aplicacin se ve como una de escritorio; el formulario despliega nuestras
configuraciones iniciales de arrastrar y colocar y de propiedades, y responde a un clic de botn al
regresar a la computadora de procesamiento para la lgica. Pero seamos honestos. No hay forma
de que una aplicacin Web alguna vez pueda responder a la misma cantidad de eventos que una
aplicacin de escritorio. Qu pasa cuando la conexin de Internet falla o est muy lenta? Cmo
maneja cosas como eventos TextChanged en campos de texto? No puede hacer que la pgina
Web regrese a la pgina de servidor cada vez que el usuario oprime una tecla.
El control TextBox ASP.NET tiene un evento TextChanged, pero no se activa para cada tecla-
zo. En realidad, no se activa nunca (como opcin predeterminada) hasta que algo (como un clic
de botn) causa que la pgina regrese al servidor. Y ah existen muchos otros eventos de control
que funcionan de esta forma. Todos estn guardados hasta que el usuario hace algo para traer
toda la pgina al servidor Web para procesamiento. En ese momento, estos eventos retrasados
finalmente se encienden, y el procesamiento contina como es normal.

Ms acerca de eventos | 653

23_PATRICK-CHAPTER_23.indd 653 17/2/10 15:33:43


Entonces, existen realmente dos tipos de eventos: regular y premium. Me refiero a postback y
nopostback. Los eventos postback son los que causan que la pgina Web regrese de inmediato
al servidor para procesamiento. Los eventos nopostback retrasan sus manejadores de evento
hasta que algo causa un regreso al servidor. Casi todos los eventos son de uno u otro tipo,
pero algunos pueden cambiarse. El control CheckBox tiene un evento CheckedChanged que
activa una forma nopostback cuando el usuario altera el estado de una casilla de verificacin.
Sin embargo, si establece la propiedad AutoPostBack del control en True, la pgina regresar
de inmediato al servidor en cualquier momento que el usuario haga clic en la casilla de verifi-
cacin.
Adems de los eventos de control, la pgina completa tiene unos cuantos eventos. El ms im-
portante es Page_Load. Esto es anlogo al evento Form_Load de Windows Form; es un buen
lugar para configurar propiedades de control inicial, llenar listas desplegables, etc. Voy a agregar
el siguiente cdigo al evento Load de mi pgina:
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
' ----- Inicializar los datos.
Producto.Text = "Sin datos"
End Sub

Ahora la etiqueta Producto desplegar Sin datos la primera vez que aparece la pgina. Lo
importante del evento Load es que se ejecuta cada vez que la pgina Web se despliega. Debido a
que esta aplicacin de prueba sigue usando la misma pgina una y otra vez para sus resultados,
el manejador de eventos Load se ejecutar de nuevo cada vez. Este programa de prueba no es
realmente importante; el cdigo en el manejador de eventos AccMultiplicar_Click pasa por
alto su valor inicial Sin datos. Pero en otras aplicaciones tal vez no quiera seguir reinicializando
los datos. Por fortuna, el evento Load le permitir saber si sta es la primera vez que se ejecuta
mediante un miembro de nivel de pgina llamado IsPostBack.
' ----- Initializar los datos, pero solo la primera vez.
If (Me.IsPostBack = False) Then Producto.Text = "Sin datos"

Estado y vista de estado


Espere un minuto. Si estoy recargando la pgina desde cero cada vez y es necesario inicializar va-
lores en el manejador de eventos Page_Load, cmo es que los dos cuadros de texto mantienen
los valores insertados por el usuario cuando la pgina se recarga? No agregamos ningn cdigo
para guardar y restaurar esos valores durante la inicializacin.
Aqu est la historia. Aunque el evento Page_Load le da la oportunidad de inicializar la pgina
cada vez que la pgina se carga, la pgina recordar lo que se encuentra en la mayor parte de los
campos. Recuerde que ASP.NET est diseado para que piense que se est ejecutando como una
aplicacin de Windows Forms. Nunca estara feliz si los campos de su formulario de escritorio
se borraran cada vez que el usuario hace clic en un botn. Tampoco estara feliz si se borraran en
una aplicacin Web Forms.

654 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 654 17/2/10 15:33:43


Debido a que casi siempre las pginas Web estn desconectadas del servidor Web, cada pgina
Web necesita alguna forma de retener el estado (la propiedad actual y las configuraciones de
datos) de cada control entre cargas de pgina. El sistema Web Forms hace esto mediante una
caracterstica denominada View State. Aqu se muestra cmo funciona: cada pgina Web de ASP.
NET incluye un campo esttico oculto que contiene una versin serializada de toda la informa-
cin de estado importante para los controles. Cuando el usuario hace cambios a cada control
y activa algn evento que regresa la pgina al servidor Web, regresa con View State incrustado
(generado de la construccin anterior de la pgina) y todas las configuraciones actuales para cada
control. Al usar informacin combinada, ASP.NET puede reconstruir el estado real visible de
cliente de cada control, y comunicar correctamente eso en su cdigo de manejador de eventos
del lado del servidor.
Cuando ejecute una aplicacin ASP.NET, use el comando de men Ver Cdigo fuente en
Internet Explorer o su explorador favorito del mes, y ver algo como lo siguiente:
<input type="hidden" name="_ _VIEWSTATE" id="_ _VIEWSTATE"
value="/wEPDwUKMTEyMTc3MTQwNg9kFgICAw9kFgICBw8P
FgIeBFRleHQFB05vIERhdGFkZGQME+xLedutk85TvXy9OJd
kQF02YA==" />

Eso es View State. No me pregunte cmo funciona; no se lo dir (porque no lo s). Pero no es
importante saberlo. Slo es importante que ASP.NET sepa cmo funciona para que pueda man-
tener su aplicacin en funcionamiento como el sistema Windows Forms no lo hace.
Conforme agregue controles a su pgina, aumentar el tamao de View State. Debido a que
todo el contenido de pginas Web debe transportarse varias veces por Internet, un View State
ms grande lleva a tiempos de transmisin ms largos. Es posible desactivar View State para
controles especficos mediante la propiedad EnableViewState. Si no necesita que el valor de
un control se retenga tras cada uso de una pgina, es una buena idea desactivarlo.

Validacin de datos
Debido a que este cdigo de ejemplo usa la funcin Val de Visual Basic para preprocesar los
datos proporcionados por el usuario, casi siempre funciona sin error. Cualquier dato considera-
do invlido simplemente se convierte en cero. Otra opcin sera castigar al usuario por insertar
datos que no son vlidos antes de que el procesamiento ocurra, para validar los valores propor-
cionados. Los cinco validadores en la seccin Validation del cuadro de herramientas de Web
Forms le ayudan a hacer eso:
RequiredFieldValidator confirma que el usuario proporcione cualquier valor en un
control.
RangeValidator se queja si el valor de un control no cae entre dos valores.
RegularExpressionValidator le permite comparar el valor de un control contra un pa-
trn de expresin regular. Por ejemplo, puede comparar la entrada del usuario de un nmero
de serie con un patrn, para asegurarse de que incluya dos letras seguidas de cinco dgitos.

Validacin de datos | 655

23_PATRICK-CHAPTER_23.indd 655 17/2/10 15:33:43


CompareValidator afecta a dos controles, comparando el valor entre ellos. El control tam-
bin duplica una funcin similar como validador de tipo de datos, confirmando que un solo
campo contiene el tipo apropiado de datos, como un valor de fecha o un entero.
CustomValidator le permite realizar cualquier tipo de validacin que quiera a travs del
cdigo que proporcione.
Todos estos controles realizan validacin del lado del servidor, y como opcin hacen su revisin
de datos al usar secuencias de comandos del lado del cliente (la opcin predeterminada). Las
revisiones del lado del cliente reducen la necesidad de regresar al servidor Web slo para asegurar
que un campo requerido tenga datos. Tener la revisin del lado del servidor asegura que los datos
sean vlidos, aunque el cliente ha deshabilitado el soporte para secuencias de comandos.
Los validadores despliegan sus propios mensajes de error, as que se colocan en la pgina donde
quiere que los mensajes de error aparezcan. Tambin puede hacer que varios validadores desplie-
guen sus problemas colectivos en una sola ubicacin al usar un control ValidationSummary.
Agreguemos algo de validacin a dos campos de entrada del ejemplo de multiplicacin. Quere-
mos asegurar que se proporcionen los datos y que ambos valores sean enteros vlidos. Para esto,
debemos agregar un RequiredFieldValidator y un CompareValidator a cada campo. Haga
clic con el botn derecho en la celda de la esquina inferior derecha de la tabla, justo despus de
la etiqueta Producto, y seleccione Insertar Columna a la derecha, del men desplegable que
aparece. En la nueva celda superior derecha, agregue un control RequiredFieldValidator.
Establezca las propiedades siguientes:
Establezca ControlToValidate en PrimerOperando.
Establezca Display en Dynamic. Esto permite que el tamao del validador se reduzca a
nada cuando no hay algn error que desplegar.
Escriba Faltante en ErrorMessage.
Justo a la derecha de ese validador, en la misma celda de tabla, agregue un control CompareVa-
lidator, y establezca estas propiedades:
Establezca ControlToValidate en PrimerOperando.
Establezca Display en Dynamic.
Escriba Debe ser un entero en ErrorMessage.
Establezca Operator en DataTypeCheck.
Establezca Type en Integer.
Agregue un par similar de validadores a la segunda fila de la tabla, usando SegundoOperando
para los controles. Su pgina Web debe verse como la figura 23-8.
Ejecute el programa y trate de insertar datos incorrectos en las celdas de insercin. La pgina se
quejar inmediatamente cuando haga clic en el botn Multiplicar.
sa es toda la multiplicacin que haremos por ahora. He guardado una copia del proyecto en el
subdirectorio SitioWeb1 en el directorio principal donde instal el cdigo de ejemplo de este libro.

656 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 656 17/2/10 15:33:43


Figura 23-8. Aumento del soporte de validacin.

Integracin de base de datos


Conectar pginas ASP.NET a una base de datos, sobre todo si usa alguna caracterstica estilo asis-
tente de Visual Studio, es realmente sencillo. Eso se debe a que muchos de los controles incluidos
con ASP.NET estn diseados especficamente para desplegar e interactuar con datos de origen
tabulares. Probaremos un asistente rpido de ejemplo aqu, y haremos mucha ms integracin
de base de datos en la seccin Proyecto de este captulo.
En el captulo 20, el primero de cinco informes integrados que creamos para el sistema Biblio-
teca desplegaba una lista de todos los elementos revisados. Diseamos un informe RDLC para
ste, y como ASP.NET incluye un control RDLC Report Viewer, podemos volver a utilizarlo
para crear un informe Web. En cambio, desplegaremos el informe al usar uno de los controles
Web Forms, GridView. Aqu se muestra la consulta que recupera los elementos revisados:
SELECT PA.Apellido + ', ' + PA.Nombre AS NombreCliente,
PA.CodigoBarras AS CodigoBarrasCliente,
PC.FechaVencimiento, IC.NumeroCopias, IC.CodigoBarras AS CodigoBarrasArticulo,
NI.Titulo, CMT.NombreCompleto AS Inicial
FROM Cliente AS PA
INNER JOIN CopiaCliente AS PC ON PA.ID = PC.Cliente
INNER JOIN CopiaArticulo AS IC ON PC.CopiaArticulo = IC.ID
INNER JOIN ArticuloConNombre AS NI ON IC.IDArticulo = NI.ID
INNER JOIN CodigoTipoMedio AS CMT ON NI.TipoMedio = CMT.ID
WHERE PC.Regresado = 0
AND PC.Faltante = 0
AND IC.Faltante = 0
ORDER BY NI.Titulo, IC.NumeroCopias, PA.Apellido, PA.Nombre

Eso debe verse familiar. Cree un nuevo sitio Web ASP.NET en Visual Studio. Escriba la siguiente
lnea en la parte superior de la pgina de contenido:
Biblioteca ACME Artculos prestados

Sintase libre de embellecerlo para que se vea mejor. Yo agregu las etiquetas <h1> alrededor
en el marcado para que se destaque. Debajo de esa lnea de ttulo, agregue un nuevo control
GridView a la pgina. Yo lo encontr en la seccin Datos de mi cuadro de herramientas de Vi-
sual Studio. La etiqueta inteligente del control se abre y muestra un panel Tareas de GridView,
como se muestra en la figura 23-9.

Integracin de base de datos | 657

23_PATRICK-CHAPTER_23.indd 657 17/2/10 15:33:44


Figura 23-9. Una lista corta de tareas para el control GridView.

Si quiere hacer clic en la tarea Formato automtico y cambiar la apariencia de la cuadrcula,


puede hacerlo, pero la tarea importante ahora es Elegir origen de datos. Seleccione <Agregar
nuevo origen> de la lista. Nuestro viejo amigo el Asistente para la configuracin de orgenes de
datos aparece nuevamente, aunque con algunos cambios especficos para ASP.NET. Seleccione
Base de datos, como tipo de origen de datos, y haga clic en el botn Aceptar. Cuando se le pida
la conexin, ya debe tener una conexin de base de datos Biblioteca en la lista. Seleccinela
(o cree una nueva conexin) y haga clic en Siguiente.
Se le pedir que guarde la cadena de conexin en el archivo de configuracin de la aplicacin. Si
lo hace, agregar una entrada a la seccin <connectionStrings> del archivo web.config creado
para la aplicacin ASP.NET. Si desea participar en juegos de poder con su administrador de sis-
tema, deje este campo sin marcar. Pero si quiere una forma sencilla de modificar la informacin
de conexin ms adelante, mejor deje este campo como est, dndole a la entrada un nombre
razonable. Haga clic en Siguiente.
El asistente le pide detalles de una tabla y campos. Seleccione Especificar una instruccin SQL
o un procedimiento almacenado personalizado, haga clic en Siguiente y escriba la consulta
de artculos prestados mostrada hace unos prrafos. Haga clic en Siguiente nuevamente. El
asistente le da una ltima oportunidad de probar la consulta antes de que haga clic en el botn
Finalizar.
Ahora aqu viene la parte simple. Visual Studio conecta la base de datos, lee el esquema y crea
columnas en la cuadrcula perfectamente diseadas para la consulta. Su aplicacin est comple-
tada. Presione F5 para ejecutarla.
Vamos a detenernos ah por ahora y continuar con esto en la seccin Proyecto.

Base de comunicacin de Windows


Alguna vez ha querido extraer una pieza de datos de un sitio Web para usarlo en su aplicacin
de Visual Basic? No? Bueno djeme decirle: se llama rascado de pantalla, y es un dolor en el
cuello. Casi todos los sitios Web con contenido valioso estn diseados por personas egostas,
programadores que slo piensan en las necesidades de su propia compaa y nada acerca de otros

658 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 658 17/2/10 15:33:44


desarrolladores que necesitan hurtar datos esenciales (digo, quin necesita agregar valor a sus
propias aplicaciones al mejorarlas con contenido de un tercero confiable).
El rascado de pantalla suele ser algo malo. No slo el contenido HTML es ridculamente difcil
de analizar, sino que nunca sabe cundo el dueo del sitio Web va a cambiar el contenido sin
la cortesa de contactarnos primero. Por fortuna, la base de comunicacin de Windows (Win-
dows Communication Foundation) proporciona una solucin a este problema. Esta tecnologa
esencial de Microsoft, antes llamada Indigo, existe para transportar datos significativos entre
aplicaciones y sistemas, locales o remotos.
La base de comunicacin de Windows, por lo general abreviado WCF, une varias tecnologas
distintas en un todo unificado: consultas de mensajes (como MSMQ), servicios Web (vase la
nota a continuacin), transacciones distribuidas (como MSDTC) y .NET Remoting. Ya que
cada una de estas tecnologas requiere el desplazamiento de informacin de una aplicacin a
otra, fue una decisin sencilla para Microsoft gastar ms dinero del que vera normalmente en
un servicio combinado.
Si un sitio tiene contenido o procesos que necesitan usarse por aplicaciones externas, puede
incluir un servicio en el sitio que hace rascado de pantalla innecesario. WCF implementa el
equivalente basado a intersistema de llamadas de funcin, junto con parmetros y valores de
regreso, que pueden accederse de manera remota. Estn basados en estndares publicados, como
el protocolo simple de acceso a objetos (SOAP, Simple Object Access Protocol), que usa texto
simple y XML para simular la funcin de llamada entre dos sistemas.

Antes de Visual Studio 2008, los desarrolladores de .NET utilizaban un sistema


denominado XML Web Services que proporcionaba funcionalidad similar a la
porcin de servicios de WCF. Si quiere usar XML Web Services, todava est
disponible en Visual Studio 2008. Sin embargo, Microsoft est recomendando
que el nuevo software use WCF en lugar de XML Web Services.

Muchas tecnologas intervienen para hacer WCF posible, pero no necesita conocerlas. En cam-
bio, implementar uno o ms mtodos de Visual Basic basados en una interfaz que usted defina.
Esta interfaz, marcada con atributos especficos de WCF, establece el contrato de servicio que
hace posible la comunicacin funcional entre dos sistemas.
Los servicios WCF aparecen como archivos .svc en su sitio Web. En Visual Studio puede crear
un nuevo sitio Web y seleccionar WCF Service como tipo de proyecto, o agregar un elemento
WCF Service a un proyecto de sitio Web existente. Cuando lo hace, Visual Studio agrega los
archivos necesarios a su proyecto. El primero es el archivo real .svc. Es una interfaz inteligente
conducida entre el sitio Web y el cdigo de servicio Web real. Aqu est lo que he encontrado
en mi archivo Service.svc:
<%@ ServiceHost Language="VB" Debug="true" Service="Service"
CodeBehind="/App_Code/Service.vb" %>

Base de comunicacin de Windows | 659

23_PATRICK-CHAPTER_23.indd 659 17/2/10 15:33:45


Esta directiva hace referencia al que llama a la clase Service en el archivo de cdigo fuente aso-
ciado Service.vb. Ese archivo es mucho ms interesante. Aqu se muestra una parte del archivo:
Public Class Service
Implements IService

Public Function GetData(ByVal value As Integer) _


As String Implements IService.GetData
Return String.Format("You entered: {0}", value)
End Function
End Class

Esto se ve como cdigo de ejemplo para m, y lo reemplazar cuando escriba su propio servicio.
La clase Service en el cdigo implementa los miembros de la interfaz IService, encontrados
en el archivo relacionado IService.vb.
<ServiceContract()> _
Public Interface IService
<OperationContract()> _
Function GetData(ByVal value As Integer) As String
End Interface

Como se mostr, esta interfaz tambin contiene un miembro sin importancia de ejemplo, Get-
Data, que debe reemplazarse. Est marcado con el atributo enfocado en WCF <OperationCon-
tract> que, junto con el atributo <ServiceContract> de la interfaz, declara: Hay servicios
de WCF aqu. Recuerde que un atributo agrega metadatos a un ensamblado para que el compi-
lador u otro programa hagan algo especial con los elementos marcados. En este caso, el atributo
<OperationContract> le indica a WCF que trate el mtodo GetData (cuando se implementa)
como un miembro de servicio. WCF responde al conectar toda la plomera de cdigo que hace
el servicio posible.
Voy a reemplazar la funcin GetData con otra que al menos pretenda hacer algn trabajo real.
Primero, cambiar la interfaz IService para que defina el contrato.
<ServiceContract()> _
Public Interface IService
<OperationContract()> _
Function NumeroATexto(ByVal numeroOrigen _
As Integer) As String
End Interface

Despus, en la clase Service, implementar la interfaz y su miembro NumeroATexto.


Public Class Service
Implements IService

Public Function NumeroATexto(ByVal numeroOrigen As Integer) _


As String Implements IService.NumeroATexto
Select Case numeroOrigen
Case 0 : Return "Cero"
Case 1 : Return "Uno"
Case 2 : Return "Dos"
Case 3 : Return "Tres"

660 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 660 17/2/10 15:33:45


Case 4 : Return "Cuatro"
Case 5 : Return "Cinco"
Case 6 : Return "Seis"
Case 7 : Return "Siete"
Case 8 : Return "Ocho"
Case 9 : Return "Nueve"
Case Else : Return "Fuera de rango"
End Select
End Function
End Class

Si ejecuta esta aplicacin en Visual Studio, su explorador Web se abrir con la pgina (parcial)
que se muestra en la figura 23-10.

Figura 23-10. Un servicio WCF ejecutndose en su explorador Web.

Los servicios WCF son mtodos, y un explorador Web no es un medio tpico prctico para
ejecutar subrutinas y funciones, as que aparece, en cambio, la pgina de la figura 23-10. Su
contenido informativo le muestra cmo puede probar o usar el servicio, ya sea a travs de una
utilera diseada para ese fin, o a travs de cdigo Visual Basic o C#.
Ya que tengo este servicio en ejecucin en mi sistema al usar mi servidor Web de prueba ASP.NET,
escribir una aplicacin de escritorio para llamar al mtodo NumeroATexto. Iniciar una instancia
separada de Visual Studio y crear un nuevo proyecto Windows Forms. Seleccione el comando de
men Proyecto Agregar referencia de servicio. Aparece el formulario Agregar referencia de servi-
cio; se trata de una herramienta que se usa para ubicar servicios WCF locales y remotos.
Puede pedir especficamente el servicio si sabe su direccin. Para determinar esto, haga doble
clic en el cono ASP.NET Development Web Server en la bandeja del sistema. El campo Root
URL proporcionar la base de la direccin. En mi sistema en este momento particular dice
http://localhost:49210/WebSite2, aunque, como predeterminada, cambiar nmeros de puer-
to si reinicio el servicio. Agregue esto al nombre del archivo .svc para su servicio.
http://localhost:49210/WCFService1/Service.svc

Base de comunicacin de Windows | 661

23_PATRICK-CHAPTER_23.indd 661 17/2/10 15:33:45


Inserte esta direccin en el campo Address del formulario Agregar referencia de servicio y haga
clic en Ir. Si tiene xito, la forma ubica el servicio y despliega sus contratos en el campo Servicios.
En la figura 23-11 se muestra el operador ubicado NumeroATexto. Puede proporcionar acceso
con nombre al servicio en su cdigo al cambiar el campo NameSpace. Despus haga clic en el
botn OK.

Figura 23-11. Un servicio Web reconocido.

Para probar nuestro servicio, agregu un control TextBox y uno Button a Form1, y agregu el si-
guiente cdigo (us el nombre de espacio de servicio predeterminado de ServiceReference1):
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
MsgBox((New ServiceReference1.ServiceClient). _
NumeroATexto(CInt(Val(TextBox1.Text))))
End Sub

Ejecute el programa, escriba un nmero del 0 al 9 y despus haga clic en el botn para llamar
correctamente al servicio Web y obtener la versin en espaol del nmero. Y hubiera funciona-
do bien igualmente si el servicio NumeroATexto se ejecutara en un servidor Web en una de las
instalaciones de investigacin en el Polo sur.

662 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 662 17/2/10 15:33:46


Resumen
Realmente sola odiar la escritura de aplicaciones ASP. Era doloroso incrustar VBScript dentro
de contenido HTML. Aunque ASP.NET todava da soporte a una variacin de este mtodo, es
mucho mejor usar el cdigo detrs de las caractersticas de Web Forms. Esto hace que el desarro-
llo Web sea un poco ms complicado que el de aplicacin de escritorio. La base de comunicacin
de Windows tambin hace interacciones entre el cdigo Web alojado en el servidor y el de escri-
torio con slo desarrollar una clase con mtodos.
Cuando Microsoft surgi por primera vez con .NET Framework, su departamento de mercado-
tecnia realmente aplic fuerza a la promocin de los aspectos de desarrollo Web de Visual Studio.
Yo tena mis dudas. Y todava aunque soy, sobre todo, un desarrollador de aplicaciones de escrito-
rio, ya no pierdo una semana de sueo cuando contemplo generar aplicaciones para Internet.

Proyecto
Para el proyecto de este captulo gener un sitio Web simple de varias pginas que 1) permite
al usuario buscar elementos en la base de datos Biblioteca y 2) duplica el informe Estadstica
de biblioteca creado en el captulo 21, pero sin el componente RDLC. Fui ms all e inclu un
proyecto completado en su directorio de cdigo fuente instalado, en el subdirectorio SitioWeb-
Biblioteca. Puede abrirlo al ubicar su directorio con el comando de men Archivo Abrir sitio
Web en Visual Studio.
Como se muestra en la figura 23-12, el proyecto incluye 11 archivos y dos subdirectorios.

Figura 23-12. Los archivos de proyecto del sitio Web Biblioteca.

Proyecto | 663

23_PATRICK-CHAPTER_23.indd 663 17/2/10 15:33:46


Aqu se muestra un informe rpido de cada archivo y su subdirectorio:
App_Code
El directorio de todo el cdigo del proyecto que no est codificado detrs de una pgina
Web ASP.NET real. Todos sus mdulos generales y clases para un proyecto aparecen aqu.
General.vb
Un mdulo de cdigo con seis mtodos que rob casi literalmente del archivo General.vb
del proyecto Biblioteca principal. Hice slo algunos cambios, sobre todo para tratar con no
tener la variable global BDBiblioteca junto a su informacin de conexin.
EsquemasUnidos.vb
Cuando empezamos el informe de artculos prestados antes en este captulo, unimos un
control GridView a una consulta de base de datos. El control GridView, como todos los
controles de Web Forms, tambin puede unirse a cualquier clase que d soporte a la interfaz
IList, incluidas las clases de coleccin genricas. Las clases de este archivo se usarn para
instancias dentro de una coleccin genrica en dos o ms pginas Web.
App_Data
Este directorio normalmente contiene datos necesarios por la aplicacin. Fue creado auto-
mticamente por Visual Studio. No lo uso en este proyecto.
Default.aspx y Default.aspx.vb
ste es el punto de entrada del sitio Web Biblioteca. El explorador de cliente pide que la
pgina Web Default.aspx inicie la experiencia de biblioteca. La pgina incluye un vnculo al
informe de estadsticas, adems de campos que le permiten buscar elementos de biblioteca
por ttulo o autor.
ResultadosBusqueda.aspx y ResultadosBusqueda.aspx.vb
Las bsquedas realizadas por la pgina Default.aspx terminan aqu, con consultas procesadas
en cdigo y despus unidas a una cuadrcula.
DetalleBusqueda.aspx y DetalleBusqueda.aspx.vb
Cada resultado de bsqueda incluye un vnculo a esta pgina. Proporciona detalle adicional
para un elemento, en el mismo formato utilizado en el archivo BsquedaArticulo.vb del
proyecto Biblioteca.
Estadisticas.aspx y Estadisticas.aspx.vb
Esta pgina despliega el informe Estadsticas Biblioteca como una pgina Web unida.
web.config
Cada proyecto ASP.NET incluye un archivo web.config utilizado para especificar configura-
ciones especficas de proyecto en los entornos de desarrollo y produccin.

Configuracin de la base de datos


El archivo web.config contiene un lugar para cadena de conexin de base de datos. He agregado
una entrada dentro de ste para la base de datos Biblioteca.

664 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 664 17/2/10 15:33:46


<connectionStrings>
<add name="LibraryConnection" connectionString=
"Data Source=MYSERVER\SQLEXPRESS;
Initial Catalog=Library;Integrated Security=True" />
</connectionStrings>

Modifique la porcin MYSERVER\SQLEXPRESS del nombre de su instancia de base de


datos SQL Server y modifique las otras partes de la cadena de conexin como sea necesario. Las
cuatro pginas Web usan la base de datos Biblioteca y todas acceden a cadenas de conexin desde
esta entrada, por medio del objeto ConfigurationManager:
Public BDBiblioteca As System.Data.SqlClient.SqlConnection

...y mas adelante...

BDBiblioteca = New SqlClient.SqlConnection( _


ConfigurationManager.ConnectionStrings( _
"BibliotecaConnection").ConnectionString)
BDBiblioteca.Open()

...y aun mas adelante...

BDBiblioteca.Close()

La pgina predeterminada
La pgina Default.aspx es el punto de inicio para la aplicacin Web Biblioteca y aparece en la
figura 23-13.

Figura 23-13. La pgina predeterminada del sitio Web Biblioteca.

Proyecto | 665

23_PATRICK-CHAPTER_23.indd 665 17/2/10 15:33:47


Su cdigo no tiene mucho de que hablar. Simplemente llena la lista desplegable Tipo de medios
con los tipos disponibles de la base de datos.
sqlText = "SELECT ID, NombreCompleto FROM CodigoTipoMedio " & _
"ORDER BY NombreCompleto"
infoBD = CrearLector(textoSql, BDBiblioteca)
Do While infoBD.Read
SearchMediaType.Items.Add(New WebControls.ListItem( _
CStr(infoBD!NombreCompleto), CStr(infoBD!ID)))
Loop
infoBD.Close()

La pgina en s es un poco ms interesante. Cuando generamos la aplicacin Web ASP.NET


de ejemplo, cada clic en el botn Multiplicar enviaba la pgina de regreso a s misma. Era una
aplicacin de una pgina. Casi todas las aplicaciones Web seran intiles con slo una pgina,
porque los clics en botones y los vnculos necesitan brincar a cualquier parte del proyecto. El vn-
culo de informe en la parte inferior de esta pgina es un hipervnculo estndar a Estadisticas.aspx,
otra pgina dentro de la aplicacin. En la porcin de bsqueda de la pgina, el botn Buscar
(AccBuscar) tambin brinca a otra pgina del proyecto, ResultadosBusqueda.aspx. Esto se hace
a travs de la propiedad PostBackUrl, que est configurada en /SearchResults.aspx. La
nueva pgina tendr acceso indirecto a todas las secciones de campo en esta pgina de inicio.

Resultados de bsqueda
La pgina ResultadosBusqueda.aspx despliega cualquier resultado coincidente de la seccin de bs-
queda de elemento Default.aspx. Como se muestra en la figura 23-14, incluye un control GridView
para la lista de resultados, adems de un control Label que muestra un conteo de coincidencias.

Figura 23-14. La pgina de resultados de bsqueda del sitio Web Library.

666 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 666 17/2/10 15:33:48


A diferencia del control GridView llenado antes, sta no se conecta directamente a una consulta
de base de datos. En cambio, gener a mano instancias de la clase UnirEsquemaResulta-
dosBusqueda (de EsquemasUnion.vb), las recolect en una List genrica y las un a campos
GridView. En realidad, unir de esta forma es instantneo. Cada columna que configur en el
control GridView busca una propiedad en los registros entrantes que coincidan con un nombre
de campo especfico. Estas columnas se definen a travs del Editor de columnas (vase la figura
23-15), al que se accede por medio de la propiedad Columns del control.

Figura 23-15. Edicin de columnas en un control GridView.

En la figura 23-15 se muestran las propiedades para la primera columna de datos unida, "Nom-
bre de artculo. Est unida a un campo en los datos denominado DatosArticulo por medio
de la propiedad DataField. Las siguientes dos columnas se configuran de manera similar pero
usan los datos entrantes NombreAutor y TipoMedio. La cuarta columna proporciona un hi-
pervnculo a DetalleBusqueda.aspx para cada registro coincidente. Para generar esta columna, la
agregu como una columna HyperLinkField en lugar de una BoundField. Ingrese Detalle
en su propiedad Text, que aparecer en cada registro. Hice clic en el vnculo que pasar el ID
del elemento coincidente (establec DataNavigateUrlFields en ID) a la pgina de destino por
medio de una cadena de consulta. La propiedad DataNavigateUrlFormatString contiene
una cadena que se enviar al mtodo String.Format, junto con los campos mostrados en Da-
taNavigateUrlFields. Aqu se muestra la cadena de formato:
DetalleBusqueda.aspx?ID={0}

Proyecto | 667

23_PATRICK-CHAPTER_23.indd 667 17/2/10 15:33:48


La parte {0} se reemplaza con el valor de campo ID de cada registro.
El manejador de eventos Load de esta pgina se activa por una llamada del botn Buscar en la
pgina Default.aspx. Cuando una pgina Web Forms se llama a s misma, puede examinar direc-
tamente los valores en controles. Pero los controles en la pgina Default.aspx no existen aqu en la
pgina ResultadosBusqueda.aspx. Por fortuna, los controles de la pgina anterior se envan como
datos a la nueva pgina. Puede acceder a stos a travs del objeto PreviousPage. El siguiente
cdigo extrae los valores de cada uno de los campos de bsqueda:
' ----- Obtener el texto de busqueda de titulo.
textBoxOrigen = CType(PreviousPage.FindControl( _
"BuscarTitulo"), TextBox)
If (textBoxOrigen IsNot Nothing) Then _
usarTitulo = Trim(textBoxOrigen.Text)

' ----- Obtener el texto de busqueda de apellido.


textBoxOrigen = CType(PreviousPage.FindControl( _
"BuscarApellido"), TextBox)
If (textBoxOrigen IsNot Nothing) Then _
usarApellido = Trim(textBoxOrigen.Text)

' ----- Obtener el texto de busqueda de nombre.


textBoxOrigen = CType(PreviousPage.FindControl( _
"BuscarNombre"), TextBox)
If (textBoxOrigen IsNot Nothing) Then _
usarNombre = Trim(textBoxOrigen.Text)

' ----- Obtener el valor de tipo de medio.


tipoMedioOrigen = CType(PreviousPage.FindControl( _
"BuscarTipoMedio"), DropDownList)
If (tipoMedioOrigen IsNot Nothing) Then _
usarTipoMedio = tipoMedioOrigen.SelectedValue

Lo increble es que la pgina anterior no envi sus campos como valores de cadena. En cambio,
siguieron viviendo como objetos verdaderos. Usar la funcin CType para convertirlos a controles
TextBox y DropDownList bast para acceder a sus propiedades de control.
Uso los valores proporcionados por el usuario para generar una instruccin SQL y consultar la base
de datos para resultados. Si hay alguno, los datos resultantes se incluyen en una lista de objetos.
Dim unaEntrada As UnirEsquemaresultadosBusqueda
Dim datosInforme As Collections.Generic.List( _
Of UnirEsquemaResultadosBusqueda)

Do While infoBD.Read
' ----- Agregarlo a los datos del informe.
unaEntrada = New UnirEsquemaResultadosBusqueda
unaEntrada.ID = CInt(infoBD!ID)
unaEntrada.NombreArticulo = CStr(infoBD!Titulo)
If (IsDBNull(infoBD!Apellido) = True) Then _
usarApellido = "" Else _
usarApellido = CStr(infoBD!Apellido)
If (IsDBNull(infoBD!Nombre) = True) Then _

668 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 668 17/2/10 15:33:48


useNombre = "" Else _
usarNombre = CStr(infoBD!Nombre)
If (usarNombre <> "") Then
If (usarApellido <> "") Then usarApellido &= ", "
usarApellido &= usarNombre
End If
unaEntrada.NombreAutor = usarApellido
unaEntrada.TipoMedio = CStr(infoBD!NombreMedio)

datosInforme.Add(unaEntrada)
Loop

Los resultados se unen a la cuadrcula, y un conteo se despliega para el usuario.


CuadriculaResultados.DataSource = datosInforme
CuadriculaResultados.DataBind()
CuentaCoincidencias.Text = datosInforme.Count & " articulos coincidentes."

Debe llamar al mtodo DataBind del control GridView o no ver ningn resultado.

Detalle de bsqueda
Cuando el usuario hace clic en uno de los vnculos de detalle en los resultados de bsqueda,
enva el ID del registro ArticuloConNombre seleccionado a la pgina SearchDetail.aspx como
una cadena de consulta. La pgina en s, que no mostrar aqu, incluye muchos controles Label
que intentan imitar la salida en el panel de detalle del formulario ItemLookup.vb en la aplicacin
principal Biblioteca. Aunque uso casi las mismas instrucciones de hoja de estilos en cascada
(Cascading Style Sheet, CSS) en esta pgina que en la aplicacin.
Cuando el manejador de eventos Load de la pgina se activa, primero examina la cadena de
consulta para extraer el ID de ArticuloConNombre proporcionado. Un ID faltante lleva a un
regreso al formulario de bsqueda principal.
idArticulo = Val(Page.Request.QueryString("ID"))
If (idArticulo <= 0) Then
Response.Redirect("Default.aspx")
Return
End If

Casi todo el cdigo de formato para esta pgina viene del archivo BusquedaArticulo.vb en la apli-
cacin principal. Consulta a la base de datos para detalles del registro ArticuloConNombre es-
pecificado, y actualiza cada etiqueta al usar estos valores. Lo nico que es interesante (adems del
hecho de que parece todo muy sencillo para el desarrollo de pgina Web) es la creacin de la tabla
de copias de artculos cerca de la parte inferior de la pgina. En la versin BusquedaArticulo.vb del
cdigo, hice a mano un conjunto HTML <table> y llen sus columnas con el estado de cada
copia disponible del elemento de biblioteca nombrado. Pens que era una pena ignorar todo ese
cdigo grandioso, as que slo lo copi casi sin cambio en el cdigo de DetalleBusqueda.aspx.vb.
Hasta ahora, no he tenido que hacer nada con HTML, excepto cuando quise agregar etiquetas
<h1> alrededor de los ttulos de pgina. Pero ya que he escrito el cdigo de generacin HTML,
y ya que las aplicaciones ASP.NET tienen por objetivo HTML, pens que poda usarlo.

Proyecto | 669

23_PATRICK-CHAPTER_23.indd 669 17/2/10 15:33:49


Y puedo. Uno de los controles Web Forms es Literal, que slo existe para que pueda establecer
su propiedad Text con contenido HTML formado de manera apropiada. Despus de generar la
estructura de tabla en un objeto StringBuilder denominado tablaCopia, asigno ese conte-
nido HTML al control Literal.
' ----- Agregar la tabla a la salida.
PonerTablaAqui.Text = tablaCopia.ToString(
)

Informe de estadsticas
La pgina Estadisticas.aspx despliega la misma informacin resumida incluida en uno de los
informes del captulo 21. En el informe de estadsticas original desplegu conteos de registro de
seis diferentes tablas y las present como una lista en un formato de informe RDLC. En esta p-
gina Web hago las mismas seis consultas, genero una lista genrica de resultados y uno esa lista a
(sorpresa) un control GridView, que rpidamente se est convirtiendo en nuestro favorito. Aqu
se muestra el cdigo total de la pgina en su conjunto:
Imports System.Data

Partial Class Estadisticas


Inherits System.Web.UI.Page

Public BDBiblioteca As System.Data.SqlClient.SqlConnection

Protected Sub Page_Load(ByVal sender As Object, _


ByVal e As System.EventArgs) Handles Me.Load
' ----- Preparar los datos para el informe.
Dim textoSql As String
Dim datosInforme As Collections.Generic.List( _
Of BoundSchemaStatistics)
Dim unaEntrada As BoundSchemaStatistics
Dim valorResultado As Integer
Dim counter As Integer
Dim conjuntosTablas() As String = {"Autor", "Editor", _
"Subject", "ArticuloConNombre", "CopiaArticulo", "Cliente"}
Dim titulosTabla() As String = {"Autores", "Editores", _
"Encabezados de tema", "Articulos", "Copias de articulos", "Clientes"}

' ----- Conectar con la base de datos.


BDBiblioteca = New SqlClient.SqlConnection( _
ConfigurationManager.ConnectionStrings( _
"BibliotecaConnection").ConnectionString)
BDBiblioteca.Open()
' ----- Generar los datos del informe. Proviene de diferentes tablas.
datosInforme = New Collections.Generic.List( _
Of BoundSchemaStatistics)
For contador = 0 To UBound(conjuntosTablas)
' ----- Procesar una tabla.
textoSql = "SELECT COUNT(*) FROM " & _
conjuntosTablas(contador)

670 | Captulo 23: Desarrollo Web

23_PATRICK-CHAPTER_23.indd 670 17/2/10 15:33:49


valorResultado = CInt(EjecutarSQLRegresar
(textoSql, _
BDBiblioteca))

' ----- Agregarlo a los datos del informe.


unaEntrada = New UnirEsquemaEstadisticas
unaEntrada.NombreEntrada = titulosTabla(contador)
unaEntrada.ValorEntrada = CStr(valorResultado)
datosInforme.Add(unaEntrada)
Next contador

' ----- Finalizar la conexion.


BDBiblioteca.Close()

CuadriculaEstadisticas.DataSource = datosInforme
CuadriculaEstadisticas.DataBind(
)
End Sub
End Class

Slo inclu un conjunto mnimo de caractersticas en el sitio Web, y no comience a hacer chistes
acerca de mis habilidades de diseo de pginas Web. Si planeara desplegar este sitio Web, cierta-
mente hubiera habilitado algunos vnculos en la pgina DetalleBusqueda.aspx para que el usuario
pudiera hacer clic en la bsqueda para otros elementos por el mismo autor, editor, serie, etc.
Tambin hubiera agregado caractersticas especficas de cliente que nos hubieran permitido a los
usuarios revisar sus artculos prestados y cualquier multa vencida. Otra caracterstica grandiosa
para agregar hubiera sido el contenido de ayuda en lnea que dijera al cliente o administrador
cmo usar el sistema. Y eso resulta ser el tema del siguiente captulo. Suerte.

Proyecto | 671

23_PATRICK-CHAPTER_23.indd 671 17/2/10 15:33:49


Captulo 24
Adicin de ayuda en lnea

Si hay algo que he aprendido en casi 25 aos de programacin, es que los usuarios a menudo
necesitan ayuda para ejecutar software en sus sistemas. Los programadores necesitan ayuda,
tambin; pero regresando a las computadoras: es raro que encuentre un usuario tcnicamente
experto. Si escribe aplicaciones que tienen por objetivo negocios y departamentos dentro de
organizaciones (que es lo que hago), encontrar que los usuarios tienen mucha habilidad en su
trabajo, pero no necesariamente tienen habilidades para usar una computadora. Por eso resulta
imperativo que haga los programas ms sencillos posibles.
Tambin debe agregar ayuda en lnea a sus aplicaciones. Estos documentos listos actan como
la primera oleada de soporte para las necesidades de software de los usuarios. Por supuesto, rara
vez la leen, y entonces usted (o el personal de soporte tcnico) ser realmente la primera oleada
de soporte. Pero es de alguna manera un alivio decir: Revis la ayuda en lnea, que cubre este
problema a detalle?
En este captulo analizaremos las opciones de ayuda en lnea disponibles en Visual Basic y nos con
centraremos en HTML Help 1.x, el sistema de ayuda de Windows XP estndar de Microsoft.

Opciones de Windows Online Help


La ayuda en lnea ha sido una parte de Windows desde su lanzamiento inicial, desde los das
cuando las aplicaciones y sistemas operativos todava venan con manuales impresos y nunca
requeran ms de dos discos flexibles. Realmente extrao esos das. Esa sensacin de tocar las
pginas fras y suaves en mis manos. Recuerdo el primer software de Windows que compr, un
Personal Information Manager apenas lanzado. Tena todo lo que necesitaba, incluida una
gua de usuario de 400 pginas y un manual de referencia. Un deleite total.
Esos das se han ido, reemplazados por sistemas de ayuda en lnea y archivos leme HTML.
Ahora se compran libros como ste para traer esa sensacin de gua de usuario incluida. Pero
puede hacer mucho con la ayuda en lnea, sobre todo en estos das, con la habilidad de incluir
contenido activo dinmico en pginas de ayuda en lnea.

672

24_PATRICK-CHAPTER_24.indd 672 17/2/10 15:34:04


WinHelp
El sistema de ayuda original de Windows fue WinHelp. Inclua pginas de ayuda con formato
simple con hipervnculos a otras pginas. Un archivo contenido separado agregaba soporte de
tabla de contenido; tena que incluir el archivo de contenido .cnt con el archivo .hlp como un
conjunto. Estos archivos de ayuda bsicos fueron (y en muchas formas, todava lo son) suficien
temente buenos para la mayor parte de las necesidades del usuario, y todava tienen soporte en
todos los lanzamientos de Microsoft Windows.
Los archivos WinHelp fueron diseados con formato de texto enriquecido (RTF), un formato
de procesamiento de palabras soportado por muchos vendedores. Debido a esto, el contenido
fue fcil de generar, aunque los hipervnculos y otras caractersticas especficas de ayuda reque
ran texto extrao y combinaciones de formato. Pero WinHelp cubri las necesidades de los
usuarios de Windows por aos.

HTML Help
Los documentos RTF son de la dcada de 1980. Cuando Internet empez a entrar en el
mundo con su capacidad de generar pginas con formato hermoso mediante lenguaje comn
basado en etiqueta HTML, Microsoft decidi actualizar su sistema de ayuda a uno que usaba
documentos HTML estndar: HTML Help. Como su nombre lo indica, HTML Help est
basado en HTML. Cualquier cosa que genera HTML puede generar contenido HTML Help:
herramientas de diseado de pgina Web de terceros, procesadores de palabras, sus propias
aplicaciones, incluso el Bloc de notas. Como se esperaba, algunos vendedores disearon herra
mientas que tenan por objetivo especficamente al sistema HTML Help.
HTML Help es mejor que WinHelp, debido a su dependencia de HTML y otras tecnologas
relacionadas. Cada pgina de su archivo de ayuda en lnea es un archivo/pgina HTML separa
do. Los hipervnculos para otras pginas de ayuda son hipervnculos estndar HTML. Y HTML
Help emplea casi todas las caractersticas utilizadas en cualquier pgina Web, incluidas hojas de
estilo en cascada (Cascading Style Sheets, CSS) y secuencias de comandos Java.
Los archivos de ayuda HTML Help compilados tienen una extensin .chm, y un solo archivo
incluye contenido principal, la tabla de contenido, y un ndice predefinido de trminos. Usare
mos tecnologa HTML Help para agregar contenido de ayuda en lnea al proyecto Biblioteca.
Me saltar los detalles del sistema hasta un poco despus en el captulo.

Microsoft Help 2
La mayor parte de las aplicaciones que se venden al momento de escribir este libro usan HTML
Help, pero no todas. Una gran excepcin es Visual Studio. Su sistema de ayuda (Microsoft Help 2,
conocido como HTML Help 2.x) combina contenido HTML y XML en un conjunto de colec
ciones que funcionan juntas. Si ha instalado la versin completa de SQL Server en un sistema
con Visual Studio, comparten una interfaz de ayuda comn. Puede incluso buscar pginas en
ambas colecciones al mismo tiempo.

Opciones de Windows Online Help | 673

24_PATRICK-CHAPTER_24.indd 673 17/2/10 15:34:04


Microsoft tiene disponible un kit de integracin de ayuda para desarrolladores que desean
combinar su propio contenido en el sistema Microsoft Help 2. Esto es lo ms til para vendedo
res que desarrollan controles de terceros y herramientas que integran con .NET o SQL Server.
Microsoft Help 2 rara vez se usa para software de usuario.

Assistance Platform
Windows Vista usa un nuevo sistema de ayuda denominado Assistance Platform (AP, plataforma
de asistencia). Toda la ayuda en lnea que viene con Vista est escrita en AP, pero no hay ms
que eso. Lo anterior es porque Microsoft decidi no lanzar el formato de archivo para que otros
vendedores lo usaran. Bueno, existen algunas compaas grandes y OEM que usan AP guiadas
por Microsoft, pero usted y yo no somos una de ellas.

Otros mtodos
No todas las aplicaciones usan estos sistemas de ayuda definidos por Microsoft. Algunas apli
caciones no incluyen ayuda en lnea porque estn diseados por malas personas. No, slo estoy
bromeando. Tal vez haya casos donde la ayuda en lnea no agregue valor al programa. Pero suele
ser mejor incluir algn tipo de asistencia escrita.
Las pginas HTML independientes estn slo un paso abajo de los archivos HTML Help, y
son una opcin viable para las aplicaciones simples, o las hospedadas en un sitio Web. Puede
usar otros formatos estndar, como procesamiento de palabras o documentos de texto, si no
tiene recursos para generar archivos en lnea verdaderos. Y por supuesto existen los libros, que
obtendrn mi atencin.
Visual Studio incluye una caracterstica que le permite generar documentacin de comentarios
XML agregados a cada miembro de su clase. (No analizo esto en este libro; consulte la ayuda
en lnea de Visual Studio, no est feliz de que se encuentre ah?, para informacin adicional
sobre Comentario XML.) Ni siquiera considere usar esto para las necesidades de usuario en su
propia documentacin, a menos que est desarrollando componentes basados en clase para uso
por otros desarrolladores.

Diseo de HTML Help


Los archivos HTML Help estn generados a partir de varios archivos origen:
Los archivos de contenido, sobre todo archivos HTML estndar, comunican informacin
bsica al usuario, ya sea a travs de texto esttico o grficas o de comportamientos avanzados
estilo pgina Web y secuencias de comandos normalmente disponibles en pginas Web.
El archivo Help Contents usa .hhc para su extensin de archivo. Al usar etiquetas HTML
estndar <ul> y <li>, el archivo especifica la tabla jerrquica de contenido usada por el
archivo de ayuda.

674 | Captulo 24:Adicin de ayuda en lnea

24_PATRICK-CHAPTER_24.indd 674 17/2/10 15:34:05


El archivo Help Keywords usa una extensin de archivo .hhk, y documenta el ndice utilizado
para acceder a pginas de ayuda de palabras especficas predefinidas.
El archivo Help Project, que usa una extensin de archivo .hhp, define un proyecto de ayuda
completo y su archivo .chm de destino. Este archivo de texto estilo INI identifica todos los
dems archivos que se compilarn en el archivo de ayuda de destino. Tambin define unas
cuantas opciones en el nivel del proyecto.
Puede generar los archivos de contenido principales a mano al usar cualquier herramienta HTML es
tndar que desee, siempre y cuando el formato de salida coincida con lo que espera HTML Help
Compiler (proporcionado por Microsoft). Para los archivos de contenido, generalmente no im
porta qu herramienta se usa, porque el HTML estndar es suficiente. Cualquier hipervnculo
que incluya en el contenido a otras pginas de ayuda en el mismo directorio se volver vnculos
de ayuda estndar en el archivo de ayuda compilado.
Los archivos que no son de contenido requieren un formato muy preciso, todos estn basados en
HTML, excepto el archivo Help Project, que es un archivo INI. Necesitar ya sea designar estos
archivos a mano al usar el formato esperado, o usar una herramienta que pueda generar estos ar
chivos para usted en el formato preciso.
Microsoft proporciona una herramienta gratuita que le ayuda a crear archivos que no son de
contenido, y los une con los archivos de contenido para una compilacin final. Puede descargar
HTML Help Workshop directamente del sitio Web de Microsoft. Vaya a Microsoft Download
Center en http://www.microsoft.com/downloads y busque HTML Help Workshop. Recibir
unos cuantos resultados, pero el primero en la lista (cuando se ordena por popularidad) debe ser
el que necesita. En la figura 24-1 se muestra la pgina principal de HTML Help Workshop con
un archivo de proyecto activo abierto.

Figura 24-1. Dar ayuda a quienes realmente la necesitan.

Diseo de HTML Help | 675

24_PATRICK-CHAPTER_24.indd 675 17/2/10 15:34:05


En el resto de esta seccin usaremos HTML Help Workshop para generar un archivo HTML
Help que contenga dos pginas: una de bienvenida y una de ms informacin. Encontrar
este proyecto de ayuda de ejemplo en el subdirectorio EjemploHTMLHelp del directorio de
instalacin del libro.

Archivos de contenido
Nuestro miniproyecto incluye dos archivos de contenido: bienvenido.htm y masinfo.htm. Como
siempre he sido un especialista en tecnologa, los gener en el Bloc de notas. Aqu se muestra el
contenido de bienvenido.htm:
<html>
<head><title>Bienvenido a mi ayuda</title></head>
<body>
Bienvenido a mi ayuda. For conocer ms informacin,
<a href="masinfo.htm">haga clic aqu</a>.
</body>
</html>

El archivo masinfo.htm es muy parecido.


<html>
<head><title>Mi informacin de ayuda adicional</title></head>
<body>
No hay mucho ms que decir. Para recibir la bienvenida,
<a href="bienvenido.htm">haga clic aqu</a>.
</body>
</html>

Puede agregar archivos de imagen (JPEG y GIF) y vincularlos como lo hara en una pgina
Web. Asegrese de almacenar los archivos grficos en el mismo directorio (o subdirectorio) que
el archivo principal, para fcil acceso.

Archivo Help Project


Generemos los archivos restantes mediante HTML Help Workshop. Incielo y use el coman
do de men archivo File New para crear un proyecto nuevo. Al usar New Project Wizard,
identifique la ubicacin y el nombre de su nuevo archivo .hhp. Crear un archivo denominado
Simple.hhp en la misma carpeta que los dos archivos de contenido. El asistente pide los archivos
ya creados. Marque el campo HTML files, como se muestra en la figura 24-2.
Agregue los dos archivos HTML en el siguiente paso y complete el asistente. El archivo de pro
yecto se crea con referencias a sus dos archivos.
El proyecto est muy vaco, ni siquiera tiene un ttulo de ventana definido para el archivo de
ayuda compilado. Puede establecer el ttulo y otras configuraciones generales a travs de las
opciones del proyecto, que se acceden a travs del botn superior de la barra de herramientas
que se ejecuta en el lado izquierdo de la ventana principal. Tambin puede hacer doble clic en el
elemento [OPTIONS] en la lista de detalles del proyecto. Cuando aparezca la ventana opcin,
inserte Ayuda simple en el campo Title, y despus haga clic en OK.

676 | Captulo 24:Adicin de ayuda en lnea

24_PATRICK-CHAPTER_24.indd 676 17/2/10 15:34:05


Figura 24-2. Ubique los archivos ahora, o puede hacerlo despus.

Aqu se muestra lo que contiene el archivo de proyecto hasta este punto:


[OPTIONS]
Compatibility=1.1 or later
Compiled file=Simple.chm
Default topic=bienvenido.htm
Display compile progress=No
Language=0x409 English (United States)
Title=Simple Help

[FILES]
bienvenido.htm
masinfo.htm

[INFOTYPES]

El archivo cambiar conforme agreguemos los otros dos archivos que no son de contenido, pero
no por mucho.
Si compila el archivo en este momento (al usar el men de comando File Compile) y lo eje
cuta, se desplegar una ventana de ayuda muy simple, como se muestra en la figura 24-3.

Archivo Help Contents


Una tabla de contenido le ayudar al usuario a estudiar esta experiencia masiva de ayuda en lnea.
Para agregar un archivo de contenido, haga clic en la ficha Contents, en el lado izquierdo del
formulario principal, y responda si desea crear un nuevo archivo y, de ser as, asgnele el nombre
Simple.hhc. El formulario cambia para desplegar un editor de tabla de contenido. Otra forma de
crear el archivo de contenido consiste en usar el comando de men File New, y seleccionar
Table of Contents del formulario de seleccin New. Esto es menos directo, ya que no conecta
inmediatamente al archivo de contenido con el proyecto.

Diseo de HTML Help | 677

24_PATRICK-CHAPTER_24.indd 677 17/2/10 15:34:06


Figura 24-3. Una pequea ayuda; muy poca.

Use los nuevos botones de la barra de herramientas hacia el lado izquierdo de la ventana para
agregar y modificar entradas de contenido. Primero, use el botn superior (Contents proper
ties) para editar las opciones para la tabla de contenido. En el formulario Table of Contents
Properties, quite la marca del campo Use folders instead of books y haga clic en OK.
Los siguientes dos botones el botn de libro (Insert a heading) y el de pgina/signo de inte
rrogacin (insert a page) son los botones principales utilizados para agregar nuevas entradas
a los contenidos. Hice clic en el botn Insert a page para ir al formulario Table of Contents
Entry que se muestra en la figura 24-4.

Figura 24-4. Adicin de una pgina de ayuda.

678 | Captulo 24:Adicin de ayuda en lnea

24_PATRICK-CHAPTER_24.indd 678 17/2/10 15:34:07


Como se muestra en la figura, establec el ttulo de insercin (Bienvenido) y seleccione el
archivo Bienvenido a mi ayuda (bienvenido.htm) mediante el botn Add. Hice lo mismo para
el archivo masinfo.htm, al darle un ttulo de Ms informacin. Tambin agregu una entrada
de encabezado al usar el botn Insert a heading de la barra de herramientas en el formulario
principal, llamndolo Otras pginas. Utilic los botones de flechas de las barras de herramien
tas para mover la entrada masinfo.htm en esta seccin de encabezado. Despus tom un descanso
bien merecido y vi mi tabla de contenido completada en la figura 24-5.

Figura 24-5. La tabla completa de contenido.

Si compila y ejecuta el archivo, ahora incluye la tabla de contenido en un panel separado, adems
de una barra de herramientas (vase la figura 24-6).

Figura 24-6. Tabla de contenido nueva y mejorada; el mismo contenido grandioso.

Archivo Help Keywords (Index)


Un archivo de ndice le permite al usuario acceder a pginas especficas al buscar un concepto o
tema de una lista. Existen muchas relaciones varias a varias entre estas palabras clave y las pginas
de ayuda: una palabra clave puede llevar a una o ms pginas, y una sola pgina puede ser el
objetivo de varias palabras clave.
Cree un ndice al hacer clic en la pestaa Index, en la mitad izquierda del formulario principal, y
responda si quiere crear un nuevo archivo de ndice, llamndolo Simple.hhk. Como con el editor
Contents, el editor Index incluye una barra de herramientas vertical pequea. Use el segundo

Diseo de HTML Help | 679

24_PATRICK-CHAPTER_24.indd 679 17/2/10 15:34:08


botn en la barra de herramientas, que est con la imagen clave, para crear nuevas entradas de
palabras clave. Agregar tres palabras clave:
basico, vinculado a bienvenido.htm
avanzado, vinculado a masinfo.htm
todo, vinculado a ambas pginas.
El formulario de edicin Index Entry funciona como el formulario Table of Contents Entry,
permitindole especificar las pginas objetivo para cada palabra clave.
Guardar y compilar el proyecto agrega caractersticas de ndice al archivo de ayuda compilado.

Formato a ventanas de ayuda


En mi sistema, al ejecutar el archivo de ayuda compilado se despliega el contenido en una
pequea ventana en la esquina superior derecha de la pantalla. Pero mi contenido de ayuda es
importante; quiero que aparezca mucho ms cerca del medio de la pantalla y en una ventana ms
grande. Afortunadamente, puede controlar estas ventanas utilizadas para desplegar el contenido.
Regresar a la pestaa Project y hacer clic en el tercer botn de la barra de herramientas en el lado
izquierdo de la ventana. Este botn Add/modify window definitions le permite definir una o
ms ventanas para usar para distintas pginas de ayuda en su archivo. Cuando se le pida, agregue
New Window Type llamada SimpleWindow.
El cuadro de dilogo Window Types que aparece tiene muchas opciones para obtener la ventana
que desee, aunque probablemente ser muy quisquilloso si necesita ms que, digamos, 243 tipos
diferentes de ventanas. La pestaa Position es muy divertida. Incluye un botn Autosizer que
le permite arrastrar una ventana al tamao deseado. Ajuste el tamao a algo razonable, agregue
un Title bar text de Ayuda simple en la pestaa General, y haga clic en OK. Ya que sta es
la nica ventana definida, se vuelve la predeterminada, y se usar para el despliegue de la ayuda
principal la siguiente vez que compile y ejecute el archivo.

Acceso a HTML Help


Visual Studio proporciona dos mtodos principales para integrar ayuda en lnea en aplicaciones
de escritorio. El primero usa el control HelpProvider, encontrado en la seccin Components
del cuadro de herramientas de Visual Studio. El segundo usa el mtodo Help.ShowHelp del
paquete Windows Forms. Ambos mtodos le permiten desplegar pginas especficas o porciones
de un archivo HTML Help compilado.

El control HelpProvider
El control HelpProvider puede agregarse a un formulario para habilitar el acceso a ayuda en
lnea. Proporciona dos experiencias principales de ayuda en lnea: 1) acceso estndar a HTML
Help compilado y 2) ayuda desplegable. Ambos mtodos colocan el enfoque en controles indi
viduales de una forma y en caractersticas de ayuda especficas para unirse a cada control.

680 | Captulo 24:Adicin de ayuda en lnea

24_PATRICK-CHAPTER_24.indd 680 17/2/10 15:34:08


Acceso a archivos de ayuda HTML
Para usar el control HelpProvider con archivos HTML Help compilados, establezca la propie
dad HelpNamespace del control a la ubicacin de un archivo de ayuda vlido. Despus ajuste
las propiedades de otros controles del formulario para que hagan referencia a caractersticas
especiales dentro del archivo de ayuda. El control HelpProvider afecta a otros controles, al
agregar varias propiedades adicionales a cada una. En la figura 24-7 se muestran cuatro propie
dades adicionales (HelpKeyword, HelpNavigator, HelpString y ShowHelp) que se agregan
automticamente a un control.

Figura 24-7. Adicin de soporte en lnea a controles individuales.

La propiedad HelpNavigator agregada a cada control define a qu caractersticas del archivo de


ayuda acceder cuando el usuario presiona la tecla F1 mientras ese control tiene el enfoque. Para
acceder a una pgina especfica dentro del archivo de ayuda (como bienvenido.htm), se establece
la propiedad HelpNavigator del control objetivo en Topic y se establece la propiedad Help
Keyword relacionada con el nombre de archivo de la pgina (bienvenido.htm).
La propiedad HelpNavigator de un control puede establecerse para acceder a secciones que no tie
nen pgina del archivo de ayuda en lnea tambin. El valor TableOfContents despliega el esquema
de contenido del archivo; Index salta al ndice de palabra clave. Existen otras opciones tambin.

Exhibicin de ayuda desplegable


El control HelpProvider tambin habilita la ayuda desplegable en controles individuales.
Esta variacin de ayuda causa que una pequea ventana de informacin de herramientas aparez
ca arriba de un control, desplegando un mensaje corto que proporciona informacin til para
tal control, como se muestra en la figura 24-8.

Figura 24-8. Ayuda desplegable en un control de botn.

Acceso a HTML Help | 681

24_PATRICK-CHAPTER_24.indd 681 17/2/10 15:34:09


La ayuda desplegable funciona cuando habilita Pop-up button en la barra de ttulo del formu
lario. Para configurar la ayuda desplegable para un control, siga estos pasos:
1. Agregue un control HelpProvider al formulario, pero no se moleste en configurar su pro
piedad HelpNamespace con un archivo.
2. Establezca la propiedad HelpButton del formulario en True.
3. Establezca las propiedades MaximizeBox y MinimizeBox del formulario en False.
4. Establezca la propiedad HelpString en HelpProvider1 a algn texto informativo en cada
control que desplegar su propia ayuda desplegable.
El usuario muestra la ayuda desplegable al hacer clic primero en el botn de signo de interroga
cin help en la barra de ttulo del formulario, y despus al hacer clic en un control.

Mtodo ShowHelp
El mtodo System.Windows.Forms.Help.ShowHelp despliega porciones especficas de un ar
chivo HTML Help basado en los argumentos pasados al mtodo. Es muy similar a la porcin
de ayuda basada en archivo del control HelpProvider, pero en formulario de mtodo. Para
desplegar una pgina especfica dentro de un archivo de ayuda, use esta sintaxis:
Windows.Forms.Help.ShowHelp(Me, "Simple.chm", _
HelpNavigator.Topic, "masinfo.htm")

El primer argumento es una referencia al formulario que llama al mtodo.


Una forma comn de usar este mtodo es monitorear la forma para la tecla F1, y llamar a
ShowHelp del manejador de eventos KeyDown del formulario.
Private Sub Form1_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles Me.KeyDown
' ----- llamar a ayuda onlnea.
If (e.KeyCode = Keys.F1) Then
Windows.Forms.Help.ShowHelp(Me, "Simple.chm", _
HelpNavigator.Topic, "masinfo.htm")
End If
End Sub

Debe establecer la propiedad KeyPreview en True para desencadenar el evento KeyDown en el


nivel del formulario. De otra forma, todas las teclas activan el control y desactivan los eventos
en el nivel del formulario.
El mtodo ShowHelp ofrece mucho ms control a travs de la experiencia de ayuda en lnea del
usuario, porque usted (y no el control HelpProvider) determina exactamente cundo acceder
al archivo de ayuda.

682 | Captulo 24:Adicin de ayuda en lnea

24_PATRICK-CHAPTER_24.indd 682 17/2/10 15:34:09


Resumen
Si su plan es quedarse viendo por encima del hombro de cada usuario y darle instrucciones
verbales mientras se sienta ante su software, por todos los medios evtese la escritura de cual
quier ayuda en lnea u otra documentacin de usuario. Pero si planea tener tiempo para vivir,
hgala ms sencilla al incluir soporte til en la aplicacin. stos no son los das malos de la
antigedad cuando tena que proporcionar su propio mtodo de despliegue de ayuda en lnea,
o necesitaba escarbar en una biblioteca de Windows API para encontrar la funcin que acceda
al archivo de ayuda. Esto es .NET! Tiene todas las caractersticas de ayuda que necesita ya
integradas.
Crear archivos HTML compilados no es tan difcil con la herramienta HTML Help Workshop.
Pero si trabajar en cualquier archivo de ayuda que puede cambiar de tamao, o si quiere agregar
caractersticas mejoradas consistentemente, debe pensar acerca de invertir unos cuantos dlares
en una herramienta de terceros de desarrollo de ayuda.

Proyecto
Una vez que ha accedido a un archivo de ayuda en lnea, tiene acceso a todas las pginas de ste.
Suele ser algo bueno, porque los usuarios son curiosos. (Me refiero a que son inquisitivos y no
slo meramente objetos de curiosidad.) Pero en el caso del proyecto Biblioteca, esa curiosidad
puede llevar a temas que no son para los clientes ordinarios. La mayor parte de las caractersticas
en la aplicacin Biblioteca son slo para uso administrativo. Para mantener las cosas bajo el ma
yor control posible, el proyecto Biblioteca incluye dos archivos en lnea:
BibliotecaBasica.chm, un archivo de ayuda concentrado en clientes que describe slo las
partes del programa a las que el cliente puede acceder.
BibliotecaAdmin.chm, un archivo que tiene por objetivo administradores y bibliotecarios
que describen completamente las caractersticas de la aplicacin.
En esta seccin se generan ambos archivos de ayuda en lnea y se integra en la aplicacin Biblio
teca.

Generacin de archivos de ayuda


He escrito el contenido para ambos archivos en lnea por usted. Los encontrar en el subdirec
torio Ayuda en lnea en el directorio de instalacin principal de este libro, con distintas ramas de
directorio para archivos Bsico y Admin. En las figuras 24-9 y 24-10 se muestran los archivos
encontrados en cada directorio.

Proyecto | 683

24_PATRICK-CHAPTER_24.indd 683 17/2/10 15:34:09


Figura 24-9. Los archivos de ayuda en lnea en el nivel del cliente.

Figura 24-10. Los archivos de ayuda en lnea en el nivel del administrador.

La mayor parte de los archivos HTML tienen un vnculo uno a uno con formularios especficos
de la aplicacin. Por ejemplo, el archivo BusquedaArticulo.htm incluye el contenido de ayuda en
lnea del formulario BusquedaArticulo.vb en la aplicacin. Y esta pgina de ayuda se muestra en las
versiones bsica y administrativa del archivo. Cuando el usuario oprime F1 desde el formulario
Buscar artculo, la aplicacin intenta mostrar la pgina de ayuda en lnea BusquedaArticulo.htm.
Si el usuario es un cliente estndar, accede a esta pgina en el archivo BibliotecaBasica.chm; los
usuarios administrativos, en cambio, acceden al mismo nombre de pgina, pero desde el archivo
BibliotecaAdmin.chm.
Cada carpeta de origen de ayuda contiene archivos .hhp, .hhc y .hhk que definen el proyecto, el
contenido y los detalles de ndice, respectivamente. La versin administrativa tambin incluye
unos cuantos archivos grficos GIF.
Ya he compilado cada archivo y he colocado una copia del archivo .chm en estos directorios.

Adicin de soporte de ayuda a la aplicacin


Para mantener las cosas simples y centralizadas de alguna forma, emplearemos el mtodo
ShowHelp descrito antes para desplegar ayuda en lnea para cada forma en la aplicacin. Debi
do a la naturaleza ocupacional de los cambios en el cdigo de proyecto de este captulo, ya he
hecho todas las actualizaciones al proyecto. Casi todos los cambios se relacionan con hacer el
mismo cambio a cada formulario del proyecto, los cuales describir pronto.

684 | Captulo 24:Adicin de ayuda en lnea

24_PATRICK-CHAPTER_24.indd 684 17/2/10 15:34:10


Acceso al proyecto
Cargue el proyecto Cap24 (Final) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Este captulo no
incluye una variante Antes del cdigo del proyecto.

El formulario Mantenimiento.vb ya proporciona un formulario para que el administrador espe


cifique la ubicacin de cada archivo de ayuda en lnea. Actualice dos configuraciones a travs del
objeto My.Settings.
My.Settings.HelpFile = Trim(RegistroAyudaBasica.Text)
My.Settings.HelpFileAdmin = Trim(RegistroAyudaAdmin.Text)

Estas configuraciones tambin se almacenan en dos variables globales.


ArchivoPrincipalAyuda = RegistroAyudaBasica.Text
MainAdminHelpFile = RegistroAyudaAdmin.Text

Eso significa que slo necesitamos llamar a ShowHelp de cada formulario y acceder a uno o de
los dos archivos cuando el usuario presione F1.
Pero qu pasa si el administrador nunca usa el formulario Mantenimiento.vb para configurar las
ubicaciones de los archivos de ayuda? Ya que stos tal vez estarn instalados en la misma carpeta
que el archivo de programa Biblioteca.exe, debemos ver ah automticamente. El mtodo Ini
cializarSistema en General.vb ya establece las dos variables locales a los valores almacenados
en las configuraciones.
' ----- Localizar los archivos de ayuda en linea.
ArchivoPrincipalAyuda = My.Settings.HelpFile & ""
MainAdminHelpFile = My.Settings.HelpFileAdmin & ""

Slo en caso de que estas configuraciones no existan, agreguemos algo de cdigo justo despus
de estas lneas para proporcionar acceso predeterminado a los archivos.
If (ArchivoPrincipalAyuda = "") Then ArchivoPrincipalAyuda = _
My.Computer.FileSystem.CombinePath( _
My.Application.Info.DirectoryPath, "BibliotecaBasica.chm")
If (MainAdminHelpFile = "") Then MainAdminHelpFile = _
My.Computer.FileSystem.CombinePath( _
My.Application.Info.DirectoryPath, "BibliotecaAdmin.chm")

Ya que necesitamos adaptarnos continuamente al estado de usuario actual de la aplicacin (cuan


do el usuario sea un cliente o un administrador), una rutina centralizada que despliegue la ayuda
del archivo correcto parece lo mejor. Aqu se muestra el cdigo para AyudaEnLinea, un nuevo
mtodo en el archivo General.vb:
Public Sub AyudaEnLinea(ByVal whichForm As _
System.Windows.Forms.Form, _
ByVal contextName As String)
' ----- Mostrar la ayuda en linea. Diferenciar entre el uso
' de ayuda en linea basica y administrativa.
Dim archivoAUsar As String

Proyecto | 685

24_PATRICK-CHAPTER_24.indd 685 17/2/10 15:34:10


' ----- Which file to use.
If (LoggedInUserID = -1) Then
archivoAUsar = ArchivoPrincipalAyuda
Else
archivoAUsar = ArchivoAyudaAdminPrincipal
End If
If (archivoAUsar = "") Then
MsgBox("La ayuda en linea no esta configurada de manera apropiada.", _
MsgBoxStyle.OkOnly Or MsgBoxStyle.Exclamation, _
TituloPrograma)
Return
End If

' ----- Mostrar la ayuda en linea.


Try
Help.ShowHelp(cualFormulario, archivoAUsar, _
HelpNavigator.Topic, nombreContexto)
Catch
MsgBox("Ha ocurrido un error mientras trataba de acceder al " & _
"archivo de ayuda en linea.", MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
End Try
End Sub

La mayor tarea en este captulo se relaciona con ir a cada formulario del proyecto y hacer estos
dos cambios:
Establezca la propiedad KeyPreview del formulario en True.
Agregue una llamada a AyudaEnLinea del manejador de eventos KeyDown del formulario.
Aqu se muestra el cdigo agregado al formulario CambiarUsuario.vb:
Private Sub CambiarUsuario_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles Me.KeyDown
' ----- F1 muestra la ayuda en linea.
If (e.KeyCode = Keys.F1) Then _
AyudaEnLinea(Me, "CambiarUsuario.htm")
End Sub

Algunos de los formularios procesan las peticiones de ayuda en lnea de manera un poco diferen
te que otros. ProgramaAcercaDe.vb no incluye su propia pgina de ayuda. En cambio, despliega
Bienvenido.htm. Bienvenido.vb no muestra ninguna ayuda en lnea, porque se supone que el
usuario no debe interactuar con ste. InformeVisorIntegrado.vb, el formulario que muestra cada
uno de los cinco informes integrados, despliega la ayuda para un formulario relacionado por me
dio de SeleccionarInforme.htm. El formulario BuscarEntradaSalida.vb tiene dos pginas de ayuda
en lnea asociadas: una para salida y otra para entrada de artculos. Su manejador de eventos
KeyDown selecciona la pgina adecuada basada en el modo actual del formulario.
If (e.KeyCode = Keys.F1) Then
If (ModoEntrada = True) Then
AyudaEnLinea(Me, "BuscarEntrada.htm")
Else

686 | Captulo 24:Adicin de ayuda en lnea

24_PATRICK-CHAPTER_24.indd 686 17/2/10 15:34:10


AyudaEnLinea(Me, "buscarsalida.htm")
End If
End If

El formulario Principal.vb es mucho ms diverso, seleccionando de entre nueve distintas pginas


en lnea cuando est en modo administrativo. Cada panel del formulario principal es como un
formulario completamente separado, as que agregu una pgina de ayuda en lnea para cada
panel. El cdigo en el manejador de eventos KeyDown del formulario muestra la pgina correcta
basada en el panel desplegado actualmente.
If (PanelArtsBiblioteca.Visible = True) Then
AyudaEnLinea(Me, "MainForm_Biblioteca.htm")
ElseIf (PanelRegistroClientes.Visible = True) Then
AyudaEnLinea(Me, "MainForm_Cliente.htm")
ElseIf (PanelAyuda.Visible = True) Then
AyudaEnLinea(Me, "FormularioPrincipal_Ayuda.htm")
ElseIf (PanelSalida.Visible = True) Then
AyudaEnLinea(Me, "FormularioPrincipal_Salida.htm")
ElseIf (PanelEntrada.Visible = True) Then
AyudaEnLinea(Me, "FormularioPrincipal_Entrada.htm")
ElseIf (PanelAdmin.Visible = True) Then
AyudaEnLinea(Me, "FormularioPrincipal_Admin.htm")
ElseIf (PanelProcesamiento.Visible = True) Then
AyudaEnLinea(Me, "FormularioPrincipal_Diario.htm")
ElseIf (PanelInformes.Visible = True) Then
AyudaEnLinea(Me, "FormularioPrincipal_Imprimir.htm")
Else
AyudaEnLinea(Me, "FormularioPrincipal_Basico.htm")
End If

El panel Ayuda del formulario principal incluye botones diseados para brincar a la tabla de
contenido e ndice del archivo de ayuda en lnea actual. Agregue el manejador de eventos para
estos botones. El cdigo para ambos FormularioPrincipal.AccAyudaContenido_Click y
FormularioPrincipal.AccAyudaIndice_Click es como el cdigo en la rutina AyudaEnLi
nea genrica, excepto para la llamada final a ShowHelp.
Private Sub AccAyudaContenido_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles AccAyudaContenido.Click
' ----- Muestra la tabla de ayuda en linea de contenido.
...
Ayuda.ShowHelp(Me, archivoAUsar, _
HelpNavigator.TableOfContents)
...
End Sub

Private Sub AccAyudaIndice_Click(ByVal sender As Object, _


ByVal e As System.EventArgs) _
Handles AccAyudaIndice.Click
' ----- Mostrar el indice de ayuda en linea.
...
Ayuda.ShowHelp(Me, archivoAUsar, HelpNavigator.Index)
...
End Sub

Proyecto | 687

24_PATRICK-CHAPTER_24.indd 687 17/2/10 15:34:10


Una vez que los archivos de ayuda en lnea (.chm) estn en su lugar, y una vez que la aplicacin
est configurada apropiadamente para ubicar los archivos en la estacin de trabajo, el usuario
puede acceder a ayuda de cualquier formulario al oprimir la tecla F1. En la figura 24-11 se mues
tra la ayuda accedida desde el panel Artculos de la biblioteca del formulario principal.

Figura 24-11. Respuesta a la llamada de ayuda.

Hablando de configurar correctamente los archivos .chm, todava tenemos que descubrir cmo
llevar la aplicacin completa (incluidos los archivos de ayuda en lnea) a la estacin de trabajo
del cliente, y a un costo que ponga comida en nuestra mesa. Veremos estos asuntos de la imple
mentacin en el siguiente captulo.

688 | Captulo 24:Adicin de ayuda en lnea

24_PATRICK-CHAPTER_24.indd 688 17/2/10 15:34:11


Captulo 25
Implementacin

Aunque Esopo vivi hace miles de aos, tiene mucho que decirnos sobre desarrollo Web. Su
historia de Pedro y el lobo es un ejemplo perfecto. Se trata de un nio pastor que engaa a los
aldeanos varias veces al gritar, Lobo! cuando no existe ese peligro. El truco era bueno para
algunas risas, pero despus el nio descubri las consecuencias de sus acciones: no pudo hacer
que ningn aldeano comprara su oveja y tuvo que comrsela l mismo. Uff! Si tan slo el nio
hubiera aprendido a llevar apropiadamente su rebao a las manos de los aldeanos en vez de in-
ventar mentiras basadas en el lobo, nunca hubiera tenido que llegar a ese final trgico.
Entonces, Esopo claramente nos muestra qu tan importante es la implementacin. Y Micro-
soft tom esta leccin al incluir varias opciones diferentes en Visual Studio que le permitieron
instalar aplicaciones compiladas y dar soporte a archivos en una estacin de trabajo de destino.
Veremos estos mtodos en este captulo, y usaremos uno de ellos para generar un programa de
instalacin para el proyecto Biblioteca.

Qu elementos participan en la implementacin?


En los das antes de Microsoft Windows, la implementacin no era tan difcil. Muchos progra-
mas no eran ms que un archivo ejecutable MS-DOS, con uno o dos datos de soporte y archivos
de ayuda. Eso era todo. Una vez que copiaba esos archivos en alguna carpeta en la estacin de
trabajo del cliente y actualizaba la variable de entorno PATH, estaba listo.
Las aplicaciones de Microsoft Windows (y programas grandes y complejos de MS-DOS) no
eran fciles de instalar. A menudo tenan colgando estos archivos DLL (archivos que tenan que
colocarse en lugares apropiados). Y algunas veces no saba cul era ese lugar apropiado, porque
un vendedor poda proporcionar el DLL sin documentacin suficiente. Despus estaban los
archivos de configuracin y de soporte de datos, cambios especficos de usuario o especficos de
la estacin de trabajo al sistema de registro, accesos directos en el escritorio y en el men Inicio,
desinstalacin de configuraciones y programas, dos conjuntos de formularios (triplicados) una
Biblioteca del Congreso, archivos de ayuda en lnea y de acuerdo de licencia, y lame para el CD
de distribucin, fuentes especiales que podan requerirse para el programa, etctera.

689

25_PATRICK-CHAPTER_25.indd 689 17/2/10 15:34:29


Creo que nunca he incluido la mitad de los archivos que necesita para desplegar una aplicacin
de Windows completa, pero ya puede ver lo complicado que es. Por fortuna, Visual Studio com-
partir la carga con usted a cambio de algo de configuracin simple de su parte.
Las caractersticas de despliegue en Visual Studio le proporcionan la funcionalidad bsica para
distribuir aplicaciones estndar de escritorio y basadas en Web. Si sus necesidades de implemen-
tacin son complejas, tambin puede comprar una herramienta de terceros de instalacin e im-
plementacin que incluya caractersticas avanzadas como soporte a secuencias de comandos.

Mtodos de implementacin dentro de Visual Studio


Con los lanzamientos tempranos de Visual Basic, si quera instalar su propio software personali-
zado al usar un programa de instalacin, tena que escribirlo usted mismo o usar una herramienta
comprada. Las herramientas de implementacin llegaron en algn momento a Visual Basic, sobre
el infame Asistente para empaquetamiento e implementacin. Este programa de instalacin
enlatado fue escrito en Visual Basic y poda mejorarlo para cumplir sus propias necesidades de
implementacin personalizado. Pero no era fcil. Y el resto del mundo ya estaba adoptando la
nueva plataforma Windows Installer para implementacin estandarizada por medio de archi-
vos .msi. El Asistente para empaquetamiento e implementacin utilizaba el viejo formato de
archivos .cab. Incluso para alguien como yo que realmente disfrutaba de la programacin, la
necesidad de escribir programas de instalacin efectivos algunas veces me arruin la vida.
Cuando surgi Visual Basic .NET 2002, la vida volvi a ser hermosa. Visual Studio inclua
herramientas que le permitan tener por objetivo tecnologa Windows Installer, al igual que los
grandes lo usaban. Seguro, fue una versin reducida que permita lanzar slo las aplicaciones ms
simples, pero vendedores de terceros deban tener algo para divertirse.
En estos das, Visual Studio incluye varios mtodos de desarrollo, un tributo a los diferentes ti-
pos de aplicaciones, los diferentes tipos de usuarios y los distintos tipos de entornos de seguridad
que un programador puede tener como destino. Lea cada uno de los mtodos disponibles para
ver cul satisface mejor las necesidades de su programa. Ya he hecho mi seleccin para el proyec-
to Biblioteca, que revelar en una ceremonia pblica como a la mitad de este captulo.

Implementacin directa con ASP.NET


Las aplicaciones ASP.NET son claramente diferentes de las aplicaciones de escritorio. Una gran
diferencia es que, para el usuario final, las aplicaciones ASP.NET realmente no tienen ninguna
implementacin. Slo explore al sitio Web correcto y ya estar usando la aplicacin. Pero la
implementacin todava es necesaria para el servidor Web que hospeda.
Si su servidor Web tiene Microsoft FrontPage Extensions instalado, puede instalar una aplica-
cin ASP.NET compilada desde la comodidad y seguridad de su entorno de desarrollo. Yo las

690 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 690 17/2/10 15:34:29


saqu a relucir en el captulo 23, pero Visual Studio le presenta la opcin de colocar una aplica-
cin Web en un sitio Web vivo cuando intenta crear la aplicacin ASP.NET. En el formulario
Nuevo sitio Web, puede seleccionar una URL HTTP como ubicacin de desarrollo, como se
muestra en la figura 25-1.

Figura 25-1. Inicio temprano en un sitio Web.

Ya que estar desarrollando interactivamente su sitio Web, tal vez no quiera usar este mtodo en un
servidor de produccin. En cambio, puede desarrollar de manera local en un directorio o en un ser-
vidor Web de desarrollo, y despus publicar el sitio en el servidor de produccin. Esto es tan fcil
como establecer la ubicacin HTTP desde el inicio. Con el sitio Web abierto en Visual Studio,
seleccione el men de comando Build Publicar sitio Web y especifique el URL del nuevo sitio
Web. No se requiere programa de instalacin.
ASP.NET es cuidadoso acerca de cmo maneja los archivos en su aplicacin. No publicar su
cdigo fuente. Copiar su archivo web.config al servidor (es un archivo requerido), que puede
contener su cadena de conexin de base de datos. Pero un servidor Web ASP.NET configurado
apropiadamente mantendr este archivo fuera de ojos fisgones.

Implementacin con XCopy


Los ensamblados .NET compilados contienen un manifiesto que describe por completo el en-
samblado y sus necesidades. Esto significa que puede copiar cualquier ensamblado en otro sis-
tema que tenga la versin correcta de .NET Framework instalada, siempre y cuando los otros

Mtodos de implementacin dentro de Visual Studio | 691

25_PATRICK-CHAPTER_25.indd 691 17/2/10 15:34:30


archivos que el ensamblado necesita se copien tambin, el programa se ejecutar. Esto se deno-
mina implementacin con XCopy porque puede usar el comando XCopy de lnea de coman-
dos para mover los archivos.
Tal vez piense, Bueno, vaya! Un ensamblado EXE es un programa de Windows real. Por su-
puesto que se ejecutar cuando lo copie a un nuevo sistema. Bueno, eso es cierto. Pero no es
cierto para aplicaciones viejas de Visual Basic. Los controles ActiveX utilizados por aplicaciones
de Visual Basic basadas en COM tienen que registrarse en el Registro de Windows antes de que
pueda acceder a ellos un motor en tiempo de ejecucin. Los programas viejos de Visual Basic
tambin requieren que las bibliotecas de tiempo de ejecucin de Visual Basic estn instaladas.
.NET Framework tambin debe instalarse para programas .NET, pero ya que el marco concep-
tual es administrado automticamente por el sistema Windows Update, no es tanto problema.
Lo que me ha tomado muchas frases decir es que en casi todos los casos podr instalar una
aplicacin .NET en una estacin de trabajo con slo copiar el programa, y tal vez unos cuantos
archivos de soporte, a un directorio. No estoy diciendo que as deba instalar programas. Real-
mente, estara asombrado (asombrado!) si descubriera a cualquiera de mis amigos programado-
res usando este mtodo en un entorno de negocios real. Pero .NET pone a su disposicin esta
opcin de implementacin, si ya no quiere ser mi amigo.
Si usa la implementacin con XCopy, tal vez no tendr ningn problema con seguridad o limi-
taciones administrativas que puedan imponerse en la estacin de trabajo. Las posibilidades son
que si est instalando software al usar el comando XCopy o al arrastrar y colocar archivos, tal
vez se debe a que es amigo del dueo de la estacin de trabajo, y no es realmente mi problema a
quin quiera tener por amigo.

Implementacin con Windows Installer


Windows Installer es el sistema de instalacin oficial proporcionado por Microsoft. Sirve como
sistema base para paquetes de instalacin estndar generados por Visual Studio, y tambin pro-
porciona las bases para las herramientas de instalacin ms populares de terceros.
Antes de Windows Installer, cada vendedor de paquete de instalacin haca las cosas como lo
crea conveniente. Pero esto significaba que los productos instalados algunas veces se golpeaban
entre s, porque un paquete de software no necesariamente buscaba archivos instalados por otra
herramienta. Reparar ese dao era difcil para el usuario, que en ocasiones ni siquiera saba qu
archivos se instalaban o actualizaban.
Microsoft busc cambiar eso con Windows Installer. Una de las caractersticas clave del sistema
es su base de datos de archivos instalados y actualizados. Tambin da soporte a una capacidad de
desinstalacin/restauracin y regreso a la ltima configuracin buena conocida para que cual-
quier falla pudiera deshacerse por completo, restaurando el sistema a su estado anterior. Otras
caractersticas incluyen soporte para parches, reinicio, mejoras personalizadas, algo de diseo
limitado de interfaz de usuario y peticin, y la habilidad de reparar o sanar un programa insta-
lado antes pero daado, e instalacin bajo demanda, que mantiene caractersticas o aplicaciones
completas en el medio de instalacin hasta que el usuario intenta usar esa caracterstica.

692 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 692 17/2/10 15:34:30


Windows Installer Version 4.x es la versin ms reciente para Windows Vista y otros sistemas pa-
ralelos de Windows. (Todava puede obtener la versin 3.x para Windows XP, o 2.x para algunos
sistemas de Windows viejos como Windows 98.)
El corazn del sistema Windows Installer es el archivo MSI (con un archivo de extensin .msi),
el archivo que contiene todos los archivos e instrucciones necesarias para instalar, actualizar y
desinstalar un producto de software. Visual Studio puede crear proyectos de instalacin basados
en el estndar MSI, aunque puede usar algunas de las caractersticas ms avanzadas de Windows
Installer a travs de Visual Studio. An as, si sus necesidades son simples (y la mayora del soft-
ware a nivel negocio escrito en Visual Basic tiene necesidades de instalacin simples), tal vez no
necesitar nada ms que Visual Studio.
Generar un proyecto de instalacin es tan fcil como crear proyectos de desarrollo de Visual
Studio. Pero primero necesito algo para configurar. Para el anlisis presentado en esta seccin,
he creado una aplicacin de escritorio. Bueno, no una muy buena. Simplemente he creado un
proyecto nuevo WindowsApplication1 con su Form1 predeterminada, y lo he guardado en mi
carpeta C:\temp. Todo lo que hace cuando la ejecuta es desplegar Form1.
Para crear un archivo de instalacin MSI para un proyecto de Visual Basic, abra ese proyecto en
Visual Studio y use el comando de men Archivo Agregar Nuevo Proyecto para agregar un
proyecto de configuracin a la solucin completa que contiene su proyecto original. En la figura
25-2 se muestra el cuadro de dilogo Agregar nuevo proyecto. Seleccione el tipo de proyecto Ins-
talacin e implementacin, y despus la plantilla Asistente para proyecto de instalacin, para crear
un programa de instalacin para el proyecto activo. Incluya el nombre y la ruta que desee en los
campos Nombre y Ubicacin de acuerdo con sus necesidades, y despus haga clic en Aceptar.

Figura 25-2. Adicin de un proyecto de instalacin a su solucin.

Mtodos de implementacin dentro de Visual Studio | 693

25_PATRICK-CHAPTER_25.indd 693 17/2/10 15:34:30


Aparece el Asistente para el proyecto de instalacin, llevndolo a travs de cinco pasos a la paz,
la armona y un archivo MSI funcionando.

Paso 1
El primer paso del asistente slo dice Bienvenido, as que haga clic en Siguiente y entre al
trabajo real.

Paso 2
El paso 2 le pregunta el tipo de proyecto de instalacin que habr de generarse. En lo personal,
pienso que pudo haberlo descubierto a partir del contenido de los proyectos ya cargados, pero
si el asistente hace todo, para qu necesitara el mundo programadores como nosotros? Existen
cuatro opciones, como se muestran en la figura 25-3.

Figura 25-3. Seleccin del tipo de programa de instalacin.

Las primeras dos opciones crean archivos de instalacin completos para cualquier aplicacin
de escritorio o basada en Web. (La instalacin basada en Web se entregara a un administrador de
sitio Web para instalacin en el servidor.) Los mdulos combinados le permiten crear una porcin
de una instalacin que puede despus combinarse en un archivo MSI completo. sta es una bue-
na opcin si est diseando una biblioteca que se usar para varias aplicaciones, pero no es til
por s sola. La opcin de archivo CAB crea un archivero de archivos que pueden instalarse al usar
una tecnologa vieja de distribucin de archivos. Es tambin el sistema de distribucin utilizado
para dispositivos porttiles. Como tengo como objetivo una aplicacin de escritorio, seleccionar
Crear un programa de instalacin de una aplicacin para Windows y har clic en Siguiente.

Paso 3
Aunque puede crear un programa de configuracin que simplemente instale varios archivos que
devoren su disco duro, por lo general generar un proyecto de instalacin basado en archivos o
salida compilada de otros proyectos. El tercer paso del asistente le pide que incluya elementos
de otros proyectos encontrados en la solucin activa de Visual Studio. He decidido incluir el
archivo EXE compilado desde mi proyecto de escritorio, como se muestra en la figura 25-4.
Por lo general, no quiero incluir mi cdigo fuente en el proyecto de instalacin, as que dejo ese
elemento sin marca. Pero el elemento Archivos de contenido puede ser til. Si mi proyecto tiene
un archivo de ayuda en lnea compilado (con una extensin de archivo .chm), podra agregarlo
como un archivo de contenido estndar para el proyecto principal mediante el comando de

694 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 694 17/2/10 15:34:31


Figura 25-4. Seleccin de elementos de proyecto que habrn de incluirse en la instalacin.

men Proyecto Agregar elemento existente. Ese archivo se clasificara como Contenido, y
podra moverse a esta instalacin de proyecto a travs de la seccin Archivos de contenido. Pero
hay otras formas de incluir ayuda en lnea en la instalacin, que veremos en el siguiente paso. Por
ahora, me quedar con la seccin Resultado principal y har clic en el botn Siguiente.

Paso 4
En este paso puede agregar cualquier otro archivo no especfico de proyecto que quiera a la ins-
talacin del proyecto (vase la figura 25-5). Los archivos Lame, el contenido de ayuda en lnea,
los acuerdos de licencia, las imgenes de sus hijos y casi cualquier cosa puede incluirse aqu. No
tengo nada ms que agregar. Haga clic en Siguiente.

Figura 25-5. Agregue esos otros archivos que siempre han querido una oportunidad para el estrellato en la instalacin
de proyecto.

Paso 5
El paso final despliega un resumen de las opciones que decidi (vase la figura 25-6). Bueno,
ese asistente fue muy sencillo. Tuvimos que trabajar en slo tres de los cinco pasos. Haga clic en
Finalizar para completar el asistente.

Mtodos de implementacin dentro de Visual Studio | 695

25_PATRICK-CHAPTER_25.indd 695 17/2/10 15:34:32


Figura 25-6. Confirmacin de sus opciones para el proyecto de instalacin.

Despus del asistente


Una vez que el asistente se completa, la interfaz principal para el diseo de proyecto de instala-
cin de Visual Studio aparece en la ventana de desarrollo. En la figura 25-7 se muestra Visual
Studio desplegando el proyecto de instalacin generado recientemente para WindowsApplica-
tion1, otro proyecto que tambin aparece en el panel Explorador de soluciones.

Figura 25-7. Un proyecto de instalacin dentro del entorno de desarrollo.

La ventana principal en la figura 25-7 es uno de los varios editores que le permiten personalizar
el proyecto de instalacin. Puede acceder a cada editor a travs del comando de men Ver
Editor, o al usar los botones de la barra de herramientas en el panel Explorador de soluciones.
Editor Sistema de archivos
Es el editor que ya vio en la figura 25-7. Presenta una vista estndar de carpeta/elemento
de porciones del sistema de archivos del sistema de destino. A travs de esta jerarqua,

696 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 696 17/2/10 15:34:33


puede colocar archivos (la salida EXE de su proyecto principal, los archivos de ayuda,
archivos de configuracin, mtodos abreviados a cualquiera de estos archivos, etc.) en
carpetas especiales (la carpeta Aplicaciones, Escritorio, Archivos de programa de 32 o 64
bits, Fuentes, la carpeta Men Inicio, y otras). Si no ve una carpeta que quiere en el siste-
ma de archivo, en panel de Equipo de destino, use el comando Accin Agregar carpeta
especial para incluirla en una lista. Adems de las carpetas especiales estndar, el men
Agregar carpeta especial incluye una opcin de carpeta Personalizada que le permite crear
una carpeta especfica en cualquier lugar del sistema de destino.
Editor Registro
Este editor despliega una jerarqua truncada de los panales de Registro. Cualquier clave o
valor agregado aqu se crear en el Registro del usuario durante la instalacin.
Editor Tipos de archivo
Este editor le permite definir asociaciones entre una extensin de archivo (como .txt) y
programas o acciones especficos. Cualquier accin personalizada, como Abrir o Imprimir,
puede vincularse a cualquier texto de comando que desee, incluidos los comandos que tie-
nen por objetivo el ensamblado principal que se instala.
Editor Interfaz de usuario
El proyecto de instalacin predeterminado incluye unos cuantos formularios que piden
cosas como la ubicacin de la instalacin y confirmacin de que la instalacin debe ocu-
rrir. Puede insertar cuadros de dilogo adicionales en el flujo de la instalacin. Pero tenga
cuidado: no estar agregando formularios completos habilitados por Visual Basic. En cam-
bio, seleccionar de un par de cuadros de dilogo predefinidos (como el cuadro de dilogo
Acuerdo de licencia, o 4 botones de opcin), y establecer las propiedades del dilogo para
configurar el texto de implementacin de cada campo o peticin del cuadro dilogo. Cada
campo/control de entrada del usuario incluye un valor con nombre que se usa en los otros
editores para limitar una accin de instalacin especfica. Por ejemplo, puede monitorear el
valor de una casilla de verificacin pedida por el usuario y, si el usuario no la marc, puede
detener la instalacin de ciertos archivos que estaban asociados a esa casilla de verificacin.
Editor Acciones personalizadas
Si necesita el nivel de control mximo, puede agregar una accin personalizada, una llamada
a un programa externo o secuencia de comandos, que se ejecuta en cierto punto del proceso
de instalacin (o desinstalacin).
Editor Condiciones de inicio
Si la estacin de trabajo de destino debe estar en un cierto estado antes de que pueda insta-
larlo correctamente, este editor le permite definir las condiciones limitantes. Como opcin
predeterminada, el instalador agrega .NET Framework como una condicin de instalacin;
el marco conceptual debe estar instalado antes de que el proyecto pueda instalarse. Puede ver
archivos especficos o claves de registro que deben estar presentes antes de que la instalacin
comience. Por ejemplo, tal vez quiera confirmar que los controladores de la base de datos de
destino estn en el sistema antes de que instale la aplicacin dependiente de base de datos.

Mtodos de implementacin dentro de Visual Studio | 697

25_PATRICK-CHAPTER_25.indd 697 17/2/10 15:34:33


Generacin del archivo MSI
Una vez que ha configurado su proyecto a travs de varios editores, da salida al archivo final MSI
al generar la solucin por medio del comando de men Generar Generar solucin. El archivo
MSI aparece en la ubicacin especificada en las propiedades del proyecto de instalacin (Proyec-
to Propiedades). Este archivo contiene todas las instrucciones y el contenido requerido para
instalar completamente la aplicacin en la estacin de trabajo de destino.

Implementacin con ClickOnce


Visual Studio 2008 incluye un mtodo de implementacin denominado ClickOnce. Est di-
seado para proporcionar la mxima facilidad de implementacin de instalacin para aplica-
ciones de escritorio (Windows Forms). Todava requiere un asistente, demonios!, pero para
instalaciones bsicas, eso es todo. Una vez que su aplicacin se publica mediante ClickOnce,
el usuario puede instalarlo directamente desde un sitio Web u otra ubicacin almacenada.
Esto suena como una instalacin MSI estndar, pero es diferente en varias formas:
Las implementaciones ClickOnce pueden instalarse aunque el usuario actual no tenga pri-
vilegios administrativos locales. Muchas instalaciones de software afectan a archivos clave
en las carpetas Windows y Windows\System32, o en otras carpetas importantes pero restrin-
gidas. Si es un desarrollador, es probable que nunca experimente este problema porque es el
administrador de su propia estacin de trabajo. Pero en organizaciones administradas por
el departamento de tecnologa de la informacin con muchos usuarios, existe un beneficio
en reducir el nivel de privilegio de usuarios individuales. Un efecto colateral negativo de
esto es que un administrador debe estar presente para instalar cualquier software. Pero
ste no es el caso con ClickOnce. Est su departamento de tecnologa de la informacin
comiendo? (en el sentido literal). No hay problema. Cualquier usuario puede instalar cual-
quier aplicacin publicada con ClickOnce. El software se instala en una caja de arena que
protege el sistema y otras aplicaciones de los intentos malvados del programa instalado por
ClickOnce.
Una aplicacin implementada con ClickOnce puede activar sus propias actualizaciones de
software automticas. Si se configura en esta forma, el programa revisar la ubicacin origi-
nal desplegada para una nueva versin, cada vez que se ejecuta. Si existe una nueva versin,
se instalar automticamente sin que el usuario tenga que hacer nada.
Las aplicaciones de ClickOnce estn diseadas para facilidad de instalacin. Con una apli-
cacin implementada con MSI, necesita descargar el archivo MSI y procesarlo a travs del
sistema Windows Installer. Aunque tambin tiene que descargar una implementacin con
ClickOnce, pasa de manera ms o menos transparente. Una aplicacin publicada por Click
Once puede configurarse para que se vea como una extensin de una pgina Web: haga
clic en un vnculo y el programa se ejecuta inmediatamente, desplegando su formulario
principal al usuario. (Puede haber algo de retraso, porque el programa se descarga a travs
de Internet.)

698 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 698 17/2/10 15:34:33


Eso suena grandioso. Pero no todo es pan comido. Ya que las aplicaciones con ClickOnce habi-
litado (como opcin predeterminada) se ejecutan en su propia caja de arena, estn limitadas en
su acceso a algunos recursos locales. Adems, para dar soporte completo a todas las caractersticas
automticas, debe agregar cdigo a su aplicacin que realiza la actualizacin real. (La propiedad
My.Application.Deployment proporciona acceso a esas caractersticas.)
Para implementar su proyecto por medio de ClickOnce, use el comando de men Generar
Publicar, en Visual Studio. Despus de hacerle algunas preguntas muy bsicas acerca del lugar
del que el usuario obtendr el archivo de implementacin (de un sitio Web, de una carpeta o de
un CD/DVD), Visual Studio genera el archivo de instalacin y lo hace disponible inmediata-
mente para su uso.
Por supuesto, tal mtodo le da slo las opciones de instalacin ms bsicas. Hace el EXE o DLL
principal de su proyecto (y sus dependencias) disponibles para instalacin en su estacin de
trabajo objetivo, pero es todo. Si quiere ms control sobre el proceso de publicacin y los com-
ponentes que incluir, use la pestaa Publish de sus propiedades del proyecto, como se muestra
en la figura 25-8.

Figura 25-8. El mundo de la publicacin, a slo un clic de distancia.

Este panel incluye campos que le permiten establecer el nmero de versin del paquete de insta-
lacin publicado. Si modifica este nmero de versin y vuelve a publicar la aplicacin, el cdigo
de implementacin personalizado que agregue a la aplicacin puede detectar la nueva versin e
iniciar una actualizacin desde la ubicacin de distribucin.

Mtodos de implementacin dentro de Visual Studio | 699

25_PATRICK-CHAPTER_25.indd 699 17/2/10 15:34:34


Resumen
Es realmente bueno que Visual Studio proporcione diferentes mtodos de implementacin para
sus aplicaciones personalizadas. Visual Basic y el entorno ms grande, Visual Studio, fueron
diseados como sistemas de programacin de propsito general que le permiten resolver casi
cualquier problema de desarrollo que enfrente usted o sus usuarios. Al tener unas cuantas opcio-
nes de implementacin diferentes, Visual Studio es de un propsito an ms general que antes,
y pienso que eso es grandioso. Seguro, tiene que tomarse cinco minutos y decidir entre MSI y
ClickOnce. Pero en casi todos los proyectos, las necesidades de los usuarios lo empujarn a una
direccin o la otra.
Le promet al principio del captulo que le dira mi eleccin para el mtodo de implementacin
del proyecto Biblioteca. He decidido una implementacin estndar de Windows Installer con
un archivo MSI. Explicar algunas de mis razones para seleccionar este mtodo en la siguiente
seccin.

Proyecto
Seleccion una implementacin estndar Windows Installer porque pens que coincidira ms
de cerca con las necesidades del usuario tpico del sistema Biblioteca. La aplicacin Biblioteca
est destinada a ser una caracterstica permanente en la estacin de trabajo de destino, as que es
probable que alguien con conocimiento de tecnologa de la informacin o privilegios adminis-
trativos realice las instalaciones reales. Como es un producto con licencia, hay poca probabilidad
de que pudiera colocar copias de la instalacin Biblioteca desde mi sitio Web pblico. Una
distribucin en CD (comn para instalaciones MSI) es el medio esperado. Adems, como es una
pieza de software de calidad de un vendedor confiable (se soy yo), no hay necesidad de una caja de
arena protectora. An as, la aplicacin incluye varios archivos, incluidos dos de ayuda en lnea;
entonces una instalacin XCopy sera una carga. A todo esto, una instalacin con MSI estndar
es el mejor plan de implementacin.

Planeacin de la implementacin
El Asistente para el proyecto de instalacin agrega automticamente mi ensamblado de proyecto
al archivo MSI, pero estoy seguro de que se necesitan otros archivos para desplegar apropiada-
mente el proyecto Biblioteca. Una vista rpida a travs de captulos previos revela la siguiente
lista de requisitos de archivado:
.NET Framework 3.5
ste debe estar instalado en el sistema de destino para ejecutar la aplicacin Biblioteca. El
programa de instalacin necesita instalar el marco conceptual automticamente si no est
ya en el sistema objetivo.
Biblioteca.exe
ste es el ensamblado principal. La instalacin sera intil sin ste.

700 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 700 17/2/10 15:34:34


BibliotecaBasica.chm y BibliotecaAdmin.chm
Estos archivos en lnea se instalarn en la misma carpeta que la aplicacin principal.
La fuente de cdigo de barras
Si ha obtenido derechos de distribucin para su fuente de cdigo de barras, su programa
instalacin puede copiarla directamente en la carpeta Fonts del sistema objetivo.
LicenciaBiblioteca.lic
Ah!, el archivo de licencia (recuerde que este archivo generado a mano necesita estar hecho
a la medida para cada cliente que compre la aplicacin Biblioteca). Compilarlo directamen-
te en el programa de instalacin parece extremo, porque tendra que regenerar la instalacin
para cada cliente. En cambio, pondr el archivo en el medio de distribucin (el CD) y har
que el usuario lo localice cuando ejecute el programa Biblioteca.
Kit de recursos de la Biblioteca ACME.pdf
Este archivo de nivel de administrador no debe instalarse como opcin predeterminada en
una estacin de trabajo. En cambio, permanecer en el CD de distribucin.
Script de creacin de base de datos.sql
Si estuviera desarrollando una aplicacin de usuario completa, generara un sistema de ins-
talacin separado para la porcin de servidor, enfocndome sobre todo. Ya que este libro est
diseado slo como una introduccin, slo copiar la secuencia de comandos de generacin
de base de datos al CD de distribucin y supondr que un representante de tecnologa de la
informacin calificado o un administrador de base de datos se ocupar de la instalacin.
El sitio Web Biblioteca
Como con la secuencia de comandos de creacin de base de datos, voy a copiar los archivos
de sitio Web al CD y permitir al administrador descubrir las cosas.
Lame.htm
El CD debe incluir un archivo de informacin en la raz que le diga al usuario cmo usar
los archivos en el CD. No he escrito el archivo todava, pero lo har antes de que el captulo
termine.
El archivo Setup generado incluir slo los primeros cuatro elementos de esta lista (tres si exclu-
ye la fuente), y los primeros dos los agregar automticamente el Asistente para el proyecto de
instalacin. Esto no ser muy difcil.

Generacin de proyecto de instalacin


En pginas anteriores de este captulo agregamos un nuevo proyecto de instalacin a un proyecto
existente, combinndolos en una sola solucin. Es posible generar un proyecto de instalacin
que aparezca solo dentro de Visual Studio. En estos proyectos necesita localizar el ensamblado
de destino (release\Biblioteca.exe) para incluirlo en la salida de Setup. Sin embargo, el Asistente
para el proyecto de instalacin no hace mucho si va por esa ruta. Entonces, para el proyecto
Biblioteca, agreguemos un nuevo proyecto de instalacin a un proyecto Biblioteca ya cargado
en Visual Studio.

Proyecto | 701

25_PATRICK-CHAPTER_25.indd 701 17/2/10 15:34:34


Acceso al proyecto
Cargue el proyecto Cap24 (Final) cdigo mediante las plantillas de Nuevo proyecto o ac-
cediendo directamente al proyecto desde el directorio de instalacin. Despus guarde el
proyecto en una carpeta donde quiera generar la solucin Setup completa. Tambin he
incluido una carpeta Cap25 en el directorio de instalacin, pero no como una plantilla de
proyecto. Esta carpeta ya contiene un proyecto de instalacin vinculado. Si desea ver esta
solucin terminada, abra el archivo Biblioteca.sln en la carpeta Cap25.

Los primeros pasos son iguales a los que dimos antes en este captulo. Una vez que tenga el
proyecto Biblioteca cargado y guardado en su carpeta de destino, agregue un nuevo proyecto
de instalacin al usar el men de comando Archivo Agregar Nuevo Proyecto. Seleccio-
ne Asistente para el proyecto de instalacin como plantilla, inserte InstalacionBiblioteca
como Nombre, y use la carpeta del proyecto Biblioteca que acaba de guardar como Ubicacin.
Aplique las siguientes configuraciones dentro del asistente:
En el paso 2 seleccione Crear un programa de instalacin de una aplicacin para Windows.
En el paso 3 seleccione Resultado principal de Biblioteca, de la lista.
En el paso 4 ubique y agregue los archivos BibliotecaBasica.chm y BibliotecaAdmin.chm. En
el directorio de instalacin de este libro puede encontrarlos en el subdirectorio denominado
Ayuda en lnea.
Complete el asistente y use el comando de men Archivo Guardar todo. Cuando se le pida
guardar el archivo de solucin (Biblioteca.sln), slo almacnelo en el directorio de proyecto Bi-
blioteca, que debe estar seleccionado.
Como antes, el proyecto de instalacin abre el Editor Sistema de archivos. Antes de hacer cual-
quier cambio dentro del editor, configuremos algunas propiedades en el nivel de la instalacin.
Haga clic en InstalacionBiblioteca en el panel Explorador de soluciones y modifique las siguien-
tes propiedades en el panel Propiedades:
Establezca la propiedad Author en Tim Patrick, o su propio nombre.
Establezca la propiedad Manufacturer en ACME.
Establezca la propiedad ManufacturerURL en http://www.timaki.com o cualquier sitio
Web que desee usar.
Establezca la propiedad ProductName en Biblioteca ACME.
Establezca la propiedad Title en Instalacin de la biblioteca ACME.
Debido a que el Editor Sistema de archivos est abierto, hagamos algunos cambios ah. Cuando
agregamos el ensamblado Biblioteca.exe a travs del asistente, descifr todas las dependencias
necesarias. No slo el programa principal y los elementos de archivo de ayuda aparecen en la
seccin Carpeta de la aplicacin, sino tambin tres DLL adicionales; todos solan ejecutar los
informes de Biblioteca (vase la figura 25-9).

702 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 702 17/2/10 15:34:34


Figura 25-9. Muchos archivos ms de los que negociamos.

Ya que Microsoft proporciona estos tres DLL como parte de .NET, no tiene mucho sentido
almacenarlos en mi propio directorio de instalacin de la aplicacin. Deben ir en el cach de
ensamblado global (GAC, Global Assembly Cache), la carpeta de sistema especial que mantiene
los ensamblados .NET compartidos. GAC no es una de las opciones de carpeta desplegadas
en el editor, pero puede serlo. Asegrese de que el panel de la izquierda del Editor del Sistema
de archivos est seleccionado (el que tiene Sistema de archivos en Equipo de destino) y use el
comando de men Accin Agregar carpeta especial Carpeta Cach de ensamblado global.
Una nueva carpeta, Carpeta Cach de ensamblado global, aparece en el panel de la izquierda.
Seleccione el elemento Carpeta de la aplicacin de nuevo y arrastre los tres elementos DLL al
elemento Carpeta Cach de ensamblado global como se muestra en la figura 25-10.

Figura 25-10. Haga que los tres archivos DLL sean responsabilidad de alguien ms.

Agreguemos dos accesos directos al sistema del usuario durante la instalacin: uno en el escritorio
y uno en la seccin Programas del men Inicio. Ambos mtodos abreviados apuntan al ensambla-
do Biblioteca.exe principal. Al Asistente para el proyecto de la instalacin anticip nuestras nece-
sidades al agregar las carpetas Escritorio de usuario y Men programas del usuario al Editor Sistema
de archivos. Todo lo que tenemos que hacer es agregar un acceso directo a cada carpeta.
Empecemos con el escritorio. Seleccione la carpeta Escritorio de usuario y despus haga clic con el
botn derecho en el panel de la derecha (donde aparecern los archivos). Del men contextual,
seleccione el comando de men Crear nuevo acceso directo. (Este mismo comando est disponi-
ble en el men Accin principal cuando el panel del lado derecho est activo.) Aparece el cuadro
de dilogo Seleccionar elemento en el proyecto, como se muestra en la figura 25-11. Explore
el elemento Carpeta de la aplicacin y seleccione Resultado principal de biblioteca (Activo).
El nuevo acceso directo aparece en el panel de la derecha, esperando que le d un nombre ms
significativo. Asgnele el nombre Biblioteca ACME.

Proyecto | 703

25_PATRICK-CHAPTER_25.indd 703 17/2/10 15:34:35


Figura 25-11. Adicin de un nuevo acceso directo a la carpeta de sistema de archivos objetivo.

Para crear el mismo acceso directo en el men Inicio, siga los pasos del prrafo anterior, pero
inicie desde la carpeta Men Programas del usuario en lugar de Escritorio del usuario.
Agregar estos accesos directos fue una buena idea, pero despus de que instalo algn software
nuevo, siempre borro inmediatamente cualquier acceso directo que se agrega al escritorio. Agre-
gar un cono en la carpeta Programas del men Inicio tiene sentido, pero me gusta mantener un
escritorio limpio y agradable. Rase si quiere, pero mantener el escritorio libre de desorden es lo
que me hizo un autor y desarrollador famoso en todo el mundo.
Lo que necesitamos es una forma de alterar el comportamiento del programa de instalacin para
que no cree el cono de escritorio, si el usuario no quiere uno. El proyecto de instalacin propor-
ciona una forma de hacerlo. Primero, necesitamos agregar una peticin donde el usuario indique
una preferencia de cono de escritorio, y despus necesitamos actuar sobre esa preferencia. El
primer paso consiste en alterar la interfaz de usuario del programa de instalacin. Estos cambios
ocurren con el Editor Interfaz de usuario. Despliegue este editor al usar el comando de men
Ver Editor Interfaz de usuario. Aparece el editor Interfaz de usuario, como se muestra en
la figura 25-12.
El editor Interfaz de usuario se divide en dos tipos de instalacin principales: Instalar e Instala-
cin administrativa. La rama administrativa se usa slo cuando un administrador quiere almace-
nar la imagen de instalacin en una carpeta de red compartida. No permite los tipos de cambios
que queremos hacer. Entonces, enfoqumonos en la rama Instalar estndar, que maneja las ins-
talaciones de usuario estndar en una estacin de trabajo de cliente. Ambas ramas incluyen indi-

704 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 704 17/2/10 15:34:36


Figura 25-12. El editor Interfaz de usuario despliega cada cuadro de dilogo e indicador.

cadores paso a paso que aparecen al usuario durante el proceso de instalacin. Los indicadores de
recoleccin de datos slo pueden agregarse a la entrada Inicio en la rama principal Instalar.
Durante la instalacin real, la interfaz de usuario interacta con el usuario en una forma parecida
a un asistente. Durante la fase Inicio, el programa de instalacin recolecta los deseos del usuario
para el resto del proceso. Una vez que esta seccin termina, la instalacin contina hasta que
se completa o falla. Lo que queremos hacer es insertar un nuevo paso en el proceso de asisten-
te, desplegando una casilla de verificacin que le pregunte al usuario si el cono de escritorio
debe aparecer o no. Los campos de recoleccin de datos adicional como stos se agregan a travs
de nuevos cuadros de dilogo. Y se resulta ser un cuadro de dilogo que incluye una casilla de
verificacin personalizable. En la rama Instalar, haga clic con el botn derecho en el elemento
Inicio y seleccione Agregar cuadro de dilogo del men contextual. La ventana Agregar cuadro
de dilogo, como se muestra en la figura 25-13, despliega los cuadros disponibles. Seleccione el
elemento Casillas (A) de la lista y haga clic en Aceptar.
El nuevo elemento Casilla (A) aparece en la seccin Instalar/Inicio. Use el ratn para arrastrarlo
hasta que aparezca entre los cuadros de dilogo Pantalla de bienvenida y Carpeta de instalacin.
El cuadro de dilogo Casilla le permite desplegar hasta cuatro selecciones de casilla de verifica-
cin con leyendas personalizadas. Asegrese de que est seleccionado en el esquema del dilogo
y despus use el panel Propiedades para establecer estas nuevas propiedades del dilogo:
Escriba Opciones de instalacin en la propiedad BannerText. Este texto aparecer cerca
de la parte superior de la ventana de dilogo, desplegando un ttulo principal grande.
En la propiedad BodyText escriba Seleccione las opciones que desee usar para esta insta-
lacin.

Proyecto | 705

25_PATRICK-CHAPTER_25.indd 705 17/2/10 15:34:36


Figura 25-13. Unas cuantas opciones de cuadro de dilogo diferentes estn disponibles para personalizar la instalacin.

En la propiedad Checkbox1Label escriba Agregar un cono para la Biblioteca ACME en el


escritorio. Esto define el texto personalizado para el primer control de casilla de verificacin.
Establezca la propiedad Checkbox1Property en LIBRARY_DESKTOP_LINK. Esto le
da un nombre a la casilla de verificacin que podemos usar despus para modificar el proce-
so de instalacin.
Establezca la propiedad Checkbox1Value en Checked. Esto hace que la inclusin de un
cono en el escritorio sea la opcin predeterminada de la instalacin.
Establezca la propiedad Checkbox2Visible, Checkbox3Visible y Checkbox4Visible
en False, ocultando las otras tres casillas de verificacin no utilizadas.
Durante el proceso de instalacin, el usuario ver la nueva consulta mediante el cuadro de di-
logo de la figura 25-14. Incluye un texto en una franja, el cuerpo de texto y una sola casilla de
verificacin, como se configur en las propiedades del dilogo personalizado.
Ahora es momento de usar esa configuracin de casilla de verificacin. Seleccione Editor Interfaz
de usuario y regrese a Editor Sistema de archivos. Seleccione la carpeta Escritorio del usuario en el
panel del lado izquierdo y despus vaya al panel Propiedades. Una de las propiedades mostradas
es Condition, que permite definir una condicin Boolean que, cuando es cierta, instala los ar-
chivos asociados en el escritorio del usuario. Sin embargo, si la condicin es falsa, ningn archivo
asociado se colocar en el escritorio del usuario durante la instalacin. Incluya el siguiente texto
en esta propiedad:
LIBRARY_DESKTOP_LINK

ste es el nombre que le dimos a la primera casilla de verificacin en el diseo del dilogo.
Durante la instalacin, el programa de instalacin revisa la seleccin del usuario y modifica la
actualizacin de escritorio como se pida.

706 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 706 17/2/10 15:34:37


Figura 25-14. El escaso pero til cuadro de dilogo con una casilla de verificacin en accin.

Algo que no agregar a mi versin del programa de instalacin es la fuente de cdigo de barras.
Lamentablemente, no he adquirido una licencia para distribuir una fuente de tercero a usted o
nadie ms que lea este libro. La buena noticia es que le ahorr 10 dlares en el costo del libro. La
mala noticia es que tendr que decirle cmo agregar la fuente, pero no lo haremos en realidad.
Realmente, tal vez adivine cmo hacerlo. La carpeta Fonts es una de las carpetas especiales dispo-
nibles en el editor Sistema de archivos. Cuando el elemento Sistema de archivos en el equipo de
destino, en el panel de la izquierda, use el comando de men Accin Agregar carpeta especial
Carpeta Fuentes. Despus agregue el archivo de fuente original (un archivo TrueType .ttf) a la
seccin de carpetas Fuentes. No podr agregar esta fuente directamente desde su carpeta Windows\
Fonts. En cambio, necesitar obtener el archivo .ttf y usar eso. En la estacin de trabajo de destino,
el programa de instalacin instalar y registrar apropiadamente la fuente para uso en Windows.
El proyecto de instalacin est completo. Lo nico que queda por hacer es generar el archi-
vo MSI. Tal vez no lo haya notado, pero Visual Studio incluye diferentes configuraciones de
compilacin en cada proyecto. Las dos configuraciones predeterminadas son Depuracin y
Liberacin, y cada una puede generar un conjunto distinto de archivos de salida finales cuando
compila su aplicacin. Por lo general, su proyecto est establecido en Depuracin, pero puede
cambiarlo con el Administrador de configuracin. En Visual Studio seleccione el comando de
men Generar Administrador de configuracin para desplegar el formulario del adminis-
trador (vase la figura 25-15). En este formulario cambie la configuracin Configuracin de
soluciones activas de Debug a Release y despus haga clic en el botn Cerrar.

Proyecto | 707

25_PATRICK-CHAPTER_25.indd 707 17/2/10 15:34:37


Figura 25-15. El formulario Administrador de configuracin.

Es tiempo de generar el archivo MSI. Haga clic con el botn derecho en la raz InstalarBiblioteca
en el panel Explorador de soluciones, y seleccione Generar del men contextual. En slo unos
cuantos segundos, su archivo MSI estar horneado y listo para comer. Lo encontrar en el sub-
directorio Release del proyecto de instalacin. Este directorio tambin incluye un archivo Setup.
exe que acta como arranque. Cualquier estacin de trabajo con el sistema Windows Installer
presente funcionar con el archivo MSI simple, pero proporcionar un archivo Setup.exe agrega
un nivel de confort a los usuarios novatos.

El medio de distribucin
Odio cuando los usuarios vienen a mi oficina e intentan copiar el archivo MSI directamente de
mi disco duro. Encuentro que proporcionar el archivo en un CD tiende a mejorar la relacin
vendedor-cliente. As que generemos un CD para uso de cliente.
El CD de distribucin contiene todo el contenido necesario para la biblioteca de personal de
tecnologa de la informacin para soporte a la aplicacin. Contiene distintos directorios para
cada tipo de contenido. Aqu est lo que planeo colocar en la raz del CD:
Lame.htm, un archivo HTML que despliega informacin acerca de contenidos del CD.
Base de datos, un directorio que contiene la secuencia de comandos de creacin de base de
datos, Script de creacin de la base de datos.sql.
Licencia, un directorio que contiene el archivo de licencia del usuario especfico, LicenciaBi-
blioteca.lic.
Instalacin, un directorio que contiene el archivo MSI principal, InstalacionBiblioteca.msi.
Recursos tcnicos, un directorio que contiene la documentacin de soporte tcnico, Kit de
recursos de la Biblioteca ACME.pdf.
Web, un directorio que contiene un cdigo fuente completo para el sitio Web Biblioteca que
creamos en el captulo 22. El administrador puede usar esto como la base de un sitio Web
Biblioteca expandido.

708 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 708 17/2/10 15:34:38


He puesto todos estos directorios y sus archivos en el directorio de instalacin del libro, en un
subdirectorio denominado Contenido CD Biblioteca.
El archivo Lame.htm contiene el siguiente contenido amigable para el administrador.

Biblioteca Acme 1.0


Bienvenido al sistema Biblioteca Acme. Este producto fue desarrollado como parte del
proyecto del libro Programacin en Visual Basic 2008, escrito por Tim Patrick. Cuando se
instala y configura apropiadamente, la aplicacin debe darle aos de valor de administra-
cin de biblioteca.
El CD de instalacin incluye las siguientes carpetas:
Base de datos
El archivo Script de creacin de la base de datos.sql contiene una secuencia de comandos
SQL Server que puede usarse para generar una nueva base de datos ACME.
Licencia
El archivo LicenciaBiblioteca.lic contiene la licencia para su sitio. Una vez que ha ins-
talado la aplicacin Biblioteca en una estacin de trabajo, copie el archivo de licencia
a esa estacin. Al usar la aplicacin Biblioteca, inicie sesin como administrador. Se le
pedir la ruta de archivo de la licencia en ese momento.
Instalacin
El archivo InstalacionBiblioteca.msi realiza una instalacin de cliente estndar del pro-
ducto Biblioteca.
Recursos tcnicos
El archivo ACME Library Resource Kit.pdf contiene informacin tcnica acerca del
sistema Biblioteca ACME, sus archivos de configuracin y su base de datos.
Web
Este directorio contiene un ejemplo de aplicacin ASP.NET basada en Web que pue-
de modificar para permitir que los clientes interacten con la base de datos Biblioteca
ACME a travs de un explorador Web.

Este CD y su contenido son 2008 por Tim Patrick.

Proyecto | 709

25_PATRICK-CHAPTER_25.indd 709 17/2/10 15:34:38


Quiero que este archivo aparezca automticamente cuando el usuario inserte el CD en la unidad
de la estacin de trabajo. Esto requiere un archivo adicional denominado autorun.inf en la raz
del CD. Este archivo estilo INI simple da soporte a la caracterstica Auto Run utilizada por CD
de Windows. Aqu est el contenido de ese archivo que desplegar el archivo Lame.htm auto-
mticamente:
[Autorun]
Open=explorer.exe Lame.htm

Copiar todos estos directorios y archivos a un CD y agregar una etiqueta bonita debe producir
un bibliotecario feliz.
Nos estamos acercando rpidamente al final de este libro. Slo falta un captulo. Voltee la pgina
para descubrir qu contenido emocionante encontrar ah.

710 | Captulo 25: Implementacin

25_PATRICK-CHAPTER_25.indd 710 17/2/10 15:34:38


Captulo 26
Proyecto completo

Lo ha hecho! Ha completado el proyecto Biblioteca y lo ha hecho con aclamacin de com-


paeros usuarios y programadores. Y tambin ha logrado algo que pocos pensaron posible: ha
trabajado persistentemente a travs de los 26 captulos de este libro. Tal vez est ansioso por con-
tinuar con su vida como un consultor de software bien pagado, trabajando slo seis meses al ao
como programador a quien otros programadores llaman cuando el sistema falla. Bueno, no lo
entretendr mucho tiempo. Pero existen algunos otros problemas para analizar correspondientes
al proyecto Biblioteca y la programacin en general.

El proyecto Biblioteca
El proyecto Biblioteca est lleno de caractersticas que tienen por objetivo organizaciones peque-
as estilo biblioteca. Pero tal vez no cumpla las necesidades de todas las personas. Y eso est bien.
Los usuarios saben su direccin y nmero telefnico; sabr de ellos. Cuando ellos llamen, puede
decirles que el software no est diseado para todos; ningn software puede estarlo. Todo el soft-
ware, incluidas aplicaciones de propsito general como Visual Studio, nunca pueden cumplir
las necesidades de cada persona u organizacin. Lo que es importante es que las caractersticas
incluidas en el proyecto cumplen las necesidades de la audiencia planeada. La audiencia puede
ser el pblico que usa catlogo con tarjetas, o puede ser slo una pequea biblioteca con un
miembro de personal de medio tiempo.
An as, siempre hay espacio para mejoras. Debido a que la audiencia de destino real del proyec-
to Biblioteca fue usted (el estudiante de Visual Basic y .NET) no tiene todas las caractersticas
que casi todas las bibliotecas requieren. Al revisar rpidamente el cdigo fuente, se me ocurrieron
al menos los siguientes cambios que pueden hacer que el proyecto lleve mucho ms valor a los
administradores de biblioteca y usuarios:
Registro de errores
La aplicacin incluye deteccin de errores rudimentaria y caractersticas de manejo, pero
pueden definitivamente ser mejoradas. La caracterstica de registro utilizada en el mtodo
ErrorGeneral de la aplicacin (que incluye una llamada a My.Application.Log.Wri-
teException) enva el contenido escrito a cualquiera que escucha el protocolo registrado.

711

26_PATRICK-CHAPTER_26.indd 711 17/2/10 15:34:54


Usamos los mismos escuchas, pero pudimos haber agregado escuchas a informes de error re-
colectados de manera central y detalles en una base de datos o archivo para anlisis posterior.
Manejo de errores
Cuando un error ocurre, la mayor parte del cdigo Biblioteca simplemente informa del
error y contina. Algunos mtodos ignoran los errores por completo. En general, el cdigo
puede hacer un mejor trabajo de resultados de procesamiento de error. Algunos errores son
ms fatales que otros, y errores especficos deben incluir opciones adicionales a los que el
usuario puede acceder para recuperarse mejor de la falla.
Multiprocesamiento
No aprovechamos ni analizamos ninguna de las caractersticas de multiprocesamiento inclui-
das en .NET Framework. Las actividades intensas de proceso tienden a matar la respuesta
de la interfaz de usuario, pero hay formas de mitigar el impacto. En el proyecto Biblioteca,
dos reas especficas se beneficiaran del uso de subprocesos de trabajo en segundo plano, ya
sea usando las caractersticas de espacio de nombres System.Threading directamente, o el
control Back groundWorker: 1) buscar artculos de la biblioteca con el formulario Busque-
daArticulo, y 2) procesando de datos de vencimiento y multa para un solo da en todas las
ubicaciones a travs del controlador de evento MainForm.AccProcesar_Click.
Interfaz de usuario y presentacin
Aunque inclu algunas bonitas imgenes en el formulario principal del proyecto Biblioteca
y el formulario Bienvenida, no hice mucho ms que eso. En especial, fue un tema de tiempo
y esfuerzo, pero tambin tengo muy poco talento para las artes grficas. El programa puede
usar una actualizacin en su aspecto general y presentacin. Y con unas cuantas caractersti-
cas grficas disponibles mediante la base de presentacin de Windows (WPF, Windows Pre-
sentation Foundation) puede habilitar algunos efectos realmente sorprendentes con poco
esfuerzo de programacin.
Consistencia de interfaz de usuario
Aunque he intentado ser cuidadoso, tal vez existan etiquetas, controles y mensajes de error
que usan dos nombres diferentes para lo mismo. Tal vez us la palabra libro o DVD cuando
tuve que haber usado un trmino ms general. Aunque rastrear tal consistencia es mucho
trabajo, incrementa el nivel de profesionalismo en su aplicacin. Tambin hace que la tarea
de traduccin a idiomas extranjeros sea ms fcil cuando se localiza el programa.
Prueba de nueva base de datos
El formulario LocalizarBaseDatos.vb genera una cadena de conexin de los campos propor-
cionados por el usuario, pero no prueba la conexin para ver si funciona. Proporcionar una
opcin para probar los valores insertados puede reducir errores a largo plazo. Una mucho
mejor opcin sera dejar que el usuario busque la base de datos, as como SQL Server rastrea
y presenta servidores y bases de datos ubicados.
Bsquedas de ttulo numrico
Las caractersticas de salida y entrada le permiten ubicar un elemento por nombre o por
cdigo de barras. Si inserta un nmero, el programa supone que ha insertado un cdigo de

712 | Captulo 26:Proyecto completo

26_PATRICK-CHAPTER_26.indd 712 17/2/10 15:34:54


barras y recupera el elemento coincidente. Pero algunos ttulos de libros son numricos. Por
ejemplo, el libro 1776 de David McCullough causara al programa algo de dificultad si cada
copia no incluyera su propio cdigo de barras. Una mejora al programa proporcionar las
opciones para eliminar estas ambigedades cuando una entrada numrica coincidiera con el
cdigo de barras y con el ttulo.
Bsquedas de ttulo mejoradas
Aunque tengo mucha razn para estar impresionado por mi cdigo de bsqueda de ele-
mentos, el programa podra hacer mucho ms. Cuando usa el sistema de catlogo de tar-
jetas en bibliotecas ms grandes, las caractersticas de bsqueda incluyen bsquedas de
proximidad, que regresan resultados con semejanza alfabtica a los trminos de bsqueda
proporcionados por el usuario. SQL Server tambin tiene una opcin bsqueda de texto
completo que puede usarse para ampliar las bsquedas de elemento.
Reservaciones
Empec a agregar una caracterstica reservaciones al proyecto Biblioteca para que los clien-
tes pudieran agregar sus nombres a una lista de espera de artculos de la biblioteca prestados
y hacer que el personal de la biblioteca los aparte cuando el cliente anterior los devuelva.
Aunque sera una caracterstica grandiosa y til para una biblioteca, no agregaba ningn
valor pedaggico al libro, as que lo dej fuera. Pero todava escucho al software sorbiendo y
llorando a veces cuando piensa en la caracterstica que pudo haber sido. sta sera una gran
mejora para la versin 2.
Historia incompleta de artculos
En el formulario RegistrosCliente.vb, la lista Multas muestra los elementos prestados antes al
cliente slo si tales elementos alguna vez han estado vencidos y han incurrido en multas. Los
elementos que se regresaron a tiempo no pueden desplegarse en la lista al usar el formulario
lgico actual. Un cambio satisfactorio agregara una casilla de verificacin Mostrar todos
los artculos devueltos que incluyera estos elementos devueltos. Esto permitira a un biblio-
tecario cobrar cosas como daos a artculos que, de otra forma, estaran libres de multas.
Regreso de elementos faltantes
Si un artculo se marca como faltante, el personal de la biblioteca puede cobrar al cliente la
prdida del libro. Si ste devuelve despus este artculo, el bibliotecario puede procesar un
reembolso al cliente. Pero el programa puede simplificar esta tarea al hacer automticamente
que el artculo sea elegible para ese reembolso. Esto requerira un nuevo campo de estado en
la tabla de base de datos CopiaCliente para rastrear el estado.
Interaccin de diseo de cdigo de barras
El formulario EtiquetaCodigoBarras.vb es, creo, bastante impresionante con su vista previa
de grficos de cdigo de barras. Pero la vista previa es slo unidireccional; el usuario no
puede seleccionar un elemento de despliegue al hacer clic en ese elemento en la vista previa.
En cambio, es necesario hacer clic en el elemento relacionado en la lista DesplegarArti-
culos. Mejorar el programa para detectar clics en la vista previa y traducirlos en selecciones
de elementos hara que el programa fuera muy parecido a otras aplicaciones que soportan
caractersticas de dibujo bsicas.

El proyecto Biblioteca | 713

26_PATRICK-CHAPTER_26.indd 713 17/2/10 15:34:54


Caractersticas de instalacin de base de datos
Aunque generamos el programa de instalacin para la aplicacin Biblioteca principal, escati-
mamos en el lado del servidor, slo proporcionando secuencias de comandos de creacin de
bases de datos como archivos de texto en medios de instalacin. Un sistema ms profesional
proporcionara un programa de instalacin separado que pudiera generar y configurar una
base de datos desde una instalacin SQL Server existente.
Soporte para estndares de biblioteca
Al igual que el mundo de desarrollo de software tiene formatos estndar y protocolos como
XML, los sistemas de biblioteca tambin comparten estndares comunes. Dos estndares
aceptados son MARC (Machine-Readable Cataloging, un formato de datos estndar de
manejo de categora mediante tarjetas) y la interfaz Z39.50 (un protocolo de comunicacin
utilizado para bsquedas entre computadoras y recuperacin de datos). Incorporar estos
estndares en un sistema de biblioteca pequeo puede ser muy complicado, pero traeran un
nivel mucho mayor de automatizacin y conveniencia al personal de biblioteca.
Reparaciones de errores
Tal vez dej unos cuantos errores en la aplicacin. No, espere. Creo que los puse ah para
hacerle una prueba, para ver si estaba aprendiendo y creciendo en sus habilidades de pro-
gramacin. Los encontr?
stas son slo algunas mejoras que pens con la parte superior de mi cabeza. Si hubiera ido hasta
mis hombros, hubiera surgido con muchas ms. Si su software tendr por objetivo la poblacin
general de usuarios, tal vez lanzar actualizaciones en un programa regular, como anualmente,
y cambiar apropiadamente caractersticas mejoradas. Si escribi la aplicacin para un cliente
especfico, las actualizaciones pueden ser ms frecuentes, incluso mensuales o diarias en algunos
casos. Sin importar el tamao de la audiencia, sus oportunidades de mejorar el software sern
regulares y continuas.

Flexibilidad de Visual Basic


Empec a usar Visual Basic cuando la versin 2.0 del producto estaba de moda. Como resultado,
tom algunos hbitos de codificacin previas a .NET que han sido difciles de romper, aunque
concentrndome por completo en el cdigo .NET. He llegado a un nivel de comodidad en mi
codificacin de Visual Basic, y tal comodidad se muestra en mi estilo de programacin en .NET.
Como mencion en captulos anteriores, muchas de las caractersticas que existieron en Visual
Basic antes que en .NET fueron apartadas del lenguaje e incluidas en clases de Framework. La
ms notable de estas caractersticas matemticas ahora se encuentra en la clase System.Math.
Pero fueron otras palabras clave de lenguaje Visual Basic no matemtico que tambin se volvie-
ron mtodos de clase. Muchos de stos aparecen en el espacio de nombres Microsoft.Visual-
Basic, incluidos mtodos como Left, Trim y MsgBox.
Cuando escrib el cdigo del proyecto Biblioteca, utilic libremente algunas caractersticas en-
contradas en el espacio de nombre Microosft.VisualBasic. Aunque no tengo problema con

714 | Captulo 26:Proyecto completo

26_PATRICK-CHAPTER_26.indd 714 17/2/10 15:34:54


esta prctica, tal vez haya encontrado a otros desarrolladores de Visual Basic que no estn de
acuerdo con la manera en que he escrito el cdigo. Han apuntado que la mayor parte, y posible-
mente todas, las caractersticas en Microsoft.VisualBasic tienen equivalentes en la bibliote-
ca de clases de Framework (FCL, Framework Class Library), y stas deben usarse para razones
de compatibilidad con otros lenguajes y sistemas .NET.
Un ejemplo clave es la funcin MsgBox. La he usado en todo el cdigo fuente de Biblioteca. La
palabra clave MsgBox siempre ha sido parte del lenguaje de Visual Basic, pero ms all de su exis-
tencia continua en Microsoft.VisualBasic, no es parte de las clases Framework. En lugar de
MsgBox, otros programadores (incluidos los programadores de C#) usan el mtodo SystemWin-
dows.Forms.MessageBox.Show. Ofrece ms opciones que MsgBox y despliega un cuadro de
mensaje que es tan hermoso como la versin de Visual Basic. Pero en mi caso, mis dedos se han
acostumbrado a escribir la palabra clave de seis caracteres MsgBox (MessageBox.Show tiene 15
caracteres!) Tambin, los argumentos pasados a MessageBox.Show estn un poco reordenados
en relacin con los que se utilizaban. Usar ambos en un solo programa puede llevar a confusin.
Quienes apoyan MessageBox.Show destacan que si alguna vez se necesita convertir el cdigo
de Visual Basic a C#, la presencia de MsgBox hara ms lenta la conversin. Aunque entiendo
sta y otras preocupaciones, todava no se me ha convencido completamente de que haya algn
problema con el uso de MsgBox. Cualquier herramienta de conversin que existe para cambiar
cdigo de Visual Basic a C# ciertamente sabr cmo manejar MsgBox.

A partir de la edicin 2008, Visual Basic incluye algo llamado agilidad de


tiempo de ejecucin. sta es una forma lujosa usada por la mercadotecnia
para decir que ahora puede compilar y destruir aplicaciones Visual Basic sin la
necesidad del espacio de nombres Microosft.VisualBasic y ensamblados
relacionados. Aunque esto no es un gran problema para la mayor parte de las
aplicaciones de escritorio o ASP.NET, la capacidad de compilar un programa
de Visual Basic con algunas dependencias, y por tanto una recoleccin de in-
formacin ms pequea, afecta la descarga rpida de lgica personalizada en
la Web mediante el producto Silverlight de Microsoft. Si tendr por objetivo
esta plataforma, ser una buena idea omitir todas las referencias a caractersticas
encontradas en Microsoft.VisualBasic.

Como otro ejemplo, considere la antigua instruccin Exit Sub. Todava existe en Visual Basic
para .NET, pero una nueva palabra clave Return realiza el mismo trabajo de terminar inmedia-
tamente desde el mtodo actual. (Return tena un significado diferente en Visual Basic antes que
.NET, pero ahora slo es un mtodo de salida.) Puede usar Exit Sub o Return en su cdigo,
tienen una funcionalidad idntica. Hay programadores que consideran la antigua instruccin
Exit Sub como si fuera (bueno) vieja. Pero a diferencia de mis reservas para dejar mi mtodo fa-
vorito MsgBox, he cambiado sin reservas a la nueva instruccin Return. Si fuera slo cuestin de
comparacin entre Exit Sub y Return, no hubiera hecho el cambio. Pero existe un problema
relacionado de la diferencia de Exit Function y Return. Nunca estuve feliz con la forma en
que las funciones antes de .NET de Visual Basic obtenan los valores de regreso a travs de una

Flexibilidad de Visual Basic | 715

26_PATRICK-CHAPTER_26.indd 715 17/2/10 15:34:54


instruccin de asignacin al nombre de la funcin. Estaba listo para hacer el cambio a la nueva
instruccin Return. Lo hice por claridad; mantener el valor regresado lo ms cerca posible de
la instruccin que activa el regreso al cdigo que llama es algo bueno. Antes de .NET, deba
asignar el valor de regreso, y despus no dejar la funcin por decenas de lneas. Combinar la
asignacin y el regreso en una sola instruccin tiene sentido para m. De ah, fue un viaje corto
para reemplazar Exit Sub con Return. No encontrar (espero) una sola instruccin Exit Sub
en el proyecto Biblioteca. Mi transformacin en esta rea est completa.
Por qu surg con todo esto? Hago esto para animarlo a que haga de la flexibilidad su amigo
en cuanto a las variaciones en el cdigo que existen en Visual Basic. Si dos diferentes formas de
desarrollar un bloque de cdigo parecen moralmente equivalentes y puede aclarar la lgica sin
importar qu mtodo seleccione, elija y disfrute del estilo de cdigo con el que est ms cmodo.
Algunos programadores le dirn que lo haga de una forma u otra, y est bien. (Si es parte de un
equipo de desarrollo, el equipo completo debe estar de acuerdo con un estilo comn.) Recuerde
que Visual Basic es un lenguaje de programacin de propsito general, y tiene cierta cantidad
de flexibilidad integrada en el lenguaje y caractersticas relacionadas. Experimente con las varia-
ciones, y encuentre patrones que disfrute y que incrementen su efectividad como desarrollador.

El marco conceptual de la programacin


Conforme se adentre en el mundo del desarrollo de software, rpidamente descubrir que el
proceso de generacin de aplicaciones es mucho ms que sintaxis, instrucciones y lgica. Se
relaciona tambin con quin es usted como programador. La forma en que piense acerca del
software y el cuidado que ponga a la tarea de programar, tienen un impacto directo en la calidad
del cdigo que escribe. Esto es cierto en otras reas de la vida. Si es un pintor de retratos, pero
no toma sus pinceladas en serio, o si es perezoso en el uso de sus pinturas y pinceles, se reflejar
en la baja calidad de su trabajo.
En uno de mis libros anteriores, The Visual Basic .NET Style Guide (Prentice Hall), escrib acerca
de tres cualidades que proporcionan las bases fuertes para la vida en la programacin:
Disciplina
El acto de autoenseanza con una meta de orden incremental, enfoque y calidad en sus
proyectos y tica laboral.
Planeacin
El anlisis cuidadoso y la aplicacin de procedimientos y estndares que piden calidad.
tica
El impulso y el carcter internos que se muestra a travs de la honestidad pblica y privada
en actitudes y acciones.

716 | Captulo 26:Proyecto completo

26_PATRICK-CHAPTER_26.indd 716 17/2/10 15:34:55


Si tiene deficiencias en cualquiera de estas tres reas de su vida de programacin, sus aplica-
ciones y cdigo tambin sern deficientes por un factor similar. He intentado rociar un poco
de humor y diversin a travs de las pginas de este libro. Pero en este punto no har chistes.
Necesita estos tres elementos en su vida diaria.
Si piensa seriamente en hacer carrera en el desarrollo de software, dse tiempo para plantearse
preguntas que se enfoquen en estos tres aspectos. Empleo disciplina regular en la forma en que
hago mi software? Creo planes razonables y confiables, y despus me apego a stos durante
un proyecto? Exhibo estndares ticos en la forma en que me comunico con mis clientes, mi
empleado, mis compaeros de trabajo e incluso conmigo mismo? Si no es capaz de responder
estas preguntas a su satisfaccin, encuentre recursos que le ayuden a sobrepasar los errores. Har
su trabajo de programacin ms sencillo e impactar positivamente en otras reas de su vida
tambin.

Resumen
Ahora que realmente ha llegado al final del libro, puede leer los apndices e ndices si todava
quiere ms. Pero una mejor solucin sera descubrir si he elaborado la nueva edicin del libro y
comprarla. Ja!
Y gracias por tomarse el tiempo de leer Programacin con Visual Basic 2008. Lo escrib para que
pudiera expandir su entendimiento y experiencia de un tema prctico y que poda disfrutarse:
Visual Basic. Y disfrutable es la palabra clave. Nadie tiene que ser un programador de compu
tadoras, sin importar lo que los historiadores digan. Debe tomar la funcin de un desarrollador
de Visual Basic slo si realmente siente placer en ayudar a otras personas a volverse ms produc-
tivos mediante software especializado o general. Si, incluso despus de leer este libro, encuentra
que hacer cdigo es un trabajo aburrido y pesado, le recomiendo la industria de los servicios de
alimentos como una alternativa.
Y todos ustedes que todava estn emocionados por programar en Visual Basic, divirtanse todo
lo que puedan. Microsoft est actualizando constantemente el lenguaje y la interfaz de Visual
Studio se presenta de una manera en que realmente puede disfrutar mientras programa. Por qu
piensa que Microsoft coloca todas estas caractersticas de animacin? Tome tiempo para ir ms
all de lo mundano en su cdigo y en sus interfaces de usuario. Desafese a s mismo a probar
nuevas caractersticas dentro del lenguaje y en el marco conceptual. Y encima de todo, sonra
cada vez que complete con xito un proyecto. Su autor y sus usuarios se lo agradecern.

Resumen | 717

26_PATRICK-CHAPTER_26.indd 717 17/2/10 15:34:55


26_PATRICK-CHAPTER_26.indd 718 17/2/10 15:34:55
Apndice A
Instalacin del software

Usted tiene en sus manos ms que slo un libro. Sostiene una idea. No, espere, eso es lo que
tiene cuando lee un libro de filosofa. En este caso, lo que tambin obtiene es software (software
gratuito). Y todo se encuentra en el sitio Web de este libro:
www.mcgraw-hill-educacion.com
Cuando descarga y ejecuta el programa de instalacin proporcionado en el sitio Web, los si-
guientes elementos se agregan a su sistema:
Una estructura de directorio con todo el cdigo fuente y la documentacin especfica de
todos los captulos.
Un archivo vsi que instala un conjunto de plantilla de proyecto de Visual Studio Project.
Cada plantilla crea un nuevo proyecto basado en las imgenes de cdigo fuente de antes
y despus para casi todos los captulos del libro. Una vez que instala este archivo, tendr
la opcin de acceder a los procesos especficos de cada captulo empleando el comando de
men Archivo Nuevo proyecto en Visual Studio.
Un directorio de fragmentos de cdigo que le permiten seguir la accin en el Proyecto de
cada captulo, sin que tenga que volver a escribir cada lnea de cdigo impresa en el libro.
La instalacin requiere casi 50 MB de espacio en disco. En este apndice se analizan los proce-
dimientos de descarga e instalacin.

Descarga del software


Para obtener el software del libro, vaya al sitio Web del libro, localice el vnculo Descargar C-
digo en esta pgina y haga clic en l. Cuando se le pregunte, guarde el archivo descargado en su
sistema empleando las caractersticas estndar de descarga de archivos de su explorador. Puede
guardar el archivo, llamado Programacin en Visual Basic 2008.exe, en un rea temporal de su
sistema. Una vez que complete la instalacin, ya no necesitar este archivo, a menos que desee
conservarlo como copia de seguridad.

719

27_PATRICK-APPENDIX A.indd 719 17/2/10 15:35:38


Instale el software
Haga doble clic o ejecute el archivo descargado Programacin con Visual Basic 2008.exe. cuando
se le pregunte, indique el directorio de destino que usar para todos los archivos del proyecto.
Una vez que se hayan extrado los archivos, aparecer un archivo lame describiendo los pasos
finales de la instalacin.

Instale las plantillas de proyecto


Uno de los archivos instalados en el directorio de destino se denomina Programacin con Visual
Basic 2008 Plantillas.vsi. Haga doble clic en l o abra este archivo para instalar las plantillas del
proyecto para el libro. Aparece la ventana Instalador de contenido de Visual Studio, como se
muestra en la figura A-1.

Figura A-1. El instalado de contenido de Visual Studio.

Para completar la instalacin, haga clic en el botn Siguiente, y despus otro en el botn Fi-
nalizar. La prxima vez que ejecute Visual Studio, todas las plantillas instaladas del proyecto
aparecern cuando use el comando de men Archivo Nuevo proyecto.

720 | Apndice A:Instalacin del software

27_PATRICK-APPENDIX A.indd 720 17/2/10 15:35:39


Instale los fragmentos de cdigo
Los fragmentos de cdigo se instalan dentro de la propia aplicacin de Visual Studio. Inicie Visual
Studio y ejecute el comando de men Herramientas Administrador de fragmentos de cdigo.
Aparece la ventana Administrador de fragmentos de cdigo, como se muestra en la figura A-2.

Figura A-2. El Administrador de fragmentos de cdigo.

Haga clic en el botn Agregar y vaya al directorio donde extrajo el contenido descargado del
libro. Busque el directorio Fragmentos de cdigo, seleccione el subdirectorio Programacin con
Visual Basic 2008 y haga clic en el botn Seleccionar carpeta. Cuando el control regrese al for-
mulario Administrador de fragmentos de cdigo, haga clic en el botn Aceptar para completar
la instalacin.

Soporte a cdigo de barras


El sitio Web que hospeda el contenido del proyecto tambin contiene informacin sobre la lo-
calizacin y obtencin de fuentes de cdigo de barras. Puede usar uno de los cdigos de barras
mencionados en este sitio con el cdigo del proyecto o puede obtener su propia fuente de cdigo
de barras vlida.

Soporte a cdigo de barras | 721

27_PATRICK-APPENDIX A.indd 721 17/2/10 15:35:39


Apndice B
Acuerdo de licencia de software

Cuando descargue e instale el software proporcionado con este libro, usted expresa su acuerdo
con los trminos del acuerdo de licencia de software.

Trminos de uso
Los componentes de cdigo fuente y software proporcionados con Programacin con Visual Basic
2008 (conocidos de manera colectiva como el software) estn diseados para usarse con ese
libro, y slo estn disponibles para quienes obtienen y usan el libro. Como tal, el software est
cubierto por los derechos de autor y las licencias del propio libro. Sin embargo, hay algunos
trminos y condiciones adicionales que deben hacer el software an ms til para sus actividades
de desarrollo y aprendizaje:
Uso del software con el libro
Puede instalar y usar el software junto con la lectura del texto. Si utiliza varias estaciones en
sus empeos de aprendizaje, sintase en la libertad de instalar el software en cada uno de
esos sistemas.
Distribucin del software proporcionado
No puede empaquetar, distribuir, vender ni poner a disposicin de otros las aplicaciones
parciales o completas proporcionadas con el libro. Afirmar que este trabajo es suyo, y tratar
de distribuirlo o venderlo como tal, es una mala, muy mala idea.
Uso de partes del software en sus proyectos
Puede usar parte de este software en sus propias aplicaciones y proyectos de desarrollo. Si
incluye partes significativas del software en su trabajo derivado, por favor d crdito a quien
crdito merece, y haga saber que su aplicacin emplea el til contenido proporcionado con
Programacin en Visual Basic 2008.
Agradecimientos
El software fue desarrollado por Tim Patrick, autor de Programacin en Visual Basic 2008.
Tim Patrick y OReilly Media, Inc. ponen con gusto este software a su disposicin para su
enseanza y disfrute.

722

28_PATRICK-APPENDIX B.indd 722 17/2/10 15:36:20


Garanta
No se proporciona garanta alguna con el software. Aunque se han hecho todos los intentos
posibles por mantener el software seguro y benigno cuando se instale en cualquier sistema
de destino, esa seguridad no est garantizada. Tim Patrick y OReilly Media, Inc. no sern
responsables por ningn dao que se produzca a su sistema o a cualquier dato almacenado
en su sistema como resultado de la instalacin de este software.
Otros trminos y condiciones
Puede haber trminos y condiciones adicionales instituidos en la descarga del sitio Web
donde obtuvo este software. Por favor lalos cuidadosamente porque contienen informa-
cin importante relacionada con las descargas accedidas desde el sitio Web.
Disfrtelo
Espero que estos trminos y condiciones no le espanten. El software tiene el objetivo de
ayudarle a aprender y avanzar en su comprensin de los conceptos de desarrollo de software
de Visual Basic. Pienso que encontrar el software muy til en su capacitacin, de modo
que descrguelo y disfrtelo.

Trminos de uso | 723

28_PATRICK-APPENDIX B.indd 723 17/2/10 15:36:20


28_PATRICK-APPENDIX B.indd 724 17/2/10 15:36:20
ndice

Smbolos *= (multiplicacin y asignacin), operador, 171


operador de multiplicacin, 48, 168
sobrecarga, 332, 333
& (signo de unin)
\ (diagonal invertida)
&= (unin y asignacin), operador, 34, 172
\= (divisin entera y asignacin), operador, 171
mtodos abreviados de botn, 148
operador de divisin entera, 48, 168
operador de unin de cadenas, 36, 48, 169
sobrecarga, 333
sobrecarga, 334
^ (acento circunflejo)
< y > (picoparntesis)
^= (exponenciacin y asignacin), operador, 171
< (menor que), operador, 170
operador de exponenciacin, 48, 168
sobrecarga, 334
sobrecarga, 334
< > (no es igual a), operador, 48, 170 { } (llaves)
sobrecarga, 334 inclusin de elementos de matriz, 175
<< (desplazamiento a la izquierda), operador, 48, inclusin de restricciones genricas mltiples,
170 438
sobrecarga, 335 . (punto)
<<= (desplazamiento a la izquierda y asignacin), acceso a miembro de instancia, 233
operador, 172 eje XML de miembro descendente, 377
<= (menor que o igual a), operador, 48, 170 separacin de nodos en jerarqua de tipo, 11
sobrecarga, 334 sintaxis de SQL, 101
> (mayor que), operador, 48, 170 = (signo de igual)
>= (mayor que o igual a), operador, 48, 170 operador de asignacin, 47, 171
sobrecarga, 334 operador igual a, 48, 170
>> (desplazamiento a la derecha), operador, 48, sobrecarga, 334
170 (signo menos)
sobrecarga, 335 = (resta y asignacin), operador, 171
>>= (desplazamiento a la derecha y asignacin), operacin de negacin unaria, 47, 168
operador, 172 sobrecarga, 333
<%@, directivas de pgina de ASP.NET, 648 operador de resta, 47, 168
<%...%> par de parntesis para comandos y cdigo sobrecarga, 333
especfico de ASP.NET, 648 # (signo de nmero)
<%= y %>, smbolos en directivas, 135
expresiones XML incrustadas, 376 en literales de fecha y hora, 37
inclusin entre picoparntesis de cdigo ( ) (parntesis)
especfico de LINQ, 462 agrupamiento de clusulas en operandos, 49
<?xml...?>, declaracin en documento XML, 372 agrupamiento en instrucciones SQL, 104
* (asterisco) llamadas a subrutinas, 50

725

29_PATRICK-INDEX.indd 725 17/2/10 15:37:48


% (signo de porcentaje), carcter comodn en SQL administracin del proyecto, 83
Server, 351 mtodos cclicos y lineales, 84
+ (signo ms) Administrador de configuracin en Visual Studio,
+= adicin y asignacin, operador, 171 707
operador de adicin, 47, 168 ADO (objetos de datos de ActiveX), 277
sobrecarga, 333 ADO.NET, 277-302
operador ms unario, 168 conexin a SQL Server con Visual Studio,
sobrecarga, 333 284-289
? (signo de interrogacin), sufijo para instancias que conjuntos de datos, 281
son nulas, 441 definicin de, 278
" " (comillas dobles) Entity Framework, 293
alrededor de atributos XML, 366 herramientas de acceso a bases de datos, 294-302
alrededor de literales de cadena, 36 interaccin con SQL Server en cdigo, 289-292
'' (comillas nicas) pros y contras de usar, 282
comentarios entre comillas, 45 proveedores, 279-281
literales de cadena en instrucciones SQL, 103, proveedores LINQ, 463-468
300 soporte a MARS, 284
literales de fecha y hora en instrucciones SQL, transacciones de bases de datos, 292
103 Aggregate, palabra clave, 459
; (punto y coma), final de instrucciones SQL, 100 agilidad del motor en tiempo de ejecucin, 715
/ (diagonal) Agregar, botn (formulario ArticuloConNombre),
/= (divisin y asignacin), operador, 171 357
operador de divisin, 48, 168 Agregar referencia a servicio, formulario, 661
sobrecarga, 333 agrupamiento
adicin a un informe, 591
en instrucciones SQL, 105, 599
Nmeros Ajax, 32
3D, imgenes, 507 Ajax Extensions, controles, 650
al.exe (vinculador de ensamblados), programa,
536
A alfa, mezcla, 491
abreviaturas de espacio de nombres, 68 lgebra
Abrir archivo, cuadro de dilogo, 411 booleana, 37
abstracciones, 220 relacional, 97
accesores, 60 algoritmo de firma digital (DSA), 309
Access, base de datos, 99 algoritmos
ActiveX, controles, 692 de cifrado, 305
Actividad, entrada, de hash, 306, 310
ActivityBindingSource, control, 288 uso para claves de instalacin, 613
actualizaciones alias en consultas LINQ, 460
automticas, aplicaciones implementadas con All, funcin, 459
ClickOnce, 698 AllowCurrentPage, control, 561
de pantalla, 242 AllowSelection, control, 561
de versin de servicio, 89 AllowSomePages, control, 561
acuerdos de licencia, 615 almacenamiento de datos, 4
software para este libro, 722 ALTER TABLE, instrucciones, 101
AddHandler, instrucciones, 209 Alt-F4, tecla para salir de una aplicacin, 217
AddressOf, operador, 171 mbito
adicin, operador (vase + [signo ms], bajo ayuda para determinar los objetivos del proyecto,
Smbolos) 85

726 | ndice

29_PATRICK-INDEX.indd 726 17/2/10 15:37:48


cambio en, 87 arquitectos, 86
de bloque, 165 AS, clusula, instruccin SELECT, 105
en el nivel del procedimiento, 165 As, clusulas en marcadores de posicin genricos,
nivel de bloque para variables, 165 437
variables, 165 As, palabra clave, 43, 161, 453
ancestro-descendiente, relaciones, 230 AS, palabra clave (SQL), 453
And, operador, 48, 169 As New, clusula, 438
sobrecarga, 335 ASCII, 153
AND y OR, palabras clave, 104 asignacin, 34
AndAlso, operador, 48, 169 asignacin predeterminada por Visual Basic, 45
animacin, interfaces de usuario, 507 datos, 293
Any, funcin, 459 operador de asignacin (vase = [signo de igual],
AP (plataforma de ayuda), 674 bajo Smbolos)
aplicaciones operadores, 171
archivos EXE, ensamblados y, 131 propiedades, 60
de consola, 23 valores para variables, 38
cdigo fuente de Visual Basic, 8 versin, 15, 127
de origen abierto, 612 Asistente para configuracin de orgenes de datos,
de una sola instancia, 218 658
versiones, 15 Asistente para instalacin, 693, 700
Web, hospedadas dentro de un navegador ASP (pginas de servidor activo), 644
de usuario, 507 ASP.NET, 644
app.config, archivo, 393, 395 avances en tecnologa de desarrollo Web, 645
Apple Macintosh, 1 conexin de pginas Web a una base de datos,
Application Framework, sistema, 212 657
evento Startup para aplicaciones, 213 creacin de una aplicacin, 646-653
Application, mtodo Run de la clase, 191 estado y View State, 654
archivo intercambiable de imagen (EXIF), eventos y aplicaciones Web, 653
archivos, 497 implementacin directa, 690
archivos validacin de datos, 655-656
binarios, 361 <asp:xxx>, etiqueta, 651
recursos, 16, 527 Assemblylnfo.vb, archivo, 147
recursos intermedios, 528 AssemblyVersion, atributo, 147
y directorios, 416-428 atributos, 14
administracin de archivos tradicional de clase, 510
Visual Basic, 417 XmlAttribute, 372
archivos de recursos, 529 Servicios WCF, 660
espacio de nombres My y administracin de XML, 366
archivos de Visual Basic, 424-426 audio (en archivos de recursos), 529
lectura de archivos mediante flujos, 422 autentificacin de usuario, 311
lectura y escritura a travs de My, 426 AutoCompletion (Visual Studio), 18
lista de archivos del ensamblado, 129 autodescripcin (aplicaciones .NET), 136
manipulacin a travs de flujos, 418-424 autorun.inf, archivo, 710
argumentos, 34, 58 Average, funcin, 460
eventos, 143 ayuda emergente, 681
opcional, 50 ayuda en lnea, 672-688
nmero ilimitado para un mtodo, 243 acceso a HTML Help, 680-682
para miembros de clase sobrecargados, diseo de HTML Help, 674-680
230 proyecto Biblioteca (ejemplo), 683-688
subrutina, 50, 226 Windows, 672-674

ndice | 727

29_PATRICK-INDEX.indd 727 17/2/10 15:37:48


B en programas de Visual Basic, 64
inclusin en el procedimiento Sub Main, 194
base de comunicacin de Windows (vase WCF) Boolean, tipo de datos, 39, 156
base de datos de conocimientos de Microsoft, artcu- conversiones entre valores enteros y, 156
lo sobre soporte a impresin simple, 564 .NET, 153
base de presentacin de Windows (vase WPF) BoundField, columna del control GridView, 667
bases de datos, 95-125 BoundSchemaSearchResults, clase, 667
ADO.NET Entity Framework, 463 BrowsableAttribute, atributo, 511
archivos almacenados en formato CSV, 362
bucles, 54-57
biblioteca de bases de datos para .NET (vase
anidados, 57
ADO.NET)
Do...Loop, 55
documentacin, 108
For Each... Next, 55
herramientas de interaccin de base de datos,
For....Next, 54
277
instrucciones
relacionales, 95, 109
Continue, 57
ADO.NET, 278
Exit, 56
sistemas especficos del vendedor, 97
GoTo y, 62
sistemas de base de datos relacional, 95-97
BufferedStream, objeto, 419
soporte de LINQ para, 449
Button, clase, 15
SQL (lenguaje estructurado de consultas),
Button, control, 141
100-107
ByRef, palabra clave, 58
SQL Server 2005, xvii, 98
Byte, tipo de datos, 39, 154
SQL Server 2008, 20
conversiones, 337
uso en aplicaciones de Visual Basic, xvi, 107
BASIC, lenguaje, 31, 49 ByVal, palabra clave, 58
definicin de objetos que contienen una funcin parmetros de mtodos parciales, 240
de entero, 253
BCL (biblioteca de clases base), 11 C
caractersticas obsoletas, 14
jerarqua de espacios de nombres y, 13 c (literales que denotan caaracteres), 36
BeginPrint, manejador de eventos, 559 C, lenguaje, 49
cambio al nmero de pgina de inicio correcto, C#, 31
563 conversiones
Berners-Lee, Tim, 642 a enteros, 157
beta, versiones, 87 de cdigo de Visual Basic, MsgBox y, 715
biblioteca de clases base (vase BCL) valores booleanos, 41
biblioteca de clases, proyectos, 23 cach de ensamblado global (vase GAC)
biblioteca de clases del marco conceptual cadenas
(vase FCL) clase SecureString, 312
bibliotecas comparaciones binarias y de texto, 46
programas WPF de explorador, 507 conexin, 289
(vase tambin BCL; FCL) guardado en el archivo web.config, 658
bigint y smallint, tipos de datos, 101 constructores predeterminados, 42
BinaryReader, clase, 421 en archivos de recursos, 528
BinaryWriter, clase, 421 funciones para manipulacin de cadenas, 179
Bloc de notas, 18 inmutabilidad en .NET, 156
bloques literales, 36
instrucciones, 165 preparacin para impresin, 567
registros de base de datos, 279 proyecto Biblioteca (ejemplo), 183-186
bomba de mensajes, 64, 189 vacas (), 34
cola de mensajes, 64, 189, 659 cajas negras, 222

728 | ndice

29_PATRICK-INDEX.indd 728 17/2/10 15:37:49


clculos implementacin y distribucin, 89
contabilidad, 179 objetivos del proyecto, 85
financieros y de contabilidad, 179 prueba de los criterios de aceptacin, 88
lambda, 253 reunin de inicio, 84
calendarios, 85 soporte continuo, 89
aprobacin del calendario propuesto, 87 cifrado
cambios, 87 bidireccional, 306
cambio de ubicacin de la salida del registro, 428, clave pblica, 305, 309
429, 430 (vase tambin criptografa)
Camel, uso de maysculas y minsculas, 166 unidireccional, 306
campos, 4, 43 CifrarClave, rutina (ejemplo), 316
mbito de, 165 CInt, operador, 339, 342
columnas de base de datos, 95 clases, 6, 9, 225
convenciones de denominacin, 166 abstractas, 237
propiedades y, 61 definidas por interfaces, 237
valores nulos en base de datos, 104 anidadas, 10
variables y constantes declaradas fuera de un atributos, 14, 510
procedimiento, 164 base, 27, 222
CancelButton, propiedad, 141 herencia de miembros de clases derivadas,
capacidad de uso, 80 230
CAPI (Criptografa de API), 311 implementacin de miembros especficos,
caracteres forzados en clases derivadas, 237
continuacin de lnea, cdigo LINQ to XML, miembros bajo clases derivadas, 232
461 paso de variables de instancia entre clases
conversin a valores binarios, 153 derivadas y, 233
tipos de datos en .NET, 153 bibliotecas de clases, .NET, 10-13
CAS (seguridad de acceso a cdigo), 304 campos contenedores, variables locales y
Case, instruccin Select Case de las clusulas, 52 constantes, 164
Case Else, condicin, 53 constructores, 28, 163
Catch, instruccin Try... Catch... Finally de la creacin de instancias de, 28, 232
clusula, 266 de cierre, 258
CD, distribuciones, 708 denominacin, 12
claves de instalacin, 613 derivacin de System.Object, 157
CDate, operador, 537 derivadas, 27, 222
Char, tipo de datos, 40, 156 clases parciales, 230
CheckBox, controles cobertura de miembros de clase base, 232
casillas de verificacin del proceso de instalacin, constructores, 235
705-707 forzadas para implementar miembros de clase
cuadro de dilogo Checkboxes, 705 base especficos, 237
evento CheckedChanged que dispara como no herencia de miembros de clase base, 231
postback, 654 paso de variables de instancia entre clase base
Church, Alonzo, 253 y, 233
ciclo de vida del proyecto, 83-89 desencadenamiento de un evento (ejemplo), 65
aceptacin del proyecto, 89 divisin de una sola clase entre varios archivos de
aprobacin del documento de diseo, 86 cdigo fuente, 27
cambios al proyecto, 87 eliminacin de instancias, 235
diseo y planeacin, 85 espacios de nombres, 66
documentacin apropiada y completa, 84 formularios, 142
documento de aprobacin del proyecto, 87 herencia, 230-232, 244
fase de desarrollo, 87 mtodos de extensin, 340

ndice | 729

29_PATRICK-INDEX.indd 729 17/2/10 15:37:49


miembros, 225-228 divisin de una sola clase entre varios
compartidos, 228 archivos, 27
sobrecargados y argumentos opcionales, 229 inclusin/exclusin empleando directivas,
Object como raz, 39 134
parciales, 225 programas de ejemplo de este libro, xvii
propiedades, 60 sistemas de control, 89
referencia a una biblioteca de, 68 uso de ejemplos de este libro, xviii
soporte por tipos de referencia, 158 Visual Studio y Visual Basic, 17
tipos fuente (ejemplo), 208
annimos, 451 mquina, 2, 33
de datos, 153 no administrado, 7
genricos de restriccin, 437, 438 biblioteca winspool.drv, 567
Class y End class, palabras clave, 214 presentacin en tiempo de diseo, 318
Class, palabra clave, 225 que revisa licencia (ejemplo), 634
clusulas de consulta, 453 tras caractersticas de Web Forms, 646, 663
claves cdigo de mensaje de autentificacin (MAC), 311
de licencia generadas cola de mensajes del sistema, 189
generales, 613 colecciones, 440
personalizadas, 613
conversin de resultados de LINQ a, 459
instalacin, 613
colores, 488
principal, 96
especificacin para plumas, 491
Click, evento, 144
plumas predefinidas, 490
adicin a un formulario, 198
propiedad Color de los controles TextBox, 593
control Button
columnas, edicin, 95
adicin de origen de datos SQL Server, 290
de la coleccin Columns para el control
definicin de manejador, 208
extraccin de errores de, 269 ListView, 357
Click, evento en Visual Basic, 207 en el control GridView, 667
Click, manejador de eventos, 208 COM, componentes y aplicaciones, 564
ClickOnce, implementacin, 698 ComboBox, controles, 244
clics del ratn, 66, 189 coleccin Items, 245
prueba de, 503 mejoramiento a travs de dibujo de propietario,
(vase tambin Click, evento) 505
CLR (motor en tiempo de ejecucin de lenguaje rastreo de nmeros de ID en, 246, 342
comn), 7, 35 relleno de listas, 247
compilacin final justo a tiempo (JIT) de comentarios, 44
ensamblado MSIL, 17 clase XmlComment, 372
CLS (especificacin de lenguaje comn), 8 XML, 366
Codd, Edgar, 95 documentacin generada a partir de, 674
cdigo comillas (vase bajo Smbolos)
administrado, 7 Command, objeto, 280
de barras Commit, mtodo, 293
fuentes, 431, 721 comparaciones
soporte para lectura, 349 binarias, 46
de espagueti resultado del abuso de instrucciones de objetos
GoTo, 62 igual a, operador (Is), 48
fuente, 34 no es igual a, operador (IsNot), 48
archivos con extensin .vb, 16 de patrones (Like), operador, 48, 170
cdigo de Visual Basic tras pginas ASP.NET, de valor contra una lista, 52
646 sobrecarga, 335
control de la experiencia de usuario, 289 CompareValidator, 656

730 | ndice

29_PATRICK-INDEX.indd 730 17/2/10 15:37:49


compilacin manual de archivos .resx, 535-537 pros y contras del uso, 282
compiladores registros unidos a regiones de datos de
adicin de constructores, 29 informes, 587
compilacin de cdigo fuente de Visual Basic, 17 de entidad, 293
generacin de IL, 8 de registros del lado del cliente, 282
HTML Help, 675 conjuntos de resultados activos mltiples (MARS),
lenguaje orientado a objetos, 219 284
nmero de versin del compilador de Visual inclusin de soporte en cadena de conexin de
Basic, 136 SQL Server, 290
Complementos de Office, plantillas de proyecto, Connection, objeto, 280
584 #Const, directiva, 134
componentes de edicin (Visual Studio Const, palabra clave, 43
Professional), 24 definicin de constantes, 160
compresin/decompresin de datos, 419 precedencia de palabras clave en el modificador
computadoras personales (PC), 1 de acceso, 161
concepcin de la programacin, 716 constantes, 43, 160
concurrencia pesimista, 279 campos constantes como miembros de clase, 226
condiciones, 50-54 convenciones de asignacin de nombres, 165
funciones Ilf e If, 53 de compilador, 135
inclusin/exclusin de partes del cdigo fuente, establecimiento de una vez para toda la
135 aplicacin, 136
instrucciones tipos de datos, 136
If, 51-52 declaracin de, 43
Select Case, 52, 53 declaradas fuera de un procedimiento, 164
locales, 164
Condition, propiedad, 706
constructores, 28, 42, 163, 234
conectividad abierta de base de datos (vase ODBC)
creacin de constructores personalizados, 235
.config, archivos, 393
predeterminados, 42, 234
configuraciones
consulta integrada de lenguaje (vase LINQ)
aplicacin, 392-415
consultas agregadas (LINQ), 459, 475
adicin de configuraciones a un proyecto,
consultas LINQ, 452
395-398
contenido
en Visual Basic 2008, 394-400 archivos (HTML Help), 674, 676
My.Settings, 398-400 valores de datos, 36
unida, 400 contexto de datos, 465
compilacin en proyectos, 707 Continue, instrucciones, 57
de unin, 400 contraseas
establecimiento de la posicin del formulario cifrado (ejemplo), 312-328
principal, 404 generacin en sistemas Unix, 303
(vase tambin unin de datos) SQL Server, 290
persistentes, 399 contrato entre interfaces e implementacin de clase
predeterminadas, 399 o estructura, 237
usuario, 402 Control, clase, 191, 197
modificacin y guardado, 398 control de flujo (vanse tambin instrucciones
ConfigurationManager, objeto, 665 condicionales; bucles)
conjuncin en el nivel de bits, operador (vase And, controles, 189, 191
operador) caracterstica de unin de datos, 288
conjuntos cdigo para presentacin en tiempo de diseo,
de datos, 279, 281 318
con tipo, 282, 464 controles de creacin de informes en .NET,
LINQ to DataSet, 463 584-597

ndice | 731

29_PATRICK-INDEX.indd 731 17/2/10 15:37:49


creacin de informes, 650 datos que aseguran la integridad de los datos,
diseo con WPF y XAML, 509 305
estndar, 649 en .NET, 306-311
etiquetas inteligentes, 200 clave secreta, 307
eventos y delegados, 206-209 par de claves pblicas-privadas, uso en firmas
HTML Help, 680 digitales, 623
mejoramiento mediante dibujo de propietario, simtrica, 305, 307
505 tcnicas de cifrado, 305
mtodo CreateGraphics, 489 verificacin de identidad con firmas digitales,
navegacin, 650 306
pgina Web de ASP.NET que retiene estado, 655 Criptografa API (CAPI), 311
PropertyGrid, 511 CryptoStream, clase, 307-309, 419
propiedades comunes para formularios y Crystal Reports, 583
controles, 197 CSS (hojas de estilo en cascada), 480
regin de datos en informes RDLC, 587 ajuste de diseo de aplicaciones Web, 653
suministro de cdigo de dibujo a (dibujo de soporte en Visual Studio 2008, 20
propietario), 488 CSV (valores separados por comas), 362
unin de propiedades en un sistema de CTS (sistema de tipo comn), 9, 34
configuracin, 400 CType, operador, 336
Web Forms, 649-651 sobrecargado, 339
validadores, 655 cuadro de herramientas (Visual Studio), 138
Windows Forms cuerpo de un procedimiento, 59
adicin, 15 cultura, 527
disponibles en Visual Studio, 200-205 establecimiento de, 129
conversiones formato de fechas, 551
conversiones de datos simples por Visual Basic, incrustada en el ensamblado, 537
45 manipulacin de cadenas para despliegue
de ensanchamiento, 337 localizado, 537
entre bytes y caracteres, 420 CustomValidator, 656
estrechamiento, 45, 337
implcitas, generacin de errores en tiempo
de compilacin, 260 D
personalizadas con operador CType DAO (objetos de acceso a datos), 277
sobrecargado, 338 DataAdapter, objeto, 280
resultados de consulta LINQ, 459 DataBind, mtodo del control GridView, 669
costos, aprobacin para un proyecto, 87 DataContext, clase, 468
Count, funcin, 460 DataNavigateUrlFields, propiedad, 667
creacin DataNavigateUrlFormatString, propiedad, 668
instancias, 41 DataReader, objeto, 280
secuencias de comandos DataRelation, objetos, 281
del lado del cliente, 644 DataSet, objetos, 281
del lado del servidor, 644 (vase tambin conjuntos de datos)
CreateGraphics, mtodo, 489 DataTable, objetos, 281, 463, 603
CreateReader, funcin, 298 Date, clase, 40, 178
CREATE TABLE, instrucciones, 100, 103 DateTime, clase, 178
criptografa, 304-311 datos, 151
asimtrica, 305, 309 controles, 650
cifrado definidos, 79
clave de instalacin, 613 intercambio, mejoramiento mediante el uso de
clave pblica-privada, 613 estndares, 3

732 | ndice

29_PATRICK-INDEX.indd 732 17/2/10 15:37:49


naturaleza de los datos computacionales, 151 integracin de base de datos, 657
y necesidades de informacin, 79 .NET Framework mejorado, 3
DayOfWeek, enumeracin, 162 programacin de Internet, 644
dbml, archivos, 465 sitio Web del proyecto Biblioteca, 663-671
archivos de diseador, 467 validacin de datos, 655-656
DDL (lenguaje de definicin de datos), 97 WCF (base de comunicacin de Windows),
instrucciones, 100-103 658-662
DEBUG, constante, 136 desbordamiento de bfer, problemas, 3
Debug, objeto, 273 DESCryptoServiceProvider, clase, 306, 307-309
DebuggerNonUserCode, atributo, 27 DesignerGenerated, atributo, 27
Decimal, clase, 40, 155 desplazamiento, operadores (vase < y >
DecirHola, clase (ejemplo), 72 [picoparntesis], bajo Smbolos)
campos privados, 72 destructores, 235
declaraciones DialogResult, propiedad, 149, 211
combinacin de la palabra clave New con dibujo de propietario, 488
asignacin de miembros, 259 controles de mejoramiento, 505
documentos XML, 372 Dictionary, coleccin, 459
enumeracin, 162 Dim, instrucciones
instruccin de declaracin Sub, 58 al principio de los procedimientos, 163
operador, 332 dentro de las instrucciones de bloque, 165
propiedad, 60 Dim, palabra clave, 38, 44, 162
proporcionado por Visual Basic, 45 dimensiones (matrices), 174
sobrecargas de operador, 339 dinero (vase formato monetario, localizacin)
variables, 38 directivas
Declare, instrucciones, 228 directivas de pgina ASP.NET, 648, 660
Default.aspx, archivo, 646 ensamblados y, 134-136
Default.aspx.vb, archivo, 646 directivas de pgina (ASP.NET), 648
DeflateStream, objeto, 419 directorio de instalacin, 126
delegados, 9, 207 disciplina (programadores), 716
espacios de nombres, 66 diseador, archivo dbml, 467
miembro de clase, 227 Diseador de consultas (SQL Server), 598
soporte para LINQ, 450 diseador relacional de objetos (vase O/R,
vinculacin de funciones a variables, 254 diseador)
DELETE, instrucciones, 97, 104 diseo y planeacin, 85
DeleteFile, mtodo, 134 disparo de un evento, 64
Deployment, propiedad, 699 Dispose, mtodo, objeto Graphics, 489
depuracin dispositivos de entrada y salida para acceder a
soporte mejorado en Visual Studio 2008, 21 datos almacenados, 4
soporte para JavaScript en Visual Studio 2008, Distinct, clusula, consultas LINQ, 455
21 distribucin de aplicaciones, 89
DES (estndar de cifrado de datos), algoritmo, Proyecto Biblioteca (ejemplo), 708
306, 307 disyuncin en el nivel de bits, operador (vase Or,
desarrollador de productividad, mejoramiento con operador)
.NET, 3 divisin, operador (vase / [diagonal], bajo
desarrollo Web, 642-671 Smbolos)
caractersticas de ASP.NET, 645 DLL
creacin de una aplicacin ASP.NET, 646-653 identificacin de archivos que contienen tipos de
estado y View State, 654 espacio de nombres, 67
eventos, 653 implementacin del proyecto Biblioteca, 702
funcionamiento de Internet, 642 proyectos de la biblioteca de clases, 23

ndice | 733

29_PATRICK-INDEX.indd 733 17/2/10 15:37:49


soporte a impresora simple en Windows, 564 registro, 697
versin, 127 sistema de archivos, 697, 702
.dll, archivos, 13 carpeta Fuentes, 707
DLR (motor en tiempo de ejecucin de lenguaje tipos de archivo, 697
dinmico), 22 efecto de desvanecimiento, 524
DML (lenguaje de manipulacin de datos), 97 eje de atributos de propiedades XML, 377
instrucciones, 103-106 ejecucin diferida, 468
Do... Loop, instrucciones ejecucin porttil (PE), archivos, 128
bloque Do While... Loop, 34 ejemplos de cdigo de este libro
bucles Do... Loop, 55 acuerdo de licencia, 722
instrucciones Do versin Antes y Final, 70
instruccin Continue Do, 57 el demonio de DLL, 3
instruccin Exit Do, 56 elementos
documentacin dibujo (GDI+), 488
documentacin de la base de datos, 108 que se pueden entregar, 85
generada a partir de comentarios XML para temporales, identificados por marcas de
miembros de clase, 674 comparacin, 86
importancia en todo el proyecto, 84 raz, 365
necesidades del usuario especficas del proyecto, XML
83 atributos, 366
documento de definicin de tipo (DTD), 369 clase XElement, 376
documentos clase XmlElement, 372
aceptacin de un proyecto, 89 elevacin de variable, 258
aprobacin del proyecto, 87 Else, palabra clave
de diseo, 85 instruccin If, 51
aprobacin por el usuario y el programador, Elself, palabra clave, 51
86 instruccin If, 52
diseo del proyecto, 85 Emacs, 18
XML, 372-374 encabezado, archivos PE, 128
creacin con LINQ to XML, 461 encuadre y desencuadre, 158
objeto XDocument object, 376 End Enum, lnea, 161
DoEvents method, 242
End If, instrucciones, 51, 52
problemas causados por el abuso, 243
dongles, 614 End Sub, instruccin, 58, 59
Dotfuscator, 616 End, clusula del espacio de nombres, 69
Double, tipo de datos, 40, 155 End, instrucciones, 52, 64
Drawing, espacio de nombres, 487 End, palabra clave de clase, 214
DROP TABLE, instrucciones, 101 EndPrint, evento, 559
DSA (algoritmo de firma digital), 309 ensamblados, 13, 126-150
DSACryptoServiceProvider, clase, 309 aplicaciones y, 131
DTD (definicin de tipo de documento), 369 compilacin manual de ensamblados satlite a
duplicados, eliminacin de los resultados de la partir de archivos .resx, 535-537
consulta LINQ, 455 contenido de, 128-130
archivo PE de .NET, 128
E creacin e implementacin, 17
directivas y, 134-136
editores espacio de nombres My y, 132-134
acciones personalizadas, 697 establecimiento de nmero de versin, 146
condiciones de lanzamiento, 697 examen de contenido usando reflexin, 131
interfaz de usuario, 697, 704-706 generacin de archivos de recursos mltiples,
localizacin de recursos de Windows, 534 en idiomas extranjeros para, 536

734 | ndice

29_PATRICK-INDEX.indd 734 17/2/10 15:37:49


metadatos, 13 clases
movimiento de un archivo .resx, a un ADO.NET, 278
ensamblado satlite, 535 BCL y FCL, 13
ofuscacin, 617 en su proyecto, 69
recurso compilado, archivos como espacio de nombres My, 69
ensamblados satlite, 528 espacio de nombres y ensamblados My, 132
revisin general de, 126-128 importacin, 68
satlite, 528 importados, 295
versin de componentes compartidos, 16 palabra clave Global y, 27
ensamblados Interop primarios (PIA), 584 servicios WCF, 662
enteros, 34, 37 XML, 370
clase Integer, 40 inclusin en contenido XML, 378
con signo, 154 especificaciones, 86
conversin de valores booleanos a, 156 esquemas XML, 368-370
sin signo, 154 para literales XML, 378
tipos de datos de .NET, 153, 154 verificacin, 374
entidades, 293 estado, 395
herencia, 293 retencin en una pgina Web, 655
LINQ to Entities, 463 estndar avanzado de cifrado (AES), 307
Entity Framework, ADO.NET, 293, 463 estndar de cifrado de datos (DES), algoritmo,
disponibilidad, 294 306, 307
Entrada de ndice, formulario de editor, 680 estndares, uso en .NET Framework, 3
Enum, instruccin, 162 estructuras, 9, 153
enumeraciones, 9, 161 espacios de nombres, 66
definicin de miembro de clase, 226 implementacin de tipos de valor, 239
definido como miembro de un tipo, 162 soporte para tipos de valor, 158
espacios de nombres, 66 tipos definidos por el usuario, 10
envo de correo electrnico como resultado del tica (rasgos del programador), 716
evento LinkClicked, 145 etiquetas
Equals, mtodo, sobrescritura en bsquedas en ASP.NET, 651
el control ListBox, 246 coincidentes de apertura y cierre (XML), 364, 367
Equals, palabra clave, 457 lnea, 61
Err, objeto, 264, 272 XML, 366
mtodo GetException, 270 Event, instrucciones, 65, 207
mtodo Raise, 270 empleo de delegados en lugar de listas completas
errores, 260-263 de argumentos, 207
en tiempo de compilacin, 260 EventArgs, clase, 206, 207
en tiempo de ejecucin, 261 eventos, 64-66, 143, 190
funcin ErrorToString, 273 adicin de un evento Click a un formulario, 198
funcin IsError, 273 aplicacin Web application, 653
generacin, 269 argumentos, 143
y registro, 428 clic de un botn, procesamiento entre accin y
ignorancia, 265 lgica personalizada, 206
lgicos, 262 conexin
no administrados, 267 a una instancia local de PrintDocument, 554
elevacin en la pila de llamada, 268 a una subrutina con Handles, 74
no manejados, 267 controles, 206
rutinas de interaccin con base de datos, 298 manejador de eventos del control Button,
Escritorio del usuario, carpeta, 703, 706 206
espacios de nombres, 11, 66-69 de teclado, 66, 189

ndice | 735

29_PATRICK-INDEX.indd 735 17/2/10 15:37:49


definicin para clases, 227 Express Edition, 646
del sistema, 66 Express Edition de Visual Studio 2008, 18
disparo, 64 Extension, atributo, 341, 345
importancia en el desarrollo de aplicaciones
.NET, 209
llamadas indirectas a un procedimiento, 64 F
Load, 145 False, valor, 37
monitoreo de manejadores de eventos, 207-209 conversin a enteros, 156
uso de eventos en lugar de mtodos parciales, fase de desarrollo de proyectos, 87
241 FCL (bibliotecas de clases del marco de trabajo),
excepciones 11, 127
clase Exception, 271 caractersticas
inclusin en cach, 267 administracin de cultura, 538
lanzamiento, 270 obsoletas, 14
(vanse tambin manejo de errores; errores) clases y objetos en, 225
exclusin en el nivel de bits, operador (vase Xor, generacin de errores, 269
operador) jerarqua de espacio de nombres y, 13
EXE, archivos, 13, 131 versin 3.5, 13
versin, 127 filas, 95
EXIF, archivos, 497 FileLogTraceListener, clase, 429
Exit Function, instrucciones, 63 FileStream, objeto, 418
Exit, instrucciones, 56 FileSystem, objeto
Exit Sub, instruccin, 715 caractersticas de interaccin de archivos,
Exit Try, instruccin, 267 424-426
experiencia de datos desconectados (ADO.NET), mtodos
278 OpenTextFieldParser, 427
Explorador de soluciones (Visual Studio), 24, 139 OpenTextFileReader y OpenTextFileWriter,
exponenciacin, operador (vase ^ 426
[acento circunflejo], bajo Smbolos) ReadAllText y ReadAllBytes, 426
expresiones, 49, 167 WriteAllText y WriteAllBytes, 427
agregadas en consultas no agregadas, 460 FillColor, propiedad, 518
rboles de expresiones, 256 FillListWithRecords, mtodo, 252
de consulta, 450 Finalize, mtodo, 236
avanzadas, 460 supresin, 237
bsica LINQ, 453-458 Finally, clusula, instrucciones Try... Catch... Finally,
bsicas, 453-458 267
Editor de expresiones, 591 firmas digitales, 306, 614
espacio de nombres Expressions, 256 adjuntas al manifiesto del ensamblado, 13
lambda, 253-259 clase SignedXml, 625
rboles de expresin, 256 generacin, 625
complejas, 257 para archivo de licencia de Biblioteca,
con tipos inferidos, 255 623-626
definicin de una variable como una reordenacin y comparacin con el resto de la
funcin simple, 254 licencia, 627
levantamiento de variables y clases de cierre, validacin (cdigo de ejemplo), 631
258 flujos, 309, 418-424
soporte para LINQ, 450 cdigo de ejemplo, entrada y salida de datos de
productos de diseo de expresiones, 508 un flujo de memoria, 419
XML incrustadas, 376 lectores y escritores de datos de flujo, 420
(vase tambin expresiones lambda) lectura de un archivo mediante, 422

736 | ndice

29_PATRICK-INDEX.indd 736 17/2/10 15:37:49


For Each... Next, bucles, 55 FreeFile, funcin, 417
For, instrucciones Free Software Foundation, GNU General Public
Continue For, 57 License, 612
Exit For, 56 Friend, instruccin, 28
For...Next, bucles, 54 modificador de acceso amigable, 223
instrucciones GoTo y, 62 Friend, variables, 164
Form, clase, 142, 193, 195 From, clusula, expresiones de consulta LINQ,
acceso, 68 453
mtodo ShowDialog, 210 FrontPage Extensions, 691
formas fuentes, 493-496
controles, 140 alineacin, 495
detalladas genricas, 248-250 carga de la lista de fuentes instaladas, 409
elementos de dibujo GDI, 488 carpeta Fuentes, 707
transformaciones, 503 clase Font, 493
Format, funcin, 548 cdigo de barras, 431, 512, 721
formato de archivo de imagen con etiquetas eleccin, 493
(TIFF), archivos, 497 elementos de dibujo GDI+, 488
formato de intercambio de imgenes (GIF), familias, 493
archivos, 497 manipulacin compleja con GDI+, 496
formato de moneda, localizacin, 537, 544, 548 mezcla y concordancia en un lienzo de salida,
formato de texto enriquecido (RTF), 673 494
formatos binarios de propietario, 361 fugas de memoria, 3
formularios, 189, 191 Func, palabra clave, definicin de expresiones
adicin lambda, 254
cdigo para eventos, 142-146 funciones, 49, 59
controles, 138-142, 198-205 agregadas, 105, 459
cierre, 149 listadas, 459
control PrintDocument, 554 complejas divididas en funciones bsicas, 257
de detalle genricos, 248-250 de conversin, 176
de resumen genricos, 250-252 diversas, 181
eventos y delegados, 206-209 funciones de conversin, 176
formulario de informacin del ensamblado, integradas, 176
147 intrnsecas, 35
localizacin dentro de Visual Studio, 531-534 manipulacin de cadena, 179
mejoramiento del control Combos mediante modificacin de resultados de consulta LINQ,
dibujo de propietario, 505 454
mtodo CreateGraphics, 489 numricas, 179
modales, 210 operadores como, 331
modificacin de propiedades mediante cdigo relacionadas con fechas, 177
fuente, 197 valor de devolucin, 50
propiedades interesantes y sus usos, 195-197 Function, palabra clave, inicio de expresiones
sin modo, 210 lambda, 254
tipo genrico usado con, 437
unin de propiedades en el sistema de
configuracin, 400
G
fracciones, 152, 154 GAC (cach de ensamblado global), 13, 127
fragmentos de cdigo GDI (interfaz grfica de dispositivo), 486
insercin, 71 (vase tambin GDI+)
instalacin, 721 GDI+, 487-488, 511
Fragmentos de cdigo, caracterstica (Visual Studio), colocacin de texto en la superficie de su imagen,
70 493-496

ndice | 737

29_PATRICK-INDEX.indd 737 17/2/10 15:37:49


dibujo grupo de unin de expertos fotogrficos (vase
de propietario, 505 JPEG, archivos)
de texto e imgenes en pginas impresas, 582 GZipStream, objeto, 419
imgenes, 497-499
para generar pginas impresas, 553, 563
pinceles, 491 H
plumas y pinceles, 490
Handles, palabra clave, 65, 74, 208
uso en el proyecto Biblioteca, 511-525
hash, funciones, 305
generacin de recursos, 528
hash, valor, 306
generadores de pares de clave pblica/privada, 309
Hawaii (versin prxima de Visual Basic), 22
Generic.Dictionary, coleccin, 459
Help, archivo de palabras clave (HTML Help), 675
Generic.List, coleccin, 459
Help Contents, archivo (HTML Help), 674
genricos, 433-447
HelpProvider, control, 680-682
anidado, 439
acceso a archivos de HTML Help, 681
marcador de posicin general (T), 434
ayuda emergente en controles individuales, 681
restriccin de parmetro de tipo, 437
sobrecarga de tipos y miembros, 440 Help.ShowHelp, mtodo, 682
tipos herencia, 222
annimos, 451 clases que implementan interfaces, 238
de datos y restriccin de interfaz, 436-438 entidad, 293
no genricos con miembros genricos, 439 palabra clave Mustlnherit, 237
que pueden ser nulos, 441 soporte en Visual Basic, 230-232
varios marcadores de posicin en una clase, 436 Hex, funcin, 317
Get, accesor, 60 .hhc, archivos, 674
GetData, mtodo, interfaz IService, 660 .hhk, archivos, 675
GetException, mtodo, objeto Err, 270 .hhp, archivos, 675
GetLowerBound, mtodo, 174 Hill, comando, 134
GetPrivateProfileString, llamada a API, 423 HMACSHA1, clase, 311, 316
GetType, operador, 171 hojas de estilo en cascada (vase CSS)
GetUpperBound, mtodo, 174 Hola, mundo., ejemplo de cdigo, 8, 70-74
GetXmlNamespace, funcin, 378 HTML, 582
GIF, archivos, 497 archivo Default.aspx, 646
Global, palabra clave, 27, 66 asignacin de contenido al control literal, 669
globalizacin cdigo fuente de aplicacin de ASP.NET, 648
cambio de la propiedad Localizable de un contenido personalizado de detalle de elemento,
formulario, 532 control WebBrowser, 479-481
cultura, manipulacin de interfaz de usuario y controles, 650
cadena, 537 editor mejorado, 20
definida, 527 generacin
espacio de nombres Globalization, caractersticas datos XML, 368
de administracin de cultura, 538 mediante ASP.NET, 644
GNU General Public License, 612 secuencias de comandos del lado del cliente y
GO, comando, 100 del sevidor, 644
GoTo, instrucciones, 61 vnculos para el control WebBrowser, 481-482
limitacin del uso de, 62 (vase tambin formularios; desarrollo Web)
GraphicsPath, clase, 501 HTML Help, 673
GridView, controles acceso, 680-682
edicin de columnas, 667 control HelpProvider, 680-682
lista de informes de estadsticas unidas a, 670 diseo, 674-680
unin de resultados de bsqueda a campos, archivo de palabras clave Help, 679
666-669 archivo de proyecto de ayuda, 676

738 | ndice

29_PATRICK-INDEX.indd 738 17/2/10 15:37:49


archivo Help Contents, 677 archivos agregados a las pginas de HTML, 676
archivos de contenido, 676 de rutas, 488, 501
formato de ventanas de ayuda, 680 uso para establecer regin de recorte
HTML Help Workshop, 675 personalizada, 502
HyperLinkField, columna, control GridView, 667 dibujo en superficies grficas, 499-501
en archivos de recursos, 528
I en los primeros sistemas de pantalla, 486
estticas, video e imgenes animadas de interfaz
IBM, PC, 1 de usuario, 507
ICO, archivos, 497 formatos de archivo, 497
conos GDI+, 487-488
archivos ICO, 497 soporte de .NET para, 486
de escritorio, configuracin en el proyecto de vectoriales (de lnea)
instalacin, 704 dibujo con GDI+, 487
en archivos de recursos, 529 metaarchivos, 497
ID de usuario, SQL Server, 290 objeto GraphicsPath, 488
identidad de hardware con clave de licencia, 614 imgenes de red porttiles (PNG), archivos, 497
IDENTITY, palabra clave, 101 implementacin de aplicaciones, 3, 89, 689-710
idioma-cultura, selecciones, 532 ASP.NET, 645
idiomas, 527 ensamblados y manifiestos, 13
configuraciones de idioma, 129 implementacin lado a lado, 16
propiedad Language, 532 mtodos dentro de Visual Studio, 690-700
traductor que convierte un formulario a un ClickOnce, 698
idioma especfico, 534 implementacin con XCopy, 691
IDisposable, interfaz, 236 implementacin directa de ASP.NET, 690
IEnumerable, interfaz, 55, 451 Windows Installer, 692-698
mtodos de extensin, 461 proceso afectado, 689
objetos DataTable y, 463 proyecto Biblioteca (ejemplo), 700-710
orgenes de datos usados con el control implementacin, objeto, 6, 224
MicrosoftReportViewer, 593 Implements, palabra clave, adicin de interfaces a
IEnumerable(Of T), interfaz, 451, 459 una clase, 238
If, instrucciones, 51-52 Imports, instruccin, 68
clusulas Elself, 52 definicin del espacio de nombres XML, 378
condiciones, 51 espacio de nombres My y, 69
palabras clave de instrucciones, 52 impresin, 552-580
variaciones para uso en lnea, 53 conteo y numeracin de pginas, 561
If (ternario), operador, 51, 54 controladores de impresora de Windows que
#If, directiva, 134 maneja variaciones de impresora, 553
igual a, operador (vase = [signo de igual], controles de impresora para Windows Forms,
bajo Smbolos) 554
IIS (servidor de informacin de Internet), 644 en modo simple, 563
IL Disassembler, herramienta, 618 en .NET, 554-557
IL (lenguaje intermedio), 2, 8 lenguajes de impresora, 553
cdigo MSIL en archivos .NET PE, 128 programa que imprime un documento, 557-559
compilacin y descompilacin, 17 vista previa de impresin, 559
ofuscacin en .NET, 617 impresoras instaladas, 409
ildasm.exe, herramienta, 17 In, palabra clave (LINQ), 453
Ilf, funcin, 53 IndexOf, mtodo, coleccin Items, 247
Image, clase, 497 ndice (palabras clave de ayuda), archivo, 679
imgenes, 497-499 ndices (SQL Server), 101

ndice | 739

29_PATRICK-INDEX.indd 739 17/2/10 15:37:49


inferencia de tipo, 376 GoTo, 61
combinacin con expresiones lambda, 255 Option, 45
local, 166 Return, 63
encendido y apagado, 167 (vase tambin SQL)
soporte para LINQ, 450 Int16, tipo de datos, 154
uso por tipos annimos, 451 Int32, tipo de datos, 154
informacin definida, 79 Int64, tipo de datos, 154
informes, 581-610 integracin de base de datos, pginas ASP.NET, 657
controles de creacin de informes en .NET, integridad referencial, 323
584-597 IntelliSense (Visual Studio), 18, 652
Crystal Reports, 583 soporte para JavaScript en Visual Studio 2008,
documentos XPS, 582 21
en bandas, 587 ventanas transparentes en Visual Studio 2008, 21
impresin basada en PrintDocument, 582 interaccin con datos, 4
informe de salida a una impresora, 487 interfaces, 9, 222, 228
integracin con Microsoft Office, 583 contrato con implementacin de clase o
pginas HTML/Web, 582 estructura, 237
servicios y controles, 583 de usuario, 486-525
Inherits, palabra clave, 27, 230 controles, 191
INI, archivos, 393 creacin con WPF, 507-510
archivo de proyecto de ayuda, 675 cultura de la sociedad local, 537
extraccin de un valor, 422 dibujo de primitivas con plumas, 490
inicializadores dibujo en el contexto de los objetos Graphics,
constantes, 161 488-490
de objeto flujo de texto a partir de fuentes, 493-496
soporte para LINQ, 450 imgenes, 497-499
uso (ejemplo), 451 imgenes de dibujo, 499-501
objeto, 259 mejoramiento de controles con dibujo de
inicio de sesin, controles, 650 propietario, 505
inicio del proyecto, 84 regiones, 502
InitializeComponent, procedimiento, 28, 143, 193 relleno entre lneas de dibujo con pinceles,
definicin de la instancia del control Button, 208 491
innovacin en comparacin con lo comn, 81 revisin general de GDI+, 487-488
INSERT, instrucciones, 97, 103 rutas grficas, recoleccin de objetos de
devolucin de un solo campo a partir de un dibujo en unidades agrupadas, 501
registro creado mediante, 292 transformaciones de objetos de dibujo, 503
instalacin lado a lado, 16, 400 espacios de nombres, 66
InstalledFontCollection, objeto, 409 grficas de usuario, 507
InstalledPrinters string, coleccin, 557 (vase tambin interfaz de usuario)
instancias, 6 mltiples, con restriccin de un tipo genrico,
clase usando miembros compartidos en lugar 438
de, 229 objeto, 5, 224
creacin de instancias de clase, 232 restriccin de tipos genricos, 437
predeterminadas de formularios de proyecto, ventajas de uso, 238
149 interfaz de programacin de aplicaciones (API), 392
instrucciones, 34 interfaz grfica de dispositivo (GDI), 486
bloque, 165 (vase tambin GDI+), 486
de control de flujo, 34, 61-64 Internet
de una sola lnea, 52 cmo funciona, 642
End y Stop, 64 programacin, 644

740 | ndice

29_PATRICK-INDEX.indd 740 17/2/10 15:37:50


Internet Explorer lenguaje extensible de marcado (vase XML)
control WebBrowser en aplicaciones, 479 lenguaje extensible de marcado de aplicaciones
vista del cdigo fuente de aplicacin de (vase XAML)
ASP.NET, 655 lenguaje intermedio (vase IL)
interop, 564 lenguaje intermedio de Microsoft (vase IL)
ensamblados Interop primarios (PIA), 584 lenguajes
Is, operador, 48, 171 con fuerte imposicin de tipos, 166
ISAM (mtodo de acceso secuencial indizado), 277 de alto nivel, 33
IsError, funcin, 273 de consulta, 97
IsFalse, operador, 336 (vase tambin LINQ; SQL; SQL Server)
IsNot, operador, 48, 171 de programacin
IsNumeric, funcin, 184, 262 .NET, 2
IService, interfaz, 660 procedimentales, 49
IsTrue, operador, 336 uso de clculo lambda, 253
ItemData, matriz, 244 Let, palabra clave (LINQ), 475
ItemProperties, control, 522 licenciamiento, 611-641
Items, coleccin, 245 acceso controlado, 614
mtodo IndexOf, 247 clave de licencia
con identidad de hardware o candado, 614
J generada personalizada, 613
mtodo slo licencia o acuerdo, 612
japons, localizacin de formulario en idioma, opciones de software para, 611
533-534 LicenseStatus, enumeracin (ejemplo), 628
JavaScript, 648 lienzo
Ajax, 650 generalizacin por GDI+, 488
IntelliSense y soporte de depuracin, Visual
lienzo de impresora en memoria, 553
Studio 2008, 21
objetos Graphics, 488
jerarqua de tipos .NET, 11
Like, operador, 48, 170
JPEG, archivos, 497
sobrecarga, 335
GDI+, 487
lmite inferior de una matriz, 174
lneas
K base de bloques de texto, 495
Kemeny, John, 31 de comandos
KeyDown, manejador de eventos, 217, 686 aplicaciones basadas en texto, 23
KeyPreview, propiedad, 217, 686 cmd.exe, 535
Keys, enumeracin, 217 de etiquetas, 61
kit de integracin de ayuda, 674 lgicas, 34
kit de recursos tcnicos, 109 transformaciones geomtricas, 503
Kurtz, Thomas, 31 y formas, adicin a un formulario, 140
LinkClicked, evento, 325
LinkLabel, controles, 141
L vnculos mltiples estilo Web, 145
La Regla (XML), 367 LINQ (consulta de lenguaje integrada), 32, 448-485
Label, control, 139 actualizaciones de almacenes de datos, 469
lectores y escritores de datos de flujo, 420 caractersticas de Visual Studio 2008, 20
Left, funcin, 183 consultas agregadas, 459
Len, funcin, 183 conversiones de resultados de consulta, 459
Length, propiedad, objeto Stream, 418 desventajas de, 449
lenguaje de definicin de datos (vase DDL) ejecucin diferida de consultas, 468
lenguaje de manipulacin de datos (vase DML) expresiones de consulta avanzadas, 460

ndice | 741

29_PATRICK-INDEX.indd 741 17/2/10 15:37:50


expresiones de consulta bsicas con clusulas, cadena, 36
453-458 en instrucciones SQL, 103
Distinct, 455 una sola comilla dentro, 45
From, 453 carcter, 36
Order By, 456 fecha y hora, 37
Select, 454 no reutilizable, 37
Skip y Take, 458 numricas, 159
unin de orgenes, 456 en instrucciones SQL, 103
Where, 455 XML, 376, 461
LINQ para datos de ADO.NET, 463-468 contenido de variable no lateral, 376
LINQ to DataSet, 463 espacios de nombres y esquemas, 378
LINQ to Entities, 463 (vase literales XML)
LINQ to SQL, 464-468 llamadas a funcin, 34
LINQ to Objects, 451 Load, eventos, 145
LINQ to XML, 461 aplicaciones Web Forms, 654
tecnologas de soporte, 450 Localizable, propiedad, 532
tipos annimos, 450 localizacin
ventajas, 449 caractersticas en .NET, 526
LISP, lenguaje, 4, 331 definida, 527
List, coleccin, 459 despliegue de horas, fechas y valores monetarios,
List, controles 537
agrupamiento de datos en un informe, 591 fechas en formato de cultura neutral, 551
con un campo del conjunto de datos, 587 formato de moneda, 544, 548
List, matriz, 244 localizacin
listas, valor de comparacin contra, 52 formularios dentro de Visual Studio, 531-534
ListBox, controles, 244 idioma con archivos de recursos, 527-530
almacenamiento de objetos como elementos, 382 Location, propiedad, 400
coleccin Items, 245 lgica
ejemplo, 245 errores en, 262
formularios separacin del diseo de la aplicacin de
BusquedaArticulo, 470 presentacin, 508
de resumen genrico, 250 traduccin para computadoras con lenguajes de
lista de familias de fuentes instaladas, 493 programacin, 33
mejoramiento mediante dibujo de propietario, Long, tipo de datos, 40, 45
514-516
propiedades M
DisplayMember, 245
ValueMember, 245 MAC (cdigo de autentificacin de mensaje), 311
rastreo de nmeros de ID en, 342 Macintosh, 1
sobreescritura del mtodo Equals, 247 Main, mtodo, 193
suministro de cdigo de dibujo personalizado personalizado, 194
para, 488 Management Studio Express, 123
ListltemData, objetos, 476 manejadores
adicin de sobrecarga CType, 342 de archivo, 417
ejemplo, 246 de eventos, 64-66, 206
ListView, control, modificacin de la coleccin adicin de plantillas para LinkClicked, 144
Columns, 357 adjuntos a instancias de clase, 65
Literal, control, 670 aplicacin WPF y XAML, 510
literales, 36, 159 argumentos, 65
Boolean, 37 control Button del evento Click, 207

742 | ndice

29_PATRICK-INDEX.indd 742 17/2/10 15:37:50


definidos, 64 Max, funcin, 460
tpicos para el control Button, 206 mayor que, operador (vase < y > [picoparntesis],
vinculados a un evento, 144 bajo Smbolos)
(vase tambin eventos) MD5, algoritmo de hash, 311
manejo de errores, 260, 263 Me, palabra clave, 207
captura todo, captacin de excepciones no referencias a miembros de instancia, 233
administradas, 268 medidas comparativas, 86
deshabilitacin, 265 MemoryStream, objeto, 419
estructurado, 265-269 menor que, operadores (vase < y > [picoparntesis],
mezcla con manejo de errores no bajo Smbolos)
estructurado, 270 mensajes, 189
ignorancia de errores, 265 de error
mezcla de estructurados y no estructurados, 270 desplegados por validadotes de Web Forms,
no estructurado, 263-265 656
mezcla con manejo de errores estructurado, generacin y registro, 428
270 men Programas del usuario, carpeta, 703
manifiestos, 13, 129 MessageBox.Show, mtodo, 242
manipulacin de datos, 4 metaarchivos, 497
Map.xml, archivo, 618 metadatos, 13
mapas de bits archivo PE de .NET, 128
archivos BMP, 497 Metafile, clase, 497
asociacin del objeto Graphics a, 489 mtodo de acceso indizado secuencial (ISAM), 277
BMP nativo, formato de archivo en Windows, mtodos, 50
497 abreviados de escritorio, 703
carga y guardado, 498 argumentos de matriz de parmetros, 243
creacin en diversos formatos, 498 cclicos para administracin de proyectos, 84
dibujo convenciones de asignacin de nombres, 166
con GDI+, 487 de extensin, 341
en una superficie grfica, 498 clase SqlDataReader, 344, 473
extensin, recorte y generacin de miniaturas creacin, 341
mientras se dibuja, 499 interfaz IEnumerable, 461
imagen como dibujo en una cuadrcula de bits, soporte para LINQ, 450
498 de formulario, acceso en cdigo fuente, 197
objeto Bitmap, 489, 497 de funcin, 227
pinceles de textura, 491 de maysculas y minsculas, clase String, 341
texto basado en, 496 genricos, 439
Mapping, espacio de nombres, 468 iterativos para la administracin de proyectos, 84
marco conceptual de metodologa para proyectos, 83 lineales para administracin de proyectos, 84
MARS (conjuntos de resultados activos mltiples), manejo de errores, 271
284 miembro de clase, sub y funciones, 226
incluido soporte en cadena de conexin de SQL parciales, 239
Server, 290 restricciones en, 240
Math, clase, 179 soporte para LINQ, 450
matrices, 172-175 uso de sistema de eventos en lugar de, 241
argumentos ParamArray, 243 (vase tambin, funciones; subrutinas)
conversin de resultados de consultas LINQ a, Microsoft Access, 99
459 Microsoft Expression Blend, 508
inicializacin, 175 Microsoft FrontPage Extensions, 691
lmites, 174 Microsoft Help 2, 673
multidimensionales, 174 Microsoft Office

ndice | 743

29_PATRICK-INDEX.indd 743 17/2/10 15:37:50


acuerdo de licencia del consumidor, 616 en Visual Basic, 239
ensamblados Interop primarios (PIA), 584 espacios de nombres, 66
integracin de Visual Basic, 583 monitoreo de notificaciones de eventos, 208
Microsoft Solutions Framework (MSF), 84 motor en tiempo de ejecucin de lenguaje dinmico
Microsoft Visual SourceSafe, 89 (DLR), 22
Microsoft Windows (vase Windows, sistemas) MSBuild, herramienta, 136
Microsoft Word, 361 MS-DOS, 187
Microsoft.Reporting, espacio de nombres, 583 MSF (Microsoft Solutions Framework), 84
Microsoft.VisualBasic, espacio de nombres, 12, 35 MsgBox, procedimiento, 50, 241, 715
mtodo MsgBox, 241 despliegue de literales, 36
Microsoft.VisualBasic.dll, ensamblado, 131 MsgBoxResult, enumeracin, 241
Microsoft.VisualBasic.Logging, espacio de nombres, .msi, archivos, 693
429 MSI, instalaciones, 693-698
MicrosoftReportViewer, control, 583 comparacin con la implementacin con
descarga, 585 ClickOnce, 698
implementacin de orgenes de datos distribucin en CD, 700
IEnumerable, 593 generacin de archivo para el proyecto
integracin con SQL Server Reporting Services, Biblioteca, 707
584 MSIL (lenguaje intermedio de Microsoft) (vase IL)
uso en un formulario, 588 multilnea, instrucciones, 52
miembros multimedia, 507
afectados, 232 interactiva, 507
de clase compartidos, 228 multiplicacin, operador (vase * [asterisco],
de instancia, 229 bajo Smbolos)
de una clase, 4, 10, 225-228 Must Inherit, palabra clave, 248, 318
compartidos, 228 Mustlnherit, palabra clave, 231, 237
convenciones de denominacin, 166 deshabilitacin de creacin directa de instancias,
miembros sobrecargados y argumentos 248
opcionales, 229 problemas de Visual Studio con, 318
objeto, 221 Must Override, palabra clave, 248, 318
descendientes, propiedad de eje XML, 377 MustOverride, palabra clave, 231, 237
internos, 5 problema de Visual Studio con, 318
pblicos, 5 My, espacio de nombres, 69
secundarios, propiedad de eje XML, 377 administracin de archivos, 424-426
Min, funcin, 460 ensamblados y, 132-134
MinimumSplashScreenDisplayTime, propiedad, mtodo DoEvents, 243
214 nodos principales de la jerarqua, 132
Mod (mdulo), operador, 48, 168 My.Application.Deployment, propiedad, 699
sobrecarga, 334 My.Application.Info.Version, 146
modelo fsico de datos, abstraccin en la vista lgica, MyApplication_Shutdown, manejador de eventos,
463 298
modificador de acceso, palabras clave, 44 MyApplication_Startup, evento, 297
constantes, 161 carga de configuracin de base de datos, 406
miembros de clase, 225 mtodo RefreshHolidays, 447
variables, 164 MyBase, palabra clave, 234
modificadores (vase modificador de acceso, MyClass, palabra clave, 233
palabras clave) My.Computer.FileSystem, objeto
modo de diseo de flujo, 648 caractersticas de interaccin con archivos, 424-
modo simple, complicaciones con impresoras, 563 426
mdulos, 9, 158, 182 mtodo DeleteFile, 134

744 | ndice

29_PATRICK-INDEX.indd 744 17/2/10 15:37:50


My.Forms, coleccin, 70, 149 tipos de datos y equivalentes de Visual Basic,
My.MySettings, objeto, 397 158
My.Resources, objeto, 529 versin, 15
My.Settings, objeto, 398-400, 410, 685 versiones soportadas por Visual Studio 2008,
My.User, objeto, 311 21
Visual Studio 2008, 18
N Visual Studio y Visual Basic, 17
(vase tambin ADO.NET), 278
Name, propiedad, My.User, 311 NetworkStream, objeto, 419
NameMyChild, mtodo (ejemplo), 258 New, palabra clave, 28
Namespace, instrucciones, 69 As New, clusula, 438
Narrowing, palabra clave, 338 asignacin de instancia de tipo de referencia a
navegadores Web, 642 una variable, 163
ejecucin de un servicio Web, 661 constructores, 234
independencia de aplicaciones de ASP.NET, 646 creacin de instancias
necesidades de los usuarios, 79-83 de clases personalizadas, 232
capacidad de uso, 80 de tipos de referencia, 42
comparacin entre lo comn y la innovacin,
New Project, cuadro de dilogo (Visual Studio), 23
81
niveles de acceso, 10, 161
datos e informacin, 79
no es igual a, operador (vase < y > [picoparntesis],
especficas del proyecto, 83
bajo Smbolos)
proceso, 80
no postback, eventos, 654
negacin
nodos
en el nivel de bits, operador (vase Not,
documento XML, 372
operador)
ubicacin, 374
operadores (vase [signo menos],
jerarqua de tipos .NET, 11
bajo Smbolos; Not, operador)
raz en espacios de nombres de .NET, 11, 12
unaria, operador (vase [signo menos],
nombre fuerte (ensamblados), 13, 127, 129
bajo Smbolos)
nombres, variable, 38
.NET, tipo de datos, 154
.NET Framework, xv, 1-29 normalizacin, 96
antes de .NET, 1 Not, operador, 48, 169
beneficios, 2 sobrecarga, 335
biblioteca de clases, 10-13 notacin hngara, 165
CLR (motor en tiempo de ejecucin de Nothing, valor, 175
lenguaje comn), 7 argumentos del operador IF evaluados como, 54
CLS (especificacin de lenguaje comn), 8 asignacin a variables, 162
CTS (sistema de tipo comn), 9, 34 comparacin entre tipos de referencia con, 42
ensamblados, 126-150 variables creadas con constructor
y manifiestos, 13 predeterminado, 235
falta de soporte a impresora simple, 564 Notlnheritable, palabra clave, 232
historia de, 31 NotOverridable, palabra clave, 231
implementacin de tipos de datos de Visual NULL, palabra clave, 104
Basic, 41 nulos, valores, 104
metadatos y atributos, 13 paso en instrucciones SQL, 299
objetos, 3-7 nmeros
proceso de implementacin de Visual Basic, 16 decimales, 34, 152
Remoting, 659 negativos, 152
sistema de impresin, 554-557 tratamiento como valores booleanos, 37
soporte de ASP.NET, 645 variables para, 34

ndice | 745

29_PATRICK-INDEX.indd 745 17/2/10 15:37:50


O On y Equals, palabras clave, 457
Onlnitialize, mtodo, 214
O/R (relacional de objeto), diseador, 465-467 Opacidad, propiedad, 524
localizacin de tablas de base de datos SQL
opciones
Server, 471
comunes, 82
OBA (Office Business Applications), 584
de inicio, aplicaciones de Windows Forms, 193
Object, clase, 39, 40, 157
SQLServer, 101
mtodos
operadores, 47, 167-172
Finalize, 236
agrupamiento de operandos por, empleando
ToString, 245
rboles de expresiones, 256
parmetros de tipo genrico, 436
asignacin, 171
tipo dbil, 434
binarios, 47, 167, 331
objetivos del proyecto, 85
combinacin de operandos como expresiones
objetos, 3-7, 220
complejas, 49
abstraccin, 220
como funciones, 331
de datos de ActiveX (ADO), 277
de comparacin, 48, 170
definidos, 4
sobrecarga, 334
grficos, 488-490
de divisin de enteros (vase \ [diagonal
desecho apropiado, 489
invertida], bajo Smbolos)
dibujo de propietario, 488
en el nivel de bits
lienzo para salida de comando de impresora
sobrecarga, 335
GDI+, 554
(vase tambin operadores individuales,
mtodo Drawlmage, 498
bajo Smbolos)
mtodo DrawString, 493, 523
LINQ, 452, 454
mtodos, 499
mtodos de extensin que corresponde a, 461
mtodos que se aplican a transformaciones,
lgicos, 48, 104, 169
504
sobrecarga, 335
obtencin y creacin, 489
matemticos, 47, 168
paso de comandos de dibujo mediante
sobrecarga, 333
transformaciones geomtricas, 503
resumen, 168-171
sobrecargas, 499
suministro de un lienzo para dibujo, 488 operandos, 167
herencia, 222 Operator, palabra clave, 332, 338, 339
inicializadores, 259 Option Compare, instruccin, 46
instancias y, 6 Option Explicit, instruccin, 45
interfaces y, 5 Option Infer, instruccin, 46
LINQ to Objects, 451 Option Infer, instrucciones, encendido y apagado
polimorfismo, 223 de tipo, 167
tecnologa basada en objetos de ASP.NET, 645 Option Infer On, instruccin, 256
ODBC (conectividad abierta de base de datos), 277 Option Strict, instruccin, 45
implementacin por parte de Microsoft, 279 Option Strict On, instruccin, 233, 256
reemplazo por proveedores en .NET, 280 conversiones de estrechamiento implcitas
Office Business Applications (OBA), 584 que generan errores, 260
ofuscacin, 17, 130, 616-618 Option, instrucciones, 45
OLEDB, 277, 280 Optional, palabra clave, 230
On Error, instrucciones, 270 Or exclusivo (Xor), operador, 48, 169
habilitacin o deshabilitacin de manejo de sobrecarga, 335
errores, 264 Or, operador, 48, 169
On Error GoTo, instruccin, 265 sobrecarga, 335
On Error Resume Next, instruccin, 265 OR, palabra clave, 104
rutinas de interaccin de base de datos, 298 Oracle, 279

746 | ndice

29_PATRICK-INDEX.indd 746 17/2/10 15:37:50


OracleClient, clase, 278 Password, palabra clave reservada, 542
orden de tabulacin, 141 PDF, documento esttico parecido a, 507
ordenamiento PE (ejecucin porttil), archivos, 128
comparacin de cadena binaria y de texto, 46 Peek, mtodo, clase Stack, 441
datos de informe, 592 PIA (ensamblados Interop primarios), 584
Order By, clusula, consultas LINQ, 456 PictureBox, control, 213
ORDER BY, clusula, instruccin SELECT, 105 manejador de eventos Paint, 493
OrElse, operador, 48, 169 propiedades, 494
sobrecarga, 336 pilas, clases, 478
Orgenes de datos, panel, 286 genrica Stack(Of T), 441
orgenes de datos Stack, 440
adicin a informes RDLC, 585 pinceles, 488, 491
creacin, 284-286 degradado, 491
datos personalizados usados en informes RDLC, dibujo de rectngulos simples (ejemplo), 492
593 objeto Brush, 490
personalizados para informe RDLC, 595-597 patrn, 491
uso, 286 slidos, 491
vinculacin con la regin del informe, 587 textura, 491
OUTPUT INSERTED, clusula, 292 uso en la salida de texto, 496
Overloads, palabra clave, 229 planeacin
sobrecargas sobrecargadas y, 340 diseo y, 85
Overridable, palabra clave, 231 importancia en el concepto de programacin,
Overrides, palabra clave, 231 716
plantillas
P de proyecto especficas del captulo, 23
instalacin de plantillas de proyecto para este
Page_Load, evento, 654 libro, 720
PageSetupDialog, control, 554 Plataforma de ayuda (AP), 674
pgina Web de este libro, xviii, 719 plumas, 488
pginas, conteo y numeracin para impresin, 561 clase System.Drawing.Pens, 490
pginas de servidor activo (ASP), 644 creacin, 490
(vase tambin ASP.NET) desecho apropiado, 490
Paint, controles del evento, 489 objeto Pen, 490
PictureBox, 494 predefinidas, 490
vista previa de etiqueta de cdigo de barras, 522 PNG, archivos, 497
palabras clave polimorfismo, 223
archivo de palabras clave de ayuda, 675 posicionamiento absoluto, 648
de instrucciones, 52 Position, propiedad, objeto Stream, 418
LINQ, 452 postback, eventos, 654
Panel de control, applet Configuracin regional y PostScript, 553
de idioma, 538 preferencias controladas por el usuario, 400
ParamArray, argumentos, 243 presentacin, separacin de la lgica en el diseo
parmetros de la aplicacin, 508
de tipo, 436 PreviousPage, objeto, 668
propiedad, 60 PRIMARY KEY, clusula, instruccin CREATE
subrutina, 58 TABLE, 101
Partial, palabra clave, 27, 225 PrintDialog, control, 554, 558
Pascal, 49 PrintDocument, clase, 554, 557, 582
Pascal, uso de maysculas y minsculas, 166 instancia en el nivel del campo, clusula With
paso por valor o por referencia, 58 Events en definicin, 554

ndice | 747

29_PATRICK-INDEX.indd 747 17/2/10 15:37:50


manejador de eventos PrintPage, 561 clase, 227
nmeros de pgina de documento y, 561 controles, 288
propiedad PrinterSettings.PrintRange, 561 de eje (XML), 377
PrinterSettings, clase, 557 formulario, 195-197
propiedad PrintRange, 561 mtodos de clase sub y, 226
PrintPage, manejador de eventos, 559, 561 objeto, 221
modificacin de cdigo que determina cundo propiedades del eje XML, 377
salir del proceso de impresin, 563 Propiedades, panel (Visual Studio), 15, 24, 139
PrintPreviewControl, clase, 555 establecimiento de propiedades del formulario,
PrintPreviewDialog, clase, 554, 560 139
Private, modificador, 44 Protected Friend, variables, 164
ensamblados, 126 Protected, modificador de acceso
miembros de clase base, 223 miembros de clase base, 223
variables, 164 variables, 164
problemas con el mbito, 88 prototipos, 87
procedimientos, 35 proveedores
colocacin, 61 ADO.NET, 279-281
creacin de propios, 57-61 LINQ, 451
variables y constantes declaradas soporte usando Entity Framework, 294
dentro, 164 proyectos
fuera, 164 ayuda, archivo, 675, 676
ventana (vase WndProc) en Visual Basic
procesamiento de datos, 4
(vase tambin proyecto Biblioteca)
proceso, 80
instalacin, construccin, 693-698
publicacin para aplicaciones, 699
marco conceptual de la metodologa, 83
Process, objeto, 145
pruebas
mtodo Start, 390
criterios de aceptacin, 88
Professional Edition de Visual Studio 2008, 19
interfaz, 88
programacin
sistema, 88
entorno unificado en .NET, 2
funcional, 253 unidad, 88
(vase tambin expresiones lambda) visitas, 503
orientada a objetos, 31, 219-241 pseudocdigo, 33
clases en Visual Basic, 225 Public, modificador, 44
instruccin On Error y, 270 ensamblados, 127
interfaces e implementacin, 224 variables, 164
manejo de errores estructurado, 265-267 Public, palabra clave en declaraciones
objetos, 220 de operador, 332
tareas bsicas realizadas por computadoras, 4 sobrecargadas de operador, 339
programas publicacin de un sitio a servidor de produccin,
cdigo fuente de los ejemplos de este libro, xvii 691
ejemplos en este libro, xvi punto (.)
uso de los ejemplos de cdigo de este libro, xviii separacin de nodos en jerarqua de tipo, 11
WPF de navegador, 507 (vase tambin . [punto], bajo Smbolos)
Prompt, parmetro, MsgBox, 241 punto flotante, valores, 37, 153
Property, palabra clave, 61 Push y Pop, mtodos, clase Stack, 440
PropertyBinding, propiedad, 400 Python, 22
PropertyGrid, control, 511, 518
atributos agregados a propiedades de clase, 511
Q
instancia del control ItemProperties, 522
propiedades, 4, 50, 60 QueryPageSettings, evento, 559

748 | ndice

29_PATRICK-INDEX.indd 748 17/2/10 15:37:50


R establecimiento de regin de recorte
personalizada, 502
Raise, mtodo, objeto Err, 270 uso en prueba de visitas, 503
ramas en cdigo, 51 registros, 95, 393
instrucciones If, 51 reglas para uso de maysculas y minsculas para
rascado de pantalla, 658 variables, 166
RC2 (Rivest Cipher numero 2), 307
RegularExpressionValidator, 655
RC2CryptoServiceProvider, clase, 307
relaciones
RDLC, informes, 586-597
ADO.NET Entity Framework, 293
adicin
primario-secundario, tablas de base de datos,
encabezado y pie de pgina, 590
106
origen de datos, 585
tabla, 106
controles de regin de datos, 587
una a una, 106
datos personalizados, 593
varias a varias, 106
diseo de superficie de informe, 587
Reload, mtodo, objeto Settings, 399
ejecucin, 589
REM, palabra clave, 45
esquema de informe, 599
RemoveHandler, instrucciones, 209
formato de estilo, 592
Reporting, espacio de nombres, 583
soporte a agrupamiento y ordenamiento de
ReportViewer, clase, 583
datos, 591-593
creacin de un informe simple, 584
suministro de orgenes de datos personalizados,
(vase tambin Microsoft ReportViewer,
595-597
uso de control de informe, 588 control)
RDLC Report Viewer, control, 657 RequiredFieldValidator, 655
.rdlc, archivos, 586 Reset, mtodo, objeto Settings, 399
RDO (objetos de datos remotos), 277 resgen.exe, utilera, 535
ReadOnly o WriteOnly, palabra clave, 61 Resource Kit, 109
recarga de pginas Web, 654 ResourceManager, clase, 530
recoleccin de basura, 236 .resources, archivos, 536
mtodo SuppressFinalize y, 237 Resources, objeto, 529
tipos de referencia, 158 Resources.resx, archivo, 530
recursin, 315 resta, operador (vase [signo menos],
recursos, 213, 527 bajo Smbolos)
adicin fuera de Visual Studio, 534 restricciones, 101
compilados, archivos, 528 clases que restringen tipos genricos, 437
generacin y compilacin manual, 535-537 interfaces que restringen tipos genricos, 437
limpieza, 237 resultados de consulta jerrquica (LINQ), 457
REFERENCES, clusula de opcin, instruccin resultados de paginacin, consultas LINQ, 458
CREATE TABLE, 101 Resume Next, instruccin, 265
REFERENCES, restriccin, 123 .resx, archivos, 528
referencias Return, instrucciones, 63, 715
entre tablas de base de datos, 101 Rijndael, algoritmo de cifrado, 307
manifiesto del ensamblado, 129 Rivest Chipre, nmero 2 (RC2), 307
referencias externas, 101, 463 Rollback, mtodo, 293
reflejo, 131 root, espacio de nombres, 69
Refresh, mtodo, 242 RSA algoritmo, 309
regin de datos, controles (informes RDLC), 587 RSA, clase, 624
#Region, directiva, 134 RSACryptoServiceProvider, clase, 309, 624
regiones, 502 RTF (formato de texto enriquecido), 673
de recorte, 502 Ruby, 22

ndice | 749

29_PATRICK-INDEX.indd 749 17/2/10 15:37:50


Run, mtodo, clase Application, 191 Settings.Designer, archivo, 396
runat=servidor, atributos, 651 Settings.settings, archivo, 394, 396
Setup.exe, archivo, 708
SHA-1, algoritmo de hash, 311
S Shadows, palabra clave, 232
Save, mtodo, clase Settings, 399 SHAlManaged, clase, 311
SaveMySettingsOnExit, marca, 399 Shared, palabra clave en declaraciones, 229, 338
SByte, tipo de datos, 40, 154 de operador, 332
secretos, 303 sobrecargadas de operador, 339
secuencias de escape, 553 Short, tipo de datos, 40
seguridad, 303-329 Show, mtodo, 194
autentificacin y My.User, 311 clase MessageBox, 242
caracterstica de .NET, 304 ShowDialog, mtodo, clase Form, 210
clase SecureString, 312 ShowHelp, mtodo, 682, 684
criptografa y cifrado, 304-311 Shutdown, evento para aplicaciones, 298
datos, 304 SignedXml, clase, 625, 631
externa (.NET), 304 Silverlight, plataforma, 507
interna (.NET), 304 Microsoft.VisualBasic y, 242
mejoras de .NET, 3 simulacin de lneas y rectngulos, 140
nivel ms elevado con uso de software, 614 Single, tipo de datos, 40, 155
seguridad de acceso a cdigo (CAS), 304 sistema de administracin de datos (CLR), 7
Select, clusula, consultas LINQ, 454 sistema de dibujo (vase GDI+)
SELECT, instrucciones, 97, 104, 598 sistema de tipo comn (vase CTS)
consulta SQL, 599 sistemas
clusula WHERE, 599 de archivos, 416
Select Case, instrucciones, 52 operativos, 4
manejador de eventos KeyDown, 217 (vanse tambin entradas bajo nombres de
procedimientos de ventana, 190 sistema individuales)
SelectedObject, propiedad, 511 Windows
Service, clase, 660 aplicacin de escritorio, adicin de controles
ServiceContract, atributo, 660 a un formulario, 15
servicios WCF, 659-662 aplicaciones, 187
solicitud, 661 archivos de registro en Windows Vista, 429
suministro de acceso con nombre a, 662 ayuda en lnea, 672-674
servicios Web (vase WCF) controladores especficos de la impresora que
servidores maneja variaciones de impresora, 553
independientes, 279 formato de archivo nativo de imagen de
Web mapa de bits, 497
conexin al servidor Web de Google, 643 lnea de comandos (cmd.exe), 535
creacin de secuencias de comandos del lado programacin simplificada con .NET, 3
del servidor, 644 soporte a impresora simple, 564
IIS (servidor de informacin de Internet), Version 1.0, 2
652 Sitio Web, plantilla, 646
implementacin ASP.NET, 690 Skip, clusula, consultas LINQ, 458
procesamiento de cambios de pgina Web, Sleep, funcin, 214
653 smallint, tipo de datos, 101
servidor de desarrollo ASP.NET, 652, 661 Smart, etiquetas, 200
Set, accesor, 60 SOAP (protocolo simple de acceso a objetos), 659
SET, clusula, instruccin UPDATE, 104 sobrecarga, 224
Settings, objeto, 398-400, 410, 685 de operadores, 330-340, 342

750 | ndice

29_PATRICK-INDEX.indd 750 17/2/10 15:37:50


declaraciones, 339 Management Studio Express, 123
operador CType, 336 SQL Server 2008, 20, 98
operadores de comparacin, 334 SQL Server Management Studio, 99
operadores matemticos, 333 SQL Server Management Studio Express, 99
otros problemas, 338 caractersticas de consulta, 360
precaucin con, 340 diseador de consultas, 598
sobrecarga de operadores sobrecargados, 340 SQLClient, clase, 278
tipos genricos y miembros, 440 SqlCommand, objeto, 290
sobrescritura mtodo ExecuteScalar, 292
base heredada, miembros de clase, 222 propiedad Transaction, 293
palabra clave MustOverride, 237 SqlConnection, objeto, 290
software SqlDataReader, objeto, 291
desarrollo, 87 extensin, 345, 473
en el nivel de negocios, xvi SqlMetal.exe, herramienta, 465
opciones de licenciamiento, 611 SqlTransaction, objeto, 292
para este libro Standard Edition of Visual Studio 2008, 19
acuerdo de licencia, 722 Start, mtodo, objeto Process, 145
descarga de contenido, xvii Startup, evento para aplicaciones, 213, 297
instalacin, 719-721 StartupNextInstance, manejador de eventos, 218
(vase tambin licenciamiento) Stop, instrucciones, 64
Split, funcin, 185 StrDup, funcin, 38
SQL (lenguaje estructurado de consulta), 97, Stream, objeto, 418
100-107 StreamReader, clase, 421
generacin de instrucciones, 598-600 implementacin con una funcin personalizada,
influencia en la industria de la base de datos, 109 423
instrucciones StreamWriter, clase, 421
DDL, 100-103 String, clase, 41, 156
DML, 103-106 constructores, 42, 163
ms all de los fundamentos, 106 extensin, 341
palabra clave AS, 453 mtodos integrados que devuelven instancia de
rutinas que preparan datos para instrucciones cadena modificada, 341
SQL o datos recuperados, 299 propiedades y mtodos de la clase System.String,
uso de instrucciones SQL en SQL Server, 290 181
SQL Query Debug Visualizar, herramienta, 468 tipos de referencia, derivacin de, 157
SQL Server, 279 StringBuilder, clase, 480, 570
ayuda, 673 StringFormat, clase, 515
conexin StringReader, clase, 421
con entidades en lugar de, 294 StringWriter, clase, 421
empleando Visual Studio, 284-289 Sub, instruccin de la declaracin, 58
establecimiento de una conexin, 290 Sub Main, procedimiento, 194
generacin de la cadena de conexin, 289 sub, mtodos, 226
LINQ to SQL, 464-468 subrutinas
modificacin de datos, 291 llamada indirecta mediante eventos, 64
nombre de instancia de base de datos, 665 sobrecargadas, 50
procesamiento de resultados a partir de, 291 Sum, funcin, 460
Reporting Services, 583, 584 uso en consulta agregada LINQ, 459
tipos de datos, 101 sumas de verificacin, 306
transacciones de base de datos, 292 superficies
uso de instrucciones SQL, 290 adicin de superficie de diseo de informe, 586
SQL Server 2005, xvii, 19, 98 del formulario, 138

ndice | 751

29_PATRICK-INDEX.indd 751 17/2/10 15:37:51


superficies de dibujo generalizadas por GDI+, System.Security.Cryptography.RSA, clase, 624
488 System.Security.Cryptography.Xml, espacio de
SuppressFinalize, mtodo, 237 nombres, 627
.svc, archivos, 659 System.Security.SecureString, clase, 312
System, espacio de nombres, tipos de datos, 11, 66 System.Single, clase, 155
centrales, 39 System.String, clase, 42, 181
implementados como clases, 153 (vase tambin String, clase; cadenas)
System.Collections, espacio de nombres, 440 System.Timers, espacio de nombres, 66
System.Collections.Generic, espacio de nombres, System.ValueType, clase, 41, 157, 239
441 System.Version, clase, 146
System.Windows.Forms, espacio de nombres, 68,
System.Collections.Stack, clase, 440
191, 193
System.Data, espacio de nombres, 278, 295
System.Windows.Forms.Application.Run, mtodo,
System.Data.Linq.Mapping, espacio de nombres,
191
468
System.Windows.Forms.Control, clase, 191, 197
System.Data.OracleClient, espacio de nombres, 278
System.Windows.Forms.dll, 68
System.Data.SqlClient, espacio de nombres, 278
System.Windows.Forms.Form, clase, 142
System.DateTime, clase, 178
System.Windows.Window, clase, 509
System.DayOfWeek, enumeracin, 162
System.Xml, espacio de nombres, 295, 371
System.Decimal, tipo de datos, 155
System.Xml.Linq, espacio de nombres, 371, 376
System.Diagnostics, espacio de nombres, 145
System.Xml.XPath, espacio de nombres, 374
System.dll, 68, 131
System.Double, tipo de datos, 155
System.Drawing, espacio de nombres, 487 T
System.Drawing.Font, clase, 493
System.Drawing.Graphics, clase, 488 tablas, 95
System.Drawing.Pens, clase, 490 abreviaturas para nombres, 105
System.Drawing.Point setting, 400 de base de datos
System.Drawing.Printing.PrintDocument, clase, de archivos planos, 96
554 generacin de campos ID, 292
System.Drawing.Printing.PrinterSettings, clase, 557 relleno de listas ComboBox, 247
System.Drawing.Text.InstalledFontCollection, 409 unin, 97, 105
System.EventArgs, clase, 144, 206, 207 Take, clusula, consultas LINQ, 458
Take While, clusula, consultas LINQ, 458
System.Exception, clase, 271
Team Foundation Server, 20
System.Globalization, espacio de nombres, caracte-
Team System 2008, Visual Studio, 20
rsticas de administracin de cultura, 538
tecnologas orientadas a objetos, 2
System.IO, espacio de nombres televisin (TV), considerado como un objeto, 5
lectores y escritores de datos de flujo, 420 Telnet, programa, 643
objeto Stream, 418 ternario, operador (If ), 54
System.Linq.Expressions, espacio de nombres, 256 TextBox, controles
System.Math, clase, 179 adicin a encabezado y pie de informe, 590
System.Object, clase, 39, 157 ASP.NET, evento TextChanged, 653
con tipo dbil, 434 propiedad Color, 593
parmetros de tipo genrico, 436 texto
(vase tambin Object, clase; objetos) alineacin con cuadro lmite, 523
System.Reflection, espacio de nombres, 131 antes de interfaces grficas de usuario, 493
System.Runtime.CompilerServices, espacio de colocacin en superficie de imgenes, 493-496
nombres, 341 comparaciones, 46
System.Security.Cryptography, espacio de nombres, datos de cadena, 34
306, 316 tipos de datos, 156

752 | ndice

29_PATRICK-INDEX.indd 752 17/2/10 15:37:51


transformaciones antes de la salida a superficie tipos de valor y tipos de referencia, 39
grfica, 503 tipos que pueden ser nulos, 175
variables para, 34 variables, 35, 162
TextReader, clase, 421 Visual Basic, 158
TextWriter, clase, 421 de referencia, 9, 39
Then, palabra clave, 51 asignacin a instancia de System.Object, 158
Throw, instruccin, 270 creacin de instancias, 41, 42
tiempo de vida de una variable, 165 declaracin, 42
TIFF, archivos, 497 diferencias de tipos de valor en uso, 157
Timer, control, 191 paso por valor o por referencia, 58
tipos, 9 System.Object, 157
anidados, 228 . de valor, 9
annimos, 450 asignacin a la referencia System.Object, 158
colocacin en espacios de nombres subordinados asignacin predeterminada por parte de
a partir del raz, 69 Visual Basic, 45
CTS (sistema de tipo comn), 9 constantes, 161
de datos, 39, 152 declaracin, 42
anidados en clases, 228 derivacin de System.ValueType, 41
annimo, 450 diferencias de tipos de referencia en uso, 157
carcter, 156 implementacin mediante estructuras, 239
clases, trato de una instancia como objeto, paso por valor o por referencia, 58
157 que pueden ser nulos, 175
como recursos, 529 definidos del usuario, 10
configuraciones, 395 inferidos con expresiones lambda, 255
constantes, 160 que pueden ser nulos, 175
convenciones de denominacin, 166 genricos, 441
conversiones, 45, 176 soporte para LINQ, 450
CTS (sistema de tipo comn), 9 valor Nothing, 163
decimal, 154 referencia de espacio de nombres, 67
delegado, 207 valores de datos, 36
enteros en .NET, 154 variable, 38
enumeraciones, 161 Tipos de ventana, cuadro de dilogo, 680
equivalente en .NET e intercambiable con ToArray, mtodo, 459
equivalentes de .NET, 159 ToDictionary, mtodo, 459
equivalentes en .NET, 158 ToList, mtodo, 459
genricos como marcadores de posicin para, ToLower, mtodo, clase String, 341
433 ToString, mtodo, 245
informacin de tipo exportada control ListBox, 382
(ensamblados), 129 ToUpper, mtodo, clase String, 341
informacin interna de tipo TRACE constante, 136
(ensamblados), 129 transacciones, 292
lenguajes con imposicin fuerte de tipos, 166 distribuidas, 659
limitacin de una pila a un tipo especfico, Transaction, propiedad, objeto SQLCommand, 293
441 transformaciones
literales, 159 geomtricas de objetos grficos, 503
.NET, 153 rotaciones, 523
no genricos, con miembros genricos, 439 (vase tambin XSLT)
parmetros de tipo genricos, 436 transparencia
pasados por valor o por referencia, 58 establecimiento de nivel, 491
SQL Server, 101 incremento lento para, 524

ndice | 753

29_PATRICK-INDEX.indd 753 17/2/10 15:37:51


Trim, funcin, 184 Upgrade, mtodo, objeto Settings, 399
Trimming, propiedad, clase StringFormat, 515 URI (identificador uniforme de recursos), 370
Triple DES, algoritmo de cifrado, 307 URL, creacin de vnculos falsos parecidos a URL,
True, valor, 37 481
conversin a enteros, 157 user.config, archivo, 395
TrueType, fuentes, 512 UShort, clase, 41
Try... Catch... Finally, instruccin, 266 Using, instruccin, 237
Try, clusula, instruccin Try... Catch... Finally, 266 uso en consultas LINQ, 454
T-SQL, lenguaje de creacin de secuencias de usuario clave, 75
comandos, 98
TV considerado como un objeto, 5 V
TypeOf, operador, 171
Val, funcin, 655
validacin
U controles, 650
ubicacin datos, 655-656
cambio de la salida del archivo de registro, 429 del lado del cliente, 656
predeterminada, parmetro, 360 Web Forms, 655
UInt16, tipo de datos, 154 del lado del sevidor, 656
UInt32, tipo de datos, 154 Validador de rango, 655
UInt64, tipo de datos, 154 ValidationSummary, control, 656
UInteger, clase, 41 valores
ULong, clase, 41 actuales, 399
ltimo en entrar, primero en salir (LIFO), 440 binarios, 151
unario ms, operador (vase + [signo ms], para caracteres, 153
bajo Smbolos) booleanos
unarios, operadores, 47, 167, 331 constante de compilador, 135
UnhandledException, mtodo, 276 instrucciones condicionales que producen, 51
Unicode, 153 representacin en un formulario binario, 153
tipo de datos String y, 156 de datos (XML), 366
UnicodeEncoding, objeto, mtodo GetBytes, 317 de fecha y hora, 153
uniones, 105 configuracin sensible a la cultura, 551
cartesianas, 106 funciones relacionadas con fecha, 177
cruzadas, 106 literal en instrucciones SQL, 103
de cadena, operador (vase & [unin], localizacin, 537
bajo Smbolos) tipo de datos en .NET, 153
de datos, 107, 288 tipo de datos System.DateTime, 156
caracterstica de controles, 288 decimales de punto fijo, 153
combinacin de componentes de informes, devueltos, 49
589 expresin lambda, 254
resultados de bsqueda para el control valores separados por comas (CSV), 362
GridView, 667 ValueType, clase, 157, 239
externas completas, 106 varchar, tipo, 101
externas derechas, 106 variables, 34, 37, 162
externas izquierdas, 105 alcance y tiempo de vida, 165
internas, 105 asignacin de nueva instancia de tipo de
consulta LINQ, 457 referencia a, 163
orgenes de consulta LINQ, 456 campos de variable como miembros de clase, 226
Until, clusulas, Do... Loop, 55 convenciones de denominacin, 165
UPDATE, instrucciones, 97, 104 de iteracin, 453

754 | ndice

29_PATRICK-INDEX.indd 754 17/2/10 15:37:51


de respuesta, 38 caractersticas de administracin de archivos,
declaracin y asignacin de valores, 38 424-426
definicin como funciones simples empleando comentarios, 44
expresiones lambda, 254 constantes, 43
definido dentro de un procedimiento o un tipo, creacin de sus propios procedimientos, 57-61
164 espacios de nombres, 66-69
estticas, 172 My, 69
genricos en comparacin con, 442 eventos y manejadores de eventos, 64-66
importancia de declaracin, 45 flexibilidad de, 714
locales, 164 funciones, 59
declaracin de, 43 y subrutinas, 49
modificadores de acceso, 164 fundamentos
rango (o iteracin), 453 de la lgica y los datos, 32
tipos del lenguaje y caractersticas esenciales, 32-35
de datos, 35, 167 historia de, 30
de referencia, 39 instrucciones
de valor, 39 condicionales, 50-54
.vb, archivos, 16 Option, 45
VBA (Visual Basic para aplicaciones), 31 literales, 36
VBC_VER, constante, 136 operadores, 47-49
VBx, 22 otras caractersticas de control de flujo, 61-64
ventanas, 188-189 tipos
formularios y controles, 189, 191 de datos, 39
HTML Help, 680 de datos ValueType, 157
redibujo despus de tapar o exponer, 502 de valor y tipos de referencia, 39
Version, clase, 146 y variables de datos, 35
versiones valores booleanos, conversin a enteros, 157
acceso para aplicaciones con el espacio de variables, 37
nombres My, 134 locales y declaraciones de constantes,
configuracin de aplicaciones y, 399 campos y, 43
constante VBC_VER, 136 Visual Basic 1.0, 2
control para cdigo fuente, 89 Visual Basic 2005, 31
establecimiento del nmero de versin de Visual Basic 2008, xvii, 32
ensamblado, 146 caractersticas avanzadas, 22
exprs de una aplicacin, 134 DataSets con tipo, 282
nmero de versin de ensamblado, 129 tecnologas de soporte para LINQ, 450
profesionales de una aplicacin, 134 Visual Basic para aplicaciones (VBA), 31
vi (editor), 18 Visual Studio
video y audio, 507 apertura de proyectos, 23
videocasetera, control, 288 caractersticas
View State, 655 de implementacin, 690-700
vinculacin e insercin de objetos para bases de Fragmentos de cdigo, 70
datos (OLEDB), 277, 280 controles
Vinculador de ensamblados, programa (al.exe), 536 de Windows Forms, 200-205
vnculos, 144 MicrosoftReportViewer y, 585
archivos HTML Help, 675 documentacin a partir de los comentarios XML
estilo Web, 144 para miembros de clase, 674
vistas de datos lgicas y fsicas, 463 entorno de desarrollo integrado (IDE), 138
Visual Basic escritura de parte del cdigo de un proyecto, 147
bucles, 54-57 herramienta MSBuild, 136

ndice | 755

29_PATRICK-INDEX.indd 755 17/2/10 15:37:51


insercin de un fragmento de cdigo, 71 Widening, palabra clave, 338
licenciamiento y, 611 win.ini, archivo, 393
localizacin de formularios, 531-534 Window, clase, 509
Microsoft Help 2, 673 Windows, carpeta, 393
panel Propiedades, 15 Windows, espacio de nombres, 11
problemas causados por las palabras clave Windows Forms, 187-218, 288
Mustlnherit y MustOverride, 318 aplicaciones, 23
SQL Server, 98 clase My.Forms, 70
Visual Basic y, 17 configuracin de propiedades, 195-198
Visual Studio 2008, 18 control Button, evento Click, adicin de origen
creacin de aplicaciones completas WPF a partir de datos de SQL Server, 290
de contenido XAML, 508 controles, 198-205, 488
ediciones, 18 de impresora, 554
mejoras de uso y caractersticas, 20 creacin de aplicaciones, 191-194
Visual Studio Tools for Office (VSTO), 584 disponible en Visual Studio, 200-205
Visual Web Developer 2008, 19 espacios de nombres
predeterminado, 69
W System.Windows.Forms, 68
eventos y delegados, 206-209
WarningLimit y NoticeFont, parmetros, 398 formulario Agregar referencia de servicio, 661
WCF (base de comunicacin de Windows), implementacin ClickOnce de aplicaciones, 698
658-662 localizacin de aplicaciones, 530
servicios, 659-662 mtodo Help.ShowHelp, 682
Web Forms, 583, 645 Windows Installer, 692-698
caractersticas tras el cdigo, 646, 663 archivo MSI, 693
clase de control representada por la etiqueta de creacin de archivo de instalacin MSI, 693-696
ASP.NET, 651 editores para personalizar el archivo MSI, 696
controles, 649-651 generacin de archivo MSI, 698
GridView al ver el informe RDLC, 657 implementacin de la aplicacin Biblioteca,
Literal, 670 700-710
retencin de estado de pgina con la versiones, 692
caracterstica View State, 655 Windows Live ID, sistema de autentificacin, 312
validacin de datos, 655 WinHelp, 673
Web, espacio de nombres, 11 winres.exe, 534
web.config, archivo, 393, 646 winspool.drv, biblioteca, 564, 567
cadenas de conexin, 658 With, instruccin, 146
para la base de datos Biblioteca, 664 nueva variacin, 259
copiado al servidor ASP.NET, 691 WithEvents, palabra clave, 28, 65, 208
WebBrowser, control, 470, 479 WndProc (procedimientos de ventana), 189
contenido personalizado mediante la propiedad elevacin de un evento en el control Button, 207
DocumentText, 479-481 estructura de, 190
vnculos mediante el evento Navigating, 481-482 Word, 361
WebParts, contenedores de control, 650 World Wide Web, 642-644
Where, clusula, consultas LINQ, 455 WPF (base de presentacin de Windows), 20, 32,
WHERE, instrucciones de la clusula 486, 507-510, 511, 582
DELETE, 104 caracterstica para generacin de archivos XPS,
SELECT, 599 552
UPDATE, 104 despliegue de contenido WPF, 507
While, clusulas, Do... Loop, 55 XAML y, 508-510
While... End loop, 56 WriteOnly, palabra clave, 61

756 | ndice

29_PATRICK-INDEX.indd 756 17/2/10 15:37:51


X transformaciones, 367, 375, 582
uso en .NET
XAML (lenguaje de marcado extensible de la manera antigua, 371-375
aplicaciones), 507-510 la nueva manera, 375-378
etiqueta y atributos Window, 509 ventajas como un formulario de datos, 363
generacin de componentes de interfaz de XAML, 507-510
usuario, 508 XmlAttribute, clase, 372
XCopy, implementacin, 691 XmlComment, clase, 372
XDocument, objeto, 376 XmlDeclaration, clase, 372
XDR (reducido de datos XML), esquemas, 374 XmlDocument, objeto, 372-374
XElement, clase, 376 bsqueda de nodos dentro de, 374
XML, 361-391 mtodos
Ajax, 650 Load, 374
archivos de configuracin, 394 Save, 374, 626
de informes, 605 verificacin de esquema, 374
archivo de licencia, 622 XmlDsigCanonicalizationUrl, mtodo, 625
con una firma digital, 626 XmlElement, clase, 372
bsico, caractersticas de, 365 XmlNode, clase, 372
datos delimitados por comas a partir de la base XmlNodeList, objeto, 374
de datos de ejemplo, 366 xmlns, atributo, 370
definicin de un informe RDLC, 588 definicin con la instruccin Imports, 378
espacios de nombre, 370 XmlTextReader, clase, 374
esquemas, 368-370 XmlTextWriter, clase, 374
establecimiento de datos en Visual Basic 2008, XNamespace, objeto, 378
394 Xor (Or exclusivo), operador, 48, 169
estructura jerrquica, 366 sobrecarga, 335
etiquetas coincidentes de apertura y cierre, 364, XPath, 368, 374
367 XPS (especificacin de papel XML), documentos,
firma digital, 626 507, 552
herramientas de criptografa en .NET, 623 trabajos de impresin capturados como
informes RDLC, 586 documentos XPS, 559
La Regla, 367 uso en generacin de informes, 582
limitaciones de, 364 XSD (definiciones de estructura de XML), 368-370
LINQ to XML, 461 espacio de nombres xs, 370
propiedades de eje, 377 <xsl:template>, elementos, 368
servicios Web, 659 XslCompiledTransform, objeto, 375
soporte para LINQ, 450 XSLT, 367, 375, 582

ndice | 757

29_PATRICK-INDEX.indd 757 17/2/10 15:37:51


29_PATRICK-INDEX.indd 758 17/2/10 15:37:51
Acerca del autor
Tim Patrick es arquitecto y desarrollador de software con 25 aos de experiencia en el diseo y
la construccin de soluciones personalizadas de software. MVP de Microsoft y desarrollador cer-
tificado de soluciones de Microsoft, Tim ha publicado cinco tutoriales y referencias en desarrollo
con Visual Basic, junto con varios artculos. Sus libros incluyen Visual Basic 2005 in a Nutshell
y Visual Basic 2005 Cookbook, ambos de OReilly.

Colofn
El animal en la portada de Programacin con Visual Basic 2008 es un pato cabeza de bfalo
(Bucephala albeola). El nombre alude a la forma de la cabeza, distintiva de estas especies. Los
cabeza de bfalo macho son de color blanco y negro con una larga franja blanca que se extiende
de los ojos a la parte trasera de la cabeza; las hembras son ms plidas, ms pequeas y tienen
una pequea franja blanca en los carrillos. Ambos sexos estn caracterizados por cuellos cortos y
picos estrechos de color gris.
Con variaciones en tamao que van de 35 a 42 centmetros y en peso de 250 a 650 gramos, los
cabeza de bfalo son los patos ms pequeos que se sumergen en el agua en Estados Unidos. A
diferencia de otros patos que hacen lo mismo, puede alzar el vuelo directamente desde el agua sin
tener que correr por la superficie. Viven en lagos, ros y bahas de Canad y el norte de Estados
Unidos, migrando a las aguas costeras del Atlntico, el Pacfico y del Golfo hasta zonas del sur
como Mazatln en los meses de invierno. Anidan en cavidades de lamos hechas por pjaros
carpinteros.
La dieta del pato cabeza de bfalo consiste de insectos frescos y de agua salada, caracoles, crus-
tceos y plantas. Bucean en busca de comida y la tragan bajo el agua. Los patos cabeza de bfalo
tienden a permanecer en grupo, uno o dos de ellos se alimentan mientras los dems vigilan por
cualquier posible peligro. Aunque no son apreciados entre los cazadores de patos, los cabeza de
bfalo son cazados por deporte en Estados Unidos y Canad y comprenden casi 2% de la caza
de aves acuticas en Amrica del Norte. No es una especie amenazada, pero la degradacin de su
hbitat es una preocupacin creciente. Debido a que los patos regresan a la misma zona donde
se alimentan cada ao, la cosecha y deforestacin excesiva puede tener impacto en su poblacin
si no se le vigila con cuidado.
La imagen de la portada es de la Natural History, de Johnson. La fuente de la portada es Adobe
ITC Garamond. La fuente del texto de Linotype Birka; la fuente de los encabezados es Adobe
Myriad Condensed; y la fuente del cdigo es TheSansMonoCondensed de LucasFont.

29_PATRICK-INDEX.indd 759 17/2/10 15:37:51


29_PATRICK-INDEX.indd 760 17/2/10 15:37:51
Negro Pantone 301 C

Construya aplicaciones .NET 3.5 con


la herramienta para negocios RAD de Microsoft

Programacin con Visual Basic 2008


Programacin con

Visual Basic 2008


Programacin con
Es fcil programar con Visual Basic 2008, todo lo
que necesita es comprender .NET y Visual Basic Nunca haba revisado un
libro que me hiciera disfrutar

Visual Basic
claramente y darse la oportunidad de probarlos. Este
libro le da estos elementos. No slo conseguir una tanto como ste. Excelente
firme comprensin sobre conceptos de desarrollo de software en cobertura, perfecto para la
Visual Basic, tambin tendr prctica real al disear, construir y
audiencia a la que est
desplegar una aplicacin completa orientada a base de datos.
dirigido. Descripciones

2008
Cada captulo de Programacin con Visual Basic 2008 ofrece
explicaciones claras, repletas de cdigo de ejemplo para concisas, claras, exactas.
ayudarle a construir su aprendizaje durante el proceso de Es un ganador.
desarrollo. Con esta obra completa, usted: -Ken Getz
Consultor senior
Adquirir experiencia prctica en el desarrollo de aplicaciones MCW Technologies
.NET, desde el diseo hasta la implementacin.
Disear bases de datos con SQL Server y ADO.NET.
Construir aplicaciones de escritorio complejas con Tim Patrick es arquitecto de software
formularios de Windows y aplicaciones Web con ASP.NET. y desarrollador; tiene 25 aos de
experiencia en diseo y construccin
Dominar las nuevas caractersticas de VB 2008 como de soluciones personalizadas de
expresiones lambda y tipos null. software. MVP de Microsoft y
Acelerar los procesos con consultas LINQ y generacin desarrollador de soluciones
de XML dinmico. certificado de Microsoft, Tim ha
publicado cinco tutoriales y
Descubrir cmo dar licencias, documentar, implementar
referencias sobre desarrollo de
y dar soporte a sus aplicaciones.
Visual Basic, junto con varios
Extender an ms su aprendizaje, usando el cdigo fuente artculos. Entre sus libros se incluyen
de aplicaciones incluido. Visual Basic 2005 in a Nutshell y
Visual Basic 2005 Cookbook.
Obtendr la mentalidad de un desarrollador al adquirir
habilidades de programacin cotidianas.

Patrick

Tim Patrick

Vous aimerez peut-être aussi