2013-04-10 11 views
11

Questa è una domanda C# winform. Ho una casella di testo con un listener di eventi di convalida per convalidare il contenuto della casella di testo su un'espressione regolare.Chiusura del modulo Windows C# evitando la convalida della casella di testo

Dopo la convalida, se il valore inserito non è corretto, sto visualizzando la messagebox e sto cancellando l'evento in modo che il cursore del mouse torni alla casella di testo che ha un valore errato.

Questo funziona correttamente quando esco da quella casella di testo ad altri pulsanti/caselle di testo.

Ma quando entro in valore non corretto e chiudere il modulo (con il pulsante di chiusura in alto a destra), che convalida il contenuto della casella di testo e getta il messagebox e la forma doesnot vicino sto cacelling l'evento.

Il problema è che quando faccio clic sul pulsante X nell'angolo in alto a destra del modulo, non voglio che venga eseguita la convalida perché sto chiudendo il modulo comunque. Come posso fare questo?

Inserirò lo snippet di codice il prima possibile.

+0

Forse questa risposta: http://stackoverflow.com/a/25479010/1586914 potrebbe essere d'aiuto? – Adiono

risposta

2
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { 
    // Assume that X has been clicked and act accordingly. 
} 

Creare un evento di chiusura, quindi semplicemente annullare il validatore.

+0

Ho dimenticato di parlare del framework .net. Sto usando .Net Framework 1.1. The FormClosingEventArgs non è presente in esso. –

15

Per utilizzare convalidare i gestori come il 'txtIPAddress_Validating()' handler di seguito pur essendo in grado di chiudere il modulo senza dover inserire voci valide per farlo, faccio quanto segue:

1) Initate gestori di convalida: Dalle proprietà di controllo del controllo che si desidera attivare la convalida per il doppio clic sull'evento 'Validating' da questo elenco di eventi di controllo. È possibile accedere a un elenco di eventi di controllo facendo clic sul pulsante della barra degli strumenti evento della finestra delle proprietà di questo controllo (simile a un fulmine). È quindi possibile immettere il codice nel gestore generato automaticamente con un nome che combina sia il nome del controllo sia '_Validating'. La parte di questo gestore in cui qualcosa viene stabilito come non valido può forzare voci valide aggiungendo l'istruzione 'e.Cancel = true'.

Per tali esempi di metodi di convalida, vedere il codice 'txtIPAddress_Validating()' e 'txtMaskBits_Validating()' di seguito. Non distrarti dal meccanismo di convalida completo di questi esempi specifici. Tutto ciò che serve per vedere e riprodurre nel proprio codice al fine di costringere la convalida è quello di aggiungere la 'e.Cancel = true' istruzioni al posto giusto di un proprio metodo di convalida. Questo è quando il valore è identificato come non valido.

A questo punto la convalida dovrebbe funzionare bene, ma ogni tentativo di chiudere il modulo attiverà convalida che si fermerà e insistere per i valori validi prima di poter chiudere il modulo. Questo non è sempre quello che vuoi. Quando non è così, io continuo con il seguente.

2) pulsante annulla anche (disabilita 'Cancel') tutte le convalide: metodo

a) un pulsante di regolare 'Cancel' sulla forma che è associato ad un metodo come il 'btnCancel_Click()' sotto.

b) Prima del normale 'this.close();' istruzione, aggiungere "AutoValidate = AutoValidate.Disable;" istruzioni. Questa istruzione disabilita tutti i trigger "di convalida". Tieni presente che l'evento "btnCancel_Click" viene attivato prima che venga eseguita qualsiasi convalida. Non è così per gli eventi di chiusura del modulo che verranno eseguiti tutti dopo la convalida degli eventi. Questo è il motivo per cui tale convalida non può essere disabilitata da nessuno di questi eventi di chiusura moduli.

c) Per far funzionare correttamente questo pulsante "Annulla", è necessario impostare la proprietà "CausesValidation" di questo pulsante "Annulla" su "falso". Questo è necessario, altrimenti cliccando su questo pulsante si attiverà la convalida prima che la convalida possa essere disabilitata dal precedente 'AutoValidate = AutoValidate.Disable;' istruzioni.

A questo punto, dovresti essere in grado di uscire facendo clic sul pulsante "Annulla" senza dover prima inserire valori validi. Tuttavia, facendo clic sul pulsante "X" in alto a destra della finestra del modulo, verrà comunque forzata la convalida.

3) rendere il pulsante in alto a destra "X" anche annullare la convalida:

La sfida è quella di intrappolare tale "X" cliccato evento prima che venga eseguita la convalida. Qualsiasi tentativo di farlo tramite un gestore di chiusura del modulo non funzionerà perché è troppo tardi una volta che l'esecuzione raggiunge tale gestore. Tuttavia, il clic del pulsante "X" può essere acquisito prontamente tramite l'override del metodo WndProc() e il test per una condizione 'm.Msg == 0x10'. Quando questa condizione è vera, è stato introdotto in precedenza "AutoValidate = AutoValidate.Disable;" l'istruzione può essere nuovamente utilizzata per disabilitare la convalida generale anche in quel caso. Vedere il metodo WndProc() di seguito per un esempio di codice di tale metodo. Dovresti essere in grado di copiare e incollare quel metodo così com'è nella classe del tuo form.

A questo punto, entrambi i pulsanti "Annulla" e "X" devono annullare le valdazioni. Tuttavia, la chiave di escape che può essere utilizzata per chiudere un modulo non lo fa. Tale chiave di escape viene attivata quando la proprietà 'CancelButton' del modulo viene utilizzata per collegare questa chiave di escape al pulsante 'Annulla' del modulo.

4) Fai il tasto Esc anche annullare la convalida:

Simile al pulsante "X", la chiave di fuga può essere catturato sovrascrivendo un existingmethod. Questo è il metodo ProcessDialogKey(). Ancora una volta, "AutoValidate = AutoValidate.Disable" precedentemente introdotto; l'istruzione può essere utilizzata per disabilitare la convalida complessiva anche per la chiave di escape. Vedere il metodo sottoposto a override 'ProcessDialogKey()' nel codice qui sotto per vedere come questo può essere fatto. Anche in questo caso, dovresti essere in grado di copiare e incollare quel metodo come è nella classe del tuo modulo.

A questo punto si dovrebbe fare!

Ulteriori considerazioni:

E 'bene notare che i seguenti due altri modi per chiudere la finestra dovrebbe anche funzionare bene, a questo punto. Questi due modi sono:

  • L'opzione 'Chiudi' del pulsante icona della finestra in alto a sinistra.
  • Premendo Alt + F4 che attiva la stessa azione di chiusura dell'opzione 'Chiudi' sopra.

Questi due metodi di chiusura della finestra hanno iniziato a annullare anche la convalida dopo aver introdotto il meccanismo di cattura del pulsante "X" descritto al punto 3 sopra.

Questo è tutto per me finora. Sperando che questo aiuti!

codice di mio esempio riportato di seguito:

public partial class frmMyIP : Form 
{ 
    public frmMyIP() 
    { 
      InitializeComponent(); 
    } 

    // To capture the Upper right "X" click 
    protected override void WndProc(ref Message m) 
    { 
     if (m.Msg == 0x10) // The upper right "X" was clicked 
     { 
      AutoValidate = AutoValidate.Disable; //Deactivate all validations 
     } 
     base.WndProc(ref m); 
    } 

    // To capture the "Esc" key 
    protected override bool ProcessDialogKey(Keys keyData) 
    { 
     if (keyData == Keys.Escape) 
     { 
      AutoValidate = AutoValidate.Disable; 
      btnCancel.PerformClick(); 
      return true; 
     } 
     return base.ProcessDialogKey(keyData); 
    } 
    public bool IsValidIP(string ipaddr) 
    { 
     string pattern = @"^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"+ 
     @"(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$"; 

     Regex check = new Regex(pattern); 
     bool valid = false; 

     if (ipaddr == "") 
     { 
      valid = false; 
     } 
     else 
     { 
      valid = check.IsMatch(ipaddr, 0); 
     } 

     return valid; 
    } 

