2010-03-06 6 views
5

Seguente joelonsoftware da lungo tempo, poster stackoverflow 1a volta.Accedere alla proprietà Text di un controllo dopo il modulo principale Dispose() 'd?

voglio sapere "come in modo sicuro" Posso fare quanto segue (C#):

Form formDlg = new Form(); 
TextBox box = new TextBox(); 
formDlg.Controls.Add(box); 
formDlg.ShowDialog(); 
formDlg.Dispose(); 
string sUserEntered = box.Text; // After parent Dispose'd! 

In pratica, questo (apparentemente) funziona, perché scatola (come controllo) ha un private text field (una stringa) che utilizza per implementare la sua proprietà Text dopo che il suo handle di finestra è stato distrutto.

Non sarò soddisfatto da una risposta generica che "non è possibile accedere a un oggetto dopo che è stato eliminato" perché (1) non riesco a trovare alcuna proibizione generale in documenti MS, (2) I'm non accedere a una risorsa non gestita e (3) questo codice non genera alcuna eccezione (inclusa ObjectDisposedException).

Vorrei farlo in modo da poter creare e utilizzare un metodo "ShowAndDispose" combinato per ridurre il rischio di dimenticare di chiamare sempre Dispose() dopo ShowDialog().

Per complicare, il comportamento cambia nel debugger. Se mi rompo prima di Dispose(); quindi Quick Watch box e drill down nella sua classe di base Control; quindi oltrepassare Dispose(); quindi box.Text restituisce ""! In altri scenari box.Text restituisce il testo inserito dall'utente.

+0

Perché dovresti forzare un Dispose sul modulo? Soprattutto quando non si accede a risorse non gestite. Lascia che il framework/GC si prenda cura di esso. EDIT: Ho la sensazione che tu abbia una situazione molto più complicata del codice sopra. – Zyphrax

+0

Non solo, perché accedere a una casella di testo su un modulo che è dispose() ...? perché vorresti farlo? Non ha senso per me? È come puntatori in C, tu malloc un puntatore, fai qualche cosa con esso, quindi liberalo, quindi denothi il puntatore dopo essere stato liberato! – t0mm13b

+0

Zyphrax: un modulo contiene molte risorse non gestite, 1 per controllo. –

risposta

2

Si tratta di un dettaglio di implementazione che questo codice viene eseguito senza problemi . La proprietà Control.Text viene memorizzata nella cache dalla classe Control in modo che l'eliminazione di TextBox non causi un'eccezione ObjectDisposed.

Questo è abbastanza raro, un sacco di getter e setter di proprietà di controllo generano un messaggio di Windows per chiedere al controllo nativo di Window il valore della proprietà. Otterrai un kaboom su quelli perché la proprietà Handle non è più valida. Notevole è anche che il setter della proprietà Text aggiorna il valore memorizzato nella cache ma genera anche un messaggio Window per aggiornare il controllo nativo. Kaboom qui.

Presumo che questo sia solo interesse generale, non usare mai un codice del genere nel programma. Beh, lo scopriresti abbastanza in fretta.

+0

Thx, la migliore risposta ancora. –

1

Lo scenario debugger mi fa pensare che ciò che si fa non è affidabile, per testarlo si dovrebbe almeno provare questo:

formDlg.Dispose(); 
Application.DoEvents(); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 
string sUserEntered = box.Text; // After parent Dispose'd! 
+0

OK, l'ho provato, funziona ancora ". Le variabili formDlg e box sono ancora in ambito, quindi non mi aspetto che GC possa influenzare i loro oggetti. Comunque. –

+0

@Conrad: Sono ancora dubbioso, perché il testo sparirà nel debugger? –

+0

Ho fatto alcuni test e il testo scompare con tutte le varianti che ho provato. Fino a quando non ho inserito il valore del testo dal controllo in una proprietà pubblica, non sono stato in grado di riportare il valore del testo nel mio modulo principale, vedere la mia risposta di seguito. – IAbstract

2

È possibile utilizzare il 'utilizzando' istruzione al fine di garantire un oggetto viene disposta quando il gioco è fatto con esso:

using(Form frmDialog = new Form()) 
{ 
    //Do stuff 
} 

frmDialog otterrà disposto una volta che il blocco è gestito credo.

+0

In realtà non cambia la sua domanda. In confronto, 'stringa sUserEntered = box.Text;' verrebbe dopo il blocco using. – Zyphrax

+0

Sì, è una cura migliore di un metodo ShowAndDispose(). –

+1

@Zyphrax, no, risolverebbe il problema dell'OP circa la dimenticanza di Dispose e naturalmente la scatola. Il codice del codice andrebbe nell'uso. –

0

ho messo il valore sUserEntered in una proprietà pubblica in modo che possa essere letta:

public string UserInput 
    { 
     get; 
     set; 
    } 

    public frmDialog() 
    { 
     // 
     // The InitializeComponent() call is required for Windows Forms designer support. 
     // 
     InitializeComponent(); 

     // 
     // TODO: Add constructor code after the InitializeComponent() call. 
     // 
    } 

    void Button1Click(object sender, EventArgs e) 
    { 
     UserInput = userInput.Text; 
     this.Dispose(); 
    } 

Poi nel mio mainform:

 using (dialog = new frmDialog()) 
     { 
      dialog.ShowDialog(); 
      stringUserInput.Text = dialog.UserInput; 
     }; 
+0

Thx, so che posso farlo, creare una nuova classe è molto più un codice extra di quello che voglio. –

0

Mi viene in mente, posso creare & utilizzare una classe derivata dal modulo con un metodo BeginShowDialog() che chiama ShowDialog() e un metodo EndShowDialog() che chiama Dispose(). "Begin" nel nome del metodo renderà più ovvia la necessità della chiamata "End".

Mi manca la decisa distruzione dei locali da parte del C++ all'uscita dal campo di applicazione.

+0

Dovresti ancora racchiuderlo in un blocco try/finally, quindi il guadagno sull'utilizzo è discutibile. –

+0

Salterò la prova/finalmente. Nel caso mai-accade-nel-mondo reale che ShowDialog() genera, vivrò con la perdita di risorse. –

+0

Non sono d'accordo che "usando" "risolva" il problema che voglio affrontare, che non dimentica mai, per le centinaia di classi che uso, quando/se ciascuna deve essere smaltita. Se non ricordo questo, allora non mi ricorderò di usare "using" per quella classe meglio di quanto ricorderò chiamare Dispose(). –

Problemi correlati