Introducción

En éste articulo de tipo tutorial se explicará a un nivel digerible para estudiantes o programadores con conocimientos no muy avanzados sobre programación en language C#, el úso de Threads y Delegados. Prácticamente, explicando cuál es la idea de utilizar estas herramientas y algunos problemas o causas que ameritan utilizarlas.

El énfasis de este articulo es llevar a la práctica este tema, con un simple ejemplo en una aplicación de Windows Forms, con explicaciones en partes especificas del código que necesita quedar perfectamente claro para la comprensión de ejercicio y por ende el tema.

El ejemplo consiste en un programa que intenta interactuar (modificar) un Control de Windows Forms utilizando Threads. Una simple animación interactiva utilizando estos Controles (Button) que son parte de la idea principal del ejercicio.


Definiciones

Vamos explicando primero que estas 2 herramientas "Threads" y "Delegados":


Cuando se programa una simple aplicación en Consola o Windows Forms, la misma es un solo proceso por si misma, la cuál contiene métodos/funciones que son ejecutados de manera secuencial, esto significa que es necesario la finalización de uno para que otro método inicie, continue o concluya. todo esto es parte de un "Main thread" o hilo de proceso principal.

Si se desea ejecutar mas de un método a la vez, es necesario implementar otro hilo (thread) de manera independiente al principal. Al final cada thread ejecutará su propio código "al mismo tiempo" que otro.

Un delegado es un tipo que se define con una “firma” de un método, es decir que al crearlo/declararlo se especifica con que tipo de método va trabajar, si es un método "void" o devuelve algún valor, y si recibe argumentos. Cuando se instancía un delegado a partir de su definición, se le asigna almenos un método

En éste caso, nuestro delegado se va encargar de ejecutar algunas funciones que normalmente causan problemas a la hora de utilizar Controles de Windows Forms con Threads. Un delegado simplemente es invocado para realizer su(s) métodos que le fueron asignados. También se puede encargar de "event handling", que en éste tipo de aplicaciones no es mas que eventos y delegados.


Aplicación

Vamos a crear en Visual Studio un proyecto de WindowsForms y rapidamente arrogar 3 Controles por el momento, un PictureBox, Button y TextBox:

Threads y Delegados en C#

Ahora vamos a hacer un poco de limpieza antes de continuar, renombrar los controles y asignarle una imagen de fondo al PictureBox para darle un poco de sentido gráfico al programa, para eso, puse un muñeco como imágen:

El siguiente código sera simplemente para mover el PictureBox através del Form:<br />

private void Mover()<br />
{
while (PBx_mono.Location.X + PBx_mono.Width < this.Width)
{
PBx_mono.Location = new Point(PBx_mono.Location.X + 10, PBx_Location.Y);
Thread.Sleep(200); // Este cambio de posición se hará 5 veces por Segundo.
}
}


Si asignamos este método al evento Click del botón que tenemos creado, corremos el programa y tratamos de escribir algo de texto en el TextBox, no será posible hacerlo o almenos ver lo que escribamos en el momento, ya que el Thread principal está "ocupado" haciendo el método "Mover()", al finalizar esto, entonces podremos ver el texto que escribamos. ES IMPORTANTE DAR CLICK AL TEXTBOX PARA ENFOCARLO ANTES DE ESCRIBIR AUNQUE NO SEA POSIBLE VER TEXTO:
Programacion

Esa es una posible razón por que se requiera utilizer un 2do thread.

Hay que crear uno simplemente declarando como un objeto (no se olvide de poner "using System.Threading":

Thread Segundo_thread;
private void Form1_Load(object sender, EventArgs e)
{
Segundo_thread = new Thread(Mover);
// Será el trabajo de este thread realizer el movimiento del PictureBox
}

private void Button_iniciar_Click(object sender, EventArgs e)
{
Segundo_thread.Start()
}


Ahora vamos a iniciar el programa y dar click en el botón a ver que sucede:

csharp

No es possible alterar de esa manera un Control (en este caso un PictureBox) desde otro thread que no sea el principal, por motivos de seguridad. Aqui es dónde entran los delegados.

Ya se explicó en la introducción que son y para que sirven, entonces vamos a declarar uno y asignarle la tarea de mover el PictureBox, solo sería la linea que indica la nueva posición de éste.
Además, el PictureBox por si mismo puede invocar un delegado, debido a que es con el con quién queremos trabajar, tenemos que invocar el delegado apartir del método Invoke() del PictureBox

El código quedaría asi:

threads

Si ejecutamos el programa, el resultado seria el siguiente:

deledatos

El resultado es exitoso. Hemos aprendido de un ejemplo muy simple de threads y delegados.



Gracias por tu atención, espero te haya servido el tutorial.