You are on page 1of 63

Desarrollo de componentes en

Visual Basic .NET

Índice

Descripción 1
Descripción de los componentes 2
Creación de componentes con servicio 11
Demostración: creación de un componente con servicio 29
Creación de clases de componentes 31
Demostración: Creación de un componente Stopwatch 37
Creación de controles de formularios Windows Forms 39
Demostración: Creación de una caja de texto mejorada 46
Manejo de hilos de ejecución 48
Demostración: Uso de la instrucción SyncLock 61
Desarrollo de componentes en Visual Basic .NET 1

Descripción
Objetivo
Presentar los temas y
objetivos del módulo.
Presentación „ Components Overview
En este módulo, „ Creating Serviced Components
aprenderemos cómo crear
componentes en „ Creating Component Classes
Visual Basic .NET.
„ Creating Windows Forms Controls
„ Creating Web Forms User Controls
„ Threading

Como desarrolladores de Microsoft® Visual Basic®, seguramente ya sabemos


cómo desarrollar y utilizar componentes en nuestras aplicaciones. En
Visual Basic .NET, podemos utilizar las nuevas características en tiempo de
diseño para crear fácilmente componentes y extender sus funcionalidades.
En este módulo, aprenderemos a:
„ Describir los distintos tipos de componentes que pueden crearse en
Visual Basic .NET.
„ Crear componentes que pueden ser utilizados por aplicaciones cliente
gestionadas y no gestionadas.
„ Crear componentes con servicio
„ Crear clases de componentes
„ Crear controles de formularios Windows® Forms.
„ Utilizar hilos para crear aplicaciones con múltiples hilos de ejecución.
2 Desarrollo de componentes en Visual Basic .NET

Descripción de los componentes


Objetivo
Ofrecer una descripción de
los temas tratados en esta
lección. „ Tipos de componentes
Presentación „ Uso dé módulos como componentes
Esta lección explica los
tipos de componentes que „ Uso de clases como componentes
podemos crear en una
aplicación basada en „ Uso de componentes en aplicaciones cliente no
Visual Basic .NET y cómo gestionadas
podemos hacerlos visibles
para aplicaciones cliente no „ Descripción de .NET Remoting
gestionadas. También
proporciona una descripción
de .NET Remoting para la
comunicación entre
componentes.

En Visual Basic .NET, podemos crear varios tipos de componentes accesibles


tanto desde aplicaciones cliente gestionadas (las basadas en los servicios del
entorno de ejecución del .NET Framework) y aplicaciones cliente no
gestionadas (por ejemplo, las creadas en Visual Basic 6.0).
En esta lección, aprenderemos a:
„ Describir los tipos de componentes que podemos crear en Visual Basic
.NET.
„ Utilizar módulos y clases como componentes.
„ Utilizar componentes basados en Visual Basic .NET en entornos no
gestionados.
„ Explicar los principales conceptos de .NET Remoting.
Desarrollo de componentes en Visual Basic .NET 3

Tipos de componentes
Objetivo
Explicar los diferentes tipos
de componentes que
podemos crear en „ Estructuras
Visual Basic .NET.
„ Módulos
Presentación
Podemos crear varios tipos „ Clases
de componentes en una
aplicación basada en Visual „ Clases de componente
Basic .NET.
„ Componentes con servicio
„ Controles de usuario
z Controles de usuario de formularios Windows Forms
z Controles de usuario de formularios Web Forms

En Visual Basic .NET, podemos crear varios tipos de componentes distintos,


incluyendo:
„ Estructuras
Sugerencia
Comentar que este módulo „ Módulos
se centra en cómo crear y
„ Clases
utilizar clases de
componentes, componentes „ Clases de componentes
con servicio y controles de
usuario. El resto de tipos de „ Componentes con servicio
componentes se mencionan „ Controles de usuario
únicamente como
referencia.
Estructuras
Podemos utilizar las estructuras como componentes declarándolas públicas
cuando las definamos. Las estructuras soportan muchas de las características de
las clases, incluyendo propiedades, métodos y eventos, pero son de tipo valor;
por tanto, la gestión de la memoria es más eficaz. Las estructuras no soportan
herencia.

Módulos
Podemos utilizar los módulos como componentes declarándolos públicos
cuando los definamos. Declarar módulos públicos permite crear librerías de
código que contienen rutinas útiles para múltiples aplicaciones. También
podemos utilizar módulos para crear funciones reutilizables que no son de
aplicación a un componente, clase o estructura concretos.
Si hemos utilizado las clases GlobalMultiUse o GlobalSingleUse en versiones
anteriores de Visual Basic, el concepto de librería de código no nos resultará
nuevo. Estas clases proporcionan la misma funcionalidad en Visual Basic
.NET; el código cliente no necesita cualificar estas clases por el nombre de
clase para invocar las funciones.
4 Desarrollo de componentes en Visual Basic .NET

Clases
Podemos utilizar clases como componentes declarándolas públicas en un
ensamblado. Podemos utilizar clases públicas desde cualquier aplicación cliente
basada en .NET agregando una referencia al ensamblado del componente.
Podemos extender la funcionalidad de las clases mediante mecanismos como
propiedades, métodos y eventos. Las clases también son extensibles mediante la
herencia, lo cual permite a las aplicaciones reutilizar la lógica existente en estos
componentes.

Clases de componentes
Una clase se convierte en componente cuando se ajusta a un estándar para la
interacción con componentes. Este estándar se proporciona a través de la
interfaz IComponent. Cualquier clase que implemente la interfaz IComponent
es un componente. Las clases de componentes permiten abrir la clase en un
diseñador visual y permiten a la clase ser ubicada en otros diseñadores visuales.

Componentes con servicio


Los componentes con servicio derivan directa o indirectamente de la clase
System.EnterpriseServices.ServicedComponent. Las clases configuradas de
este modo son hospedadas por una aplicación de servicios de componentes y
pueden automáticamente utilizar los servicios que ésta ofrece.

Controles de usuario
Los controles de usuario son componentes creados por un desarrollador para
ubicarlos en formularios Windows Forms o Web Forms. Cada control de
usuario tiene su propio conjunto de propiedades, métodos y eventos que lo
hacen adecuado para un determinado uso. Podemos manipular controles de
usuario en los diseñadores de formularios Windows Forms y Web Forms y
escribir código para agregar controles de usuario dinámicamente en el entorno
de ejecución, al igual que con los controles proporcionados como parte del
.NET Framework.

Nota En este módulo, aprenderemos cómo crear y utilizar clases de


componentes, componentes con servicio y controles de usuario.
Desarrollo de componentes en Visual Basic .NET 5

Uso de módulos como componentes


Objetivo
Explicar cómo utilizar
módulos como
componentes. „ Declarar el módulo como público
Presentación „ Referenciar e importa el ensamblado en código cliente
En Visual Basic .NET,
podemos utilizar módulos
Public
Public Module
Module MyMathFunctions
MyMathFunctions
como componentes fuera Public
Public Function
Function Square(ByVal
Square(ByVal lng
lng As
As Integer)
Integer) As
As Long
Long
del ensamblado en el que Return
Return (lng
(lng ** lng)
lng)
están definidos. End Function
End Function
...
...
End
End Module
Module

'Client
'Client code
code
Imports
Imports MyAssembly
MyAssembly
...
...
Dim
Dim xx As
As Long
Long == Square(20)
Square(20)

En Visual Basic .NET podemos utilizar módulos como componentes fuera del
ensamblado en el que están definidos. Para que esto sea posible, debemos
declarar el módulo como público cuando lo definamos. A continuación,
necesitaremos crear una referencia en el ensamblado cliente al ensamblado
componente y utilizar la instrucción Imports para permitir el acceso a los
métodos del módulo.
El siguiente ejemplo muestra cómo crear un módulo público denominado
MyMathFunctions que define la función Square. Este módulo está definido en
el ensamblado MyAssembly. A continuación, el módulo puede utilizarse como
un componente en el código cliente, como muestra la segunda parte del
ejemplo.
Public Module MyMathFunctions
Public Function Square(ByVal lng As Long) As Long
Return (lng * lng)
End Function
...
End Module

'Client code
Imports MyAssembly
...
Dim x As Long = Square(20)
6 Desarrollo de componentes en Visual Basic .NET

Uso de clases como componentes


Objetivo
Explicar cómo utilizar clases
como componentes.
„ Declarar la clase como pública
Presentación
En Visual Basic .NET, „ Referenciar e importar el ensamblado en código cliente
podemos utilizar clases
Public
Public Class
Class Account
Account
como componentes. Public
Public Sub
Sub Debit(ByVal
Debit(ByVal AccountId
AccountId As
As Long,
Long, Amount
Amount As
As Double)
Double)
'Perform
'Perform debit
debit action
action
End
End Sub
Sub
Public
Public Sub
Sub Credit(ByVal
Credit(ByVal AccountId
AccountId As
As Long,
Long, Amount
Amount As
As Double)
Double)
'Perform
'Perform credit
credit action
action
End
End Sub
Sub
End
End Class
Class

'Client
'Client code
code
Imports
Imports MyAssembly
MyAssembly
Dim
Dim xx As
As New
New Account(
Account( ))
x.Debit(1021,
x.Debit(1021, 1000)
1000)

Podemos utilizar clases como componentes fuera del ensamblado en el que


están definidas marcando la clase como pública. A continuación, referenciamos
el ensamblado del componente desde el ensamblado cliente, y utilizamos la
instrucción Imports para permitir el acceso directo a la clase.
El siguiente ejemplo muestra cómo crear una clase pública denominada
Account que define los métodos Debit y Credit. Esta clase está definida en el
ensamblado MyAssembly. A continuación, otro ensamblado cliente referencia
el ensamblado, y la clase puede utilizarse por instancias de objetos.
Public Class Account
Public Sub Debit(ByVal AccountId As Long, Amount As Double)
'Perform debit action
End Sub
Public Sub Credit(ByVal AccountId As Long, Amount As Double)
'Perform credit action
End Sub
End Class

'Client code
Imports MyAssembly
Dim x As New Account( )
x.Debit(1021, 1000)
Desarrollo de componentes en Visual Basic .NET 7

Uso de componentes en aplicaciones cliente no gestionadas


Objetivo
Explicar cómo crear
componentes que pueden
ser utilizados por „ Setting assembly properties
aplicaciones cliente no
z Generate a strong name
gestionadas, como clientes
basados en Visual Basic z Select Register for COM Interop in Build options
6.0.
Presentación „ Exposing class members to COM and Component
Podemos utilizar COM para Services
que todos los componentes
de Visual Basic .NET sean z Define and implement interfaces
accesibles desde clientes
z Use the ClassInterface attribute with AutoDual value
no gestionados, siguiendo
unos sencillos pasos. z Use the COMClass attribute

Podemos crear componentes con Visual Basic .NET que pueden ser utilizados
por aplicaciones cliente no gestionadas. Esta interoperabilidad permite utilizar
características de los servicios de componentes como la agrupación de objetos o
las transacciones. Para exponer nuestros componentes a COM y a los servicios
de componentes, debemos establecer propiedades específicas del ensamblado y
crear nuestras clases adecuadamente.

Establecer propiedades del ensamblado


