2010-05-14 16 views
6

Ho un problema con la modalità dei moduli in C# .NET. Diciamo che ho il modulo principale # 0 (vedi l'immagine sotto). Questo modulo rappresenta il modulo di domanda principale, in cui l'utente può eseguire varie operazioni. Tuttavia, di tanto in tanto, è necessario aprire un modulo aggiuntivo non modale per eseguire ulteriori funzionalità dell'applicazione principale che supportano le attività. Diciamo che questo è il modulo n. 1 nell'immagine. In questo modulo # 1 potrebbero essere aperte alcune forme modali aggiuntive l'una sopra l'altra (il modulo # 2 nell'immagine), e alla fine, c'è una finestra di stato che mostra un progresso e uno stato di un'operazione lunga, che potrebbe richiedere da pochi minuti fino a poche ore. Il problema è che la forma principale # 0 non è reattiva finché non si chiudono tutte le forme modali (# 2 nell'immagine). Ho bisogno che il modulo principale # 0 sia operativo in questa situazione. Tuttavia, se apri un modulo non modale nel modulo n. 2, puoi operare sia con il modulo modale n. 2 sia con il modulo non modale appena creato. Ho bisogno dello stesso comportamento tra il modulo principale # 0 e il modulo n. 1 con tutte le sue forme figlio. È possibile? O sto facendo qualcosa di sbagliato? Forse c'è un qualche tipo di soluzione, io davvero non vorrei cambiare tutto ShowDialog chiama alla Mostra ...Programmazione WinForms - Problema modale e Modale non modale

Image http://img225.imageshack.us/img225/1075/modalnonmodalproblem.png

+2

Stai chiedendo di creare un modulo che è solo modale a uno dei tuoi altri moduli? – SLaks

+0

Desidero che il modulo principale # 0 rimanga sensibile quando viene aperto un modulo non modale n. 1 con alcune forme secondarie modali secondarie (n. 2). – Povilas

risposta

12

I moduli modali fanno esattamente ciò che "modale" significa, disattivano tutte le altre finestre nell'app. Questo è piuttosto importante, il tuo programma è in uno stato un po 'pericoloso. Hai una porzione di codice in attesa che la finestra di dialogo si chiuda. Le cose veramente brutte potrebbero accadere se quelle altre finestre non fossero disabilitate. Come se l'utente potesse riavviare la finestra di dialogo modale, ora il codice è nidificato due volte. Oppure potrebbe chiudere la finestra del proprietario della finestra di dialogo, ora improvvisamente scompare.

Questi sono i tipi esatti di problemi in cui verrebbero eseguiti se si chiama Application.DoEvents() all'interno di un ciclo. Quale è un modo per far sì che un modulo si comporti modale senza disabilitare altre finestre. Per esempio:

Form2 mDialog; 

    private void button1_Click(object sender, EventArgs e) { 
     mDialog = new Form2(); 
     mDialog.FormClosed += (o, ea) => mDialog = null; 
     mDialog.Show(this); 
     while (mDialog != null) Application.DoEvents(); 
    } 

Questo è pericoloso.

È certamente meglio utilizzare le forme modali nel modo in cui sono state progettate per rimanere fuori dai guai. Se non vuoi una forma modale, semplicemente non la rendi modale, usa il metodo Show(). Iscriviti alla sua manifestazione FormClosing di sapere che sta per chiudersi:

private void button1_Click(object sender, EventArgs e) { 
     var frm = new Form2(); 
     frm.FormClosing += new FormClosingEventHandler(frm_FormClosing); 
     frm.Show(); 
    } 

    void frm_FormClosing(object sender, FormClosingEventArgs e) { 
     var frm = sender as Form2; 
     // Do something with <frm> 
     //... 
    } 
+0

Grazie per la tua risposta, penso di poter utilizzare un thread GUI separato, perché la forma principale # 0 e la forma # 1 fondamentalmente vivono le loro vite e non interagiscono tra loro. Il modulo n. 1 potrebbe essere anche un'applicazione separata. Non riesco a cambiare ShowDialog() a Show() perché ho bisogno di moduli modali ma solo nel contesto del modulo n. L'utente non può procedere con il modulo n. 1 (solo con il modulo n. 1) finché il modulo modale aperto dal modulo n. 1 non è chiuso. – Povilas

