45 Stimmen

WinForm UI-Validierung

Ich brauche, um Eingabevalidierung in meinem Winform app zu implementieren. Es gibt viele verschiedene Formulare, wo Daten eingegeben werden können, und ich möchte nicht gehen Kontrolle durch Kontrolle durch Form und erstellen isValid usw. pro Element. Wie haben andere mit diesem behandelt?

Ich sehe, dass die meisten verwandten Beiträge sich mit Web Apps befassen und/oder erwähnen Enterprise Library Validation Anwendungsblock . Ich gebe zu, dass ich ELVAB nicht gründlich recherchiert habe, aber es parece wie Overkill für das, was ich brauche. Mein derzeitiger Gedanke ist, eine Klassenbibliothek mit den verschiedenen Anforderungen zu schreiben und übergeben Sie es ein Steuerelement als Parameter. Ich habe bereits eine Bibliothek von RegEx-Funktionen für Dinge wie isValidZipCode und so weiter, also könnte das ein guter Anfang für mich sein.

Was ich haben möchte, ist eine Schaltfläche Validieren, die onClick Zyklen durch alle Steuerelemente auf dieser Formularseite und führt die erforderliche Validierung. Wie kann ich das erreichen?

66voto

Matt Brunell Punkte 9892

Die Validierung ist bereits in die WinForms-Bibliothek integriert.

Jede Control -abgeleitete Objekt hat zwei Ereignisse namens Validating y Validated . Außerdem hat es eine Eigenschaft namens CausesValidation . Wenn dies auf true gesetzt ist (standardmäßig ist es true), nimmt das Steuerelement an der Validierung teil. Andernfalls nimmt es nicht teil.

Die Validierung erfolgt als Teil des Fokus. Wenn Sie den Fokus von einem Steuerelement nehmen, werden dessen Validierungsereignisse ausgelöst. Die Fokusereignisse werden in einer bestimmten Reihenfolge abgefeuert. Von MSDN :

Wenn Sie den Fokus mit der Taste Tastatur (TAB, SHIFT+TAB, usw.), durch den Aufruf der Methoden Select oder SelectNextControl-Methoden, oder durch Setzen des ContainerControl..::.ActiveControl Eigenschaft auf das aktuelle Formular, Fokus Ereignisse in der folgenden Reihenfolge ein:

  1. Eingabe
  2. GotFocus
  3. Verlassen Sie
  4. Validierung
  5. Validiert
  6. LostFocus

Wenn Sie den Fokus mit der Taste Maus oder durch Aufruf der Methode Focus, treten Fokusereignisse in der folgenden Reihenfolge:

  1. Eingabe
  2. GotFocus
  3. LostFocus
  4. Verlassen Sie
  5. Validierung
  6. Validiert

Wenn die Eigenschaft CausesValidation auf false gesetzt ist, werden die Ereignisse Validating und Validated Ereignisse unterdrückt.

Wenn die Eigenschaft Abbrechen der CancelEventArgs auf true gesetzt wird, werden im Validierungs-Ereignisdelegat gesetzt wird, werden alle Ereignisse die normalerweise nach dem Validierungsereignis auftreten würden, unterdrückt.

Auch ein ContainerControl hat eine Methode namens ValidateChildren() die die enthaltenen Steuerelemente in einer Schleife durchläuft und sie validiert.

44voto

Bruce Punkte 551

Ich weiß, dass dieser Thread schon ziemlich alt ist, aber ich dachte, ich poste mal die Lösung, die ich gefunden habe.

Das größte Problem bei der Validierung in WinForms ist, dass die Validierung nur ausgeführt wird, wenn das Steuerelement "den Fokus verloren" hat. Der Benutzer muss also erst in ein Textfeld klicken und dann irgendwo anders klicken, damit die Validierungsroutine ausgeführt wird. Dies ist in Ordnung, wenn Sie nur darauf achten, dass die eingegebenen Daten korrekt sind. Aber das funktioniert nicht gut, wenn Sie versuchen, sicherzustellen, dass ein Benutzer ein Textfeld nicht leer gelassen hat, indem er es überspringt.

