11. Desarrollo De Componentes

  • May 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View 11. Desarrollo De Componentes as PDF for free.

More details

  • Words: 13,079
  • Pages: 63
Desarrollo de componentes en Visual Basic .NET

Índice Descripción

1

Descripción de los componentes

2

Creación de componentes con servicio

11

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

29

Creación de clases de componentes

31

Demostración: Creación de un componente Stopwatch

37

Creación de controles de formularios Windows Forms

39

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

46

Manejo de hilos de ejecución

48

Demostración: Uso de la instrucción SyncLock

61

Desarrollo de componentes en Visual Basic .NET

Descripción Objetivo

Presentar los temas y objetivos del módulo.

Presentación

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

„

Components Overview

„

Creating Serviced Components

„

Creating Component Classes

„

Creating Windows Forms Controls

„

Creating Web Forms User Controls

„

Threading

Como desarrolladores de Microsoft® Visual Basic®, seguramente ya sabemos cómo desarrollar y utilizar componentes en nuestras aplicaciones. En Visual Basic .NET, podemos utilizar las nuevas características en tiempo de diseño para crear fácilmente componentes y extender sus funcionalidades. En este módulo, aprenderemos a: „

Describir los distintos tipos de componentes que pueden crearse en Visual Basic .NET.

„

Crear componentes que pueden ser utilizados por aplicaciones cliente gestionadas y no gestionadas.

„

Crear componentes con servicio

„

Crear clases de componentes

„

Crear controles de formularios Windows® Forms.

„

Utilizar hilos para crear aplicaciones con múltiples hilos de ejecución.

1

2

Desarrollo de componentes en Visual Basic .NET

Descripción de los componentes Objetivo

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

„

Tipos de componentes

Presentación

„

Uso dé módulos como componentes

„

Uso de clases como componentes

„

Uso de componentes en aplicaciones cliente no gestionadas

„

Descripción de .NET Remoting

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.

Desarrollo de componentes en Visual Basic .NET

Tipos de componentes 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.

„

Estructuras

„

Módulos

„

Clases

„

Clases de componente

„

Componentes con servicio

„

Controles de usuario z

Controles de usuario de formularios Windows Forms

z

Controles de usuario de formularios Web Forms

En Visual Basic .NET, podemos crear varios tipos de componentes distintos, incluyendo: 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.

„

Estructuras

„

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.

3

4

Desarrollo de componentes en Visual Basic .NET

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

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

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

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

Desarrollo de componentes en Visual Basic .NET

Uso de módulos como componentes Objetivo

Explicar cómo utilizar módulos como componentes.

„

Declarar el módulo como público

Presentación

„

Referenciar e importa el ensamblado en código cliente

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

Public Public Module Module MyMathFunctions MyMathFunctions Public Public Function Function Square(ByVal Square(ByVal lng lng As As Integer) Integer) As As Long Long Return Return (lng (lng ** lng) lng) End Function End Function ... ... End End Module Module 'Client 'Client code code Imports Imports MyAssembly MyAssembly ... ... Dim Dim xx As As Long Long == Square(20) Square(20)

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

5

6

Desarrollo de componentes en Visual Basic .NET

Uso de clases como componentes Objetivo

Explicar cómo utilizar clases como componentes.

Presentación

En Visual Basic .NET, podemos utilizar clases como componentes.

„

Declarar la clase como pública

„

Referenciar e importar el ensamblado en código cliente

Public Public Class Class Account Account Public Public Sub Sub Debit(ByVal Debit(ByVal AccountId AccountId As As Long, Long, Amount Amount As As Double) Double) 'Perform 'Perform debit debit action action End End Sub Sub Public Public Sub Sub Credit(ByVal Credit(ByVal AccountId AccountId As As Long, Long, Amount Amount As As Double) Double) 'Perform 'Perform credit credit action action End End Sub Sub End End Class Class 'Client 'Client code code Imports Imports MyAssembly MyAssembly Dim Dim xx As As New New Account( Account( )) x.Debit(1021, x.Debit(1021, 1000) 1000)

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

Desarrollo de componentes en Visual Basic .NET

7

Uso de componentes en aplicaciones cliente no gestionadas Objetivo

Explicar cómo crear componentes que pueden ser utilizados por 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.

„

„

Setting assembly properties z

Generate a strong name

z

Select Register for COM Interop in Build options

Exposing class members to COM and Component Services z

Define and implement interfaces

z

Use the ClassInterface attribute with AutoDual value

z

Use the COMClass attribute

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

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

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

Una vez generado el archivo de claves, podemos agregarlo al proyecto y referenciarlo en AssemblyInfo.vb utilizando el siguiente código: <Ensamblado: AssemblyKeyFile("KeyFile.snk")>

De este modo, nuestro ensamblado tendrá un nombre seguro la próxima vez que lo generemos.

8

Desarrollo de componentes en Visual Basic .NET

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

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