3

La prima cosa che viene in mente sarebbe qualcosa di simile. È possibile disabilitare il modulo 1 quando si avvia il modulo 2 e quindi il modulo 1 gestisce l'evento chiuso del secondo modulo per riattivare se stesso. NON si aprirebbe il modale 2 usando la finestra di dialogo Mostra.

Ora tenere a mente, dal punto di vista dell'utente questo sarà piuttosto ingombrante, si potrebbe guardare a fare un'applicazione MDI per ottenere tutte le finestre all'interno di un singolo contenitore.

0

Il modulo principale non risponderà finché non verranno chiuse le finestre di dialogo modali che si trovano nello stesso spazio del processo. Non c'è lavoro per quello.

0

Sembra a me come si potrebbe usare un'applicazione MDI impostando il modulo # 0 IsMdiContainer proprietà su true.

Poi, si potrebbe fare qualcosa di simile:

public partial class Form0 { 
    public Form0 { 
     InitializeComponent(); 
     this.IsMdiContainer = true; // This will allow the Form #0 to be responsive while other forms are opened. 
    } 

    private void button1_Click(object sender, EventArgs e) { 
     Form1 newForm1 = new Form1(); 
     newForm1.Parent = this; 
     newForm1.Show(); 
    } 
} 

Utilizzando la ShowDialog() come avete dichiarato nella domanda farà tutte le forme Modal = true.

Per definizione, una forma modale è:

Quando un modulo viene visualizzato modale, nessun input (tastiera o mouse) può avvenire se non per gli oggetti sul modulo modale. Il programma deve nascondere o chiudere un modulo modale (di solito in risposta a qualche azione dell'utente) prima che possa verificarsi l'input di un altro modulo. I moduli visualizzati in modo modale vengono in genere utilizzati come finestre di dialogo in un'applicazione.

È possibile utilizzare questa proprietà [(Modal)] per determinare se un modulo ottenuto da un metodo o una proprietà è stato visualizzato in modo modale.

Quindi, un modulo modale deve essere utilizzato solo quando è richiesta assistenza/interazione immediata da parte dell'utente. L'uso di forme modali fa credere altrimenti che tu stia correndo verso una direzione sbagliata.

Se non si desidera che il modulo principale sia un contenitore MDI, quindi forse l'utilizzo del multithreading è una soluzione attraverso una semplice classe BackgroundWorker è la chiave di ciò che si desidera ottenere. Così, sembra a me come un odore di progettazione ...

  • Che cosa è che si vuole fare, a parte di rendere il vostro principale forma reattiva, ecc
  • Che cosa è che devi fare ?

Spiegando cosa si deve fare, potremmo essere in grado di guidarvi del tutto nella direzione giusta, o almeno forse migliore.

+0

Grazie per la tua risposta, cercherò di spiegarti meglio. MDI o la modifica di ShowDialog() a Show() non risolverà questo per me, perché ho bisogno di moduli modali (editor di dati personalizzati) e l'utente non può procedere finché non ha finito con quello corrente, ma ho bisogno che la modalità funzioni solo nel contesto della # 1. Sul modulo n. 1 gli utenti stanno lavorando con alcuni dati che in seguito sono necessari sul modulo principale n. Fondamentalmente, la forma principale # 0 e la forma # 1 vivono le loro vite, e la forma # 1 potrebbe essere anche un'applicazione separata. Da # 0 si stanno acquisendo dati da pochi oggetti singleton, dove il modulo # 1 sta aggiornando i dati. – Povilas

+0

Per la metà dell'anno tutto andava bene, ma a causa di nuove esigenze affrettate ho la situazione in cui lavorare con un editor di dati personalizzato potrebbe richiedere alcune ore. Quindi penso di poter usare quello che suggerisce Hans Passant - un thread GUI separato. E sincronizzare i dati tramite pochi oggetti singleton. – Povilas

-1

In realtà la risposta è molto semplice. Prova

newForm.showDialog(); 

Questo aprirà un nuovo modulo, mentre quello principale è inaccessibile.