    private void txtIPAddress_Validating(object sender, CancelEventArgs e) 
    { 
     string address = txtIPAddress.Text; 
     if (!IsValidIP(address)) 
     { 
      MessageBox.Show("Invalid IP address!"); 
      e.Cancel = true; 
     } 
    } 

    private void cmbMaskBits_Validating(object sender, CancelEventArgs e) 
    { 
     int MaskBitsValue = Convert.ToInt32(cmbMaskBits.Text); 

     if (MaskBitsValue<1 || MaskBitsValue>30) 
     { 
     MessageBox.Show("Please select a 'Mask Bits' value between 1 and 30!"); 
     e.Cancel = true; 
     } 
    } 

    private void btnCancel_Click(object sender, EventArgs e) 
    { 
     // Stop the validation of any controls so the form can close. 
     // Note: The CausesValidation property of this <Cancel> button 
     //  must also be set to false. 

     AutoValidate = AutoValidate.Disable; 
     this.Close(); 
    } 
+0

Perfetto! Grazie! Questa dovrebbe essere la risposta corretta. –

+0

Elegante. Semplice e funziona come pubblicizzato. Grazie!! –

+0

Questa è una risposta molto complicata e dà anche UX orribile (puoi * tu * immaginare di dover fare clic su un pulsante prima di poter chiudere un modulo tutto il tempo). In effetti tutti qui sembrano saltare i cerchi per farlo funzionare. La risposta è ** veramente ** semplice, vedi la mia. – MarioDS

2

Inserire quanto segue come la prima linea in caso di convalida della casella di testo:

//Allow the form to be closed 
if (this.ActiveControl.Equals(sender)) 
    return; 

Dal momento che l'evento close del modulo sta provocando convalida e dal che sarebbe (in genere almeno) essere l'unico evento forma che farebbe scattare la convalida possiamo fare l'ipotesi che ogni caso sotto forma scatenante convalida è l'evento close.

1

Quello che vi serve è un'implementazione come quello descritto qui di seguito, in cui si presume che si dispone di un pulsante Salva e un pulsante Annulla per il modulo:

public Form1() 
    { 
     // Disable validation in constructor 
     textBox.CausesValidation = false; 
    } 

    private void OnSaveClicked(object sender, EventArgs e) 
    { 
     textBox.CausesValidation = true; 
     if (ValidateChildren()) 
     { 
      // 
      // Do saving of the form data or other processing here .... 
      // 
      Close(); 
     } 
     // 
     // Set validation to false, as user may press Cancel next 
     // 
     textBox.CausesValidation = false; 
    } 