Definiendo una interfaz pública

„

Utilizando el atributo ClassInterface

„

Utilizando el atributo COMClass.

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

Desarrollo de componentes en Visual Basic .NET

9

Uso del atributo ClassInterface El espacio de nombres System.Runtime.InteropServices proporciona el atributo ClassInterface. Este atributo permite crear una clase con una interfaz dual para que todos los miembros de la clase (y las clases base) estén accesibles automáticamente para aplicaciones cliente no gestionadas a través de COM. El siguiente código muestra cómo utilizar el atributo ClassInterface: Sugerencia

Compruebe que los estudiantes saben qué son los interfaces duales. Explíquelo brevemente si fuera necesario.

Imports System.Runtime.InteropServices _ 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. Precaución Los tres planteamientos pueden provocar problemas de versionado si las firmas de métodos públicos se modifican entre versiones. Por ello, la implementación de interfaces es la aproximación preferida, ya que pueden crearse nuevas interfaces con nuevas firmas de métodos sin causar dificultades de versionado.

10

Desarrollo de componentes en Visual Basic .NET

Descripción de .NET Remoting Objetivo

Cliente AppDomain

Ofrecer una descripción de .NET Remoting.

Servidor AppDomain

Marshal By Reference

Presentación

Código cliente

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

Formateador

Servidor Proxy

Formateador

Canal

Objeto servidor

Marshal By Value Código cliente Copia objeto servidor

Formateador

Canal

Canal

Límite de Remoting

Las versiones anteriores de Visual Basic utilizaban COM y la versión distribuida de COM (DCOM) para comunicarse con componentes en diferentes procesos o con distintos equipos. Visual Basic .NET utiliza .NET Remoting para permitir la comunicación entre aplicaciones cliente y servidor a través de dominios de aplicaciones. El .NET Framework proporciona varios servicios que se utilizan en remoto: „

Los canales de comunicación son los responsables de transportar los mensajes a y desde aplicaciones remotas utilizando tanto un formato binario sobre un canal Transmission Control Protocol (TCP) como Extensible Markup Language (XML) sobre un canal Hypertext Transfer Protocol (HTTP).

„

Formateadores que codifican y decodifican mensajes antes de que sean transportados por el canal.

„

Objetos proxy que envían las invocaciones de métodos remotos al objeto adecuado.

„

Soporte para la activación remota de objetos y para la duración de objetos marshal-by-reference que se ejecutan en el servidor.

„

Objetos marshal-by-value que son copiados por el .NET Framework en el espacio del proceso en el cliente para reducir viajes de ida y vuelta entre procesos o entre equipos.

Nota Si deseamos obtener más información sobre .NET Remoting, consultar “Microsoft .NET Remoting: introducción técnica” en la documentación de Microsoft Visual Studio® .NET.

Desarrollo de componentes en Visual Basic .NET

11

Creación de componentes con servicio Objetivo

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

„

Hospedar componentes en Component Services

Presentación

„

Uso de transacciones

„

Uso del pooling de objetos

„

Uso de cadenas de constructor

„

Uso de seguridad

„

Uso de otros Component Services

„

configuración de ensamblados para Component Services

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.

12

Desarrollo de componentes en Visual Basic .NET

Hospedar componentes en los servicios de componentes 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.

„

Agregar una referencia a System.EnterpriseServices en el ensamblado

„

El espacio de nombres System.EnterpriseServices proporciona: z

Clase ContextUtil

z

Clase ServicedComponent

z

Atributos de ensamblado, clase y método

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

Uso

Clase ContextUtil

Esta clase se utiliza para participar en transacciones y para interactuar con información de seguridad. La funcionalidad de esta clase es similar a la funcionalidad de la clase ObjectContext en Visual Basic 6.0.

Clase Todas las clases de componentes que necesitan ser hospedadas en ServicedComponent una aplicación de servicios de componentes deben heredar de esta clase. Esta clase define el tipo base para todos los tipos enlazados a contexto e implementa métodos similares a los que se encuentran en la interfaz IObjectControl utilizada en las aplicaciones de servicios de componentes basadas en Visual Basic 6.0. Atributos de 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.

Desarrollo de componentes en Visual Basic .NET

13

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

14

Desarrollo de componentes en Visual Basic .NET

Uso de transacciones Objetivo

Examinar cómo los componentes pueden 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.

„

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

Public Public Class Class Account Account Inherits Inherits ServicedComponent ServicedComponent Public Public Sub Sub Debit(...) Debit(...) 'Perform 'Perform debit debit action action ContextUtil.SetComplete( ContextUtil.SetComplete( )) End End Sub Sub )> Public Public Sub Sub Credit(...) Credit(...) 'Perform 'Perform credit credit action action 'No 'No SetComplete SetComplete because because AutoComplete AutoComplete is is on on End End Sub Sub End Class End Class