Debemos proporcionar a nuestro ensamblado un nombre seguro si deseamos
que sea accesible desde código no gestionado. Para crear un ensamblado de
nombre seguro, utilizaremos un par de claves privada y pública al generar la
aplicación, para garantizar que el ensamblado es único y no puede modificarse
de forma inadecuada después de que haya sido generado.

Poner nombre al ensamblado


Podemos generar un nombre seguro para nuestro ensamblado utilizando la
herramienta de nombres seguros (sn.exe) incluida en el .NET Framework. El
siguiente código muestra cómo utilizar sn.exe para generar un archivo de claves
denominado KeyFile.snk:
sn.exe –k KeyFile.snk

Una vez generado el archivo de claves, podemos agregarlo al proyecto y


referenciarlo en AssemblyInfo.vb utilizando el siguiente código:
<Ensamblado: AssemblyKeyFile("KeyFile.snk")>

De este modo, nuestro ensamblado tendrá un nombre seguro la próxima vez que
lo generemos.
8 Desarrollo de componentes en Visual Basic .NET

Registro del ensamblado


Podemos registrar automáticamente un ensamblado que necesita
interoperabilidad con COM en la sección Propiedades de configuración de las
páginas de propiedades del ensamblado. La sección Generar proporciona una
casilla de verificación Registrar para COM Interop. Si la seleccionamos,
nuestro ensamblado se registra con COM cuando se genere la próxima vez. Si
regeneramos más veces nuestro ensamblado tras el registro inicial, primero se
eliminará del registro antes de ser registrado de nuevo. Este proceso garantiza
que el registro no contiene información desactualizada.

Exponer miembros de clases a COM y a los servicios de


componentes
Crear una clase que tenga propiedades y métodos públicos no hace que los
miembros de la clase estén accesibles en COM y en los servicios de
componentes. A menos que expongamos los miembros de clase, la clase en sí
será accesible, pero los métodos no serán accesibles excepto a través de late
binding. Podemos exponer los miembros de clases y permitir early binding:
„ Definiendo una interfaz pública
„ Utilizando el atributo ClassInterface
„ Utilizando el atributo COMClass.

Definir una interfaz pública


Definir una interfaz pública e implementarla en nuestra clase pública permite
que las aplicaciones cliente no gestionadas puedan ver y enlazarse a los
métodos de la interfaz. Esta aproximación proporciona el modo más coherente
y seguro de exponer componentes a COM ya que el uso de interfaces evita
muchos problemas asociados al versionado.
El siguiente código muestra cómo crear una interfaz pública y, a continuación,
utilizar la interfaz en una clase que estará accesible para aplicaciones cliente no
gestionadas a través de COM:
Public Interface IVisible
Sub PerformAction( )
End Interface

Public Class VisibleClass


Implements IVisible
Public Sub PerformAction( ) _
Implements IVisible.PerformAction
'Perform your action
End Sub
End Class
Desarrollo de componentes en Visual Basic .NET 9

Uso del atributo ClassInterface


El espacio de nombres System.Runtime.InteropServices proporciona el
atributo ClassInterface. Este atributo permite crear una clase con una interfaz
dual para que todos los miembros de la clase (y las clases base) estén accesibles
automáticamente para aplicaciones cliente no gestionadas a través de COM. El
siguiente código muestra cómo utilizar el atributo ClassInterface:
Imports System.Runtime.InteropServices
Sugerencia <ClassInterface(ClassInterfaceType.AutoDual)> _
Compruebe que los
Public Class VisibleClass
estudiantes saben qué son
los interfaces duales. Public Sub PerformAction( )
Explíquelo brevemente si 'Perform your action
fuera necesario. End Sub
End Class

Uso del atributo COMClass


El espacio de nombres Microsoft.VisualBasic proporciona el atributo
COMClass que podemos utilizar en una clase para exponer todos los miembros
de clase públicos a COM. Visual Basic .NET proporciona un elemento de
plantilla de clase denominado COM Class que podemos agregar a cualquier
tipo de proyecto que utilice el atributo COMClass. Cualquier ensamblado que
contenga este tipo de clase se registrará cuando sea generado y posteriormente
regenerado.

Precaución Los tres planteamientos pueden provocar problemas de versionado


si las firmas de métodos públicos se modifican entre versiones. Por ello, la
implementación de interfaces es la aproximación preferida, ya que pueden
crearse nuevas interfaces con nuevas firmas de métodos sin causar dificultades
de versionado.
10 Desarrollo de componentes en Visual Basic .NET

Descripción de .NET Remoting


Objetivo
Ofrecer una descripción de Cliente AppDomain Servidor AppDomain
.NET Remoting. Marshal By Reference
Presentación Código
cliente
El .NET Framework ofrece Formateador
varios servicios que se Formateador
utilizan en remoto. Servidor
Proxy Canal
Objeto
servidor
Marshal By Value
Código
cliente Formateador Canal
Copia Canal
objeto
servidor

Límite de Remoting

Las versiones anteriores de Visual Basic utilizaban COM y la versión


distribuida de COM (DCOM) para comunicarse con componentes en diferentes
procesos o con distintos equipos. Visual Basic .NET utiliza .NET Remoting
para permitir la comunicación entre aplicaciones cliente y servidor a través de
dominios de aplicaciones.
El .NET Framework proporciona varios servicios que se utilizan en remoto:
„ Los canales de comunicación son los responsables de transportar los
mensajes a y desde aplicaciones remotas utilizando tanto un formato binario
sobre un canal Transmission Control Protocol (TCP) como Extensible
Markup Language (XML) sobre un canal Hypertext Transfer Protocol
(HTTP).
„ Formateadores que codifican y decodifican mensajes antes de que sean
transportados por el canal.
„ Objetos proxy que envían las invocaciones de métodos remotos al objeto
adecuado.
„ Soporte para la activación remota de objetos y para la duración de objetos
marshal-by-reference que se ejecutan en el servidor.
„ Objetos marshal-by-value que son copiados por el .NET Framework en el
espacio del proceso en el cliente para reducir viajes de ida y vuelta entre
procesos o entre equipos.

Nota Si deseamos obtener más información sobre .NET Remoting, consultar


“Microsoft .NET Remoting: introducción técnica” en la documentación de
Microsoft Visual Studio® .NET.
Desarrollo de componentes en Visual Basic .NET 11

Creación de componentes con servicio


Objetivo
Ofrecer una descripción de
los temas tratados en esta
lección. „ Hospedar componentes en Component Services
Presentación „ Uso de transacciones
Esta lección examina
componentes .NET „ Uso del pooling de objetos
hospedados por los
servicios de componentes. „ Uso de cadenas de constructor
„ Uso de seguridad
„ Uso de otros Component Services
„ configuración de ensamblados para Component
Services

En esta lección, aprenderemos a:


„ Describir los requerimientos para hospedar componentes basados en .NET
en una aplicación de servicios de componentes.
„ Habilitar el procesamiento de transacciones en nuestros componentes.
„ Utilizar la agrupación de objetos para mejorar el rendimiento de los objetos
que necesitan recursos adicionales.
„ Utilizar atributos de seguridad para especificar cómo interactúan los
componentes con la seguridad de los servicios de componentes.
„ Agregar constructores para controlar la inicialización de un componente.
„ Explicar cómo utilizar otros servicios de componentes, como la activación
Just-In-Time, desde componentes Visual Basic .NET.
„ Establecer atributos a nivel de ensamblado para mejorar la instalación de
nuestra aplicación.
12 Desarrollo de componentes en Visual Basic .NET

Hospedar componentes en los servicios de componentes


Objetivo
Explicar los requerimientos
para hospedar
componentes en los „ Agregar una referencia a System.EnterpriseServices en
servicios de componentes. el ensamblado
Presentación
Para permitir que los
„ El espacio de nombres System.EnterpriseServices
componentes sean proporciona:
hospedados en los servicios
de componentes, el .NET
z Clase ContextUtil
Framework proporciona z Clase ServicedComponent
varios elementos que
necesitamos incluir en z Atributos de ensamblado, clase y método
nuestros ensamblados y en
las clases.

Debemos agregar una referencia en el proyecto al espacio de nombres


System.EnterpriseServices si deseamos hospedar un componente Visual Basic
.NET en una aplicación de servicios de componentes. Este espacio de nombres
proporciona las principales clases, interfaces y atributos para comunicar con los
servicios de componentes.
El espacio de nombres System.EnterpriseServices proporciona las siguientes
características:
Característica Uso

Clase ContextUtil Esta clase se utiliza para participar en transacciones y para


interactuar con información de seguridad.
La funcionalidad de esta clase es similar a la funcionalidad de la
clase ObjectContext en Visual Basic 6.0.
Clase Todas las clases de componentes que necesitan ser hospedadas en
ServicedComponent una aplicación de servicios de componentes deben heredar de esta
clase.
Esta clase define el tipo base para todos los tipos enlazados a
contexto e implementa métodos similares a los que se encuentran
en la interfaz IObjectControl utilizada en las aplicaciones de
servicios de componentes basadas en Visual Basic 6.0.
Atributos de Podemos definir varios atributos del ensamblado para la
ensamblado, clase y interrogación a los servicios de componentes en el archivo
método AssemblyInfo.vb. Estos valores se utilizan para establecer el
nombre y la descripción de la aplicación y demás valores cuando
la aplicación se instala como una aplicación de servicios de
componentes.
El espacio de nombres System.EnterpriseServices también
define varios atributos de clases y métodos, incluyendo
TransactionAttribute, AutoCompleteAttribute,
ObjectPoolingAttribute y ConstructionEnabledAttribute.
Desarrollo de componentes en Visual Basic .NET 13

Nota La parte “Attribute” de un nombre de atributo es opcional, por tanto, por


ejemplo, podemos utilizar AutoComplete o AutoCompleteAttribute en
nuestro código.
14 Desarrollo de componentes en Visual Basic .NET

Uso de transacciones
Objetivo
Examinar cómo los
componentes pueden „ El atributo Transaction especifica cómo participa una clase
utilizar transacciones de los en las transacciones
servicios de componentes.
„ La clase ContextUtil proporciona transaction voting
Presentación
Existen varios objetos y „ El atributo AutoComplete impide el uso de los
atributos que permiten a los métodosSetAbort, SetComplete y ContextUtil
componentes de <Transaction(TransactionOption.Required)>
<Transaction(TransactionOption.Required)> Public
Public Class
Class Account
Account
Visual Basic .NET utilizar Inherits
Inherits ServicedComponent
ServicedComponent
transacciones de los Public
Public Sub
Sub Debit(...)
Debit(...)
servicios de componentes. 'Perform
'Perform debit
debit action
action
ContextUtil.SetComplete(
ContextUtil.SetComplete( ))
End
End Sub
Sub
<AutoComplete(
<AutoComplete( )>)> Public
Public Sub
Sub Credit(...)
Credit(...)
'Perform
'Perform credit
credit action
action
'No
'No SetComplete
SetComplete because
because AutoComplete
AutoComplete is
is on
on
End
End Sub
Sub
End Class
End Class

Con frecuencia, se requieren transacciones para mantener la integridad de los


datos y sincronizar actualizaciones de datos entre múltiples fuentes de datos.
Podemos habilitar el procesamiento de transacciones en los componentes con
servicio incluyendo las clases y atributos adecuados en el código de nuestro
componente.

Opciones del atributo Transacción


Utilizamos el atributo Transaction para especificar cómo una clase puede
participar en las transacciones. Podemos establecer el soporte de transacciones
con una de las siguientes opciones:
Opción Efecto

