11.- Desarrollo de Componentes en Visual Basic .NET

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

Transcript of 11.- Desarrollo de Componentes en Visual Basic .NET

Page 1: 11.- Desarrollo de Componentes en Visual Basic .NET

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

Page 2: 11.- Desarrollo de Componentes en Visual Basic .NET
Page 3: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 1

Descripción

Components Overview

Creating Serviced Components

Creating Component Classes

Creating Windows Forms Controls

Creating Web Forms User Controls

Threading

Objetivo Presentar los temas y objetivos del módulo.

Presentación En este módulo, aprenderemos cómo crear componentes en Visual Basic .NET.

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.

Page 4: 11.- Desarrollo de Componentes en Visual Basic .NET

2 Desarrollo de componentes en Visual Basic .NET

Descripción de los componentes

Tipos de componentes

Uso dé módulos como componentes

Uso de clases como componentes

Uso de componentes en aplicaciones cliente no gestionadas

Descripción de .NET Remoting

Objetivo Ofrecer una descripción de los temas tratados en esta lección.

Presentación Esta lección explica los tipos de componentes que podemos crear en una aplicación basada en Visual Basic .NET y cómo podemos hacerlos visibles para aplicaciones cliente no 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.

Page 5: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 3

Tipos de componentes

Estructuras

Módulos

Clases

Clases de componente

Componentes con servicio

Controles de usuario

Controles de usuario de formularios Windows Forms

Controles de usuario de formularios Web Forms

Objetivo Explicar los diferentes tipos de componentes que podemos crear en Visual Basic .NET.

Presentación Podemos crear varios tipos de componentes en una aplicación basada en Visual Basic .NET.

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

Estructuras Sugerencia Comentar que este módulo se centra en cómo crear y utilizar clases de componentes, componentes con servicio y controles de usuario. El resto de tipos de componentes se mencionan únicamente como referencia.

Módulos Clases Clases de componentes Componentes con servicio Controles de usuario

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.

Page 6: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

En este módulo, aprenderemos cómo crear y utilizar clases de componentes, componentes con servicio y controles de usuario. Nota

Page 7: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 5

Uso de módulos como componentes

Declarar el módulo como público

Referenciar e importa el ensamblado en código cliente

Public Module MyMathFunctionsPublic Function Square(ByVal lng As Integer) As Long

Return (lng * lng)End Function

...End Module

'Client codeImports MyAssembly...

Dim x As Long = Square(20)

Public Module MyMathFunctionsPublic Function Square(ByVal lng As Integer) As Long

Return (lng * lng)End Function

...End Module

'Client codeImports MyAssembly...

Dim x As Long = Square(20)

Objetivo Explicar cómo utilizar módulos como componentes.

Presentación En Visual Basic .NET, podemos utilizar módulos como componentes fuera del ensamblado en el que están definidos.

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)

Page 8: 11.- Desarrollo de Componentes en Visual Basic .NET

6 Desarrollo de componentes en Visual Basic .NET

Uso de clases como componentes

Declarar la clase como pública

Referenciar e importar el ensamblado en código clientePublic 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 SubEnd Class

'Client codeImports MyAssemblyDim x As New Account( )x.Debit(1021, 1000)

Public Class AccountPublic Sub Debit(ByVal AccountId As Long, Amount As Double)

'Perform debit actionEnd Sub

Public Sub Credit(ByVal AccountId As Long, Amount As Double)'Perform credit action

End SubEnd Class

'Client codeImports MyAssemblyDim x As New Account( )x.Debit(1021, 1000)

Objetivo Explicar cómo utilizar clases como componentes.

Presentación En Visual Basic .NET, podemos utilizar clases como componentes.

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)

Page 9: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 7

Uso de componentes en aplicaciones cliente no gestionadas

Setting assembly properties

Generate a strong name

Select Register for COM Interop in Build options

Exposing class members to COM and Component Services

Define and implement interfaces

Use the ClassInterface attribute with AutoDual value

Use the COMClass attribute

Objetivo Explicar cómo crear componentes que pueden ser utilizados por aplicaciones cliente no gestionadas, como clientes basados en Visual Basic 6.0.

Presentación Podemos utilizar COM para que todos los componentes de Visual Basic .NET sean accesibles desde clientes no gestionados, siguiendo unos sencillos pasos.

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.

Page 10: 11.- Desarrollo de Componentes en Visual Basic .NET

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

Page 11: 11.- Desarrollo de Componentes en Visual Basic .NET

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 Compruebe que los estudiantes saben qué son los interfaces duales. Explíquelo brevemente si fuera necesario.

<ClassInterface(ClassInterfaceType.AutoDual)> _ Public Class VisibleClass Public Sub PerformAction( ) 'Perform your action 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.

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.

Precaución

Page 12: 11.- Desarrollo de Componentes en Visual Basic .NET

10 Desarrollo de componentes en Visual Basic .NET

Descripción de .NET Remoting Objetivo Ofrecer una descripción de .NET Remoting.

Presentación El .NET Framework ofrece varios servicios que se utilizan en remoto.

Marshal By ReferenceCódigo cliente

Servidor Proxy Canal

Formateador

Límite de Remoting

Servidor AppDomain

Código cliente

Marshal By Value

Copia objeto servidor

Cliente AppDomain

Canal

Formateador

Objeto servidor

Canal

Formateador

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.

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.

Nota

Page 13: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 11

Creación de componentes con servicio

Hospedar componentes en Component Services

Uso de transacciones

Uso del pooling de objetos

Uso de cadenas de constructor

Uso de seguridad

Uso de otros Component Services

configuración de ensamblados para ComponentServices

Objetivo Ofrecer una descripción de los temas tratados en esta lección.

Presentación Esta lección examina componentes .NET hospedados por los servicios de componentes.

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.

Page 14: 11.- Desarrollo de Componentes en Visual Basic .NET

12 Desarrollo de componentes en Visual Basic .NET

Hospedar componentes en los servicios de componentes

Agregar una referencia a System.EnterpriseServices en el ensamblado

El espacio de nombres System.EnterpriseServicesproporciona:

Clase ContextUtil

Clase ServicedComponent

Atributos de ensamblado, clase y método

Objetivo Explicar los requerimientos para hospedar componentes en los servicios de componentes.

Presentación Para permitir que los componentes sean hospedados en los servicios de componentes, el .NET Framework proporciona varios elementos que necesitamos incluir en 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 ServicedComponent

Todas las clases de componentes que necesitan ser hospedadas en 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 ensamblado, clase y método

Podemos definir varios atributos del ensamblado para la interrogación a los servicios de componentes en el archivo 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.

Page 15: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 13

La parte “Attribute” de un nombre de atributo es opcional, por tanto, por ejemplo, podemos utilizar AutoComplete o AutoCompleteAttribute en nuestro código.

Nota

Page 16: 11.- Desarrollo de Componentes en Visual Basic .NET

14 Desarrollo de componentes en Visual Basic .NET

Uso de transacciones

El atributo Transaction especifica cómo participa una clase en las transacciones

La clase ContextUtil proporciona transaction voting

El atributo AutoComplete impide el uso de los métodosSetAbort, SetComplete y ContextUtil

<Transaction(TransactionOption.Required)> Public Class AccountInherits ServicedComponent

Public Sub Debit(...)'Perform debit actionContextUtil.SetComplete( )

End Sub

<AutoComplete( )> Public Sub Credit(...)'Perform credit action'No SetComplete because AutoComplete is on

End SubEnd Class

<Transaction(TransactionOption.Required)> Public Class AccountInherits ServicedComponent

Public Sub Debit(...)'Perform debit actionContextUtil.SetComplete( )

End Sub

<AutoComplete( )> Public Sub Credit(...)'Perform credit action'No SetComplete because AutoComplete is on

End SubEnd Class

Objetivo Examinar cómo los componentes pueden utilizar transacciones de los servicios de componentes.

Presentación Existen varios objetos y atributos que permiten a los componentes de Visual Basic .NET utilizar transacciones de los servicios de componentes.

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.

Page 17: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 18: 11.- Desarrollo de Componentes en Visual Basic .NET

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

Page 19: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 17

Uso de la agrupación de objetos

La agrupación de objetos permite crear los objetos con antelación

El atributo ObjectPooling especifica MinPoolSize y MaxPoolSize

ServicedComponent proporciona el método CanBePooled

