Necesito para implementar la validación de entrada a lo largo de mi aplicación winform. Hay muchas formas diferentes en los que los datos pueden ser introducidos y me gustaría no pasar el control por el control de formulario y crear isValid etc por artículo. Cómo otros han lidiado con esto?

Veo que la mayoría de los puestos relacionados con lidiar con las Aplicaciones Web y/o mención Enterprise Library Validación De Bloqueo De La Aplicación. Admito que no he investigado a fondo ELVAB pero parece como excesivo para lo que yo necesito. Mi pensamiento actual es escribir una biblioteca de clases con los diversos requisitos y pasar un control como un parámetro. Ya tengo una Biblioteca de funciones RegEx para cosas como isValidZipCode y de tal manera que puede ser un lugar para mí para empezar.

Lo que me gustaría es tener un botón Validar que onClick ciclo a través de todos los controles que la Página de Formulario y realiza la necesaria validación. ¿Cómo puedo lograr esto?

11 Comentarios

  1. 8

    En mi aplicación tengo que validar las dimensiones, ya que se escriben en. La secuencia es como sigue

    1. El usuario selecciona o escribe a continuación, se mueve
      lejos de la de control.
    2. El control pierde el foco y notifica
      la Opinión de envío y la ID de la
      entrada de texto.
    3. La Vista de las comprobaciones de qué Forma el Programa de
      (una clase que implementa una interfaz)
      crea el Formulario y le pasa el
      ID y entrada de texto
    4. La Forma de Programa devuelve un
      respuesta.
    5. Si la Respuesta es ACEPTAR el punto de Vista
      las actualizaciones de Entrada correcta de la Forma
      Clase.
    6. Si la Respuesta es ACEPTAR el punto de Vista dice
      la Forma a través de una Interfaz que
      está bien para cambiar el foco a la siguiente entrada.
    7. Si la Respuesta es no ACEPTAR el punto de Vista
      mira la respuesta y el uso de la
      Formulario de Interfaz indica la forma de lo que
      a hacer. Esto normalmente significa que el enfoque
      cambia a la misma entrada
      con un mensaje que se muestra decirle a la
      usuario de lo ocurrido.

    La ventaja de este enfoque que la validación es centralizada en un solo lugar para una determinada Forma de Programa. Yo no tengo que ir a modificar cada control o incluso realmente preocuparse acerca de los diferentes tipos de controles en el formulario. Camino de regreso cuando he diseñado el software decidí cómo la interfaz de usuario que va a trabajar para cuadros de texto, cuadros de lista, cuadros combinados, etc. También diferentes niveles de gravedad se maneja de forma diferente.

    La Vista se ocupa de instruir el Formulario de qué hacer a través de la Interfaz. La forma en que realmente se implementa es manejado por la Forma misma en que la implementación de la Interfaz. La Vista no importa si el Formulario está mostrando el amarillo de advertencia y la roja para el error. Sólo que se encarga de esos dos niveles. Más adelante, si una mejor idea de mostrar advertencia vs los errores que viene puedo hacer el cambio en la Forma en sí, en vez jugando con el punto de Vista de la lógica o la de validar en Forma de Programa.

    Ya estás a mitad de camino si usted está considerando hacer una clase para mantener su lógica de validación de esta manera se consigue que el resto del camino en su nuevo diseño.

  2. 62

    De validación ya está integrado en la WinForms biblioteca.

    Cada Controlderivados de objeto tiene dos eventos denominado Validating y Validated. También tiene una propiedad llamada CausesValidation. Cuando se establece a true (es true por defecto), entonces el control participa en la validación. De lo contrario, no.

    De validación se produce como parte de la atención. Cuando el foco de un control, su validación eventos se activan. De hecho, el enfoque eventos se activan en un orden específico. De MSDN:

    Cuando cambie el foco mediante el uso de la
    teclado (TAB, SHIFT+TAB, y así sucesivamente),
    llamando al Seleccionar o
    SelectNextControl métodos, o por
    ajuste de la
    ContainerControl..::.ActiveControl
    propiedad a la forma actual, el enfoque
    los acontecimientos ocurren en el siguiente orden:

    1. Entrar
    2. GotFocus
    3. Dejar
    4. La validación de
    5. Validado
    6. LostFocus

    Cuando cambie el foco mediante el uso de la
    ratón o llamando al método de Enfoque,
    enfoque de los acontecimientos ocurren en el siguiente
    orden:

    1. Entrar
    2. GotFocus
    3. LostFocus
    4. Dejar
    5. La validación de
    6. Validado

    Si la propiedad CausesValidation es
    establece en false, la Validación y
    Eventos validados son suprimidos.

    Si la propiedad Cancel de la
    CancelEventArgs se establece en true en el
    La validación de delegado de eventos, todos los eventos
    que generalmente ocurren después de la
    Evento de validación se suprimen.

    También un ContainerControl tiene un método llamado ValidateChildren() que el bucle a través de controles contenidos, y validarlos.

  3. 42

    Me doy cuenta de que este hilo es bastante antiguo, pero yo pensé que había puesto la solución que se me ocurrió.

    El mayor problema con la validación de formularios windows forms es la validación que sólo se ejecuta cuando el control se ha «perdido el foco». Por lo que el usuario ha hecho clic en un cuadro de texto, a continuación, haga clic en alguna otra parte de la rutina de validación para ejecutar. Esto está bien si sólo se preocupan de los datos introducidos son correctos. Pero esto no funciona bien si usted está tratando de asegurarse de que un usuario no salir de un cuadro de texto vacío sin pasar por encima de él.

    En mi solución, cuando el usuario hace clic en el botón submit de un formulario, puedo comprobar cada control en el formulario (o cualquier recipiente se especifica) y el uso de la reflexión para determinar si la validación de un método definido para el control. Si es así, el método de validación se ejecuta. Si alguna de las validaciones de fallar, la rutina devuelve un error y permite que el proceso se detenga. Esta solución funciona bien, especialmente si usted tiene varias formas para validar.

    1) Sólo tienes que copiar y pegar esta sección de código a su proyecto. Estamos utilizando la Reflexión por lo que deberá añadir el Sistema.Reflexión para el uso de declaraciones

    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) Utilizar el estándar de evento de Validación sobre cualquier tipo de control que desea validar. Asegúrese de utilizar el correo.Cancelar cuando falla la validación!

    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) no se salte este paso! Establecer el AutoValidate de la propiedad en el formulario para EnableAllowFocusChange. Esto permitirá desplazarse a otro de control, incluso cuando falla la validación.

    4) por último, en el Botón de Enviar método, llamada el método de Validación y especificar en qué contenedor que desea comprobar. Puede ser el todo el formulario, o simplemente un contenedor en el formulario como un Panel o un Grupo.

    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();
    }

    Feliz Codificación!

    • Hola Bruce, Impresionante código! Pero ¿por qué debe establecer e.Cancel a true? creo que si yo no puedo ficha de control, si lo hago, no puede abandonar el control de corriente.
    • Mira el paso 3
    • sí, yo vi eso, yo creo que puede ser la tercera parte de los controles que usamos, porque cuando me juego que no hacer una diferencia.
    • Buena explicación paso a paso. Muy versátil respuesta, funciona para muchas arquitecturas.
    • Sistema.Refelection se ha escrito mal el anterior…
    • Usted podría simplemente llame ValidateChildren de la forma que se trigg la validación de todos los eventos y devuelve falso si uno de ellos se cancela. Estoy de acuerdo en que el comportamiento predeterminado «PreventFocusChange» no debe ser utilizado si usted utiliza un ErrorProvider (Pero esa es otra historia porque validateChildren comprobará en cualquier caso)

  4. 4

    Me gustaría no tener que pasar el control por el control de formulario y crear isValid etc por artículo.

    Como un cierto nivel, usted tendrá que definir lo que significa ser valid para cada control, a menos que todo lo que importa es que el control tiene un valor de algún tipo.

    Que dijo, no hay un ErrorProvider componente puede utilizar que funciona bastante bien.

  5. 3

    Hemos tenido buena suerte con el Noogen ValidationProvider. Es muy sencillo para los casos simples (tipo de datos de los cheques y los campos requeridos) y fácil para agregar una validación personalizada para los casos más complejos.

    • Noogen NO es Winforms, es ASP.NET WebForms!
    • Eso no es cierto. No sé cómo lo usarías ASP.NET, se usa en varias aplicaciones WinForms.
  6. 2

    En todas mis formas, me implementar el isValidating evento para el control concreto en cuestión y si los datos no validar tengo una errorProvider en la forma y uso de su SetError(…) el método para establecer el error para el control en cuestión con información relevante de por qué es malo.

    editar> debo señalar que yo generalmente uso el patrón mvc cuando se hace esto, por lo que la validación específica para ese control/miembro de la modelo que sucede en el modelo, por lo que el isValidating se ve un poco como esto:

    private uicontrol_isValidating(...)
    {
    if(!m_Model.MemberNameIsValid())
    {
    errorProvider.SetError(...);
    }
    }
  7. 2

    Ya sea de esa manera. O usted puede tener un único evento de validación asociados con todos los controles o que necesitan similar validaciones. Esto eliminará el bucle desde el código. Dicen que usted tiene cuatro cuadros de texto que puede tener entero solo. Lo que usted puede hacer es tener un evento único para cada uno de ellos. No voy a tener IDE así que el código de abajo es el mejor que me puede venir para arriba con.

    this.textbox1.Validated += <ValidatedEvent>
    this.textbox2.Validated += <ValidatedEvent>
    this.textbox3.Validated += <ValidatedEvent>
    this.textbox4.Validated += <ValidatedEvent>

    En el evento:

    1. Elenco remitente como el cuadro de texto.
    2. Comprobar si el valor en el cuadro de texto es numérico.

    Y así sucesivamente usted tiene eventos alineados.

    Espero que esto ayude.

  8. 2

    Si se combinan las ideas anteriores con este genérico Validación de controlador de evento que usted conseguirá un buen error de validación de «marco» con todos los métodos de validación en sus clases de negocios. Me acaba de prolongar Bruce código con el danés idea.
    El fue hecho para Entity Framework y Dev Express componentes, pero de esas dependencias se puede quitar fácilmente.
    ¡A disfrutar!

    public class ValidationManager
    {
    ///<summary>
    ///Call this method to validate all controls of the given control list 
    ///Validating event will be called on each one
    ///</summary>
    ///<param name="controls"></param>
    ///<returns></returns>
    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;
    }
    ///<summary>
    ///Attach all youe Validating events to this event handler (if the controls requieres validation)
    ///A method with name Validate + PropertyName will be searched on the binded business entity, and if found called
    ///Throw an exception with the desired message if a validation error is detected in your method logic
    ///</summary>
    ///<param name="sender"></param>
    ///<param name="e"></param>
    public static void ValidationHandler(object sender, CancelEventArgs e)
    {
    BaseEdit control = sender as BaseEdit;
    if (control.DataBindings.Count > 0) //control is binded
    {
    string bindedFieldName = control.DataBindings[0].BindingMemberInfo.BindingField;
    object bindedObject = control.BindingManager.Current;
    if (bindedObject != null) //control is binded to an object instance
    {
    //find and call method with name = Validate + PropertyName
    MethodInfo validationMethod = (from method in bindedObject.GetType().GetMethods()
    where method.IsPublic &&
    method.Name == String.Format("Validate{0}",bindedFieldName) &&
    method.GetParameters().Count() == 0
    select method).FirstOrDefault();
    if (validationMethod != null) //has validation method
    {
    try
    {
    validationMethod.Invoke(bindedObject, null);
    control.ErrorText = String.Empty; //property value is valid
    }
    catch (Exception exp)
    {
    control.ErrorText = exp.InnerException.Message;
    e.Cancel = true;
    }
    }
    }
    }
    }
    //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;
    }
    }

    De la muestra método de validación:

    partial class ClientName
    {
    public void ValidateFirstName()
    {
    if (String.IsNullOrWhiteSpace(this.FirstName))
    throw new Exception("First Name is required.");
    }
    public void ValidateLastName()
    {
    if (String.IsNullOrWhiteSpace(this.LastName))
    throw new Exception("Last Name is required.");
    }
    }
  9. 1

    Ciclismo a través de los controles que puede funcionar, pero es propenso a error. He trabajado en un proyecto que utiliza esa técnica (concedido fue un proyecto de Delphi no C#) y funcionó como se esperaba, pero es muy difícil de actualizar si un control se han agregado o cambiado. Esto puede haber sido corregible. No estoy seguro.

    De todos modos se trabajó mediante la creación de un único controlador de eventos que a continuación se acompaña a cada control. El controlador entonces usaría RTTI para determinar el tipo de control. Entonces se podría utilizar el nombre del control de la propiedad en una gran instrucción select para buscar el código de validación para ejecutar. Si el error de validación, un mensaje de error se envía al usuario y el control se obtiene el foco. Para hacer las cosas más complejas, el formulario se divide en varias pestañas y la propia ficha tuvo que ser visible para que el niño de control para obtener el foco.

    Así que esa es mi experiencia.

    Que me gustaría mucho uso Pasivo de la Vista patrón de diseño para eliminar todas las reglas del negocio de la forma y empuje en una clase de moderador. Dependiendo de su estado de forma que puede ser más trabajo que estás dispuesto a invertir.

    • Pasivo de la Vista patrón de diseño? Tengo cero exsposure a los Patrones de Diseño, así que voy a buscar en este. Esperar un post llamado «¿Cómo implementar un Pasivo Vista Patrón de Diseño?» 🙂
    • En realidad su más de un patrón de arquitectura. martinfowler.com/eaaDev/PassiveScreen.html
  10. 1

    Sólo una idea aproximada:

    
    void btnValidate_Click(object sender, EventArgs e)
    {
    foreach( Control c in this.Controls )
    {
    if( c is TextBox )
    {
    TextBox tbToValidate = (TextBox)c;
    Validate(tbToValidate.Text);
    }
    }
    }
     
    

    Podría palo de los cuadros de texto dentro de un panel, y sólo el bucle a través de los controles en no si desea evitar el bucle a través de otros controles.

  11. 1

    Por qué no usar evento de Validación? Usted puede tener un único evento de validación y validar los controles de allí. No habrá necesidad de la utilización de bucles y cada control será validado como se introducen los datos.

    • Evento De Validación? Para establecer el evento de Validación en cada control para la validación específica? Sería posible que usted proporcione un ejemplo más detallado o un enlace? Gracias!
    • También, lo que si nunca ir a ese campo? Lo que comienza el Evento de Validación?
    • Para el segundo comentario: AFAIK en este caso usted no tiene ninguna opción pero el bucle a través de. En la mayoría, se puede evitar la comprobación de los controles que ya han sido validados.

Dejar respuesta

Please enter your comment!
Please enter your name here