Disabled La instancia de clase no utilizará transacciones e ignorará las


transacciones de objetos padre.
NotSupported La instancia de clase no se creará en el contexto de una transacción.
Required La instancia de clase se incluirá en una transacción existente
proporcionada por el contexto del objeto que realiza la llamada. Si
no existe ninguna transacción, se creará una.
RequiresNew La instancia de clase siempre creará una nueva transacción con
independencia de las transacciones ya creadas por objetos que
realizan las llamadas.
Supported La instancia de clase se incluirá en una transacción si la proporciona
el contexto del objeto que realiza la llamada, pero no creará una
transacción si no existe ya una.
Desarrollo de componentes en Visual Basic .NET 15

Uso del atributo Transaction


El siguiente ejemplo define una clase Account y establece el atributo
Transaction a Required.
Imports System.EnterpriseServices

<Transaction(TransactionOption.Required)> Public Class Account


Inherits ServicedComponent

Public Sub Debit(ByVal id As Integer, _


ByVal amount As Double)
'Debit code
End Sub
End Class

Opciones de votación de una transacción


Podemos votar por el resultado de una transacción utilizando métodos de la
clase ContextUtil, suministrada por el espacio de nombres
System.EnterpriseServices. Esta clase estática proporciona muchos métodos y
propiedades que nos resultarán familiares si hemos creado componentes que
utilicen Microsoft Transaction Server (MTS) o los servicios de componentes. A
continuación, se describen algunos de los métodos más habituales:
Método ContextUtil Utilice este método para:

SetAbort Votar por la anulación de una transacción. La transacción


sólo puede tener éxito si todos los objetos implicados en la
transacción votan satisfactoriamente por unanimidad. Este
método también permite que el objeto sea desactivado
después de que la llamada al método finalice.
SetComplete Votar por la confirmación de una transacción. Si todos los
objetos implicados en la transacción votan con éxito, la
transacción puede completarse. Este método también
permite que el objeto sea desactivado después de que la
llamada al método finalice.
EnableCommit Votar por una finalización exitosa de la transacción, no
permitiendo al objeto ser desactivado después de que la
llamada al método finalice.
Esta opción resulta útil si deseamos mantener el estado a
través de múltiples llamadas a métodos, pero no
necesitamos más acciones para finalizar con éxito la
transacción si así lo solicita el componente de servicio de
nivel superior.
DisableCommit Votar por una finalización no exitosa de la transacción, no
permitiendo al objeto ser desactivado después de que la
llamada al método finalice.
Esta opción resulta útil si deseamos mantener el estado a
través de múltiples llamadas a métodos y necesitamos que
ocurran otras acciones antes de que la transacción pueda
finalizar con éxito.
16 Desarrollo de componentes en Visual Basic .NET

Uso de la clase ContextUtil


El siguiente ejemplo muestra cómo utilizar la clase ContextUtil para finalizar o
abortar transacciones en el método Debit de la clase Account, basándose en las
excepciones que se hayan encontrado.
Public Sub Debit(ByVal id As Integer, ByVal amount As Double)
Try
'Perform update to database
...
ContextUtil.SetComplete( )
Catch ex As Exception
ContextUtil.SetAbort( )
Throw ex
End Try
End Sub

Procesamiento de transacciones
Para evitar el uso de los métodos SetAbort y SetComplete de ContextUtil,
podemos establecer el atributo AutoComplete de los métodos específicos del
componente. Si no ocurren excepciones durante la ejecución del método, el
objeto se comporta como si se hubiera invocado SetComplete. Si ocurren
excepciones, el objeto se comporta como si se hubiera invocado SetAbort.

Uso del atributo AutoComplete


El siguiente ejemplo muestra cómo utilizar el atributo AutoComplete:
<AutoComplete( )>Public Sub Credit( _
ByVal fromAccount As Integer, ByVal amount As Double)
'Perform update to database
...
'No SetComplete or SetAbort is required
End Sub
Desarrollo de componentes en Visual Basic .NET 17

Uso de la agrupación de objetos


Objetivo
Examinar cómo los „ La agrupación de objetos permite crear los objetos con
componentes pueden antelación
utilizar la agrupación de
objetos. „ El atributo ObjectPooling especifica MinPoolSize y
Presentación
MaxPoolSize
Diversos atributos e „ ServicedComponent proporciona el método
interfaces permiten que los
CanBePooled
componentes de Visual
Basic .NET utilicen la <ObjectPooling(Enabled:=True,
<ObjectPooling(Enabled:=True, MinPoolSize:=5,
MinPoolSize:=5, __
agrupación de objetos. MaxPoolSize:=50)>
MaxPoolSize:=50)> __
Public
Public Class
Class Account
Account
Inherits
Inherits ServicedComponent
ServicedComponent
...
...
Protected
Protected Overrides
Overrides Function
Function CanBePooled(
CanBePooled( )) As
As Boolean
Boolean
Return True
Return True
End
End Function
Function
End Class
End Class

En Visual Basic .NET, podemos utilizar el atributo ObjectPooling y la clase


base ServicedComponent para crear componentes con servicio que utilicen la
agrupación de objetos.

¿Qué es la agrupación de objetos?


La agrupación de objetos permite crear con antelación un número prestablecido
de objetos, de modo que estén listos para ser usados por peticiones de clientes
cuando la aplicación se inicia. Cuando una aplicación cliente realiza una
petición de un objeto, se toma uno de la agrupación de objetos disponibles y se
utiliza para esa petición. Cuando finaliza la petición, el objeto se devuelve a la
agrupación para que pueda ser utilizado en otras peticiones de clientes.
Podemos utilizar la agrupación para mejorar el rendimiento de objetos que
requieran grandes intervalos de tiempo para adquirir recursos y completar una
operación. Los objetos que no necesiten tales recursos no se beneficiarán
significativamente de la agrupación de objetos.
18 Desarrollo de componentes en Visual Basic .NET

Habilitar la agrupación de objetos


Especificamos el atributo ObjectPooling para que los servicios de
componentes puedan ubicar el componente en una agrupación de objetos.
También podemos especificar argumentos opcionales del atributo para
establecer los valores MinPoolSize y MaxPoolSize de la agrupación.
„ MinPoolSize
Utilizamos el argumento MinPoolSize para establecer el número mínimo de
objetos que se crearán con antelación en la agrupación.
„ MaxPoolSize
Utilizamos el argumento MaxPoolSize para establecer el número máximo
de objetos que pueden crearse en la agrupación.
• Si no hay objetos disponibles en la agrupación cuando se recibe una
petición, la agrupación puede crear otra instancia del objeto si ese
número máximo de objetos preestablecido no se ha alcanzado ya.
• Si ya se han creado el número máximo de objetos y actualmente no hay
ninguno disponible, las peticiones se encolarán hasta el próximo objeto
disponible.

Devolver objetos a la agrupación de objetos


Utilizamos el método CanBePooled para especificar si nuestro componente
puede ser devuelto a la agrupación de objetos. Los objetos únicamente pueden
devolverse a la agrupación cuando están desactivados. Esto ocurre cuando se
invocan los métodos SetComplete o SetAbort cuando el objeto es
transaccional, o si se invoca explícitamente un método Dispose si el objeto no
es transaccional.
„ True
Si el componente soporta la agrupación de objetos y puede devolverse de
forma segura a la agrupación, el método CanBePooled debería devolver
True.
„ False
Si el componente no soporta la agrupación de objetos, o si la instancia
actual no puede devolverse a la agrupación, el método CanBePooled
debería devolver False.

Nota Si la agrupación de objetos se deshabilita para un componente, el método


CanBePooled no se ejecutará.
Desarrollo de componentes en Visual Basic .NET 19

Uso del método CanBePooled


El siguiente ejemplo muestra cómo crear una agrupación de objetos para el
objeto Account con un número mínimo de cinco objetos y un máximo de 50 en
un momento dado. El método CanBePooled devuelve True para informar a los
servicios de componentes de que el objeto puede devolverse a la agrupación.
<ObjectPooling(Enabled:=True,MinPoolSize:=5, _
MaxPoolSize:=50)>Public Class Account
Inherits ServicedComponent

Public Sub Debit(ByVal id As Integer, _


ByVal amount As Double)
...
End Sub

Protected Overrides Function CanBePooled( ) As Boolean


Return True
End Function
End Class
20 Desarrollo de componentes en Visual Basic .NET

Uso de las cadenas de constructor


Objetivo
Explicar cómo los
componentes pueden „ Especifican el atributo ConstructionEnabled para
utilizar las cadenas de indicar que se necesita una cadena de constructor
constructor.
Presentación „ Reemplazan el método Construct para recuperar
Los servicios de información
componentes proporcionan
cadenas de constructor a
componentes con servicio y <ConstructionEnabled(True)>Public
<ConstructionEnabled(True)>Public Class
Class Account
Account
son accesibles para Inherits
Inherits ServicedComponent
ServicedComponent
componentes de Protected
Protected Overrides
Overrides Sub
Sub Construct(ByVal
Construct(ByVal ss As
As String)
String)
Visual Basic .NET a través ''Called
Called after
after class
class constructor
constructor
del .NET Framework. ''Use
Use passed
passed in
in string
string
End Sub
End Sub
End
End Class
Class

Podemos utilizar una cadena de constructor para controlar cómo se inicializan


los componentes con servicio. Esto nos permite especificar cualquier
información inicial que necesite el objeto, como una cadena de conexión a una
base de datos, utilizando la consola de gestión de componentes de los servicios
de componentes. Podemos utilizar el atributo ConstructionEnabled para
habilitar este proceso en un componente con servicio. Nuestro componente en
Visual Basic .NET puede recibir esta información del constructor porque la
clase heredada ServicedComponent proporciona el método sobrecargable
Construct.

Uso del atributo ConstructionEnabled


Especificamos el atributo ConstructionEnabled a nivel de clase para que
pueda pasarse al objeto una cadena de constructor durante la construcción del
mismo. Podemos modificar este valor cuando el componente se instala como
una aplicación de servicios de componentes utilizando la consola de gestión de
Servicios de Componentes.

Uso del método Construct


Sobrecargamos el método Construct de la clase base ServicedComponent
para recibir el valor de la cadena enviado al componente durante la
construcción.
El siguiente ejemplo muestra cómo habilitar un constructor, sobrecargar el
método Construct y pasar una cadena de constructor almacenada en una
variable local.
Desarrollo de componentes en Visual Basic .NET 21

<ConstructionEnabled(True)>Public Class Account


Inherits ServicedComponent

Private strValue As String

Protected Overrides Sub Construct(ByVal s As String)


'Called after class constructor
strValue = s
End Sub
End Class
22 Desarrollo de componentes en Visual Basic .NET

Uso de seguridad
Objetivo
Explicar cómo la seguridad
de los servicios de
componentes es accesible „ Security configuration attributes enable security and
por los componentes de role configuration
Visual Basic .NET.
„ SecurityCallContext class provides role checking and
Presentación caller information
Los servicios de
componentes proporcionan <ComponentAccessControl(True),
<ComponentAccessControl(True), SecurityRole("Manager")>
SecurityRole("Manager")> __
Public
Public Class
Class Account
Account
información de seguridad Inherits
que pueden utilizar los Inherits ServicedComponent
ServicedComponent
Public
Public Function
Function GetDetails(
GetDetails( )) As
As String
String
componentes de With
With SecurityCallContext.CurrentCall
SecurityCallContext.CurrentCall
Visual Basic .NET. If
If .IsCallerInRole("Manager")
.IsCallerInRole("Manager") Then
Then
Return
Return .OriginalCaller.AccountName
.OriginalCaller.AccountName
End
End If
If
End
End With
With
End
End Function
Function
End
End Class
Class

Cuando se trabaja con componentes con servicio, se pueden utilizar atributos y


objetos predefinidos para configurar y probar las opciones de seguridad.

Opciones de los atributos de seguridad


Podemos establecer opciones de seguridad utilizando atributos en nuestras
clases. Los servicios de componentes utilizarán estos atributos cuando
configuremos nuestros componentes tal y como se describe en la siguiente
tabla:
Atributo Uso

ApplicationAccessControl Este atributo a nivel de ensamblado se utiliza para


habilitar o deshabilitar explícitamente la comprobación
de acceso a nivel de aplicación.
ComponentAccessControl Este atributo a nivel de componente se utiliza para
habilitar o deshabilitar explícitamente la comprobación
de acceso a nivel de componente.
SecurityRole Este atributo a nivel de ensamblado se utiliza para
agregar un rol a la aplicación. Este atributo se utiliza a
nivel de componente para agregar un rol a la aplicación
y enlazarla al componente concreto.
Desarrollo de componentes en Visual Basic .NET 23

Establecer opciones de seguridad


El siguiente ejemplo muestra cómo establecer el atributo
ApplicationAccessControl a nivel de ensamblado, habilitar la seguridad para
el componente Account, y crear el rol Manager, que se enlazará al componente
Account:
<Assembly: ApplicationAccessControl(True)>
<ComponentAccessControl(True), SecurityRole("Manager")> _
Public Class Account
Inherits ServicedComponent
...
End Class

Recuperar información de seguridad


Podemos descubrir información de seguridad sobre el llamador a un
componente con servicio utilizando la clase SecurityCallContext. Esta clase
proporciona información sobre la cadena de llamadores que llevan a la llamada
del método actual. La propiedad estática CurrentCall de la clase
SecurityCallContext proporciona acceso a los siguientes métodos y
propiedades:
Método o propiedad Uso

Propiedad DirectCaller Recupera información sobre el último usuario o


aplicación de la cadena de llamadores que directamente
invocó un método.
La propiedad devuelve una instancia de la clase
SecurityIdentity que podemos utilizar para determinar
información sobre la identidad, como AccountName.
Propiedad OriginalCaller Recupera información sobre el primer usuario o
aplicación de la cadena de llamadores que hizo la
petición original de la acción requerida.
La propiedad también devuelve una instancia de la clase
SecurityIdentity.
Método IsCallerInRole Verifica si un llamador forma parte de un rol en
particular; devuelve un valor Boolean.
Método IsUserInRole Verifica si el usuario forma parte de un rol en particular;
devuelve un valor Boolean.
24 Desarrollo de componentes en Visual Basic .NET

Uso de la clase SecurityCallContext


El siguiente ejemplo muestra cómo utilizar SecurityCallContext para
determinar si la seguridad está habilitada, comprobar si un llamador pertenece
al rol Manager y devolver la cadena AccountName desde la propiedad
OriginalCaller, que es una instancia SecurityIdentity.
<ComponentAccessControl(True), SecurityRole("Manager")> _
Public Class Account
Inherits ServicedComponent

Public Function GetDetails( ) As String


If ContextUtil.IsSecurityEnabled Then
With SecurityCallContext.CurrentCall
If .IsCallerInRole("Manager") Then
Return .OriginalCaller.AccountName
End If
End With
End If
End Function
End Class
Desarrollo de componentes en Visual Basic .NET 25

Uso de otros servicios de componentes


Objetivo
Ofrecer una descripción del
resto de servicios que
proporcionan los servicios „ Otros servicios de componentes incluyen:
de componentes.
z Activación Just-in-time
Presentación
Los servicios de z Componentes en cola
componentes proporcionan
otros servicios que z Propiedades compartidas
podemos utilizar en
componentes Visual Basic z Sincronización
.NET.

Hay otros servicios de componentes que podemos utilizar desde componentes


de Visual Basic .NET.

Activación Just-in-Time
Cuando se habilita la activación Just-in-time (JIT), un objeto es instanciado
automáticamente cuando se invoca un método en un componente con servicio
(activación), y desactivado automáticamente cuando el método finaliza
(desactivación). Cuando esta opción está habilitada, un objeto no mantiene el
estado entre llamadas a métodos, y esto incrementa el rendimiento y la
escalabilidad de la aplicación.
Podemos sobrecargar los métodos Activate y Deactivate heredados de la clase
ServicedComponent para realizar funcionalidad personalizada durante JIT. Si
la agrupación de objetos está habilitada, la activación ocurre cuando un objeto
existente se extrae de la agrupación, y la desactivación ocurre cuando el objeto
se inserta de nuevo en la agrupación.
JIT se habilita automáticamente si un componente es transaccional, y no puede
deshabilitarse. Podemos habilitar o deshabilitar JIT manualmente para
componentes no transaccionales utilizando el atributo JustInTimeActivation.

Componentes encolados
Los componentes encolados proporcionan comunicación asíncrona. Esto
permite a las aplicaciones cliente enviar peticiones a componentes encolados
sin esperar una respuesta. Las peticiones se “graban” y se envían al servidor,
donde permanecen encoladas hasta que la aplicación está lista para usar las
peticiones. A continuación, estas peticiones se “reproducen” y retornan a la
aplicación como si se hubieran enviado desde un cliente normal.
Podemos marcar una aplicación para que utilice colas utilizando el atributo
ApplicationQueuing a nivel de ensamblado. Marcamos los componentes
individuales con el atributo InterfaceQueuing.
26 Desarrollo de componentes en Visual Basic .NET

Propiedades compartidas
Podemos utilizar los componentes Shared Property Manager (SPM) para
compartir información entre múltiples objetos en el mismo proceso de
aplicación. Los componentes SPM se utilizan del mismo modo que los
componentes creados en Visual Basic 6.0.

Sincronización
Las aplicaciones distribuidas pueden recibir llamadas simultáneas de múltiples
clientes. Gestionar estas peticiones simultáneas implica una lógica de programa
compleja para garantizar que se accede a los recursos de forma segura y
correcta. Los servicios de componentes proporcionan este servicio
automáticamente para componentes que utilizan transacciones. También
podemos utilizar el atributo Synchronization para especificar este
comportamiento.
Desarrollo de componentes en Visual Basic .NET 27

Configurar ensamblados para usar los servicios de componentes


Objetivo
Explicar cómo establecer
atributos de los servicios de
componentes a nivel de „ Setting assembly attributes
ensamblado y configurar la z ApplicationName
aplicación.
z Description
Presentación
Establecer atributos de los z ApplicationActivation: library or server application
servicios de componentes a z AssemblyKeyFile
nivel de ensamblado ayuda
a definir cómo se „ Using Regsvcs to register and create Component Services
applications
comportará la aplicación
cuando la implantemos bajo z Regsvcs.exe myApplication.dll
los servicios de „ Using Lazy Registration
componentes.
z Application registered on first use by client

Podemos especificar algunos atributos a nivel de ensamblado que proporcionan


información cuando nuestro ensamblado se instala como una aplicación de
servicios de componentes. La información se almacena en el archivo
AssemblyInfo.vb que forma parte de nuestro proyecto en Visual Basic .NET.
Atributo de Uso
ensamblado

ApplicationName Si utilizamos este atributo para especificar el nombre de la


aplicación, una aplicación de servicios de componentes con
el mismo nombre cuando nuestro ensamblado sea
implantado e instalado.
Description Utilizamos este atributo para establecer el valor de la
descripción de la aplicación de servicios de componentes
cuando se implante e instale el ensamblado.
ApplicationActivation Utilizamos este atributo para especificar si deseamos
implementar nuestra aplicación de servicios de
componentes como una biblioteca o como una aplicación
de servidor.
Los valores aceptables para este atributo son
ActivationOption.Server o ActivationOption.Library.
AssemblyKeyFile Utilizamos este atributo para especificar el nombre y la
ubicación del archivo que contiene el par de claves
utilizado para generar un nombre compartido.

Establecer los atributos del ensamblado


El siguiente ejemplo muestra una sección de un archivo AssemblyInfo.vb que
especifica el nombre de la aplicación, la descripción e información acerca de
dónde debería ser activada (es decir, en un servidor o un proceso de biblioteca).
28 Desarrollo de componentes en Visual Basic .NET

<Assembly: ApplicationName("BankComponent")>
<Assembly: Description("VB .NET Bank Component")>
<Assembly: ApplicationActivation(ActivationOption.Server)>
<Assembly: AssemblyKeyFile("KeyFile.snk")>

Registro del ensamblado


Podemos registrar nuestro ensamblado con los servicios de componentes de
modo manual o automático.
„ Registro manual
Podemos utilizar la utilidad Regsvcs.exe para registrar manualmente nuestro
ensamblado. Esta utilidad utiliza la información que proporcionan los
atributos de nuestro ensamblado de modo que la aplicación de servicios de
componentes puede crearse con la información predeterminada correcta. La
sintaxis básica para utilizar Regsvcs.exe se muestra en el siguiente ejemplo:
Regsvcs.exe myApplication.dll

„ Registro automático
Si no registramos nuestra aplicación manualmente, el registro se producirá
de modo automático cuando una aplicación cliente intente crear una
instancia de una clase gestionada que herede de la clase
ServicedComponent. Todas las clases ServicedComponent de nuestro
ensamblado se registrarán como parte de la aplicación de los Servicios de
componentes. Este proceso se denomina Lazy Registration.
Desarrollo de componentes en Visual Basic .NET 29

Demostración: creación de un componente con servicio


Objetivo
Mostrar cómo crear un
componente con servicio.
Presentación
Esta demostración muestra
cómo crear un componente
con servicio.

En esta demostración, estudiaremos cómo crear un componente con servicio


que utilice la agrupación de objetos y cómo invocar el componente desde un
cliente gestionado.

Ë Examinar la aplicación de agrupación de objetos


1. Abrir Microsoft Visual Studio® .NET.
2. Abrir el proyecto ObjectPoolingComponent.sln que se encuentra en la
carpeta ObjectPoolingComponent dentro del fichero demos11.zip.
3. Visualizar el código de la clase Pooling, observando especialmente la
instrucción Imports, los atributos a nivel de clase y la utilidad de cada
miembro de la clase.
4. Visualizar el código de la clase NoPooling, y observar que la clase es casi
idéntica a la clase Pooling, excepto en que no utiliza la agrupación de
objetos.
5. Visualizar el código de la clase Report, y observar que el método
GetReport y el método GetSharedProperty del módulo modCommon.
6. Visualizar el archivo AssemblyInfo.vb file, y observar los tres primeros
atributos del ensamblado que hacen referencia a las aplicaciones del
componente con servicio.

Ë Crear la aplicación del componente con servicio


1. Generar el proyecto y cerrar Visual Studio .NET.
2. Abrir Windows Explorer, e ir a la carpeta ObjectPoolingComponent\bin.
3. Hacer clic en Inicio, seleccionar Todos los programas, seleccionar
Microsoft Visual Studio .NET, seleccionar Herramientas de Visual
Studio .NET y hacer clic en Línea de comandos de Visual Studio .NET.
30 Desarrollo de componentes en Visual Basic .NET

4. En la ventana de comandos, escribir Regsvcs.exe y arrastrar el archivo


ObjectPoolingComponent.dll desde Windows Explorer a la línea de
comandos.
5. Ejecutar el comando. Debería aparecer un mensaje indicando que el registro
se ha realizado satisfactoriamente.

Ë Examinar la aplicación del componente con servicio


1. Abrir la consola de Servicios de Componentes y analizar la aplicación
Object Pooling.
2. Ver las propiedades de los componentes NoPool y Pool, observando la
configuración de Agrupación de objetos en la ficha Activación de cada
componente.

Ë Examinar el funcionamiento de la prueba


3. Abrir Visual Studio .NET.
4. Abrir el proyecto TestPooling.sln que se encuentra en la carpeta
ObjectPoolingComponent\TestPooling. Esta carpeta se puede encontrar
dentro del fichero demos11.zip.
5. Agregar una referencia de proyecto a
ObjectPoolingComponent\bin\ObjectPoolingComponent.dll. Esta fichero se
puede encontrar dentro del fichero demos11.zip.
6. Ver el código del formulario, examinando cada método.

Ë Probar el componente
1. Ejecutar el proyecto.
2. Hacer clic en Pooling y explicar los mensajes que aparecen.
3. Hacer clic en No Pooling y explicar los mensajes que aparecen.
4. Cerrar la aplicación.
5. Ejecutar de nuevo el proyecto y mostrar que esta vez no hay nuevos objetos
creados.
6. Cerrar la aplicación y cerrar Visual Studio .NET.

Importante Si ha ejecutado esta demostración con anterioridad en el mismo


equipo, es posible que el componente con servicio ya esté instalado. Elimine la
aplicación Object Pooling de la consola de Servicios de Componentes antes de
ejecutar de nuevo esta demostración.
Desarrollo de componentes en Visual Basic .NET 31

Creación de clases de componentes


Objetivo
Ofrecer una descripción de
los temas tratados en esta
lección. „ Arquitectura de una clase de componentes
Presentación „ Creación de una clase de componentes
Esta lección examina las
clases de componentes.

En esta lección, aprenderemos a:


„ Describir la arquitectura de una clase de componentes.
„ Crear una clase de componentes.
32 Desarrollo de componentes en Visual Basic .NET

Arquitectura de una clase de componentes


Objetivo
Describir la arquitectura de
una clase de componentes.
Presentación
la se System.ComponentModel.Component
Las clases de componentes C se
ofrecen varias
características no incluidas
ba
en las clases estándares de Interfaz
Visual Basic .NET.
IComponent
Clases de componentes
es s
las vada Clases predefinidas
C ri
de Clases personalizadas

Además de soportar clases y estructuras, el espacio de nombres System


proporciona una biblioteca de componentes diseñados para facilitar el
desarrollo de componentes. Cuando creamos una clase de componentes basada
en la clase base ComponentModel.Component, automáticamente heredamos
la arquitectura básica para nuestra clase.

Interfaz IComponent
La interfaz IComponent permite crear componentes personalizados o
configurar componentes existentes como MessageQueue o Timer en el
diseñador visual de nuestro componente. Después de incluir componentes
existentes al nuestro (ubicar), podemos acceder a ellos desde el código de
nuestro componente del mismo modo que cuando están colocados en la bandeja
de componentes de un formulario Windows Forms.

Clase base ComponentModel.Component


La clase base ComponentModel.Component implementa automáticamente la
interfaz IComponent y proporciona todo el código necesario para gestionar la
ubicación de componentes. Esto resulta útil, ya que implementar la interfaz
IComponent directamente requeriría crear manualmente la funcionalidad para
gestionar componentes ubicados además de la funcionalidad para que nuestro
componente pueda ser ubicado en otro componente.
Desarrollo de componentes en Visual Basic .NET 33

Características mejoradas en tiempo de diseño


La interfaz IComponent ofrece características mejoradas en tiempo de diseño.
Podemos agregar nuestra clase de componentes al Cuadro de herramientas y a
la bandeja de componentes de un formulario Windows Form, un formulario
Web Form o cualquier otro elemento que implemente la interfaz IContainer,
incluyendo otra clase de componentes. Los desarrolladores que utilicen nuestro
componente pueden utilizar la ventana Propiedades para establecer las
propiedades del componente del mismo modo que como lo harían para
componentes del .NET Framework.
Para agregar una clase de componentes compilada al Cuadro de herramientas,
seguir estos pasos:
1. En el menú Herramientas, hacer clic en Personalizar cuadro de
herramientas.
2. En el cuadro de diálogo Personalizar cuadro de herramientas, hacer clic
en la ficha Componentes de .NET Framework.
3. Busque el componente ensamblado que desea añadir.
4. Seleccione el componente de la lista que muestra los componentes
compilados para agregarlo al Cuadro de herramientas.
34 Desarrollo de componentes en Visual Basic .NET

Creación de una clase de componentes


Objetivo
Explicar cómo crear una
clase de componentes. 1. Heredar de System.ComponentModel.Component
Presentación z Realizar las inicializaciones por parte del constructor
Crear una clase de
componentes es similar a z Sobrecargar el método Dispose
crear un elemento de clase
estándar, pero hay algunos 2. Agregar los componentes ubicados
pasos adicionales.
z Utilizar elementos del Explorador de servidores o del
cuadro de herramientas
3. Crear la funcionalidad requerida
z Propiedades, métodos y eventos
4. Generar el ensamblado

El procedimiento para crear una clase de componentes con Visual Basic .NET
es similar al procedimiento para crear clases estándares, pero hay algunos pasos
adicionales.
1. Heredar de la clase System.ComponentModel.Component.
El elemento de plantilla Component Class contiene el código necesario
para heredar de la clase System.ComponentModel.Component,
incluyendo el código de constructor requerido para agregar nuestra clase de
componentes a un contenedor. Agregar cualquier código de inicialización
para nuestra clase de componentes como parte del proceso de construcción
insertando código en el método Sub New anteriormente escrito.
Podemos sobrecargar el método Dispose de la Component Class heredada
para liberar recursos antes de que se destruya la instancia de nuestro
componente.
2. Agregar componentes ubicados.
Si nuestra clase de componentes requiere otros componentes para realizar su
propósito, podemos agregarlos a la vista de diseño arrastrándolos desde el
Cuadro de herramientas o el Explorador de servidores a nuestra clase de
componentes. Estos componentes pueden ser accedidos programáticamente
desde dentro del código de nuestra clase de componentes.
3. Crear la funcionalidad requerida.
Nuestra clase de componentes puede proporcionar propiedades, métodos y
eventos públicos para permitir que el usuario de nuestro componente pueda
interactuar con él tanto en tiempo de diseño como en tiempo de ejecución.
4. Generar el ensamblado.
La generación del ensamblado permite que otros clientes gestionados
puedan hacer referencia a nuestro componente.
Desarrollo de componentes en Visual Basic .NET 35

El siguiente ejemplo muestra cómo crear una clase de componentes derivada de


la clase System.ComponentModel.Components. Extiende la funcionalidad de
la clase Timer estándar definiendo propiedades y eventos adicionales.
Imports System.ComponentModel

Public Class Hourglass


Inherits System.ComponentModel.Component
Sugerencia
Comente que heredar de la
Public Event Finished(...)
clase Timer también
produciría un componente Private WithEvents localTimer As System.Timers.Timer
similar.
Public Sub New( )
MyBase.New( )

'This call is required by the Component Designer.


InitializeComponent( )

'Initialize the timer for 1 minute (60000 milliseconds)


localTimer = New System.Timers.Timer( )
localTimer.Enabled = False
localTimer.Interval = 60000
End Sub

Public Property Enabled( ) As Boolean


Get
Return localTimer.Enabled
End Get
Set(ByVal Value As Boolean)
localTimer.Enabled = Value
End Set
End Property

Private Sub localTimer_Tick(...) Handles localTimer.Elapsed


'Raise the finished event after localtimer_Tick is raised
RaiseEvent Finished( )
End Sub

Public Overloads Overrides Sub Dispose( )


'Disable the localTimer object
localTimer.Enabled = False
localTimer.Dispose( )
MyBase.Dispose( )
End Sub
End Class
36 Desarrollo de componentes en Visual Basic .NET

Cuando examinemos el código, observaremos lo siguiente:


„ El componente se comporta como un reloj de arena que provoca un evento
Finished un minuto después de ser habilitado.
„ El componente puede ser activado utilizando la propiedad Enabled en
tiempo de diseño o en tiempo de ejecución.
„ Se inicializa localTimer como parte del constructor Sub New y se establece
para un intervalo temporizador de 60.000 milisegundos, o un minuto.
„ El método Dispose se sobrecarga para garantizar que el objeto localTimer
se elimina de forma segura.
Desarrollo de componentes en Visual Basic .NET 37

Demostración: Creación de un componente Stopwatch


Objetivo
Mostrar cómo crear y utilizar
una clase de componentes.
Presentación
Esta demostración muestra
cómo crear una clase de
componentes stopwatch y
utilizarla desde otra
aplicación.

En esta demostración, aprenderemos cómo crear una clase de componentes que


pueda ser utilizada por otro ensamblado.

Ë Examinar la clase de componentes Stopwatch


1. Abrir Visual Studio .NET.
2. Abrir el proyecto ComponentClasses.sln en la carpeta
Stopwatch\Starter que se puede encontrar dentro del fichero demos11.zip.
3. Examinar la ventana de diseño de la clase de componentes Stopwatch y
observar el control localTimer y sus propiedades.
4. Examinar el código de la clase de componentes Stopwatch, y explicar cada
miembro de la clase. Observar especialmente los atributos utilizados en las
definiciones de las propiedades.

Ë Crear un icono en el Cuadro de herramientas para el componente


Sugerencia 5. Agregar una referencia para el ensamblado System.Drawing.dll.
Comentar que debe 6. Modificar la definición de la clase como sigue:
agregarse una referencia
adicional para permitirnos <System.Drawing.ToolboxBitmap("")> _
utilizar el atributo Public Class Stopwatch
ToolboxBitmap desde el
espacio de nombres 7. En el Explorador de soluciones, arrastrar el archivo Timer01.ico y colocarlo
System.Drawing en los entre las comillas de la cadena del código ToolboxBitmap(""). Comentar
proyectos generados sobre que agregar el mapa de bits como un recurso del ensamblado puede ser una
este tipo de plantillas de mejor opción, ya que no dependerá de que el archivo de icono esté
proyectos.
disponible en la ubicación correcta. Sin embargo, para esta demostración,
este planteamiento es aceptable.

Ë Generar el componente
1. Generar el proyecto.
2. Cerrar el proyecto.
38 Desarrollo de componentes en Visual Basic .NET

Ë Modificar el funcionamiento de la prueba