Con frecuencia, se requieren transacciones para mantener la integridad de los datos y sincronizar actualizaciones de datos entre múltiples fuentes de datos. Podemos habilitar el procesamiento de transacciones en los componentes con servicio incluyendo las clases y atributos adecuados en el código de nuestro componente.

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

Efecto

Disabled

La instancia de clase no utilizará transacciones e ignorará las transacciones de objetos padre.

NotSupported

La instancia de clase no se creará en el contexto de una transacción.

Required

La instancia de clase se incluirá en una transacción existente proporcionada por el contexto del objeto que realiza la llamada. Si no existe ninguna transacción, se creará una.

RequiresNew

La instancia de clase siempre creará una nueva transacción con independencia de las transacciones ya creadas por objetos que realizan las llamadas.

Supported

La instancia de clase se incluirá en una transacción si la proporciona el contexto del objeto que realiza la llamada, pero no creará una transacción si no existe ya una.

Desarrollo de componentes en Visual Basic .NET

15

Uso del atributo Transaction El siguiente ejemplo define una clase Account y establece el atributo Transaction a Required. Imports System.EnterpriseServices Public Class Account Inherits ServicedComponent Public Sub Debit(ByVal id As Integer, _ ByVal amount As Double) 'Debit code End Sub End Class

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

Utilice este método para:

SetAbort

Votar por la anulación de una transacción. La transacción sólo puede tener éxito si todos los objetos implicados en la transacción votan satisfactoriamente por unanimidad. Este método también permite que el objeto sea desactivado después de que la llamada al método finalice.

SetComplete

Votar por la confirmación de una transacción. Si todos los objetos implicados en la transacción votan con éxito, la transacción puede completarse. Este método también permite que el objeto sea desactivado después de que la llamada al método finalice.

EnableCommit

Votar por una finalización exitosa de la transacción, no permitiendo al objeto ser desactivado después de que la llamada al método finalice. Esta opción resulta útil si deseamos mantener el estado a través de múltiples llamadas a métodos, pero no necesitamos más acciones para finalizar con éxito la transacción si así lo solicita el componente de servicio de nivel superior.

DisableCommit

Votar por una finalización no exitosa de la transacción, no permitiendo al objeto ser desactivado después de que la llamada al método finalice. Esta opción resulta útil si deseamos mantener el estado a través de múltiples llamadas a métodos y necesitamos que ocurran otras acciones antes de que la transacción pueda finalizar con éxito.

16

Desarrollo de componentes en Visual Basic .NET

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

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

Uso del atributo AutoComplete El siguiente ejemplo muestra cómo utilizar el atributo AutoComplete: Public Sub Credit( _ ByVal fromAccount As Integer, ByVal amount As Double) 'Perform update to database ... 'No SetComplete or SetAbort is required End Sub

Desarrollo de componentes en Visual Basic .NET

17

Uso de la agrupación de objetos Objetivo

Examinar cómo los componentes pueden utilizar 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

Presentación

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

MaxPoolSize:=50)> __ Public Public Class Class Account Account Inherits Inherits ServicedComponent ServicedComponent ... ... Protected Protected Overrides Overrides Function Function CanBePooled( CanBePooled( )) As As Boolean Boolean Return True Return True End End Function Function End Class End Class

En Visual Basic .NET, podemos utilizar el atributo ObjectPooling y la clase base ServicedComponent para crear componentes con servicio que utilicen la agrupación de objetos.

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

18

Desarrollo de componentes en Visual Basic .NET

Habilitar la agrupación de objetos Especificamos el atributo ObjectPooling para que los servicios de componentes puedan ubicar el componente en una agrupación de objetos. También podemos especificar argumentos opcionales del atributo para establecer los valores MinPoolSize y MaxPoolSize de la agrupación. „

MinPoolSize Utilizamos el argumento MinPoolSize para establecer el número mínimo de objetos que se crearán con antelación en la agrupación.

„

MaxPoolSize Utilizamos el argumento MaxPoolSize para establecer el número máximo de objetos que pueden crearse en la agrupación. • Si no hay objetos disponibles en la agrupación cuando se recibe una petición, la agrupación puede crear otra instancia del objeto si ese número máximo de objetos preestablecido no se ha alcanzado ya. • Si ya se han creado el número máximo de objetos y actualmente no hay ninguno disponible, las peticiones se encolarán hasta el próximo objeto disponible.

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

True Si el componente soporta la agrupación de objetos y puede devolverse de forma segura a la agrupación, el método CanBePooled debería devolver True.

„

False Si el componente no soporta la agrupación de objetos, o si la instancia actual no puede devolverse a la agrupación, el método CanBePooled debería devolver False.

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

Desarrollo de componentes en Visual Basic .NET

19

Uso del método CanBePooled El siguiente ejemplo muestra cómo crear una agrupación de objetos para el objeto Account con un número mínimo de cinco objetos y un máximo de 50 en un momento dado. El método CanBePooled devuelve True para informar a los servicios de componentes de que el objeto puede devolverse a la agrupación. Public Class Account Inherits ServicedComponent Public Sub Debit(ByVal id As Integer, _ ByVal amount As Double) ... End Sub Protected Overrides Function CanBePooled( ) As Boolean Return True End Function End Class

20

Desarrollo de componentes en Visual Basic .NET

Uso de las cadenas de constructor Objetivo

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

„

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

Presentación

„

Reemplazan el método Construct para recuperar informació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.

Public Public Class Class Account Account Inherits Inherits ServicedComponent ServicedComponent Protected Protected Overrides Overrides Sub Sub Construct(ByVal Construct(ByVal ss As As String) String) ''Called Called after after class class constructor constructor ''Use Use passed passed in in string string End Sub End Sub End End Class Class

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

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

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

Desarrollo de componentes en Visual Basic .NET 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

21

22

Desarrollo de componentes en Visual Basic .NET

Uso de seguridad 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.

„

Security configuration attributes enable security and role configuration

„

SecurityCallContext class provides role checking and caller information

SecurityRole("Manager")> __ Public Public Class Class Account Account Inherits Inherits ServicedComponent ServicedComponent Public Public Function Function GetDetails( GetDetails( )) As As String String With With SecurityCallContext.CurrentCall SecurityCallContext.CurrentCall If If .IsCallerInRole("Manager") .IsCallerInRole("Manager") Then Then Return Return .OriginalCaller.AccountName .OriginalCaller.AccountName End End If If End End With With End End Function Function End End Class Class

Cuando se trabaja con componentes con servicio, se pueden utilizar atributos y objetos predefinidos para configurar y probar las opciones de seguridad.

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

Uso

ApplicationAccessControl

Este atributo a nivel de ensamblado se utiliza para habilitar o deshabilitar explícitamente la comprobación de acceso a nivel de aplicación.

ComponentAccessControl

Este atributo a nivel de componente se utiliza para habilitar o deshabilitar explícitamente la comprobación de acceso a nivel de componente.

SecurityRole

Este atributo a nivel de ensamblado se utiliza para agregar un rol a la aplicación. Este atributo se utiliza a nivel de componente para agregar un rol a la aplicación y enlazarla al componente concreto.

Desarrollo de componentes en Visual Basic .NET

23

Establecer opciones de seguridad El siguiente ejemplo muestra cómo establecer el atributo ApplicationAccessControl a nivel de ensamblado, habilitar la seguridad para el componente Account, y crear el rol Manager, que se enlazará al componente Account: _ Public Class Account Inherits ServicedComponent ... End Class

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

Uso

Propiedad DirectCaller

Recupera información sobre el último usuario o aplicación de la cadena de llamadores que directamente invocó un método. La propiedad devuelve una instancia de la clase SecurityIdentity que podemos utilizar para determinar información sobre la identidad, como AccountName.

Propiedad OriginalCaller

Recupera información sobre el primer usuario o aplicación de la cadena de llamadores que hizo la petición original de la acción requerida. La propiedad también devuelve una instancia de la clase SecurityIdentity.

Método IsCallerInRole

Verifica si un llamador forma parte de un rol en particular; devuelve un valor Boolean.

Método IsUserInRole

Verifica si el usuario forma parte de un rol en particular; devuelve un valor Boolean.

24

Desarrollo de componentes en Visual Basic .NET

Uso de la clase SecurityCallContext El siguiente ejemplo muestra cómo utilizar SecurityCallContext para determinar si la seguridad está habilitada, comprobar si un llamador pertenece al rol Manager y devolver la cadena AccountName desde la propiedad OriginalCaller, que es una instancia SecurityIdentity. _ Public Class Account Inherits ServicedComponent Public Function GetDetails( ) As String If ContextUtil.IsSecurityEnabled Then With SecurityCallContext.CurrentCall If .IsCallerInRole("Manager") Then Return .OriginalCaller.AccountName End If End With End If End Function End Class

Desarrollo de componentes en Visual Basic .NET

25

Uso de otros servicios de componentes Objetivo

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

Presentación

Los servicios de componentes proporcionan otros servicios que podemos utilizar en componentes Visual Basic .NET.

„

Otros servicios de componentes incluyen: z

Activación Just-in-time

z

Componentes en cola

z

Propiedades compartidas

z

Sincronización

Hay otros servicios de componentes que podemos utilizar desde componentes de Visual Basic .NET.

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

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

26

Desarrollo de componentes en Visual Basic .NET

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

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

Desarrollo de componentes en Visual Basic .NET

27

Configurar ensamblados para usar los servicios de componentes Objetivo

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

„

Setting assembly attributes

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.

„

z

ApplicationName

z

Description

z

ApplicationActivation: library or server application

z

AssemblyKeyFile

Using Regsvcs to register and create Component Services applications z

„

Regsvcs.exe myApplication.dll

Using Lazy Registration z