Wenn der Benutzer in meiner Lösung auf die Schaltfläche "Submit" für ein Formular klickt, überprüfe ich jedes Steuerelement auf dem Formular (oder dem angegebenen Container) und verwende Reflection, um festzustellen, ob eine Validierungsmethode für das Steuerelement definiert ist. Ist dies der Fall, wird die Validierungsmethode ausgeführt. Wenn eine der Überprüfungen fehlschlägt, gibt die Routine einen Fehler zurück und ermöglicht es, den Prozess zu beenden. Diese Lösung funktioniert besonders gut, wenn Sie mehrere Formulare zu validieren haben.

1) Kopieren Sie einfach diesen Abschnitt des Codes und fügen Sie ihn in Ihr Projekt ein. Da wir Reflection verwenden, müssen Sie System.Reflection zu Ihren using-Anweisungen hinzufügen

class Validation
{
    public static bool hasValidationErrors(System.Windows.Forms.Control.ControlCollection controls)
    {
        bool hasError = false;

        // Now we need to loop through the controls and deterime if any of them have errors
        foreach (Control control in controls)
        {
            // check the control and see what it returns
            bool validControl = IsValid(control);
            // If it's not valid then set the flag and keep going.  We want to get through all
            // the validators so they will display on the screen if errorProviders were used.
            if (!validControl)
                hasError = true;

            // If its a container control then it may have children that need to be checked
            if (control.HasChildren)
            {
                if (hasValidationErrors(control.Controls))
                    hasError = true;
            }
        }
        return hasError;
    }

    // Here, let's determine if the control has a validating method attached to it
    // and if it does, let's execute it and return the result
    private static bool IsValid(object eventSource)
    {
        string name = "EventValidating";

        Type targetType = eventSource.GetType();

        do
        {
            FieldInfo[] fields = targetType.GetFields(
                 BindingFlags.Static |
                 BindingFlags.Instance |
                 BindingFlags.NonPublic);

            foreach (FieldInfo field in fields)
            {
                if (field.Name == name)
                {
                    EventHandlerList eventHandlers = ((EventHandlerList)(eventSource.GetType().GetProperty("Events",
                        (BindingFlags.FlattenHierarchy |
                        (BindingFlags.NonPublic | BindingFlags.Instance))).GetValue(eventSource, null)));

                    Delegate d = eventHandlers[field.GetValue(eventSource)];

                    if ((!(d == null)))
                    {
                        Delegate[] subscribers = d.GetInvocationList();

                        // ok we found the validation event,  let's get the event method and call it
                        foreach (Delegate d1 in subscribers)
                        {
                            // create the parameters
                            object sender = eventSource;
                            CancelEventArgs eventArgs = new CancelEventArgs();
                            eventArgs.Cancel = false;
                            object[] parameters = new object[2];
                            parameters[0] = sender;
                            parameters[1] = eventArgs;
                            // call the method
                            d1.DynamicInvoke(parameters);
                            // if the validation failed we need to return that failure
                            if (eventArgs.Cancel)
                                return false;
                            else
                                return true;
                        }
                    }
                }
            }

            targetType = targetType.BaseType;

        } while (targetType != null);

        return true;
    }

}

2) Verwenden Sie das Standard-Validierungsereignis für jedes Steuerelement, das Sie validieren möchten. Achten Sie darauf, e.Cancel zu verwenden, wenn die Validierung fehlschlägt!

private void txtLastName_Validating(object sender, CancelEventArgs e)
    {
        if (txtLastName.Text.Trim() == String.Empty)
        {
            errorProvider1.SetError(txtLastName, "Last Name is Required");
            e.Cancel = true;
        }
        else
            errorProvider1.SetError(txtLastName, "");
    }

3) Überspringen Sie diesen Schritt nicht! Setzen Sie die AutoValidieren Eigenschaft auf dem Formular zu EnableAllowFocusChange . Dies ermöglicht den Wechsel zu einem anderen Steuerelement, auch wenn die Validierung fehlschlägt.