<ObjectPooling(Enabled:=True, MinPoolSize:=5, _MaxPoolSize:=50)> _

Public Class AccountInherits ServicedComponent...

Protected Overrides Function CanBePooled( ) As BooleanReturn True

End FunctionEnd Class

<ObjectPooling(Enabled:=True, MinPoolSize:=5, _MaxPoolSize:=50)> _

Public Class AccountInherits ServicedComponent...

Protected Overrides Function CanBePooled( ) As BooleanReturn True

End FunctionEnd Class

Objetivo Examinar cómo los componentes pueden utilizar la agrupación de objetos.

Presentación Diversos atributos e interfaces permiten que los componentes de Visual Basic .NET utilicen la agrupación de objetos.

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.

Page 20: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Si la agrupación de objetos se deshabilita para un componente, el método CanBePooled no se ejecutará. Nota

Page 21: 11.- Desarrollo de Componentes en Visual Basic .NET

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

Page 22: 11.- Desarrollo de Componentes en Visual Basic .NET

20 Desarrollo de componentes en Visual Basic .NET

Uso de las cadenas de constructor

Especifican el atributo ConstructionEnabled para indicar que se necesita una cadena de constructor

Reemplazan el método Construct para recuperar información

<ConstructionEnabled(True)>Public Class AccountInherits ServicedComponent

Protected Overrides Sub Construct(ByVal s As String)'Called after class constructor'Use passed in string

End SubEnd Class

<ConstructionEnabled(True)>Public Class AccountInherits ServicedComponent

Protected Overrides Sub Construct(ByVal s As String)'Called after class constructor'Use passed in string

End SubEnd Class

Objetivo Explicar cómo los componentes pueden utilizar las cadenas de constructor.

Presentación Los servicios de componentes proporcionan cadenas de constructor a componentes con servicio y son accesibles para componentes de Visual Basic .NET a través del .NET Framework.

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.

Page 23: 11.- Desarrollo de Componentes en Visual Basic .NET

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

Page 24: 11.- Desarrollo de Componentes en Visual Basic .NET

22 Desarrollo de componentes en Visual Basic .NET

Uso de seguridad

Security configuration attributes enable security and role configuration

SecurityCallContext class provides role checking and caller information

<ComponentAccessControl(True), SecurityRole("Manager")> _Public Class Account

Inherits ServicedComponent

Public Function GetDetails( ) As StringWith SecurityCallContext.CurrentCall

If .IsCallerInRole("Manager") ThenReturn .OriginalCaller.AccountName

End IfEnd With

End FunctionEnd Class

<ComponentAccessControl(True), SecurityRole("Manager")> _Public Class Account

Inherits ServicedComponent

Public Function GetDetails( ) As StringWith SecurityCallContext.CurrentCall

If .IsCallerInRole("Manager") ThenReturn .OriginalCaller.AccountName

End IfEnd With

End FunctionEnd Class

Objetivo Explicar cómo la seguridad de los servicios de componentes es accesible por los componentes de Visual Basic .NET.

Presentación Los servicios de componentes proporcionan información de seguridad que pueden utilizar los componentes de Visual Basic .NET.

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.

Page 25: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 26: 11.- Desarrollo de Componentes en Visual Basic .NET

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

Page 27: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 25

Uso de otros servicios de componentes

Otros servicios de componentes incluyen:

Activación Just-in-time

Componentes en cola

Propiedades compartidas

Sincronización

Objetivo Ofrecer una descripción del resto de servicios que proporcionan los servicios de componentes.

Presentación Los servicios de componentes proporcionan otros servicios que podemos utilizar en componentes Visual Basic .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.

Page 28: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 29: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 27

Configurar ensamblados para usar los servicios de componentes

Setting assembly attributesApplicationNameDescriptionApplicationActivation: library or server applicationAssemblyKeyFile

Using Regsvcs to register and create Component Services applications

Regsvcs.exe myApplication.dllUsing Lazy Registration

Application registered on first use by client

Objetivo Explicar cómo establecer atributos de los servicios de componentes a nivel de ensamblado y configurar la aplicación.

Presentación Establecer atributos de los servicios de componentes a nivel de ensamblado ayuda a definir cómo se comportará la aplicación cuando la implantemos bajo los servicios de componentes.

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 ensamblado

