Creando un User Control con VB.NET 2005

domingo, 6 de julio de 2008

Actualmente estoy mejorando una aplicación de escritorio que hice para los chicos de las materias de Contabilidad I y II de las carreras de Contaduaría y Administración. Esta aplicación usa una ventana para crear asientos de diario, creando y quitando registros, cuentas y asientos. Al final, con un solo clic generan los esquemas de mayor, balanza de comprobación, balance general y rayado diario y se exportan a Excel. Pues durante el upgrade me encontré nuevamente con la dificultad de dar al usuario la facilidad de agregar y quitar registros visualmente, porque en la primera versión estuve modificando manualmente todos los tamaños y posiciones de decenas de controles que tenía en la ventana de trabajo. Lo que hice en esta segunda versión fue diseñar un control personalizado (User Control) llamado ControlAsiento.vb que contiene a otro User Control llamado ControlRegistro.vb, los cuales me facilitaron la vida.
Para este pequeño tutorial estaremos consider
ando Visual Studio 2005, usando VB.

¿Qué es un UserContr
ol y para qué sirve?
Un User Control no es más que una clase común .vb que también provee las referencias para poder trabajar con las clases dentro del espacio de nombres System.Windows.Forms, a diferencia de los Class Library, que es buen tema para otro post. Con los User Control podemos crear controles más complejos o avanzados derivados de los controles que ya nos proporciona el IDE, tal como veremos más adelante con un ejemplo. Aquí les muestro paso a paso cómo crearlos y usarlos. En el siguiente ejemplo haremos una pequeñísima parte de lo que tuve que hacer para la aplicación que estaba desarrollando, esto es poder generar en tiempo de ejecución nuevas instanacias de los controles que vamos a diseñar y programar.



¿Cómo se hace?

1. Después de abrir el IDE de Microsoft Visual Studio 2005 y empleando el lenguaje Visual Basic, creamos una nueva Aplicación de Windows como comunmente. Yo he llamado "Ejemplo1" a mi proyecto.




2. Cuando se crea nuestro proyecto nos presenta un nuevo formulario vació para comenzar a trabajar. Pues bien, lo que haremos será agregar un
User Control a nuestra aplicación. En el explorador de soluciones (Solution Explorer) desplegaremos con un clic derecho sobre el nombre de nuestra aplicación una ventana emergente donde seleccionaremos la opción Add > User Control.


3. Nota que al abrir la ventana de diálogo está seleccionado el tipo de control User Control. Le daremos un nombre a nuestro nuevo control, en nuestro caso será ControlRegistro.vb. Este será el control de más bajo nivel, es decir, el último que solo contendrá a controles predefinidos por Visual Studio.





4. Podremos ver un nuevo lienzo que no contiene barras de título ni bordes, en el cual comenzaremos a diseñar nuestro control.





5. Para el ejemplo solo programaremos un botón en cada
User Control, aunque esto vendrá después de haber diseñado todo lo demás.






6. Habiendo temrinado con el diseño de ControlRegistro, crearemos
entonces ControlAsiento, que contendrá una cantidad indeterminada de registros. Para esto procederemos de la misma forma en la que creamos ControlRegistro. En el explorador de la solución (Solution Explorer) desplegaremos con un clic derecho sobre el nombre de nuestra aplicación una ventana emergente en la que seleccionaremos la opción Add > User Control y lo nombramos ControlAsiento.vb, y procederemos a hacer el diseño de la interfaz. Para esta interfaz necesitaremos agregar al menos un control del tipo ControlRegistro que hemos creado, sin embargo no podremos acceder a este control en la Caja de herramientas mientras no hayamos reconstruido la aplicación para que las modificaciones en ControlRegistro tomen efecto en los lugares en los cuales se haya usado. Hasta ahora no lo hemos usado y para esto también necesitaremos reconstruir. Seleccionamos en el menú principal Build > Rebuild Ejemplo1.





7. ControlAsiento tendrá el siguiente aspecto.








8. Al temrinar el diseño debemos reconstruir nuevamente la aplicación de la forma que ya hemos mencionado, entonces podremos ver nuestro control en la caja de herramientas.




9. Finalmente tendremos el siguiente aspecto en nuestro formulario principal Form1.












Pues bien, ya hemos diseñado nuestros controles, solo falta darles vida, para esto pondremos fragmentos de código en ControlRegistro, ControlAsiento y Form1.

*** Form1 ***

Public Class Form1
Dim asiento As ControlAsiento

Sub crearAsiento(ByVal asientoAnterior As ControlAsiento)
' Calculamos la posición del nuevo asiento a partir del asiento anterior, el cual hizo la llamada
' y agregamos el nuevo ControlAsiento al formulario
asiento = New ControlAsiento
asiento.Location = New Point(asientoAnterior.Location.X, asientoAnterior.Location.X + asientoAnterior.Height + 5)
asiento.Label1.Text = asientoAnterior.Label1.Text + 1
With GroupBox1
.Size = New Size(.Width, .Height + asientoAnterior.Height + 5)
.Controls.Add(asiento)
End With
End Sub
End Class