    private void OnCancelClicked(object sender, EventArgs e) 
    { 
     Close(); 
    } 
0

Controllare che Button è attiva nel controllo di convalida . Se si cancella il pulsante (e nel mio caso un pulsante di cancellazione), esclude. Questo è un metodo interno che chiamo dalla mia cella che convalida il gestore di eventi. (Basta rese conto che era un C# domanda, ma è possibile tradurre)

Private Sub validateCell(ByVal tagDesc As String, ByVal userInput As String, ByVal legalRegex As String, ByVal regexDesc As String, ByVal e As DataGridViewCellValidatingEventArgs) 
    Dim match As Match = Regex.Match(userInput, legalRegex) 
    Dim matches = match.Groups() 
    Dim val = match.Value 
    If val.Length = 0 Or userInput.Length > val.Length Then 
     tagGrid.Rows(e.RowIndex).ErrorText = _ 
      tagDesc & " must match pattern: " & regexDesc 
     If Me.Cancel_Button.Focused Or Me.clearButton.Focused Then 
      e.Cancel = False 
      tagGrid.Rows(e.RowIndex).ErrorText = "" 
     Else 
      e.Cancel = True 
      MsgBox(tagDesc & " must match pattern: " & regexDesc, MsgBoxStyle.Critical) 
     End If 
    Else 
     e.Cancel = False 
     tagGrid.Rows(e.RowIndex).ErrorText = "" 
    End If 
End Sub 
0

Sono venuto qui in cerca di un metodo semplice per causare una forma di chiudere quando un gestore di eventi Validating solleva un'eccezione, rapporti, e le esigenze forzare la chiusura del modulo. Dopo aver letto questo argomento e numerosi altri, seguito da un pomeriggio di sperimentare, ho fatto diverse scoperte, e ha sviluppato un semplice hack per forzare il modulo per chiudere.

Per prima cosa, però; Ho scoperto che quando un evento Validating chiama this.Close() il bandiera FormClosingEventArgs.Cancel passato nella sua routine evento From_Closing è impostato su TRUE , causando in modo efficace l'evento per annullare se stesso. Al contrario, un normale evento Chiusura riceve un bandiera FormClosingEventArgs.Cancel impostato su FALSE .

Poiché il metodo Close non accetta argomenti, non esiste un modo diretto per forzare il problema, dando origine alla necessità di un hack. Questo articolo discute un numero di tali hack, ma penso che il mio sia molto più semplice da implementare.

L'hack inizia con una variabile booleana semplice livello di modulo.

bool _fExceptionIsFatal = false; 

parte definente un Form_Closing gestore di eventi , questa è l'unica modifica strutturale necessario al modulo.

L'evento Form_Closing è semplice.

private void From1_Closing (object sender , FormClosingEventArgs e) 
    { 
     if (this.CausesValidation) 
     { // There is no sense repeating this procedure if another routine already did it. 
      DisableValidation (); 
     } // if (this.CausesValidation)   

     if (_fExceptionIsFatal) 
     { // Cancel False == Allow form to close. 
      e.Cancel = false; 
     } // if (_fExceptionIsFatal) 
    } // From1_Closing 

Sebbene DisableValidation è implementato come un metodo locale della forma attuale, la stessa cosa potrebbe essere realizzato facendo passare un Forma riferimento in una routine di libreria, dal momento che un modulo è un modulo, ei suoi controlli la collezione è una collezione di Controls, periodo. In poco tempo, lo farò così, insieme a implementare il suo inverso, per accendere la convalida di nuovo.

private void DisableValidation () 
    { 
     foreach (Control ctrl in this.Controls) 
     { 
      ctrl.CausesValidation = false; 
     } // foreach (Control ctrl in this.Controls) 

     this.CausesValidation = false; 
    } // DisableValidation 

Il quarto pezzo della soluzione è altrettanto semplice; ogni volta che vuoi forzare la chiusura del modulo, imposta _intValueAsInteger a TRUE prima di chiamare this.Close.

0

Aggiungi il seguente codice al modulo. È possibile chiudere il modulo anche se i controlli figli sono in fase di convalida.

protected override void WndProc(ref Message m) 
{ 
    if (m.Msg == 0x10) // The upper right "X" was clicked 
    { 
     this.ActiveControl = null; 
     this.AutoValidate = AutoValidate.Disable; 
    } 
    base.WndProc(ref m); 
} 
0

La risposta reale è ridicolmente semplice rispetto a tutti i suggerimenti qui che coinvolgono hack e codice aggiuntivo superfluo annullare qualcosa.

Il "trucco" è solo per consentire allo stato attivo di cambiare e non attivare la convalida dai pulsanti sul modulo stesso.

si può semplicemente impostare due proprietà sul modulo:

MyForm.CausesValidation = false; 
MyForm.AutoValidate = AutoValidate.EnableAllowFocusChange; 

Et voilà, la forma agisce normale quando si tenta di chiuderlo e convalida funziona ancora dopo altri input come ad esempio scheda cambiare clic del fuoco o del mouse .

+0

Questa risposta non disabilita i validatori a livello di campo – pmartin

Problemi correlati