Application registered on first use by client

Podemos especificar algunos atributos a nivel de ensamblado que proporcionan información cuando nuestro ensamblado se instala como una aplicación de servicios de componentes. La información se almacena en el archivo AssemblyInfo.vb que forma parte de nuestro proyecto en Visual Basic .NET. Atributo de 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).

28

Desarrollo de componentes en Visual Basic .NET
ApplicationName("BankComponent") rel="nofollow"> Description("VB .NET Bank Component")> ApplicationActivation(ActivationOption.Server)> AssemblyKeyFile("KeyFile.snk")>

Registro del ensamblado Podemos registrar nuestro ensamblado con los servicios de componentes de modo manual o automático. „

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

„

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

Desarrollo de componentes en Visual Basic .NET

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.

29

30

Desarrollo de componentes en Visual Basic .NET

4. En la ventana de comandos, escribir Regsvcs.exe y arrastrar el archivo ObjectPoolingComponent.dll desde Windows Explorer a la línea de comandos. 5. Ejecutar el comando. Debería aparecer un mensaje indicando que el registro se ha realizado satisfactoriamente.

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

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

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

Importante Si ha ejecutado esta demostración con anterioridad en el mismo equipo, es posible que el componente con servicio ya esté instalado. Elimine la aplicación Object Pooling de la consola de Servicios de Componentes antes de ejecutar de nuevo esta demostración.

Desarrollo de componentes en Visual Basic .NET

Creación de clases de componentes Objetivo

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

„

Arquitectura de una clase de componentes

Presentación

„

Creación de una clase de componentes

Esta lección examina las clases de componentes.

En esta lección, aprenderemos a: „

Describir la arquitectura de una clase de componentes.

„

Crear una clase de componentes.

31

32

Desarrollo de componentes en Visual Basic .NET

Arquitectura de una clase de componentes Objetivo

Describir la arquitectura de una clase de componentes.

Presentación

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

se System.ComponentModel.Component a l C se ba Interfaz IComponent

es s as vada l C ri de

Clases de componentes Clases predefinidas Clases personalizadas

Además de soportar clases y estructuras, el espacio de nombres System proporciona una biblioteca de componentes diseñados para facilitar el desarrollo de componentes. Cuando creamos una clase de componentes basada en la clase base ComponentModel.Component, automáticamente heredamos la arquitectura básica para nuestra clase.

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

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

Desarrollo de componentes en Visual Basic .NET

33

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

34

Desarrollo de componentes en Visual Basic .NET

Creación de una clase de componentes Objetivo

Explicar cómo crear una clase de componentes.

Presentación

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

1. Heredar de System.ComponentModel.Component z

Realizar las inicializaciones por parte del constructor

z

Sobrecargar el método Dispose

2. Agregar los componentes ubicados z

Utilizar elementos del Explorador de servidores o del cuadro de herramientas

3. Crear la funcionalidad requerida z

Propiedades, métodos y eventos

4. Generar el ensamblado

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

Desarrollo de componentes en Visual Basic .NET

35

El siguiente ejemplo muestra cómo crear una clase de componentes derivada de la clase System.ComponentModel.Components. Extiende la funcionalidad de la clase Timer estándar definiendo propiedades y eventos adicionales. Imports System.ComponentModel

Sugerencia

Comente que heredar de la clase Timer también produciría un componente similar.

Public Class Hourglass Inherits System.ComponentModel.Component 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

36

Desarrollo de componentes en Visual Basic .NET

Cuando examinemos el código, observaremos lo siguiente: „

El componente se comporta como un reloj de arena que provoca un evento Finished un minuto después de ser habilitado.

„

El componente puede ser activado utilizando la propiedad Enabled en tiempo de diseño o en tiempo de ejecución.

„

Se inicializa localTimer como parte del constructor Sub New y se establece para un intervalo temporizador de 60.000 milisegundos, o un minuto.

„

El método Dispose se sobrecarga para garantizar que el objeto localTimer se elimina de forma segura.

Desarrollo de componentes en Visual Basic .NET

37

Demostración: Creación de un componente Stopwatch Objetivo

Mostrar cómo crear y utilizar una clase de componentes.

Presentación

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

En esta demostración, aprenderemos cómo crear una clase de componentes que pueda ser utilizada por otro ensamblado.

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

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

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.

5. Agregar una referencia para el ensamblado System.Drawing.dll. 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.

38

Desarrollo de componentes en Visual Basic .NET

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

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

Importante Si ha ejecutado antes esta demostración en el mismo equipo, es posible que el componente Stopwatch ya esté disponible en el Cuadro de herramientas. Para asegurarse de que la demostración funciona correctamente, restablezca el Cuadro de herramientas mediante el cuadro de diálogo Personalizar cuadro de herramientas.

Desarrollo de componentes en Visual Basic .NET

39

Creación de controles de formularios Windows Forms Objetivo

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

„

Heredar de la clase UserControl