4) Rufen Sie schließlich in Ihrer Submit-Button-Methode die Validation-Methode auf und geben Sie an, welchen Container Sie überprüfen möchten. Dabei kann es sich um das gesamte Formular oder nur um einen Container auf dem Formular handeln, z. B. einen Bereich oder eine Gruppe.

private void btnSubmit_Click(object sender, EventArgs e)
    {
        // the controls collection can be the whole form or just a panel or group
        if (Validation.hasValidationErrors(frmMain.Controls))
            return;

        // if we get here the validation passed
        this.close();
    }

Viel Spaß beim Coding!

9voto

RS Conley Punkte 7136

In meiner eigenen Anwendung muss ich die eingegebenen Maße validieren. Die von mir verwendete Sequenz lautet wie folgt

  1. Der Benutzer wählt oder tippt und bewegt dann von dem Steuerelement weg.
  2. Das Steuerelement verliert den Fokus und benachrichtigt die Ansicht, indem es seine ID und den Eingabetext.
  3. Die Ansicht prüft, was das Shape-Programm (eine Klasse, die eine Schnittstelle implementiert) das Formular erstellt hat und übergibt ihm die ID und den Eingabetext
  4. Das Shape-Programm liefert eine Antwort.
  5. Wenn die Antwort OK ist, aktualisiert die Ansicht den korrekten Eintrag des Shapes Klasse.
  6. Wenn die Antwort OK ist, sagt die Ansicht dem Formular über eine Schnittstelle mit, dass es dass es OK ist, den Fokus auf den nächsten Eintrag zu verschieben.
  7. Wenn die Antwort nicht OK ist, wird die Ansicht die Antwort und verwendet die Formularschnittstelle dem Formular mitteilt, was zu tun ist. Dies bedeutet normalerweise, dass der Fokus auf den fehlerhaften Eintrag zurückverlagert mit einer Meldung, die dem Benutzer mitteilt was passiert ist.

Der Vorteil dieses Ansatzes ist, dass die Validierung für ein bestimmtes Shape-Programm an einer Stelle zentralisiert ist. Ich muss nicht jedes einzelne Steuerelement ändern oder mir gar Gedanken über die verschiedenen Arten von Steuerelementen im Formular machen. Schon bei der Entwicklung der Software habe ich entschieden, wie die Benutzeroberfläche für Textfelder, Listenfelder, Kombinationsfelder usw. funktionieren soll. Auch verschiedene Schweregrade werden unterschiedlich gehandhabt.

Die Ansicht kümmert sich darum, indem sie dem Formular über die Schnittstelle mitteilt, was es tun soll. Wie es tatsächlich implementiert wird, wird vom Formular selbst in seiner Implementierung der Schnittstelle gehandhabt. Die Ansicht kümmert sich nicht darum, ob das Formular gelb für Warnungen und rot für Fehler anzeigt. Es geht nur darum, dass es diese beiden Stufen behandelt. Wenn später eine bessere Idee für die Anzeige von Warnungen und Fehlern auftaucht, kann ich die Änderung im Formular selbst vornehmen, anstatt mit der Logik der Ansicht oder der Validierung im Shape-Programm herumzupfuschen.

Sie sind bereits auf halbem Wege, wenn Sie erwägen, eine Klasse zu machen, um Ihre Validierungslogik zu halten, wird dies Sie den Rest des Weges in Ihrem neuen Design zu bekommen.

4voto

Joel Coehoorn Punkte 377088

Ich möchte nicht zu gehen Steuerelement für Steuerelement von Formular und erstellen isValid etc. pro Element.

Auf einer gewissen Ebene müssen Sie definieren, was es bedeutet, ein valid für jedes Steuerelement, es sei denn, es geht Ihnen nur darum, dass das Steuerelement irgendeinen Wert hat.

Das heißt, es gibt eine ErrorProvider-Komponente die Sie verwenden können und die ziemlich gut funktioniert.

3voto

Jamie Ide Punkte 46985

Wir hatten viel Glück mit dem Noogen ValidationProvider . Für einfache Fälle (Datentypprüfungen und obligatorische Felder) ist es einfach, für komplexere Fälle kann eine benutzerdefinierte Validierung hinzugefügt werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X