2010-10-25 22 views
7

¿cómo es posible? Tengo Windows Form control, derivado de System.Windows.Forms.Form con control WebBrowser contenido en este formulario. La instancia del objeto Webbrowser se crea en el constructor de formulario (en el método InitializeComponent()). Luego en el hilo de fondo manipulo el contenido de WebBrowser, y encontré que en algunos casos Form.InvokeRequired == false, mientras que WebBrowser.InvokeRequired == true. ¿Cómo puede ser?InvocarRequired of Form == false and InvokeRequired of contain control == true

+0

¿Ocurre durante el inicio o el cierre del formulario o todo el tiempo? –

+0

Ocurre cuando el formulario ya se ha creado, pero no se muestra (forma completa, no solo el navegador). No muestro el formulario justo después de la creación. –

Respuesta

9

Form.InvokeRequired devuelve false antes de que se muestre el formulario.

Hice una prueba sencilla:

Form2 f2 = new Form2(); 
Thread t = new Thread(new ThreadStart(() => PrintInvokeRequired(f2))); 
t.Start(); 
t.Join(); 

f2.Show(); 

t = new Thread(new ThreadStart(() => PrintInvokeRequired(f2))); 
t.Start(); 
t.Join(); 

con el ayudante

private void PrintInvokeRequired(Form form) 
{ 
    Console.WriteLine("IsHandleCreated: " + form.IsHandleCreated + ", InvokeRequired: " + form.InvokeRequired); 
} 

la salida es

IsHandleCreated: Falso, InvokeRequired: Falso
IsHandleCreated: Es cierto, InvokeRequired : Verdadero

También tenga en cuenta que este es un poco documentada en MSDN:

Si el identificador del control hace aún no existe, InvokeRequired busca a la cadena principal del control de hasta que encuentra un control o formulario que tiene una tirador de ventana. Si no se puede encontrar el identificador apropiado, el método InvokeRequired devuelve falso.

Esto significa que InvokeRequired puede devolver false si Invoke no se requiere (la llamada se produce en el mismo hilo), o si el control se ha creado en un hilo diferente pero el identificador del control aún no ha sido creado .

En el caso de que aún no se ha creado el identificador del control , debe no simplemente llamar a propiedades, métodos o eventos en el control. Esto podría causar que el control del mango sea creado en el hilo de fondo, aislando el control en un hilo sin un mensaje de bomba y haciendo que la aplicación sea inestable.

Usted puede proteger contra este caso por también comprobando el valor de IsHandleCreated cuando InvokeRequired retornos falsos en un subproceso en segundo plano. Si aún no se ha creado el identificador , debe esperar hasta que se haya creado antes de llamar a Invoke o BeginInvoke. Típicamente, esto sucede sólo si se crea un subproceso de fondo en el constructor de la forma primaria para la aplicación (como en Application.Run (nuevo MainForm()), antes de que el formulario se ha demostrado o Application.Run ha sido llamado.

Su solución es comprobar también IsHandleCreated.

Editar:
El Handle se pueden crear en cualquier momento interno en el control WebBrowser o externamente. Esto no crea automáticamente el identificador del formulario principal.

creé un ejemplo:

public Form2() 
{ 
    InitializeComponent(); 

    Button button1 = new Button(); 
    this.Controls.Add(button1); 

    Console.WriteLine("button1: " + button1.IsHandleCreated + " this: " + this.IsHandleCreated); 
    var tmp = button1.Handle; // Forces the Handle to be created. 
    Console.WriteLine("button1: " + button1.IsHandleCreated + " this: " + this.IsHandleCreated); 
} 

con la salida:

el botón 1: Falso esto: Falso
el botón 1: Es cierto esto: Falso

+0

Pero compruebo la propiedad InvokeRequireled de control contenida (WebBrowser) y es True mientras form.InvokeRequired es False. De acuerdo con la lógica InvokeRequired de todos los controles secundarios en la jerarquía debe ser el mismo que InvokeRequired de parent control si los controles secundarios se crearon en el mismo hilo que el control principal. Y en mi situación, el control webbrowser se crea en el constructor del formulario, es decir, se crearon en un hilo. Tal vez tenemos algún comportamiento específico del control WebBrowser? –

+1

@Dmitry: No. El controlador de un control se puede crear independientemente del identificador del formulario principal. He actualizado mi respuesta con un ejemplo. –

+0

¡Oh, gracias! Muy interesante, ¡y esto aclara todo! –

0

He estado investigando este mismo comportamiento extraño. Necesito operar algunos controles de diferentes subprocesos (por ejemplo, mostrar información sobre un dispositivo que está conectado al host o desencadenar acciones dependiendo de los estados de los diferentes dispositivos).

Este enlace me dio una buena pista: http://csharpfeeds.com/post/2898/Control.Trifecta_InvokeRequired_IsHandleCreated_and_IsDisposed.aspx

Todavía no sé cómo las personas con EM destinados a hacer uso de sus propias cosas (y no estoy de acuerdo en muchos aspectos), pero, en una aplicación Tuve que hacer la siguiente solución sucia y sucia:

  • Cree el control/formulario en el hilo principal (asegúrese de que sea el hilo principal).
  • En el mismo procedimiento, verifique la palanca de control. Esta simple comprobación lo forzará a crear y en el hilo derecho.

How ugly, is not? Me gustaría saber si alguien más tiene una mejor manera de hacerlo.

_my_control = new ControlClass(); 
_my_control.Owner = this; 

IntPtr hnd; 

// Force Handle creation by reading it. 
if (!_my_control.IsHandleCreated || _my_control.Handle == IntPtr.Zero) 
    hnd = _my_control.Handle; 

(Lo siento por publicar algo en este antiguo puesto, pero pensé que podría ser útil para alguien).

+0

Tenga en cuenta que en su ejemplo, el identificador se creará realmente con la comprobación _my_control.Handle == IntPtr.Zero. Un método más corto podría ser _myControl = new ControlClass {Owner = this}; var temp = _myControl.Handle; –