Presentación

„

Heredar de un control de formularios Windows Forms

„

Proporcionar atributos de controles

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.

40

Desarrollo de componentes en Visual Basic .NET

Heredar de la clase UserControl Objetivo

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

„

Heredar de System.Windows.Forms.UserControl

Presentación

„

Agregar los controles necesarios al diseñador

„

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

„

Agregar propiedades y métodos adicionales

„

No InitProperties, ReadProperties ni WriteProperties

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.

z

El almacenamiento de propiedades es automático

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

Agregar los controles necesarios En Visual Basic .NET, podemos crear el mismo tipo de controles de usuario si heredamos nuestro control de la clase System.Windows.Forms.UserControl, lo que resulta automático si creamos un control utilizando el elemento de plantilla User Control. Podemos heredar de esta clase base para utilizar un diseñador similar al utilizado en versiones anteriores de Visual Basic. Utilizando este método, podemos: „

Colocar tantos controles en el diseñador como sea necesario para crear nuestro propio control de usuario.

„

Acceder a estos controles desde nuestra clase de control de usuario, ya que están declarados como variables privadas.

„

Agregar nuestras propias propiedades y métodos que correspondan a las propiedades y métodos de los controles constituyentes.

„

Añadir propiedades, métodos y eventos públicos exactamente del mismo modo en que lo hacemos para una clase convencional.

Agregar propiedades y métodos En versiones anteriores de Visual Basic, hacemos que las propiedades sean persistentes con un objeto PropertyBag, de modo que el control conserva su configuración entre tiempo de diseño y tiempo de ejecución. Para ello,

Desarrollo de componentes en Visual Basic .NET

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.

41

42

Desarrollo de componentes en Visual Basic .NET

Heredar de un control existente Windows Form Objetivo

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

„

Permite mejorar la versión de un único control

Presentación

„

Heredar de un control System.Windows.Forms

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

Public Public Class Class MyTextBox MyTextBox Inherits Inherits System.Windows.Forms.TextBox System.Windows.Forms.TextBox Private Private strData strData As As String String Public Property HiddenData( Public Property HiddenData( )) As As String String Get Get Return Return strData strData End End Get Get Set(ByVal Set(ByVal Value Value As As String) String) strData strData == Value Value End End Set Set End End Property Property ... ... End End Class Class

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

Desarrollo de componentes en Visual Basic .NET

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

Nota Para algunos controles existentes, podemos crear un nuevo interfaz gráfico sobrecargando el método OnPaint de la clase base. Sin embargo, algunos controles, como el control TextBox, son pintados directamente por Windows y no pueden ser sobrecargados.

43

44

Desarrollo de componentes en Visual Basic .NET

Proporcionar atributos a los controles Objetivo

„

System.ComponentModel proprociona atributos a los controles

Presentación

„

A nivel de clase: DefaultProperty, DefaultEvent, ToolboxBitmap

„

A nivel de propiedad: Category, Description, DefaultValue

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

Imports Imports System.ComponentModel System.ComponentModel DefaultEvent("Click")> __ Public Public Class Class MyTextBox MyTextBox Inherits Inherits System.Windows.Forms.UserControl System.Windows.Forms.UserControl DefaultValue("Empty")> __ Public Public Property Property HiddenData( HiddenData( )) As As String String ... ... End End Property Property ... ... End End Class Class

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

Establecer atributos a nivel de clase Podemos especificar varios atributos para el control, incluyendo DefaultProperty, DefaultEvent y ToolboxBitmap. El siguiente ejemplo muestra cómo establecer los atributos ToolboxBitmap y DefaultEvent para la clase MyTextBox: _ Public Class MyTextBox Inherits System.Windows.Forms.UserControl ... End Class

Desarrollo de componentes en Visual Basic .NET

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 _ Public Property HiddenData( ) As String ... End Property ... End Class

45

46

Desarrollo de componentes en Visual Basic .NET

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

Mostrar cómo crear un control basado en otro control existente de un formulario Windows Forms.

Presentación

En esta demostración, estudiaremos cómo crear un control basado en el control TextBox de Windows Forms.

En esta demostración, estudiaremos cómo crear un control de usuario de Windows Forms basado en el control TextBox existente.

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

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

Desarrollo de componentes en Visual Basic .NET

47

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

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

Valor de texto

TextBox

One

MyTextBox

One

TextBox

Two

MyTextBox

Two

TextBox

Three

MyTextBox

Three

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

48

Desarrollo de componentes en Visual Basic .NET

Manejo de hilos de ejecución Objetivo

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

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.

„

¿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

Las versiones anteriores de Visual Basic tienen un limitado soporte de manejo de hilos (threads) de ejecución. Visual Basic .NET permite a los desarrolladores utilizar todas la potencia de los hilos cuando es necesario. Si manejamos los hilos de ejecución correctamente, podemos mejorar el rendimiento de nuestra aplicación y hacerla mucho más interactiva. En esta lección, aprenderemos a: „

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

„

Conocer las ventajas de incorporar múltiples hilos a nuestras aplicaciones.

„

Crear y utilizar hilos utilizando el espacio de nombres System.Threading.

„

Evitar algunos problemas potenciales en nuestras aplicaciones que usen múltiples hilos de ejecución.

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

Desarrollo de componentes en Visual Basic .NET

49

¿Qué es un hilo? Objetivo

Explicar los conceptos 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.

„

La unidad de ejecución que procesa la CPU z

„

Todos los procesos de una aplicación contienen al menos un subproceso

Los subprocesos están programados z z

Parece que el equipo realiza varias tareas a la vez Cada subproceso contiene su propia pila de llamadas y almacenamiento

Proceso 1 Proceso 2

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

Programador de subprocesos Subproc.1 Subproc. 321 CPU Subproc. 2 Subproc. 3

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.

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.

50

Desarrollo de componentes en Visual Basic .NET

Tipos de hilos Cada lenguaje de programación puede soportar un tipo de hilo distinto: „

Las versiones anteriores de Visual Basic soportan el modelo de hilos apartamento (apartment). Este modelo impone algunas restricciones en los tipos de aplicaciones que estas versiones pueden crear. Una de estas restricciones es que un objeto está ligado al hilo en el que está creado, y no puede utilizarse con la agrupación de objetos en los servicios de componentes. Sin embargo, este modelo facilita el desarrollo, ya que nos evita tratar con aspectos más complejos como la sincronización.

„

Visual Basic .NET soporta el modelo de hilos libre (free). Este modelo permite utilizar múltiples hilos de ejecución y características como la agrupación de objetos o continuar utilizando un único hilo como en las aplicaciones creadas con las versiones anteriores de Visual Basic.

Desarrollo de componentes en Visual Basic .NET

51

Ventajas de múltiples hilos de ejecución Objetivo

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

„

Mejor respuesta de la interfaz de usuario z

Presentación

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

Ejemplo: barra de estado

„

Sin bloqueos

„

Comunicación asíncrona

„

Sin afinidad de hilos z

Los objetos no están vinculados a un hilo

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

Mejor respuesta de la interfaz de usuario Podemos utilizar múltiples hilos en un único proceso para mejorar la respuesta de la interfaz de usuario. Por ejemplo: „

Use hilos para operaciones lentas de procesamiento, como el uso del corrector ortográfico o el reformateo de páginas. Estos hilos adicionales pueden disparar eventos al hilo de la interfaz de usuario principal para actualizar elementos como una barra de estado.

„

Asignar a cada hilo un nivel de prioridad de modo que hilos específicos puedan ejecutarse con mayor prioridad que otros hilos de menor prioridad. En una aplicación que se basa en la interacción del usuario, deberíamos ejecutar el hilo de la interfaz de usuario con un hilo de mayor prioridad.

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

52

Desarrollo de componentes en Visual Basic .NET

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

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

Desarrollo de componentes en Visual Basic .NET

53

Creación de hilos Objetivo

Explicar cómo crear y utilizar hilos.

„

Presentación

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

Uso de la clase System.Threading.Thread z

El constructor especifica el método delegado

z

Los métodos proporcionan control del procesamiento de hilos

z

Las propiedades proporcionan información de estado y prioridades

Utilizar una clase si se requieren parámetros z

Permitir acceso público a variables clase

z

Lanzar un evento cuando finalice

El .NET Framework proporciona un modo sencillo de crear y trabajar con múltiples hilos.

Uso de la clase System.Threading.Thread Sugerencia

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

Usar la clase Thread para crear múltiples hilos dentro de una aplicación basada en Visual Basic .NET.

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

54

Desarrollo de componentes en Visual Basic .NET

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

Utilidad

Start

Comienza la ejecución del método delegado declarado en el constructor del hilo.

Abort

Finaliza explícitamente un hilo de ejecución.

Sleep

Pausa un hilo. Como único parámetro, especifica el número de milisegundos. Si pasamos cero como parámetro, el hilo ofrece el resto de su porción de tiempo actual. Esto es similar a DoEvents en versiones anteriores de Visual Basic.

Suspend

Interrumpe temporalmente la ejecución de un hilo.

Resume

Reactiva un hilo temporalmente interrumpido.

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

Utilidad

ThreadState

Usar la propiedad ThreadState para determinar el estado actual de un hilo, como Running, Suspended o Aborted.

Priority

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

Aviso Si establecemos las prioridades de un hilo a un valor Highest, podemos afectar a otros procesos vitales del sistema reduciéndoles ciclos de CPU. Utilizar esta configuración con extrema precaución.

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

Desarrollo de componentes en Visual Basic .NET

55

Uso de clases para proporcionar parámetros Sugerencia

El siguiente tema, Uso de hilos, muestra un ejemplo de este planteamiento.

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: „

