System.InvalidOperationException trabajando con hilos

publicado por: Anonymous

El código es el siguiente, mas abajo la explicación..

    Thread hilo = new Thread(NuevoHilo);
    hilo.Start(item);

    private void NuevoHilo(object item)
             {
              rtxMensajes = new Mensajes().NuevoMensaje(rtxMensajes, item.ToString(), tbxArchivo.Text, Color.Green);           
             }

    public RichTextBox NuevoMensaje(RichTextBox rtb, string unidad, string archivo, Color color)
             {
                string avance = "rn";
                rtb.SelectionStart = rtb.TextLength;  <---- EXCEPCION!!!
                rtb.SelectionLength = 0;

                rtb.SelectionColor = color;
                rtb.AppendText(String.Format("Se copio el archivo {0} en la unidad {1} {2}", archivo, unidad, avance));
                rtb.SelectionColor = rtb.ForeColor;
                return rtb;
             }

Cuando se ejecuta el método NuevoHilo y este instancia un objeto de la clase Mensaje que a su vez llama a un método de esta clase y que toma como parámetro un objeto RichTextBox, se produce una excepción del tipo System.InvalidOperationException, que me da la siguiente descripción;

Operación no válida a través de subprocesos: Se tuvo acceso al control ‘rtxMensajes’ desde un subproceso distinto a aquel en que lo creó.

Decir que el objeto que paso como parametro es un RichTextBox que tengo creado en el Form1, intento que cada vez que lanzo el hilo me escriba el resultado el el RichTextBox llamado rtxMensajes

solución

Cuando vayas a acceder a los controles creados en el hilo principal debes hacerlo de 2 maneras: 1 Llamando al método Invoke de tu formulario o usando BackgroundWorkers.

//Usando Invoke
Invoke(new MethodInvoker(() =>
{
  //Aqui va el código que modifica controles creados en el hilo principal
}));

//Usando BackgroundWorker
private void ThreadSafe(Action callback,Form form)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.RunWorkerCompleted += (obj, e) =>
    {
        if (form.InvokeRequired)
            form.Invoke(callback);
        else
            callback();
    };
    worker.RunWorkerAsync();
}

//Lo llamas de esta manera
ThreadSafe(() =>{
   //Código que modifica controles creados en el hilo principal
}, this)  //this si estas en la clase del formulario principal

En fin tu código quedaría de estas dos maneras (usa la que desees)

 public RichTextBox NuevoMensaje(RichTextBox rtb, string unidad, string archivo, Color color)
 {
    ThreadSafe(()=>{
        string avance = "rn";
        rtb.SelectionStart = rtb.TextLength;  <---- EXCEPCION!!!
        rtb.SelectionLength = 0;

        rtb.SelectionColor = color;
        rtb.AppendText(String.Format("Se copio el archivo {0} en la unidad {1} {2}", archivo, unidad, avance));
        rtb.SelectionColor = rtb.ForeColor;
    }, this);

    return rtb;
 }

o de esta:

public RichTextBox NuevoMensaje(RichTextBox rtb, string unidad, string archivo, Color color)
 {
    Invoke(new MethodInvoker(()=>{
       string avance = "rn";
        rtb.SelectionStart = rtb.TextLength;  <---- EXCEPCION!!!
        rtb.SelectionLength = 0;

        rtb.SelectionColor = color;
        rtb.AppendText(String.Format("Se copio el archivo {0} en la unidad {1} {2}", archivo, unidad, avance));
        rtb.SelectionColor = rtb.ForeColor;
    });
    return rtb;
 }

Prueba y me dices. Saludos

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *