2011-01-25 14 views
13

Ho un semplice modulo con un singolo TextBox, oltre ai pulsanti OK e Annulla. AcceptButton e CancelButton del modulo sono impostati correttamente e i pulsanti OK e Annulla hanno il loro DialogResult impostato su "OK" e "Annulla".WinForms L'evento di convalida impedisce la chiave di escape che chiude il modulo

Voglio aggiungere la convalida al TextBox che impedirà all'utente di inviare il modulo quando la convalida fallisce, ma che permetterà anche a loro di cancellare come al solito.

La proprietà CausesValidation è True per impostazione predefinita su tutti i controlli, ma l'ho modificata su False sul pulsante Annulla.

Abbastanza sicuro, facendo clic su OK o premendo il tasto Invio verrà eseguito l'evento di convalida che ho collegato al TextBox. Premendo il pulsante Annulla si ignora Convalida, che è perfetto.

Tuttavia, premendo Esc per annullare il modulo, lo non ha lo stesso effetto della pressione del pulsante Annulla: solleva l'evento Convalida e impedisce all'utente di uscire.

Esiste un modo per far funzionare il tasto Escape come previsto, vale a dire non sollevare l'evento Validazione, proprio come se fosse stato premuto il pulsante Annulla?

Una soluzione ha funzionato completo è:

Creare un nuovo Windows Form app. Aggiungi un secondo modulo al progetto.

incollare questo codice in costruttore di Form1, dopo InitializeComponent():

MessageBox.Show((new Form2()).ShowDialog().ToString()); 

Questo mostra il DialogResult ripassato dal nostro secondo modulo.

incollare questo codice in costruttore di Form2, dopo InitializeComponent():

TextBox txtName = new TextBox(); 

txtName.Validating += 
    new CancelEventHandler((sender, e) => 
    { 
     if (txtName.Text.Length == 3) 
     { 
      MessageBox.Show("Validation failed."); 
      e.Cancel = true; 
     } 
    }); 

Button btnOk = new Button 
{ 
    Text = "OK", 
    DialogResult = DialogResult.OK 
}; 
Button btnCancel = new Button 
{ 
    Text = "Cancel", 
    CausesValidation = false, 
    DialogResult = DialogResult.Cancel 
}; 
FlowLayoutPanel panel = new FlowLayoutPanel(); 
panel.Controls.AddRange(new Control[] 
{ 
    txtName, btnOk, btnCancel 
}); 

this.AcceptButton = btnOk; 
this.CancelButton = btnCancel; 

this.Controls.Add(panel); 

In questo esempio semplificato la casella di testo non ti consente di procedere se ci sono 3 ingressi caratteri. È possibile premere il pulsante Annulla o chiudere direttamente il modulo anche se sono presenti 3 caratteri; tuttavia premendo il tasto Esc sarà non fare lo stesso - si attiva l'evento Validating mentre dovrebbe fare lo stesso di premere Cancel.

+0

"validazione WinForms impedisce la fuga chiave di chiudere la forma" Ho lo stesso problema. –

risposta

16

Sì, questa è una strana stranezza del metodo ValidateChildren. Non sa che l'annullamento era inteso. Incolla questo codice per risolvere il problema:

protected override void OnFormClosing(FormClosingEventArgs e) { 
     base.OnFormClosing(e); 
     e.Cancel = false; 
    } 

Per evitare di avere un Convalida evento gestore esecuzione che provoca effetti collaterali, come una finestra di messaggio, aggiungere questa istruzione alla parte superiore del metodo:

private void txtName_Validating(object sender, CancelEventArgs e) 
    { 
     if (this.DialogResult != DialogResult.None) return; 
     // etc.. 
    } 

Incolla questo codice nel modulo per ottenere il DialogResult impostato prima che tenta di convalidare forma:

protected override bool ProcessDialogKey(Keys keyData) { 
     if (keyData == Keys.Escape) this.DialogResult = DialogResult.Cancel; 
     return base.ProcessDialogKey(keyData); 
    } 
+0

Siamo spiacenti, ma non sembra funzionare. L'evento Validating viene generato prima dell'evento Closing del modulo. –

+0

Ehm, come può impedire di chiudere il modulo? Cosa succede in questo gestore di eventi? Pubblica un codice per noi da guardare. –

+0

Si prega di consultare il codice che ho aggiunto sopra. Molte grazie per il vostro aiuto. –

6

ho appena visto questo problema come mi è stato a caccia di una soluzione per lo stesso ed l'overr ide di ProcessdialogKey è la soluzione approvata da MS fino a quando non risolvono il bug (Escape dovrebbe fare lo stesso di fare clic su Annulla). Una discussione di questo bug si trova anche qui (funziona solo con Visual Basic anziché C#. Bug ha più di 5 anni e apparentemente non è ancora stato risolto): Bug or Feature? CancelButton vs Escape Key Sto cercando di elaborare la soluzione C++.

Modifica per aggiungere: La soluzione dal link in C#:

protected override bool ProcessDialogKey(Keys keyData) 
{ 
    if (keyData == Keys.Escape) 
    { 
     this.AutoValidate = AutoValidate.Disable; 
     cancelButton.PerformClick(); 
     this.AutoValidate = AutoValidate.Inherit; 
     return true; 
    } 
    return base.ProcessDialogKey(keyData); 
} 
+0

Grazie! Spero sia ok che ho aggiunto il codice effettivo derivato da quel link. –

+0

Questo va perfettamente bene con me. Grazie. – galmok

1

In realtà, che causa nuovi problemi, in quanto intercetta fuga che altri controlli dovrebbe usare, per esempio se si ha una combobox abbandonata, premendo escape si dovrebbe chiudere la combobox e non uscire dalla finestra di dialogo, che farà il codice sopra.

Sarebbe possibile esentare alcuni tipi di controllo sull'evento chiave di escape ma questa non è una buona soluzione, è solo una questione di tempo fino a quando un altro controllo che utilizza l'escape internamente viene introdotto nel modulo, ad es. un controllo di diffusione in cui la modalità di modifica deve essere chiusa in uscita.

IMO è piuttosto ritardato che vengono convalidati in caso di fuga. Qualcuno sa qual è l'idea alla base, perché non è un bug ... ma è un bug.

Se quel codice dovesse chiamare base.ProcessDialogKey (keyData) anziché cancelButton.PerformClick, si sarebbe più vicini a una soluzione poiché sarebbe compito di qualcun altro determinare cosa fare con la chiave di escape. Ma impostare AutoValidate su Disabled qui e quindi restituirlo al suo valore originale non impedisce la convalida in quanto, probabilmente si limita a postare eventi e inserisce un messaggio in coda, non usa quel valore fino a quando non viene ripristinato al suo valore originale.

Impostandolo su Disabilitato e non restituendolo al valore originale, funzionerà, ma se la chiave di escape viene intercettata da ad es. sopra menzionata combobox, quindi all'improvviso hai disattivato la convalida anche su OK.

Touché!

Chiunque ha altre idee brillanti su come farlo funzionare, senza dover specificare tutti i possibili tipi di controlli che fanno e quali sono le condizioni quando hanno bisogno di uscire, ad es. il controllo è ComboBox e controlla se è caduto in basso e in tal caso di salvataggio.

0

Né le risposte ProcessDialogKeys né Validating hanno funzionato per me, forse perché sto utilizzando un ErrorProvider anziché un MessageBox. La risposta più semplice ho avuto modo di lavorare è quello di dimenticare Convalida e basta usare la seguente: -

buttonOk.Click += (_,__) => 
{ 
    if(txtName.Text.Length == 3) 
    { 
    errorProvider1.SetError(txtName, "Wrong Length!"); 
    DialogResult = DialogResult.None; 
    } 
    else 
    { 
    errorProvider1.SetError(txtName, string.Empty); 
    } 
}; 
Problemi correlati