in

Acceder a controles en aplicaciones Multithreading

Last post 02-12-2007 19:07 by jfbonnin. 2 replies.
Page 1 of 1 (3 items)
Sort Posts: Previous Next
  • 02-03-2007 12:24

    Acceder a controles en aplicaciones Multithreading

    Hola,

    Si trabajáis con aplicaciones multithreading, probablemente se os presente la ocasión en la que debáis acceder a controles UI creados en el thread principal desde otro thread distinto. Como sabréis una regla de la programación en Windows es que los cambios realizados en los controles UI deben realizarse desde el thread que creó el control. De lo contrario con .net 2.0 obtendríamos una excepción en tiempo de ejecución, pero en versiones anteriores es incluso peor porque los resultados son inesperados.

    Vamos a ver un ejemplo muy simple con el tendríamos problemas:

    1 private void bttStart_Click(object sender, System.EventArgs e) 2 { 3 System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(DoWork)); 4 thread.Name = "Worker Thread"; 5 thread.IsBackground = true; 6 thread.Start(); 7 } 8 9 private void DoWork() 10 { 11 int iteration = 0; 12 while (true) 13 { 14 iteration++; 15 textBox1.Text = iteration.ToString(System.Globalization.CultureInfo.InvariantCulture); 16 System.Threading.Thread.Sleep(3000); 17 } 18 }

    Sin embargo esto es muy sencillo de evitar. Todos los controles UI tienen una propiedad llamada InvokeRequired que nos indica si el método que intenta hacer la modificación está en un thread distinto del que creo el control. Si se diera el caso tan solo tendríamos que volver a invocar el método en el thread correcto. Veamos como arreglarlo:

    1 private void DoWork() 2 { 3 int iteration = 0; 4 while (true) 5 { 6 iteration++; 7 SetText(iteration.ToString(System.Globalization.CultureInfo.InvariantCulture)); 8 System.Threading.Thread.Sleep(3000); 9 } 10 } 11 12 public delegate void TextUpdate(string text); 13 14 private void SetText(string text) 15 { 16 if (textBox1.InvokeRequired) 17 { 18 textBox1.Invoke(new TextUpdate(SetText), text); 19 } 20 else 21 { 22 textBox1.Text = text; 23 } 24 }

    Como veréis los cambios son muy simples. Hemos creado un método SetText que comprueba si el método que va a modificar la propiedad Text está en un thread distinto, en cuyo caso crea una instancia del delegado TextUpdate que apunta de nuevo al método SetText. Al llamar al método Invoke del TextBox, lo único que hará será volver a llamar  a SetText pero esta vez desde el thread en el que se creó el control.

    Jose Fco Bonnin
    -----------------------
    Coordinador Baleares on .NET
    www.josefcobonnin.com
    Filed under: ,
    • Post Points: 22
  • 02-09-2007 9:21 In reply to

    • jmservera
    • Top 10 Contributor
    • Joined on 01-25-2007
    • Palma de Mallorca
    • Posts 59
    • Points 1,029

    Re: Acceder a controles en aplicaciones Multithreading

    Hola!

    ¿Habría alguna diferencia si usara una llamada al ThreadPool.QueueUserWorkItem ?

    Gracias!

    JM

    Juan M. Servera
    • Post Points: 22
  • 02-12-2007 19:07 In reply to

    Re: Acceder a controles en aplicaciones Multithreading

    Hola,

    El problema seguiría siendo el mismo. La principal diferencia radica en que si usamos el QueueUserWorkItem lo que hacemos es encolar nuestro thread, el cual se ejecutará cuando alguno de los threads disponibles en el Pool se libere.

    Además para encolar los threads es necesario utilizar el delegate WaitCallback, por lo que habría que modificar el método DoWork para que aceptase un parámetro object y cumpliese con la signature de dicho delegate.

    Jose Fco Bonnin
    -----------------------
    Coordinador Baleares on .NET
    www.josefcobonnin.com
    Filed under: ,
    • Post Points: 5
Page 1 of 1 (3 items)
Baleares on .NET®
Powered by Community Server (Commercial Edition), by Telligent Systems