2009-10-27 10 views
6

Tengo algunos problemas de subprocesamiento con una aplicación grande en la que estoy trabajando (obteniendo excepciones entre hilos). ¿Hay alguna manera de encontrar el nombre/id del subproceso en el que se creó un control en particular?¿Hay alguna manera de encontrar el hilo del propietario de un control?

El error se produce cuando intento agregar un nuevo control a la colección de control de mi control. Realmente no puedo crear una muestra pequeña y reproducible, así que lo describiré lo mejor que pueda.

Tengo un control principal que se encuentra en un formulario, llámalo _mainControl. En su constructor que se crea una instancia de otro control, algo así como

ChildControl _childControl = new ChildControl(); 

Ahora _childControl existe pero no agregarlo a la colección _mainControls todavía.

Eventualmente, _mainControl recibe una notificación de evento de que debo agregar el control. En el controlador de eventos puedo comprobar si this.InvokeRequired y si lo es, invoco el manejador, algo así como lo siguiente:

AddControlEventHander(...) 
{ 
    if(InvokeRequired) 
    { 
     BeginInvoke(new MethodInvoker(AddControlEventHander); 
     return; 
    } 
    Controls.Add(_childControl); 
} 

La excepción siempre se lanza a Controls.Add ("operación de la Cruz-hilo no válida: Control '_item' accedido desde un hilo que no sea el hilo en el que se creó ").

Ahora, lo que no entiendo es cómo esto es posible. Creé _childControl en el mismo hilo en el que se creó _mainControl. Cuando miro la ventana de subprocesos mientras estoy depurando, el nombre/id del subproceso actual es el mismo cuando llamo a Control.Add como cuando se agregó _childControl. Sin embargo, lo que más me confunde son las siguientes llamadas de _mainControl:

InvokeReuqired == false; 
_childControl.InvokeRequired == false; 
_childControl._item.InvokeRequired == true; //I made _item public just to try this and it returns true! 

¿Cómo es eso posible? ¿Es posible que _childControl se cree en un hilo mientras sus hijos se crean de alguna manera en otro? Todos los hijos de _childControl se crean durante la inicialización, como normalmente se hace.

Si alguien tiene alguna sugerencia/sugerencia sobre lo que podría estar pasando, por favor hágamelo saber.

Gracias.

Editar:

En caso de que a alguien le interesa, me enteré de lo que estaba ocurriendo. Tenía curiosidad sobre cómo se puede crear un control en un subproceso y se crean los secundarios en otro subproceso, aunque el componente InitializeComponent se realizó en el mismo subproceso. Entonces, descubrí en qué subproceso se estaba creando el niño usando un código similar al que Charles sugirió a continuación. Una vez que lo supe, al menos sabía en qué hilo enfocarme. Luego rompí el evento OnHandleCreated del control infantil y encontré el problema.

Una cosa que no sabía era que el control se crea cuando el control se hace visible por primera vez, no cuando se crea. Entonces, un hilo que no poseía el control intentaba establecer su visibilidad como verdadera. Así que agregué un cheque para ver si InvokeRequired y pensé que eso sería suficiente. Sin embargo, algo que realmente no esperaba es que llamar a InvokeRequired creará el control si aún no se ha creado. Esto en efecto hace que el control se cree en el hilo incorrecto y siempre devuelve falso para InvokeRequired. Lo solucioné tocando la propiedad Manejar del control para que se cree antes de invocar InvokeRequired.

Gracias por la ayuda chicos :)

+0

Gracias por la sugerencia. También descubrí que el inocente 'if (control.Handle! = Null) ...' en realidad crea el control en ese hilo. –

+0

Vea mi respuesta aquí http://stackoverflow.com/questions/8331144/ensuring-that-child-controls-are-created-in-main-ui-thread/17054689#17054689 –

Respuesta

3

Para obtener el hilo propietario de un control, prueba esto: los controles secundarios

private Thread GetControlOwnerThread(Control ctrl) 
{ 
    if (ctrl.InvokeRequired) 
     ctrl.BeginInvoke(
      new Action<Control>(GetControlOwnerThread), 
      new object[] {ctrl}); 
    else 
     return System.Threading.Thread.CurrentThread; 
} 

puede estar en un hilo diferente de la matriz (control contenedor)? Sí, todo depende de qué subproceso se estaba ejecutando cuando se construyó el control (nuevo)

Siempre tiene que comprobar InvokeRequired ... Porque nunca se sabe qué subproceso podría llamar al método que está codificando. .. Si necesita comprobar InvokeRequired por separado para cada control secundario, depende de qué tan seguro esté de que todos los controles se crearon en el mismo subproceso o no. Si todos los controles se crean cuando se crea el formulario, en la misma rutina de inicialización, entonces es probable que suponga que todos fueron creados en el mismo hilo

+0

Hmm. Entonces, ¿qué tipo de controles se requieren cuando intenta ver si InvokeRequired es necesario para un control o no? ¿Siempre necesita comprobar InvokeRequired en el control y todos sus hijos? – Flack

+0

Sí, siempre debe verificar InvokeRequired ... porque nunca sabe qué hilo podría estar llamando al método que está codificando ... Si necesita verificar InvokeRequired por separado para cada control secundario, depende de qué tan seguro esté de que todo los controles fueron creados en el mismo hilo o no. Si todos los controles se crean cuando se crea el formulario, en la misma rutina de inicialización, entonces es probable que pueda suponer que todos fueron creados en el mismo hilo. –

+0

Eso es lo que me parece tan extraño. Por lo que puedo decir, _childControl y todos sus hijos parecen creados en el mismo hilo. Además, si _childControls children se crearon de alguna manera en un hilo diferente, no veo cómo puedo llamar a _mainControl's Controls.Add ya que falla cuando se crea el controlador _childControl debido al cross-threading. O fallo debido a _childControl o debido a sus hijos. No veo cómo esto es posible. Lo volveré a visitar y haré una refactorización. Tal vez simplemente desaparecerá :) – Flack

Cuestiones relacionadas