Usar clases para proporcionar métodos que realicen operaciones sobre datos locales

„

Usar propiedades públicas o variables para suministrar los datos locales.

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

56

Desarrollo de componentes en Visual Basic .NET

Uso de hilos Objetivo

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

Explicar un ejemplo sencillo del manejo de hilos.

Presentación

Un vistazo a un ejemplo sencillo de manejo de hilos.

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

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

Preparar una clase para el manejo de hilos El siguiente ejemplo muestra cómo crear una clase Calculate y prepararla para el manejo de hilos utilizando el evento Complete: Class Calculate Public iValue As Integer Public Event Complete(ByVal Result As Integer) Public Sub LongCalculation( ) 'Perform a long calculation based on iValue ... RaiseEvent Complete(iResult)'Raise event to signal finish End Sub End Class

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

La clase proporciona una función LongCalculation, que se ejecutará en un hilo separado.

„

La función utiliza información almacenada en la variable pública entera iValue para calcular su resultado.

„

La clase Calculate proporciona un evento Complete para notificar al hilo que realiza la llamada que el cálculo ha finalizado.

Desarrollo de componentes en Visual Basic .NET

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.

57

58

Desarrollo de componentes en Visual Basic .NET

Cuándo utilizar el manejo de hilos Objetivo

„

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

Utilizar los subprocesos con precaución z

„

Presentación

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

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

Sincronizar el acceso a recursos compartidos z

z

Evitar que dos subprocesos accedan simultáneamente a datos compartidos Utilizar la instrucción SyncLock para bloquear secciones de código

Sub Sub Worker( Worker( )) SyncLock(theData) 'Lock SyncLock(theData) 'Lock this this object object variable variable theData.id theData.id == iValue iValue 'Perform 'Perform some some lengthy lengthy action action iValue iValue == theData.id theData.id End SyncLock 'Unlock End SyncLock 'Unlock the the object object variable variable End Sub End Sub

Sugerencia

Apunte que el uso incorrecto de los hilos puede tener serias consecuencias.

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.

Recursos del sistema Los hilos consumen memoria y otros recursos valiosos, como tiempo de proceso de la CPU. Si nuestra aplicación crea múltiples hilos, puede hacerlo a expensas de otras aplicaciones u otros hilos dentro de nuestro propio proceso. Cuantos más hilos creemos, mayor será el retardo entre las porciones de tiempo de CPU para cada hilo. Si todas las aplicaciones creasen un número excesivo de hilos y los utilizasen constantemente, el sistema dedicaría la mayor parte de su tiempo intercambiando hilos en la CPU, puesto que el propio planificador de hilos requiere que la CPU se encargue de la lógica de intercambio.

Recursos compartidos Si múltiples hilos necesitan acceder a la misma información al mismo tiempo, puede producirse un problema de concurrencia. Dos hilos accediendo a un recurso global compartido pueden generar resultados inconsistentes si otros hilos han alterado los datos. He aquí un ejemplo de una situación en la que esto puede suceder: „

El hilo A actualiza un valor en un recurso compartido como un entero, estableciendo el valor a 10 antes de realizar alguna acción de larga duración.

„

El hilo B actualiza el mismo valor entero a 15 durante la duración de la acción de larga duración del hilo A.

„

Cuando se completa esta acción, el hilo A puede leer de nuevo el valor entero del recurso cuyo valor es ahora 15.

Desarrollo de componentes en Visual Basic .NET

59

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

60

Desarrollo de componentes en Visual Basic .NET Imports System.Threading 'Shared data Public Class SharedReference Public Id As Integer End Class 'Class for running on other threads Public Class ThreadObj Private sr As SharedReference Private Count As Integer 'Constructor with reference and Id Public Sub New(ByRef sharedRef As SharedReference, ByVal ID As Integer) sr = sharedRef Count = ID End Sub

_

'Actual worker method Public Sub RunMethod( ) SyncLock (sr) 'Lock sr object sr.Id = Count 'Execute lengthy code 'sr.Id could have changed without SyncLock Count = sr.Id End SyncLock 'Release sr object lock End Sub End Class Module MainModule Sub Main( ) 'Create shared data object Dim sr As New SharedReference( ) 'Create two worker objects Dim worker1 As New ThreadObj(sr, 1) Dim worker2 As New ThreadObj(sr, 2) 'Create two threads Dim t1 As New Thread(AddressOf worker1.RunMethod) Dim t2 As New Thread(AddressOf worker2.RunMethod) 'Start both threads t1.Start( ) t2.Start( ) End Sub End Module

Desarrollo de componentes en Visual Basic .NET

61

Demostración: Uso de la instrucción SyncLock Objetivo

Mostrar cómo sincronizar recursos compartidos usando la sentencia SyncLock.

Presentación

Esta demostración muestra cómo utilizar la sentencia SyncLock para sincronizar un recurso compartido.

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.

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.

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

Related Documents