Uso

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).

Page 30: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 31: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 32: 11.- Desarrollo de Componentes en Visual Basic .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.

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.

Importante

Page 33: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 31

Creación de clases de componentes

Arquitectura de una clase de componentes

Creación de una clase de componentes

Objetivo Ofrecer una descripción de los temas tratados en esta lección.

Presentación 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.

Page 34: 11.- Desarrollo de Componentes en Visual Basic .NET

32 Desarrollo de componentes en Visual Basic .NET

Arquitectura de una clase de componentes

System.ComponentModel.Component

Clases predefinidasClases personalizadas

InterfazIComponent

Clase

base

Clases

derivadasClases de componentes

Objetivo Describir la arquitectura de una clase de componentes.

Presentación Las clases de componentes ofrecen varias características no incluidas en las clases estándares de Visual Basic .NET.

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.

Page 35: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 36: 11.- Desarrollo de Componentes en Visual Basic .NET

34 Desarrollo de componentes en Visual Basic .NET

Creación de una clase de componentes

1. Heredar de System.ComponentModel.ComponentRealizar las inicializaciones por parte del constructorSobrecargar el método Dispose

2. Agregar los componentes ubicadosUtilizar elementos del Explorador de servidores o del cuadro de herramientas

3. Crear la funcionalidad requeridaPropiedades, métodos y eventos

4. Generar el ensamblado

Objetivo Explicar cómo crear una clase de componentes.

Presentación Crear una clase de componentes es similar a crear un elemento de clase estándar, pero hay algunos pasos adicionales.

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.

Page 37: 11.- Desarrollo de Componentes en Visual Basic .NET

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 clase Timer también produciría un componente similar.

Public Event Finished(...) Private WithEvents localTimer As System.Timers.Timer 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

Page 38: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 39: 11.- Desarrollo de Componentes en Visual Basic .NET

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

5. Agregar una referencia para el ensamblado System.Drawing.dll. Sugerencia Comentar que debe agregarse una referencia adicional para permitirnos utilizar el atributo ToolboxBitmap desde el espacio de nombres System.Drawing en los proyectos generados sobre este tipo de plantillas de proyectos.

6. Modificar la definición de la clase como sigue: <System.Drawing.ToolboxBitmap("")> _ Public Class Stopwatch

7. En el Explorador de soluciones, arrastrar el archivo Timer01.ico y colocarlo

entre las comillas de la cadena del código ToolboxBitmap(""). Comentar que agregar el mapa de bits como un recurso del ensamblado puede ser una mejor opción, ya que no dependerá de que el archivo de icono esté 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.

Page 40: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

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.

Importante

Page 41: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 39

Creación de controles de formularios Windows Forms

Heredar de la clase UserControl

Heredar de un control de formularios Windows Forms

Proporcionar atributos de controles

Objetivo Ofrecer una descripción de los temas tratados en esta lección.

Presentación Esta lección examina cómo crear controles de 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.

Page 42: 11.- Desarrollo de Componentes en Visual Basic .NET

40 Desarrollo de componentes en Visual Basic .NET

Heredar de la clase UserControl

Heredar de System.Windows.Forms.UserControl

Agregar los controles necesarios al diseñador

Agregar propiedades y métodos que correspondan a los de los controles constitutivos

Agregar propiedades y métodos adicionales

No InitProperties, ReadProperties ni WriteProperties

El almacenamiento de propiedades es automático

Objetivo Explicar cómo crear un control que herede de la clase UserControl.

Presentación En Visual Basic .NET, podemos heredar de la clase UserControl para crear el mismo tipo de controles de usuario que podemos crear en Visual Basic 6.0.

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,

Page 43: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 44: 11.- Desarrollo de Componentes en Visual Basic .NET

42 Desarrollo de componentes en Visual Basic .NET

Heredar de un control existente Windows Form

Permite mejorar la versión de un único control

Heredar de un control System.Windows.FormsPublic Class MyTextBox

Inherits System.Windows.Forms.TextBox

Private strData As String

Public Property HiddenData( ) As StringGet

Return strDataEnd GetSet(ByVal Value As String)

strData = ValueEnd Set

End Property...

End Class

