|

|
Siguiendo con el modelo asíncrono y cuestiones de serialización de accesos, es también importante destacar que por norma general, los controles gráficos (System.Windows.Forms) no pueden ser modificados desde un thread distinto al propio de la GUI, provocando una InvalidOperationException si lo hacemos, por ello debemos realizar estas modificaciones haciendo que el mismo formulario principal invoque la modificación ejecutándola con su propio thread.
Primero, vamos a reproducir el problema para ser más conscientes de la solución, este código provoca la susodicha excepción al intentar modificar un ListBox que se encuentra en el formulario Form1:
|
|
public partial class Form1 : Form
{
private delegate void AsyncCallOut_(string p1);
private static AsyncCallOut_ AsynCallOut; public Form1()
{
InitializeComponent();
AsynCallOut = new AsyncCallOut_(AsyncFuncOut);
}
private void Form1_Shown(object sender, EventArgs e)
{
IAsyncResult ia = null;
// Lanzamos 10 tareas asíncronas.
for (int i = 0; i < 10; i++)
{
// En este punto podemos modificar el control ya que estamos en el hilo
// principal de la GUI 
listBox1.Items.Add(“-> Lanzando tarea asíncrona: “+ i.ToString());
ia = AsynCallOut.BeginInvoke(i.ToString(), new AsyncCallback(FinAsyncFuncOut), “objectstate_”+i.ToString());
}
// Esperamos a que terminen todsas las tareas.
if (!ia.IsCompleted)
{
ia.AsyncWaitHandle.WaitOne();
}
}
private void AsyncFuncOut(string p1)
{
Random rndm = new Random(p2);
System.Threading.Thread.Sleep(rndm.Next(5000, 10000));
// Aquí saltará la excepción InvalidOperationException
listBox1.Items.Add(“En ejecución: “ + p1.ToString());
}
private void FinAsyncFuncOut(IAsyncResult IA)
{
try
{
AsynCallOut.EndInvoke(IA);
listBox1.Items.Add(“Fin de AsyncFunc con objectState :”+IA.AsyncState.ToString());
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
} |
Para realizar este tipo de accesos, es necesario implementar un callback, consiste en un delegado que apunta a la función que modificará el control, esta función primero comprobará si es necesario realizar una invocación antes de modificar el control (.InvokeRequired) y en caso afirmativo, le pasará el delegado al formulario principal para que lo llame así desde su propio thread, en caso contrario (entendemos que ya esta en el hilo principal) modifica el control.
Como veréis en ejemplo es bastante sencillo:
|
public partial class Form1 : Form
{
private delegate void AsyncCallOut_(string p1);
private static AsyncCallOut_ AsynCallOut;
// Nuestro Callback
private delegate void miCallBack_(string item);
private miCallBack_ miCallBack;
public Form1()
{
InitializeComponent();
AsynCallOut = new AsyncCallOut_(AsyncFuncOut);
miCallBack = new miCallBack_(ModificarListBox);
}
private void Form1_Shown(object sender, EventArgs e)
{
IAsyncResult ia = null;
// Lanzamos 10 tareas asíncronas.
for (int i = 0; i < 10; i++)
{
// En este punto podemos modificar el control ya que estamos en el hilo
// principal de la GUI 
listBox1.Items.Add(“-> Lanzando tarea asíncrona: “ + i.ToString());
ia = AsynCallOut.BeginInvoke(i.ToString(), new AsyncCallback(FinAsyncFuncOut), “objectstate_”+i.ToString());
}
}
private void ModificarListBox(string item)
{
// Si necesitamos invocar para modificar este control …
if (listBox1.InvokeRequired)
{
// Atención a como se pasan los parámetros de la función
this.Invoke(miCallBack, new object[] {item});
}
else
{
// Entenemos que ya estamos en el hilo principal
listBox1.Items.Add(item);
}
}
private void AsyncFuncOut(string p1)
{
Random rndm = new Random(5);
System.Threading.Thread.Sleep(rndm.Next(5000, 10000));
// Ya no saltará la excepción InvalidOperationException
ModificarListBox(“En ejecución: “ + p1.ToString());
}
private void FinAsyncFuncOut(IAsyncResult IA)
{
try
{
AsynCallOut.EndInvoke(IA);
ModificarListBox(“Fin de AsyncFunc con objectState :” + IA.AsyncState.ToString());
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
} |
Lectura recomendada: Cómo: Realizar llamadas seguras para procesos en controles de formularios Windows Forms.

Happy coding
No habia tenido la oportunidad de visitar este blog pero me parece muy interesante,sobre todo cada ejemplito que haces para las personas que estan aprendiendo a programar,Ademas que los ejemplos estan hechos en C#.Net , it’s very good.
Comentario por saavedranet — Junio 20, 2007 @ 12:53 pm
Gracias
El tuyo también es bastante interesante, me gustó lo de cardspace.
Comentario por vtortola — Junio 20, 2007 @ 3:59 pm