*** ControlAsiento ***
Public Class ControlAsiento
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' Llamamos al método crearAsiento() del formulario que contiene a este asiento.
CType(Me.FindForm, Form1).crearAsiento(Me)
End Sub

Private Sub ControlAsiento_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Es solo un ejemplo de cómo se puede agregar un manejador de eventos a un control,
' ya que en micaso he usado mucho este tipo de manejadores al momento de crear controles dinámicamente
' y tener varias formas de acceder a un mismo evento
AddHandler Button1.Click, AddressOf Button1_Click
End Sub

Sub crearRegistro(ByVal sender As ControlRegistro)
Dim reg As New ControlRegistro
' La separación que agregaremos a la posición del registro y demás controles, y la cantidad que agregaremos al tamaño del GroupBox1
Dim y = sender.Height + 3
reg.Location = New Point(sender.Location.X, sender.Location.Y + y)
' Bajamos también la caja de texto multilinea y los botones del ControlAsiento
redaccion.Location = New Point(redaccion.Location.X, redaccion.Location.Y + y)
Button1.Location = New Point(Button1.Location.X, Button1.Location.Y + y)
Button2.Location = New Point(Button2.Location.X, Button2.Location.Y + y)
' Con Me.ParentForm obtenemos el formuylario que contiene a este control y lo convertimos al tipo Form1, que es la clase que tenemos
With CType(Me.ParentForm, Form1).GroupBox1
.Size = New Size(.Width, .Height + y)
End With
' Agregamos el nuevo control al contenedor correspondiente, en este caso ControlAsiento que contiene al botón que hemos presionado
Me.Controls.Add(reg)
End Sub
End Class

*** ControlRegistro ***
Public Class ControlRegistro
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' Obtenemos el ControlAsiento que contiene a este ControlRegistro
Dim asiento As ControlAsiento = Me.Parent
' Llamamos a la subrutina que hicimos en ControlAsiento para generar nuevos registros
asiento.crearRegistro(Me)
End Sub
End Class
He resaltado en negritas algunas funciones que son de mucha utilidad para poder acceder a los controles que contienen a nuestros
User Control, y así poder usar propiedades y métodos de estos.
Lo que el código anterior hará será generar un nuevo asiento debajo del asiento que contiene al botón '+' en donde se hizo clic. Y generará un nuevo registro debajo del registro en el que se encuentra el botón '+' en el que se hizo clic.


Como hemos visto, podemos usar
User Control no solo para aquellos casos en los que tendremos que usar un control complejo en varias partes de nuestra aplicación, sino también en casos en los que sea necesario crear dinámicamente algunos controles complejos sin necesidad de rompernos tanto la cabeza, como a mí me pasó.
Espero que les sirva de algo este breve tutorial.

8 comentarios:

Jose dijo...

Gracias, es exactamente lo que buscaba. Ejemplo claro y concreto. Felicidades. Ayudanos!!! sigue publicando articulos. Gracias.

Jesfre dijo...

@Jose, muchas gracias por tu comentario; aunque tenga poco tiempo entre la escuela y el trabajo, me anima a seguir publicando. Qué bueno que te haya sido de ayuda.

Anónimo dijo...

Tengo una consulta:

quiero hacer una especie de barra con un panel y tres botones, la idea es sobreescribir el evento click de cada uno de los botones en el formulario que contenga el control.
Lo he probado pero nunca me levanta el evento que puse en el form cotenedor sino que solo me levanta el evento click dentro del mismo control.
Como puedo hacer para sobreescribir los eventos click de los botones?

Saludos y gracias.

Jesfre dijo...

Te recomiendo que te inscribas y crees un nuevo tema en este foro donde podremos conversar mejor sobre este tema. Y espero que comentes mejor tu duda y copies tu código para poder entender lo que haces y así poder ayudarte pronto...

http://fit.um.edu.mx/foros/index.php?board=5.0

Jesfre dijo...

Entre otras cosas, creo necesitas explicar más detenidamente lo que necesitas y qué has hecho...

Tal vez esto te sirva... es para hacer overriding a eventos...
http://msdn.microsoft.com/en-us/library/aa290043(VS.71).aspx

Anónimo dijo...

hola jesfre, gracias por constestar.

Mira la idea es hacer un control con 3 botones, una especie de toolbar generica, que me sirva para varias paginas de un mismo sitio, es decir en lugar de estar copiando y pegando el panel y los tres botones, solo agregaria el control y programaria los eventos de los botones para cada pagina.
Pondria el codigo pero no me lo acepta el blogger, pero solo es un asp:panel con tres asp:linbutton.

Saludos, espero que me hayas entendido. Adrián.

Bunbury dijo...

me puede decir como cambiarle el icono a los User controls??

gracias de antemano

Jesfre dijo...

@Bunbury Lo que quieres hacer lo puedes encontrar en este sitio de M$:
http://support.microsoft.com/kb/311315/es

Tbmn lo encontré explicado de forma sencilla en este hilo:
http://www.eggheadcafe.com/software/aspnet/34242179/como-asociar-un-icono-a-un-usercontrol.aspx
Buen día.