Public Class MyTextBoxInherits System.Windows.Forms.TextBox

Private strData As String

Public Property HiddenData( ) As StringGet

Return strDataEnd GetSet(ByVal Value As String)

strData = ValueEnd Set

End Property...

End Class

Objetivo Explicar cómo heredar de un control en un formulario Windows Forms.

Presentación La herencia facilita la mejora de un control existente en Visual Basic .NET.

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

Page 45: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

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.

Nota

Page 46: 11.- Desarrollo de Componentes en Visual Basic .NET

44 Desarrollo de componentes en Visual Basic .NET

Proporcionar atributos a los controles System.ComponentModel proprociona atributos a los controles

A nivel de clase: DefaultProperty, DefaultEvent, ToolboxBitmap

A nivel de propiedad: Category, Description, DefaultValueImports System.ComponentModel

<ToolboxBitmap("C:\txticon.ico"), DefaultEvent("Click")> _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

Imports System.ComponentModel

<ToolboxBitmap("C:\txticon.ico"), DefaultEvent("Click")> _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

Objetivo Explicar cómo utilizar los atributos de los controles.

Presentación Los atributos de los controles pueden utilizarse para proporcionar información adicional sobre el control y sus propiedades, métodos y eventos.

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

Page 47: 11.- Desarrollo de Componentes en Visual Basic .NET

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

Page 48: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 49: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 50: 11.- Desarrollo de Componentes en Visual Basic .NET

48 Desarrollo de componentes en Visual Basic .NET

Manejo de hilos de ejecución

¿Qué es un hilo?

Ventajas de múltiples hilos de ejecución

Creación de hilos

Uso de hilos

Cuándo utilizar el manejo de hilos

Objetivo Ofrecer una descripción de los temas tratados en esta lección.

Presentación Visual Basic .NET permite a los desarrolladores utilizar la potencia de manejar hilos de ejecución de un modo no disponible anteriormente en Visual Basic.

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.

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.

Aviso

Page 51: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 49

¿Qué es un hilo?

La unidad de ejecución que procesa la CPUTodos los procesos de una aplicación contienen al menos un subproceso

Los subprocesos están programadosParece que el equipo realiza varias tareas a la vez

Cada subproceso contiene su propia pila de llamadas y almacenamiento

CPUProceso 1

Proceso 2

Subproc.1

Subproc. 2

Subproc. 3

Subproc. 2

Programador de subprocesos

Subproc. 1Subproc. 3Subproc. 1Subproc. 2Subproc. 3

Objetivo Explicar los conceptos básicos del manejo de hilos de ejecución.

Presentación Antes de examinar cómo Visual Basic .NET permite manejar hilos, es importante entender los conceptos básicos del mismo.

Una aplicación ejecutándose en un equipo es un proceso. Cada proceso realiza trabajo utilizando uno o más hilos. El hilo es la unidad de ejecución procesada por el procesador (CPU) del equipo.

Sugerencia La diapositiva asociada a este tema está animada. Hacer clic sobre ella para revelar las siguientes lecciones, mostrando el proceso iterativo del planificador de hilos: 1. Hilo 1 2. Hilo 2 3. Hilo 3 4. Hilo 1 5. Hilo 2 6. Hilo 3

Proceso de manejo de hilos de ejecución Una CPU sólo puede ejecutar un único hilo en un instante; por ello, el planificador de hilos asigna una determinada cantidad de tiempo de CPU para cada hilo para realizar tanto trabajo como sea posible antes de permitir que otro hilo acceda a la CPU. Esta planificación hace que parezca que el equipo está realizando varias tareas a la vez. En realidad, ocurre lo siguiente:

1. Cada hilo contiene su propia pila de llamadas y su propio almacenamiento 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.

Page 52: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 53: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 51

Ventajas de múltiples hilos de ejecución

Mejor respuesta de la interfaz de usuario

Ejemplo: barra de estado

Sin bloqueos

Comunicación asíncrona

Sin afinidad de hilos

Los objetos no están vinculados a un hilo

Objetivo Explicar las ventajas de tener múltiples hilos de ejecución y el manejo de hilos libre.

Presentación Tener múltiples hilos de ejecución puede proporcionar numerosos beneficios a nuestras aplicaciones.

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.

