2010-10-25 7 views
7

come è possibile? Ho il controllo di Windows Form, derivato da System.Windows.Forms.Form con controllo WebBrowser contenuto in questo modulo. L'istanza dell'oggetto Webbrowser viene creata nel costruttore del modulo (nel metodo InitializeComponent()). Poi nel thread in background ho manipolato il contenuto di WebBrowser e ho trovato che in alcuni casi Form.InvokeRequired == false, mentre WebBrowser.InvokeRequired == true. Come può essere?InvokeRequired of Form == false e InvokeRequired of contained control == true

+0

Si verifica durante l'avvio o la chiusura del modulo o tutto il tempo? –

+0

Si verifica quando il modulo è già stato creato, ma non mostrato (modulo intero, non solo browser). Non mostro il modulo subito dopo la creazione. –

risposta

9

Form.InvokeRequired restituisce false prima che venga visualizzato il modulo.

ho fatto un semplice test:

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 l'helper

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

l'uscita è

IsHandleCreated: Falso, InvokeRequired: False
IsHandleCreated: Vero, InvokeRequired : True

noti inoltre che questo è un po 'documentata sul MSDN:

Se la maniglia del controllo non ancora esiste, InvokeRequired cerca up catena di padre del controllo finché non trova un controllo o un modulo che ha un maniglia della finestra. Se non è possibile trovare un'appropriata maniglia , il metodo InvokeRequired restituisce false.

Ciò significa che InvokeRequired può restituire false se Invoke non è richiesto (la chiamata avviene sullo stesso filo), o se il controllo è stato creato in un thread diverso ma non è ancora stato creato maniglia del controllo .

Nel caso in cui non è ancora stata creata la maniglia del controllo , si dovrebbe non semplicemente chiamare proprietà, metodi o eventi sul controllo. Ciò potrebbe essere perché l'handle del controllo sia creato sul thread di sfondo, isolando il controllo su una thread senza un messaggio pump e rendendo l'applicazione instabile.

È possibile proteggersi da questo caso per controllando anche il valore di IsHandleCreated quando InvokeRequired rendimenti falsi su un thread in background. Se l'handle di controllo non è stato ancora creato , è necessario attendere che sia stato creato prima di chiamare Invoke o BeginInvoke. Tipicamente, questo accade solo se un thread sfondo viene creato nel costruttore della forma primaria per l'applicazione (come nella Application.Run (nuovo MainForm()), prima forma è stato mostrato o Application.Run è stato chiamato.

La soluzione è anche verificare .

Edit:
Il Handle possono essere creati in qualsiasi momento interno nel controllo WebBrowser o esternamente. Ciò non crea automaticamente l'handle del modulo padre.

ho creato un esempio:

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 l'uscita:

button1: Falso questo: False
button1: Vero questo: Falso

+0

Ma controllo la proprietà InvokeRequired di controllo contenuto (WebBrowser) ed è True mentre form.InvokeRequired è False. In base alla logica InvokeRequired di tutti i controlli figlio nella gerarchia deve essere uguale a InvokeRequired del controllo padre se i controlli figlio sono stati creati nello stesso thread del controllo padre. E nella mia situazione il controllo webbrowser viene creato nel costruttore della forma, cioè sono stati creati in un thread. Forse abbiamo qualche comportamento specifico del controllo WebBrowser? –

+1

@Dmitry: No. L'handle di un controllo può essere creato indipendentemente dall'handle del modulo padre. Ho aggiornato la mia risposta con un esempio. –

+0

Oh, grazie! Molto interessante, e questo chiarisce tutto! –

0

Ho indagato su questo stesso strano comportamento. Ho bisogno di operare alcuni controlli da diversi thread (ad esempio, mostra informazioni su un dispositivo che è collegato all'host o azioni di trigger a seconda dei diversi stati dei dispositivi).

Questo link mi ha dato un buon suggerimento: http://csharpfeeds.com/post/2898/Control.Trifecta_InvokeRequired_IsHandleCreated_and_IsDisposed.aspx

io ancora non so come MS persone destinate a fare uso della propria roba (e non sono d'accordo in molti aspetti), ma, in una applicazione ho dovuto effettuare la seguente soluzione sporca e sporca:

  • Creare il controllo/modulo nel thread principale (assicurarsi che sia il thread principale).
  • Nella stessa procedura, controllare la manopola di comando. Questo semplice controllo lo costringerà a creare e nella discussione giusta!

Che brutto, no? Mi piacerebbe sapere se qualcun altro ha un modo migliore per farlo.

_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; 

(Mi dispiace per la pubblicazione in questo post un po 'vecchio, ma ho pensato che potrebbe essere utile a qualcuno).

+0

Nota che nel tuo esempio, l'handle verrà effettivamente creato dal check _my_control.Handle == IntPtr.Zero. Un metodo più corto potrebbe essere _myControl = new ControlClass {Owner = this}; var temp = _myControl.Handle; –