2011-03-11 4 views
7

Ho un thread principale dell'interfaccia utente che esegue l'applicazione e crea il modulo della finestra principale (chiamiamolo W). Ho anche un thread secondario che faccio girare e che crea una finestra di dialogo (chiamiamola B).Eccezione cross-thread quando si imposta il proprietario di WinForms.Form: come fare nel modo giusto?

Desidero impostare il proprietario della finestra di dialogo B come finestra principale W. L'impostazione del proprietario di B s avviene sul thread che ha creato B. In sostanza:

b.Owner = w; 

ma questo genera un'eccezione cross-thread a dirmi che sto tryng per accedere all'oggetto W dal thread sbagliato.

Così ho provato a eseguire il codice sul thread principale dell'interfaccia utente, utilizzando uno Control.Invoke su W. Ma poi, ottengo lo stesso errore che mi dice che sto cercando di accesso B dal thread sbagliato:

System.InvalidOperationException was unhandled by user code 
    Message=Cross-thread operation not valid: Control 'B' accessed from a 
    thread other than the thread it was created on. 
    Source=System.Windows.Forms 

Come faccio a farlo bene?

+0

Non utilizzare moduli su più thread. Ti darà più problemi di quanti ne valga. – SLaks

+0

Hai letto questo post SO: http://stackoverflow.com/questions/3046245/whats-wrong-with-my-cross-thread-call-in-windows-forms? Se questo non ti aiuta, devi pubblicare il codice che ti dà l'errore. –

+0

Forse puoi dirci quali caratteristiche di proprietà speravi di sfruttare (si spera non tutte) e potremmo suggerire modi per ottenere effetti simili? –

risposta

5

È un po 'un bug in Winforms, Windows in realtà supporta la creazione del proprietario di una finestra che è stata creata su un altro thread. C'è un modo per disabilitare quel controllo, qualcosa che dovresti fare mai do. Tranne quando si deve suppongo:

private void button1_Click(object sender, EventArgs e) { 
     var t = new Thread(() => { 
      Control.CheckForIllegalCrossThreadCalls = false; 
      var frm = new Form2(); 
      frm.Show(this); 
      Control.CheckForIllegalCrossThreadCalls = true; 
      Application.Run(frm); 
     }); 
     t.SetApartmentState(ApartmentState.STA); 
     t.Start(); 
    } 

faccio Non so se questo è sicuro al 100%, ci potrebbe essere un'interazione WinForms che le viti le cose. Sei qui in acque non testate, infestate da squali filanti.

+0

Il tuo suggerimento è interessante. Nel mio caso, posso assicurarmi che il codice che mostra la finestra di dialogo non interferisca con il thread dell'interfaccia utente principale. Lo proverò. –

+2

Hai scoperto qualcosa in più sulla sicurezza dell'approccio sopra?Vorrei farlo (avere un modulo in possesso di un modulo che è associato a un thread diverso) ma vedere due dubbi: (1) Mostrare un modulo che è di proprietà di un altro chiamerà 'Owner.AddOwnedForm' che probabilmente non è thread- sicuro; meglio fare l'azione sul thread del modulo proprietario; (2) Se due moduli legati a thread diversi provano a mostrarsi simultaneamente, si può impostare 'CheckForIllegalCrossThreadCalls = true' tra il momento in cui l'altro lo imposta falso e il tempo in cui esegue l'operazione che richiede che sia falso. – supercat

3

B deve essere creato sul thread dell'interfaccia utente.

È ancora possibile interagire con B dal thread secondario utilizzando Control.Invoke.

+0

Nel mio caso, non funzionerà per ciò che intendo fare: la mia finestra 'B' non si aggiornerà se il thread principale dell'interfaccia utente è bloccato. –

2

Se in realtà stai eseguendo due loop di messaggi su thread diversi, non c'è modo di fare ciò che stai cercando. Se si desidera che B sia B, è necessario creare B nella discussione principale e Invoke tutte le interazioni con B dal secondo thread.