Page 54: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 55: 11.- Desarrollo de Componentes en Visual Basic .NET

Desarrollo de componentes en Visual Basic .NET 53

Creación de hilos

Uso de la clase System.Threading.ThreadEl constructor especifica el método delegadoLos métodos proporcionan control del procesamiento de hilosLas propiedades proporcionan información de estado y prioridades

Utilizar una clase si se requieren parámetrosPermitir acceso público a variables claseLanzar un evento cuando finalice

Objetivo Explicar cómo crear y utilizar hilos.

Presentación El .NET Framework proporciona la clase System.Threading.Thread, que permite crear múltiples hilos.

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 en Visual Basic .NET. Sugerencia

El siguiente tema, Uso de hilos, ofrece un ejemplo completo del manejo de hilos.

Construcción del hilo 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

Page 56: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

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.

Aviso

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

Page 57: 11.- Desarrollo de Componentes en Visual Basic .NET

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 constructor del hilo. Si nuestro procedimiento requiere información para realizar su acción, podemos:

Sugerencia El siguiente tema, Uso de hilos, muestra un ejemplo 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.

Page 58: 11.- Desarrollo de Componentes en Visual Basic .NET

56 Desarrollo de componentes en Visual Basic .NET

Uso de hilos

Sub Test( )Dim calc As New Calculate( )Dim th As New Threading.Thread(AddressOf calc.LongCalculation)

calc.iValue = 10AddHandler calc.Complete, AddressOf CalcResultth.Start( )

End Sub

Sub CalcResult(ByVal Result As Integer) ...

End Sub

Sub Test( )Dim calc As New Calculate( )Dim th As New Threading.Thread(AddressOf calc.LongCalculation)

calc.iValue = 10AddHandler calc.Complete, AddressOf CalcResultth.Start( )

End Sub

Sub CalcResult(ByVal Result As Integer) ...

End Sub

Class CalculatePublic iValue As IntegerPublic 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 SubEnd Class

Class CalculatePublic iValue As IntegerPublic 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 SubEnd Class

Objetivo Explicar un ejemplo sencillo del manejo de hilos.

Presentación Un vistazo a un ejemplo sencillo de manejo de hilos.

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.

Page 59: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 60: 11.- Desarrollo de Componentes en Visual Basic .NET

58 Desarrollo de componentes en Visual Basic .NET

Cuándo utilizar el manejo de hilos

Utilizar los subprocesos con precaución

El uso de más subprocesos requiere más recursos del sistema

Sincronizar el acceso a recursos compartidos

Evitar que dos subprocesos accedan simultáneamente a datos compartidos

Utilizar la instrucción SyncLock para bloquear secciones de código

Sub Worker( )SyncLock(theData) 'Lock this object variable

theData.id = iValue'Perform some lengthy actioniValue = theData.id

End SyncLock 'Unlock the object variableEnd Sub

Sub Worker( )SyncLock(theData) 'Lock this object variable

theData.id = iValue'Perform some lengthy actioniValue = theData.id

End SyncLock 'Unlock the object variableEnd Sub

Objetivo Explicar algunos de los problemas potenciales causados por el manejo de múltiples hilos de ejecución.

Presentación Usar múltiples hilos requiere tener presente el uso de los recursos.

Utilizar múltiples hilos es un concepto de programación útil en el desarrollo empresarial; sin embargo, el uso inapropiado de los hilos puede causar problemas de rendimiento, crear datos inconsistentes y otros errores.

Sugerencia Apunte que el uso incorrecto de los hilos 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.

Page 61: 11.- Desarrollo de Componentes en Visual Basic .NET

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.

Page 62: 11.- Desarrollo de Componentes en Visual Basic .NET

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

Page 63: 11.- Desarrollo de Componentes en Visual Basic .NET

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 utilicemos múltiples hilos en una aplicación creada en Visual Basic .NET. Información

Los hilos en esta demostración pueden no ejecutarse en el orden en que han sido lanzados, de modo que nuestros resultados pueden no ser estrictamente los mismos.

Para examinar la aplicación de agrupación de objetos

1. Abrir Visual Studio .NET. 2. Abrir el proyecto ThreadingDemo.sln de la carpeta ThreadingDemo que se

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.