1. Abrir el proyecto TestComponentClasses.sln de la carpeta
Stopwatch\Starter\TestStopwatch que se puede encontrar dentro del fichero
demos11.zip.
2. En el Cuadro de herramientas, hacer clic en la ficha General.
3. En el menú Herramientas, hacer clic en Personalizar cuadro de
herramientas, y clic en la ficha Componentes de .NET Framework.
4. Hacer clic en Examinar para localizar ComponentClasses.dll en la carpeta
Stopwatch\Starter\bin, hacer clic en Abrir y en Aceptar.
5. En la ventana de diseño, abra Form1 y arrastre el componente Stopwatch
desde el Cuadro de herramientas al formulario.
6. En la ventana de Propiedades del componente, cambiar el nombre del
componente por sWatch y establecer la propiedad EnabledEvents en True.
Observar la descripción de la propiedad que proporciona el atributo
Description.
7. Examinar el código del formulario.

Ë Probar el componente
1. Ejecutar el proyecto, asegurándonos de que la ventana Resultados está
visible en segundo plano.
2. Hacer clic en Start Stopwatch, y observar los eventos que se muestran en
la ventana Resultados. Hacer clic en Tick Events para desactivar los
eventos.
3. Hacer clic en Stop Stopwatch para mostrar cuánto tiempo ha pasado desde
que se invocó el método Start en el componente Stopwatch.
4. Cerrar la aplicación y cerrar Visual Studio .NET.

Importante Si ha ejecutado antes esta demostración en el mismo equipo, es


posible que el componente Stopwatch ya esté disponible en el Cuadro de
herramientas. Para asegurarse de que la demostración funciona correctamente,
restablezca el Cuadro de herramientas mediante el cuadro de diálogo
Personalizar cuadro de herramientas.
Desarrollo de componentes en Visual Basic .NET 39

Creación de controles de formularios Windows Forms


Objetivo
Ofrecer una descripción de
los temas tratados en esta
lección. „ Heredar de la clase UserControl
Presentación „ Heredar de un control de formularios Windows Forms
Esta lección examina cómo
crear controles de „ Proporcionar atributos de controles
formularios Windows Forms
en Visual Basic .NET.

En versiones anteriores de Visual Basic, podemos crear controles ActiveX que


pueden ser reutilizados por distintas aplicaciones cliente. En Visual Basic
.NET, también podemos utilizar la herencia para crear controles.
En esta lección, aprenderemos a:
„ Crear un control basado en la clase System.Windows.Forms.UserControl.
„ Crear un control basado en un control existente Windows Forms.
„ Agregar atributos a nuestros controles que habiliten funcionalidades
avanzadas en tiempo de diseño.
40 Desarrollo de componentes en Visual Basic .NET

Heredar de la clase UserControl


Objetivo
Explicar cómo crear un
control que herede de la
clase UserControl. „ Heredar de System.Windows.Forms.UserControl
Presentación „ Agregar los controles necesarios al diseñador
En Visual Basic .NET,
podemos heredar de la „ Agregar propiedades y métodos que correspondan a los
clase UserControl para de los controles constitutivos
crear el mismo tipo de
controles de usuario que „ Agregar propiedades y métodos adicionales
podemos crear en
Visual Basic 6.0. „ No InitProperties, ReadProperties ni WriteProperties
z El almacenamiento de propiedades es automático

En versiones anteriores de Visual Basic, podemos crear un control nuevo y


exclusivo colocando uno o más controles existentes en un diseñador
UserControl. A continuación, es posible crear propiedades, métodos y eventos
personalizados para establecer y recuperar valores para los controles
contenidos. Este tipo de control es útil cuando varios formularios requieren la
misma composición de controles, como formularios de direcciones o
información de contacto.

Agregar los controles necesarios


En Visual Basic .NET, podemos crear el mismo tipo de controles de usuario si
heredamos nuestro control de la clase System.Windows.Forms.UserControl,
lo que resulta automático si creamos un control utilizando el elemento de
plantilla User Control. Podemos heredar de esta clase base para utilizar un
diseñador similar al utilizado en versiones anteriores de Visual Basic.
Utilizando este método, podemos:
„ Colocar tantos controles en el diseñador como sea necesario para crear
nuestro propio control de usuario.
„ Acceder a estos controles desde nuestra clase de control de usuario, ya que
están declarados como variables privadas.
„ Agregar nuestras propias propiedades y métodos que correspondan a las
propiedades y métodos de los controles constituyentes.
„ Añadir propiedades, métodos y eventos públicos exactamente del mismo
modo en que lo hacemos para una clase convencional.

Agregar propiedades y métodos


En versiones anteriores de Visual Basic, hacemos que las propiedades sean
persistentes con un objeto PropertyBag, de modo que el control conserva su
configuración entre tiempo de diseño y tiempo de ejecución. Para ello,
Desarrollo de componentes en Visual Basic .NET 41

escribimos código en los eventos ReadProperties y WriteProperties de la


clase UserControl.
En Visual Basic .NET, esta persistencia de información es automática y no
requiere código adicional.

Ejemplo
El siguiente ejemplo muestra cómo crear un control de usuario sencillo que
contiene una etiqueta y un cuadro de texto:
Public Class LabelAndTextControl
Inherits System.Windows.Forms.UserControl

Public Property TextBoxText( ) As String


Get
Return TextBox1.Text
End Get
Set(ByVal Value As String)
TextBox1.Text = Value
End Set
End Property

Public Property LabelText( ) As String


Get
Return Label1.Text
End Get
Set(ByVal Value As String)
Label1.Text = Value
End Set
End Property
... 'Windows Form Designer generated code
End Class

Los controles TextBox1 y Label1 son variables declaradas privadas dentro del
control de usuario a las que sólo puede accederse utilizando las propiedades
públicas TextBoxText y LabelText.
42 Desarrollo de componentes en Visual Basic .NET

Heredar de un control existente Windows Form


Objetivo
Explicar cómo heredar de
un control en un formulario
Windows Forms. „ Permite mejorar la versión de un único control
Presentación „ Heredar de un control System.Windows.Forms
La herencia facilita la
Public
Public Class
Class MyTextBox
mejora de un control MyTextBox
Inherits
Inherits System.Windows.Forms.TextBox
System.Windows.Forms.TextBox
existente en Visual Basic
Private
Private strData
strData As
As String
String
.NET.
Public
Public Property HiddenData( )) As
Property HiddenData( As String
String
Get
Get
Return
Return strData
strData
End
End Get
Get
Set(ByVal
Set(ByVal Value
Value AsAs String)
String)
strData
strData == Value
Value
End
End Set
Set
End
End Property
Property
...
...
End
End Class
Class

En versiones anteriores de Visual Basic, podemos crear versiones mejoradas de


un control existente ubicando una instancia del control en el diseñador
UserControl. A partir de aquí, podemos crear propiedades, métodos y eventos
públicos que correspondan a los elementos equivalentes del control
constituyente, agregando elementos personalizados para crear un
comportamiento mejorado.
En Visual Basic .NET, podemos crear un control que herede de cualquier clase
System.Windows.Forms, como la clase TextBox o Label. Como esta
aproximación utiliza herencia, no es necesario crear propiedades, métodos y
eventos públicos que se mapeen a los del control constitutivo. Esto reduce
enormemente la cantidad de código necesario. Únicamente debemos crear la
funcionalidad adicional, según hemos comentado en el tema anterior para los
controles de usuario.
El siguiente ejemplo muestra cómo crear un control que herede de
SystemWindows.Forms.TextBox y agregue una propiedad pública:
Public Class MyTextBox
Inherits System.Windows.Forms.TextBox

Private strData As String

Public Property HiddenData( ) As String


Get
Return strData
End Get
Set(ByVal Value As String)
strData = Value
End Set
End Property
...
End Class
Desarrollo de componentes en Visual Basic .NET 43

Este código crea un nuevo control que hereda todas las funcionalidades de la
clase TextBox y añade una propiedad denominada HiddenData.

Nota Para algunos controles existentes, podemos crear un nuevo interfaz


gráfico sobrecargando el método OnPaint de la clase base. Sin embargo,
algunos controles, como el control TextBox, son pintados directamente por
Windows y no pueden ser sobrecargados.
44 Desarrollo de componentes en Visual Basic .NET

Proporcionar atributos a los controles


Objetivo „ System.ComponentModel proprociona atributos a los
Explicar cómo utilizar los controles
atributos de los controles.
Presentación „ A nivel de clase: DefaultProperty, DefaultEvent,
Los atributos de los ToolboxBitmap
controles pueden utilizarse
para proporcionar
„ A nivel de propiedad: Category, Description, DefaultValue
información adicional sobre Imports
Imports System.ComponentModel
System.ComponentModel
el control y sus <ToolboxBitmap("C:\txticon.ico"),
<ToolboxBitmap("C:\txticon.ico"), DefaultEvent("Click")>
DefaultEvent("Click")> __
propiedades, métodos y Public
Public Class
Class MyTextBox
MyTextBox
eventos. Inherits
Inherits System.Windows.Forms.UserControl
System.Windows.Forms.UserControl
<Category("Appearance"),
<Category("Appearance"), __
Description("Stores
Description("Stores extra
extra data"),
data"), __
DefaultValue("Empty")>
DefaultValue("Empty")> __
Public
Public Property
Property HiddenData(
HiddenData( )) As
As String
String
...
...
End
End Property
Property
...
...
End
End Class
Class

En versiones anteriores de Visual Basic, podemos utilizar el cuadro de diálogo


Procedure Attributes para establecer atributos para los controles, como
descripciones de las propiedades y sus categorías, que pueden ser visualizados
en el Examinador de Objetos. Podemos proporcionar información similar en
Visual Basic .NET utilizando los atributos que ofrece el espacio de nombres
System.ComponentModel.

Establecer atributos a nivel de clase


Podemos especificar varios atributos para el control, incluyendo
DefaultProperty, DefaultEvent y ToolboxBitmap. El siguiente ejemplo
muestra cómo establecer los atributos ToolboxBitmap y DefaultEvent para la
clase MyTextBox:
<ToolboxBitmap("C:\txticon.ico"), DefaultEvent("Click")> _
Public Class MyTextBox
Inherits System.Windows.Forms.UserControl
...
End Class
Desarrollo de componentes en Visual Basic .NET 45

Establecer atributos a nivel de propiedad


Podemos especificar atributos a nivel de propiedad para propiedades públicas,
incluyendo los atributos Category, Description y DefaultValue. El siguiente
ejemplo muestra cómo establecer estos atributos para la propiedad
HiddenData:
Imports System.ComponentModel

Public Class MyTextBox


Inherits System.Windows.Forms.UserControl

<Category("Appearance"), _
Description("Stores extra data"), _
DefaultValue("Empty")> _
Public Property HiddenData( ) As String
...
End Property
...
End Class
46 Desarrollo de componentes en Visual Basic .NET

Demostración: Creación de una caja de texto mejorada


Objetivo
Mostrar cómo crear un
control basado en otro
control existente de un
formulario Windows Forms.
Presentación
En esta demostración,
estudiaremos cómo crear un
control basado en el control
TextBox de Windows
Forms.

En esta demostración, estudiaremos cómo crear un control de usuario de


Windows Forms basado en el control TextBox existente.

Ë Visualizar el código
1. Abrir Visual Studio .NET.
2. Abrir el proyecto MyControls.sln project de la carpeta UserTextBox que se
puede encontrar dentro del fichero demos11.zip.
3. Visualizar el código para la clase MyTextBox y examinar todos los
miembros de la clase.
4. Generar el proyecto y cerrarlo.

Ë Crear el funcionamiento de la prueba


1. Abrir el proyecto TestControl.sln de la carpeta
UserTextBox\TestControl\Starter que se puede encontrar dentro del fichero
demos11.zip.
2. En el Cuadro de herramientas, hacer clic en la fecha General.
3. En el menú Herramientas, hacer clic en Personalizar cuadro de
herramientas. En el cuadro de diálogo Personalizar cuadro de
herramientas, hacer clic en la ficha Componentes de .NET Framework.
4. Hacer clic en el botón Examinar para localizar MyControls.dll en la carpeta
UserTextBox\bin, hacer clic en Abrir y en Aceptar.
5. Mostrar el formulario de prueba si no está visible.
6. En el Cuadro de herramientas, arrastrar MyTextBox al formulario para
crear una instancia del control MyTextBox.
7. Cambiar el nombre del control myTB, y ponerlo junto a la etiqueta
MyTextBox. Establecer la propiedad Text del control en cero.
Desarrollo de componentes en Visual Basic .NET 47

8. En el controlador de eventos Click del botón Undo, elimine el comentario


de la instrucción myTB.Undo.

Ë Probar el control
1. Ejecutar el proyecto.
2. Cambiar secuencialmente el valor del texto de cada cuadro de texto en base
a los siguientes valores:
Control Valor de texto

TextBox One
MyTextBox One
TextBox Two
MyTextBox Two
TextBox Three
MyTextBox Three

3. Hacer clic en el botón Undo cuatro veces y observar los cambios de cada
cuadro de texto.
4. Cerrar el formulario y cerrar Visual Studio .NET.
48 Desarrollo de componentes en Visual Basic .NET

Manejo de hilos de ejecución


Objetivo
Ofrecer una descripción de
los temas tratados en esta
lección. „ ¿Qué es un hilo?
Presentación
Visual Basic .NET permite a „ Ventajas de múltiples hilos de ejecución
los desarrolladores utilizar la
potencia de manejar hilos „ Creación de hilos
de ejecución de un modo no
disponible anteriormente en „ Uso de hilos
Visual Basic.
„ Cuándo utilizar el manejo de hilos

Las versiones anteriores de Visual Basic tienen un limitado soporte de manejo


de hilos (threads) de ejecución. Visual Basic .NET permite a los
desarrolladores utilizar todas la potencia de los hilos cuando es necesario. Si
manejamos los hilos de ejecución correctamente, podemos mejorar el
rendimiento de nuestra aplicación y hacerla mucho más interactiva.
En esta lección, aprenderemos a:
„ Explicar los conceptos básicos del manejo de hilos de ejecución.
„ Conocer las ventajas de incorporar múltiples hilos a nuestras aplicaciones.
„ Crear y utilizar hilos utilizando el espacio de nombres System.Threading.
„ Evitar algunos problemas potenciales en nuestras aplicaciones que usen
múltiples hilos de ejecución.

Aviso Esta sección ofrece una descripción general sobre el uso de hilos en
Visual Basic .NET. Éste es un tema muy complejo, y debemos estar seguros de
que comprendemos completamente sus implicaciones antes de utilizar estos
métodos. Si deseamos obtener más información, consultar el SDK del .NET
Framework.
Desarrollo de componentes en Visual Basic .NET 49

¿Qué es un hilo?
Objetivo
Explicar los conceptos
„ La unidad de ejecución que procesa la CPU
básicos del manejo de hilos z Todos los procesos de una aplicación contienen al menos un
de ejecución. subproceso
Presentación „ Los subprocesos están programados
Antes de examinar cómo
Visual Basic .NET permite z Parece que el equipo realiza varias tareas a la vez
manejar hilos, es importante
z Cada subproceso contiene su propia pila de llamadas y
entender los conceptos almacenamiento
básicos del mismo.
Programador de subprocesos
Subproc.1
Proceso 1 Subproc. 321
CPU
Subproc. 2
Proceso 2
Subproc. 3

Una aplicación ejecutándose en un equipo es un proceso. Cada proceso realiza


Sugerencia trabajo utilizando uno o más hilos. El hilo es la unidad de ejecución procesada
La diapositiva asociada a
este tema está animada.
por el procesador (CPU) del equipo.
Hacer clic sobre ella para
revelar las siguientes Proceso de manejo de hilos de ejecución
lecciones, mostrando el
Una CPU sólo puede ejecutar un único hilo en un instante; por ello, el
proceso iterativo del
planificador de hilos:
planificador de hilos asigna una determinada cantidad de tiempo de CPU para
1. Hilo 1 cada hilo para realizar tanto trabajo como sea posible antes de permitir que otro
2. Hilo 2 hilo acceda a la CPU. Esta planificación hace que parezca que el equipo está
3. Hilo 3 realizando varias tareas a la vez. En realidad, ocurre lo siguiente:
4. Hilo 1
5. Hilo 2 1. Cada hilo contiene su propia pila de llamadas y su propio almacenamiento
6. Hilo 3 para las variables locales. Esta información se guarda con el hilo y se envía
a la CPU cuando el hilo está programado para procesarse.
2. Cuando acaba el tiempo, el planificador de hilos elimina el hilo la CPU y
almacena la pila de llamadas y la información de las variables.

Cuantos más hilos se ejecuten en el sistema, con menor frecuencia se


programará un hilo para ejecutarse en la CPU. Esto explica que un equipo
pueda estar ejecutándose con lentitud cuando tenemos múltiples aplicaciones
abiertas y funcionando a la vez.
50 Desarrollo de componentes en Visual Basic .NET

Tipos de hilos
Cada lenguaje de programación puede soportar un tipo de hilo distinto:
„ Las versiones anteriores de Visual Basic soportan el modelo de hilos
apartamento (apartment).
Este modelo impone algunas restricciones en los tipos de aplicaciones que
estas versiones pueden crear. Una de estas restricciones es que un objeto
está ligado al hilo en el que está creado, y no puede utilizarse con la
agrupación de objetos en los servicios de componentes. Sin embargo, este
modelo facilita el desarrollo, ya que nos evita tratar con aspectos más
complejos como la sincronización.
„ Visual Basic .NET soporta el modelo de hilos libre (free).
Este modelo permite utilizar múltiples hilos de ejecución y características
como la agrupación de objetos o continuar utilizando un único hilo como en
las aplicaciones creadas con las versiones anteriores de Visual Basic.
Desarrollo de componentes en Visual Basic .NET 51

Ventajas de múltiples hilos de ejecución


Objetivo
Explicar las ventajas de
tener múltiples hilos de
ejecución y el manejo de „ Mejor respuesta de la interfaz de usuario
hilos libre.
Presentación z Ejemplo: barra de estado
Tener múltiples hilos de
ejecución puede „ Sin bloqueos
proporcionar numerosos
beneficios a nuestras „ Comunicación asíncrona
aplicaciones.
„ Sin afinidad de hilos
z Los objetos no están vinculados a un hilo

Una aplicación con múltiples hilos de ejecución tiene varias ventajas respecto a
una aplicación con un único hilo.

Mejor respuesta de la interfaz de usuario


Podemos utilizar múltiples hilos en un único proceso para mejorar la respuesta
de la interfaz de usuario. Por ejemplo:
„ Use hilos para operaciones lentas de procesamiento, como el uso del
corrector ortográfico o el reformateo de páginas. Estos hilos adicionales
pueden disparar eventos al hilo de la interfaz de usuario principal para
actualizar elementos como una barra de estado.
„ Asignar a cada hilo un nivel de prioridad de modo que hilos específicos
puedan ejecutarse con mayor prioridad que otros hilos de menor prioridad.
En una aplicación que se basa en la interacción del usuario, deberíamos
ejecutar el hilo de la interfaz de usuario con un hilo de mayor prioridad.

Sin bloqueos
El bloqueo se produce porque una llamada a una aplicación con un único hilo
debe esperar hasta que cualquier llamada previa por parte de otra aplicación
cliente haya sido completamente satisfecha antes de ejecutar cualquier otro
código. En aplicaciones basadas en servidor, el bloqueo ocurrirá si múltiples
clientes realizan peticiones simultáneas de un proceso y sólo está disponible un
único hilo.
Aplicaciones con múltiples hilos de ejecución pueden realizar acciones sobre
diferentes hilos simultáneamente (mediante la planificación de hilos) sin
esperar a que otros hilos finalicen su ejecución actual. Esto permite a múltiples
clientes ser gestionados por hilos diferentes sin bloquearse en una aplicación
basada en servidor.
52 Desarrollo de componentes en Visual Basic .NET

Comunicación asíncrona
Es posible la comunicación asíncrona en una aplicación con múltiples hilos de
ejecución porque un hilo puede realizar una petición a otro hilo. El hilo
llamador puede proseguir con otro procesamiento porque la petición se ejecuta
en un hilo separado. Puede lanzarse un evento cuando el segundo hilo finalice
la ejecución de la funcionalidad solicitada, informando al primer hilo que ha
completado su trabajo.

Sin afinidad de hilos


Visual Basic .NET usa el modelo de hilos libre. Este modelo no nos restringe a
utilizar un objeto únicamente en el hilo donde fue inicialmente creado.
Podemos crear un objeto en un hilo y pasarlo a otro hilo fácilmente. Esto
mejora la escalabilidad cuando se utiliza conjuntamente con los servicios de
componentes y con la agrupación de objetos.
Desarrollo de componentes en Visual Basic .NET 53

Creación de hilos
Objetivo
Explicar cómo crear y
utilizar hilos. „ Uso de la clase System.Threading.Thread
Presentación z El constructor especifica el método delegado
El .NET Framework
proporciona la clase
z Los métodos proporcionan control del procesamiento de
System.Threading.Thread,
hilos
que permite crear múltiples z Las propiedades proporcionan información de estado y
hilos. prioridades
„ Utilizar una clase si se requieren parámetros
z Permitir acceso público a variables clase
z Lanzar un evento cuando finalice

El .NET Framework proporciona un modo sencillo de crear y trabajar con


múltiples hilos.

Uso de la clase System.Threading.Thread


Usar la clase Thread para crear múltiples hilos dentro de una aplicación basada
Sugerencia en Visual Basic .NET.
El siguiente tema, Uso de
hilos, ofrece un ejemplo
completo del manejo de Construcción del hilo
hilos. Cuando se crea una instancia de Thread, el operador AddressOf pasa al
constructor un delegado que representa el método que debe ser ejecutado, como
se muestra en el siguiente ejemplo:
Dim th As New Threading.Thread(AddressOf PerformTask)
...
Sub PerformTask( )
...
End Sub
54 Desarrollo de componentes en Visual Basic .NET

Métodos de manejo de hilos


La clase Thread también proporciona varios métodos para controlar el
procesamiento de un hilo.
Método Utilidad

Start Comienza la ejecución del método delegado declarado en el


constructor del hilo.
Abort Finaliza explícitamente un hilo de ejecución.
Sleep Pausa un hilo. Como único parámetro, especifica el número de
milisegundos. Si pasamos cero como parámetro, el hilo ofrece el resto
de su porción de tiempo actual. Esto es similar a DoEvents en
versiones anteriores de Visual Basic.
Suspend Interrumpe temporalmente la ejecución de un hilo.
Resume Reactiva un hilo temporalmente interrumpido.

Propiedades de los hilos


La clase Thread proporciona propiedades para recuperar información sobre el
estado del hilo y manipular la prioridad del mismo.
Propiedad Utilidad

ThreadState Usar la propiedad ThreadState para determinar el estado actual de un


hilo, como Running, Suspended o Aborted.
Priority Modificar la prioridad de un hilo estableciendo su propiedad Priority
utilizando la enumeración ThreadPriority. La enumeración
proporciona los valores siguientes: AboveNormal, BelowNormal,
Highest, Lowest y Normal.

Aviso Si establecemos las prioridades de un hilo a un valor Highest, podemos


afectar a otros procesos vitales del sistema reduciéndoles ciclos de CPU.
Utilizar esta configuración con extrema precaución.

Creación y prueba de hilos


El siguiente ejemplo muestra cómo crear y probar el estado de un hilo, así como
cambiar su prioridad:
Dim th As New Threading.Thread(AddressOf PerformTask)
th.Start( )
If th.ThreadState = ThreadState.Running Then
th.Priority = Threading.ThreadPriority.AboveNormal
End If
Desarrollo de componentes en Visual Basic .NET 55

Uso de clases para proporcionar parámetros


No podemos especificar un método delegado que acepta argumentos en el
Sugerencia constructor del hilo. Si nuestro procedimiento requiere información para
El siguiente tema, Uso de
hilos, muestra un ejemplo
realizar su acción, podemos:
de este planteamiento. „ Usar clases para proporcionar métodos que realicen operaciones sobre datos
locales
„ Usar propiedades públicas o variables para suministrar los datos locales.

Para usar clases y suministrar parámetros, debemos crear una instancia de la


clase antes de llamar al constructor del hilo. Utilizar el operador AddressOf
para pasar una referencia al método de la clase como el parámetro del
constructor. A continuación podemos usar las propiedades o variables públicas
para suministrar cualquier dato requerido por el método. Cuando el método
finalice su ejecución, podemos lanzar un evento para informar al hilo que
originó la llamada que la operación se ha completado.
56 Desarrollo de componentes en Visual Basic .NET

Uso de hilos
Objetivo
Class
Class Calculate
Calculate
Explicar un ejemplo sencillo Public
Public iValue
iValue AsAs Integer
Integer
del manejo de hilos. Public
Public Event
Event Complete(ByVal
Complete(ByVal Result
Result As
As Integer)
Integer)
Public
Public Sub
Sub LongCalculation(
LongCalculation( ))
Presentación 'Perform
'Perform aa long
long calculation
calculation based
based on
on iValue
iValue
Un vistazo a un ejemplo ...
...
sencillo de manejo de hilos. RaiseEvent Complete(iResult)
RaiseEvent Complete(iResult) 'Raise
'Raise event
event to
to signal
signal finish
finish
End
End Sub
Sub
End
End Class
Class

Sub
Sub Test(
Test( ))
Dim
Dim calc
calc As
As New
New Calculate(
Calculate( ))
Dim
Dim th
th As
As New
New Threading.Thread(AddressOf
Threading.Thread(AddressOf calc.LongCalculation)
calc.LongCalculation)
calc.iValue
calc.iValue == 10
10
AddHandler
AddHandler calc.Complete,
calc.Complete, AddressOf
AddressOf CalcResult
CalcResult
th.Start(
th.Start( ))
End
End Sub
Sub
Sub
Sub CalcResult(ByVal
CalcResult(ByVal Result
Result As
As Integer)
Integer)
...
...
End
End Sub
Sub

Este tópico muestra cómo preparar una clase para el manejo de hilos; crear un
hilo, iniciar el hilo y realizar cálculos sobre el nuevo hilo.

Preparar una clase para el manejo de hilos


El siguiente ejemplo muestra cómo crear una clase Calculate y prepararla para
el manejo de hilos utilizando el evento Complete:

Class Calculate
Public iValue As Integer
Public Event Complete(ByVal Result As Integer)
Public Sub LongCalculation( )
'Perform a long calculation based on iValue
...
RaiseEvent Complete(iResult)'Raise event to signal finish
End Sub
End Class

Al examinar el código anterior, observaremos lo siguiente:


„ La clase proporciona una función LongCalculation, que se ejecutará en un
hilo separado.
„ La función utiliza información almacenada en la variable pública entera
iValue para calcular su resultado.
„ La clase Calculate proporciona un evento Complete para notificar al hilo
que realiza la llamada que el cálculo ha finalizado.
Desarrollo de componentes en Visual Basic .NET 57

Creación y uso de un hilo


El siguiente ejemplo muestra cómo crear a hilo y utilizar el manejo de hilos
para realizar cálculos:
Sub Test( )
Dim calc As New Calculate( )
Dim th As New Threading.Thread( _
AddressOf calc.LongCalculation)
calc.iValue = 10
AddHandler calc.Complete, AddressOf CalcResult
th.Start( )
End Sub

Sub CalcResult(ByVal Result As Integer)


'Perform appropriate action when calculation is finished
...
End Sub

Al examinar este código, observamos lo siguiente:


„ La subrutina Test instancia un objeto Calculate y especifica el delegado
LongCalculation en el constructor Thread.
„ Se asigna un valor a la variable iValue para su uso por parte de la función
„ Se crea un gestor de eventos para detectar la finalización del cálculo.
„ El método Start se invoca en el hilo separado para comenzar el proceso de
cálculo.
58 Desarrollo de componentes en Visual Basic .NET

Cuándo utilizar el manejo de hilos


Objetivo „ Utilizar los subprocesos con precaución
Explicar algunos de los
problemas potenciales z El uso de más subprocesos requiere más recursos del
causados por el manejo de sistema
múltiples hilos de ejecución.
Presentación „ Sincronizar el acceso a recursos compartidos
Usar múltiples hilos requiere
tener presente el uso de los z Evitar que dos subprocesos accedan simultáneamente a
recursos. datos compartidos
z Utilizar la instrucción SyncLock para bloquear
secciones de código
Sub
Sub Worker(
Worker( ))
SyncLock(theData)
SyncLock(theData) 'Lock
'Lock this
this object
object variable
variable
theData.id
theData.id == iValue
iValue
'Perform
'Perform some
some lengthy
lengthy action
action
iValue
iValue == theData.id
theData.id
End SyncLock
End SyncLock 'Unlock
'Unlock the
the object
object variable
variable
End Sub
End Sub

Utilizar múltiples hilos es un concepto de programación útil en el desarrollo


Sugerencia empresarial; sin embargo, el uso inapropiado de los hilos puede causar
Apunte que el uso
incorrecto de los hilos
problemas de rendimiento, crear datos inconsistentes y otros errores.
puede tener serias
consecuencias. Recursos del sistema
Los hilos consumen memoria y otros recursos valiosos, como tiempo de
proceso de la CPU. Si nuestra aplicación crea múltiples hilos, puede hacerlo a
expensas de otras aplicaciones u otros hilos dentro de nuestro propio proceso.
Cuantos más hilos creemos, mayor será el retardo entre las porciones de tiempo
de CPU para cada hilo. Si todas las aplicaciones creasen un número excesivo de
hilos y los utilizasen constantemente, el sistema dedicaría la mayor parte de su
tiempo intercambiando hilos en la CPU, puesto que el propio planificador de
hilos requiere que la CPU se encargue de la lógica de intercambio.

Recursos compartidos
Si múltiples hilos necesitan acceder a la misma información al mismo tiempo,
puede producirse un problema de concurrencia. Dos hilos accediendo a un
recurso global compartido pueden generar resultados inconsistentes si otros
hilos han alterado los datos.
He aquí un ejemplo de una situación en la que esto puede suceder:
„ El hilo A actualiza un valor en un recurso compartido como un entero,
estableciendo el valor a 10 antes de realizar alguna acción de larga duración.
„ El hilo B actualiza el mismo valor entero a 15 durante la duración de la
acción de larga duración del hilo A.
„ Cuando se completa esta acción, el hilo A puede leer de nuevo el valor
entero del recurso cuyo valor es ahora 15.
Desarrollo de componentes en Visual Basic .NET 59

Sincronizar recursos compartidos


Podemos evitar resultados inconsistentes bloqueando el recurso entre el tiempo
en que se establece inicialmente el valor y el tiempo que se lee de nuevo.
Podemos utilizar la sentencia SyncLock para bloquear un tipo referencia como
una clase interface, módulo, cadena o delegado.
El siguiente ejemplo define un recurso compartido denominado
SharedReference que expone una variable entera. La clase ThreadObj define
el método que será ejecutado por diferentes hilos. Este método utiliza la
sentencia SyncLock para bloquear el objeto del recurso compartido mientras
está en uso. El código del módulo muestra cómo podemos probar este
comportamiento creando dos hilos y dos objetos y a continuación iniciar ambos
hilos de forma consecutiva.
60 Desarrollo de componentes en Visual Basic .NET

Imports System.Threading

'Shared data
Public Class SharedReference
Public Id As Integer
End Class

'Class for running on other threads


Public Class ThreadObj
Private sr As SharedReference
Private Count As Integer

'Constructor with reference and Id


Public Sub New(ByRef sharedRef As SharedReference, _
ByVal ID As Integer)
sr = sharedRef
Count = ID
End Sub

'Actual worker method


Public Sub RunMethod( )
SyncLock (sr) 'Lock sr object
sr.Id = Count

'Execute lengthy code


'sr.Id could have changed without SyncLock

Count = sr.Id
End SyncLock 'Release sr object lock
End Sub
End Class

Module MainModule
Sub Main( )
'Create shared data object
Dim sr As New SharedReference( )

'Create two worker objects


Dim worker1 As New ThreadObj(sr, 1)
Dim worker2 As New ThreadObj(sr, 2)

'Create two threads


Dim t1 As New Thread(AddressOf worker1.RunMethod)
Dim t2 As New Thread(AddressOf worker2.RunMethod)

'Start both threads


t1.Start( )
t2.Start( )
End Sub
End Module
Desarrollo de componentes en Visual Basic .NET 61

Demostración: Uso de la instrucción SyncLock


Objetivo
Mostrar cómo sincronizar
recursos compartidos
usando la sentencia
SyncLock.
Presentación
Esta demostración muestra
cómo utilizar la sentencia
SyncLock para sincronizar
un recurso compartido.

En esta demostración, aprenderemos cómo usar la sentencia SyncLock cuando


Información utilicemos múltiples hilos en una aplicación creada en Visual Basic .NET.
Los hilos en esta
demostración pueden no
ejecutarse en el orden en
Ë Para examinar la aplicación de agrupación de objetos
que han sido lanzados, de 1. Abrir Visual Studio .NET.
modo que nuestros
resultados pueden no ser 2. Abrir el proyecto ThreadingDemo.sln de la carpeta ThreadingDemo que se
estrictamente los mismos. puede encontrar dentro del fichero demos11.zip.
3. Examinar el código del formulario frmThreading, explicando brevemente
cada miembro.
4. Examinar el código de la clase ThreadObj, explicando brevemente cada
miembro.

Ë Para probar la aplicación


1. Ejecutar el proyecto.
2. Hacer clic en el botón Without SyncLock y observar que los resultados no
concuerdan con los esperados.
3. Hacer clic en el botón With SyncLock y observar que los resultados
coinciden correctamente con los esperados.
4. Salir de la aplicación.
5. Examinar de nuevo el código WithSyncLock dentro de la clase
ThreadObj, clarificando el uso de la sentencia SyncLock que produce los
resultados correctos.
6. Salir de Visual Studio .NET.