none
ValidationRules para un campo de texto de fecha

    Question

  • Buenas,

    Me gustaría crear un ValidationRules para un campo de texto que detecte que lo que el usuario ha escrito (al quitar el cursor del campo de texto) evalue si es una fecha y/o por ejemplo si pones 1/1/11 te ponga despues 01/01/2011.

    Sabeis de algun ejemplo?

     

    Gracias

    Tuesday, April 19, 2011 12:12 PM

Answers

  • Hola Igor.

    ya que estamos puestos, te he realizado un ejemplillo con todo eso, y de ahi tu ya sacas lo que necesites, en un principio, se puede hacer de forma mas sencilla con propiedades DateTime, pero lo he realizado de esta forma para poder personalizarlo "al gusto".

    Bien, comenzamos con el codigo .xaml que quedaria algo asi:

      <Window.Resources>
        <local:model x:Key="model" />
        <local:DateConverter x:Key="DateConverter" />
      </Window.Resources>
      
      <Grid>
        <TextBox Height="23" Margin="60,0,98,106" x:Name="Fecha" >
          <TextBox.Text>
            <Binding Path="Date" Source="{StaticResource model}" Converter="{StaticResource DateConverter}">
              <Binding.ValidationRules>
                <local:DateTimeRule />
              </Binding.ValidationRules>
            </Binding>
          </TextBox.Text>
        </TextBox>
        
        <TextBox Height="23" HorizontalAlignment="Left" Margin="60,186,0,0" Name="textBox1" VerticalAlignment="Top" Width="172" />
        
      </Grid>
    

    En este codigo, he puesto 2 textbox, el primero para probar a insertar la fecha y el segundo para poder retirar el foco (claro esta).

    Como se puede observar, implemento una regla de validacion y un converter para modificar el resultado que se muestra.

    (Hace falta añadir el namespace 'local' con la ruta donde residan las clases del codigo .cs)

     

    El codigo .cs:

      public class model : INotifyPropertyChanged
      {
        /// <summary>Variable miembro para guardar una fecha</summary>
        private string m_date;
    
        /// <summary>
        /// Propiedad con la fecha
        /// </summary>
        public string Date
        {
          get { return m_date; }
          set
          {
            m_date = value;
            OnPropertyChanged("Date");
          }
        }
    
        #region [INotifyPropertyChanged]
    
        /// <summary>
        /// declarar el evento ocurrido cuando una propiedad de este objeto tiene un nuevo valor
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
    
        /// <summary>
        /// Definicion del evento PropertyChanged que sera llamado cuando un valor de una propiedad sea modificado
        /// </summary>
        /// <param name="_propertyName">El nombre de la propiedad con el nuevo valor</param>
        protected virtual void OnPropertyChanged(string _propertyName)
        {
          // añadir el manejador del evento
          PropertyChangedEventHandler handler = this.PropertyChanged;
          // si existe el manejador del evento, se invoca
          if (handler != null)
          {
            var e = new PropertyChangedEventArgs(_propertyName);
            handler(this, e);
          }
        }
    
        #endregion [INotifyPropertyChanged]
    
    
      }
    
      /// <summary>
      /// Clase conversora para una propiedad de fecha
      /// </summary>
      public class DateConverter : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
          return (null == value) ? "" : string.Format("{0:dd/MM/yyyy}", System.Convert.ToDateTime((string)value));
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
          DateTime resultDateTime;
          if (DateTime.TryParse((string)value, out resultDateTime))
          {
            return string.Format("{0:dd/MM/yyyy}", resultDateTime);
          }
          return DependencyProperty.UnsetValue;
        }
      }
    
      /// <summary>
      /// Clase con las reglas de validacion para una fecha valida
      /// </summary>
      public class DateTimeRule : ValidationRule
      {
        public override ValidationResult Validate(object _value, System.Globalization.CultureInfo _cultureInfo)
        {
          // expresion regular para fechas en formato dd/mm/yyyy
          System.Text.RegularExpressions.Regex regex =
           new System.Text.RegularExpressions.Regex(@"^(((0?[1-9]|[12]\d|3[01])[\.\-\/](0?[13578]|1[02])[\.\-\/]((1[6-9]|[2-9]\d)?" +
             @"\d{2}|\d))|((0?[1-9]|[12]\d|30)[\.\-\/](0?[13456789]|1[012])[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|((0?[1-9]|1\d|2[0-8])" +
            @"[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|(29[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|" +
            @"((16|[2468][048]|[3579][26])00)|00|[048])))$");
    
          return new ValidationResult(regex.IsMatch((string)_value), null);
        }
      }
    

     

    Bueno, este codigo, tampoco hay que hablar mucho de el, tan solo son 2 clases, 1 con la regla de validacion (en la cual he modificado la expresion regular para poder insertar fechas de tipo 'd/m/yyyy' o 'dd/mm/yyyy' para probar.

    La otra clase es un modelo CLR de prueba, que sera reemplazado por el tipo de modelo que tu quieras.

    Bueno, en principio, ha quedado bastante chulo ;), se modifica la fecha y todo.

    Pruebalo y me cuentas que tal.

     


    Saludos
    David González
    MCP, MCTS
    Visita mi Blog en: http://www.dgzornoza.com/
    Wednesday, April 20, 2011 1:51 PM

All replies

  • Hola Igor.

    Bueno, una opcion bastante personalizable seria crearte un validador propio con una expresion regular que valide la fecha, algo como esto:

    codigo xaml:

     

      <TextBox x:Name="fecha" Margin="0,0,0,251">
       <TextBox.Text>
        <Binding Path="date" Source="{StaticResource model}">
         <Binding.ValidationRules>      
          <local:DateTimeRule />      
         </Binding.ValidationRules>
        </Binding>
       </TextBox.Text>
      </TextBox>
    

     

    y luego en el codigo defines la clase que tendra el validador:

     

     public class DateTimeRule : ValidationRule 
     {
    
      public override ValidationResult Validate(object _value, System.Globalization.CultureInfo _cultureInfo)
      {   
       // expresion regular para fechas en formato dd/mm/yyyy
       System.Text.RegularExpressions.Regex regex =
        new System.Text.RegularExpressions.Regex(@"(((0[1-9]|[12][0-9]|3[01])([/])(0[13578]|10|12)([/])(\d{4}))" + 
         @"|(([0][1-9]|[12][0-9]|30)([/])(0[469]|11)([/])(\d{4}))|((0[1-9]|1[0-9]|2[0-8])([/])(02)([/])(\d{4}))" + 
         @"|((29)(\.|-|\/)(02)([/])([02468][048]00))|((29)([/])(02)([/])([13579][26]00))|((29)([/])(02)([/])" + 
         @"([0-9][0-9][0][48]))|((29)([/])(02)([/])([0-9][0-9][2468][048]))|((29)([/])(02)([/])([0-9][0-9][13579][26])))");
    
       return new ValidationResult(regex.IsMatch((string)_value), null);
      }
    
     }
    

     

    Con esto ya tendrias un validador para fechas de tipo DD/MM/YYYY, puedes encontrar expresiones regulares en:

    http://regexlib.com/

     

    Luego para que te cambie el formato, yo implementaria un converter, aunque si te pasa la expresion regular, lo puedes convertir directamente en la propiedad.

     

     


    Saludos
    David González
    MCP, MCTS
    Visita mi Blog en: http://www.dgzornoza.com/

    • Proposed as answer by CorsarioVasco Tuesday, April 19, 2011 7:11 PM
    • Unproposed as answer by CorsarioVasco Wednesday, April 20, 2011 6:30 PM
    Tuesday, April 19, 2011 7:03 PM
  • Buenas David,

     

    Lo primero, gracias por contestar.

     

    Te comento, en primer lugar he implementado la función que me has puesto en VB.NET. Queda así:

     

    Public MustInherit Class DateTimeRule
        Inherits ValidationRule

        Public Overrides Function Validate(ByVal _value As Object, ByVal _cultureInfo As System.Globalization.CultureInfo) As ValidationResult

            Dim regex As New System.Text.RegularExpressions.Regex("(((0[1-9]|[12][0-9]|3[01])([/])(0[13578]|10|12)([/])(\d{4}))" & "|(([0][1-9]|[12][0-9]|30)([/])(0[469]|11)([/])(\d{4}))|((0[1-9]|1[0-9]|2[0-8])([/])(02)([/])(\d{4}))" & "|((29)(\.|-|\/)(02)([/])([02468][048]00))|((29)([/])(02)([/])([13579][26]00))|((29)([/])(02)([/])" & "([0-9][0-9][0][48]))|((29)([/])(02)([/])([0-9][0-9][2468][048]))|((29)([/])(02)([/])([0-9][0-9][13579][26])))")

            Return New ValidationResult(regex.IsMatch(DirectCast(_value, String)), Nothing)

        End Function

    End Class

     

    Al ejecutar me da este fallo que no se por donde cojerlo:

     

    No se puede crear un objeto de tipo 'ValidationRules.DateTimeRule'. Error de CreateInstance que puede estar causado por no tener un constructor público predeterminado para 'ValidationRules.DateTimeRule'.  Error en el objeto 'System.Windows.Data.Binding' en el archivo de marcado 'ValidationRules;component/window1.xaml' Línea 15 Posición 26.

     

    Desde luego tu solución va por buen camino. Es similar al código que estoy encontrado por foros. Dada mi inexperencia con el mundo del XAML pues no consigo ejecutrarlo,

    Wednesday, April 20, 2011 7:09 AM
  • Hola Igor.

    ¿has implementado el recurso en el codigo xaml?, (no lo puse en el codigo, pero hay que ponerlo), algo como:

    <window.Resources>

    <local:DateTimeRule x:Key="model" />

    </window.Resources>

     

    Lo he puesto sin verificar la sintaxis pero deberia de ser algo parecido.

    Ya contaras como te va.


    Saludos
    David González
    MCP, MCTS
    Visita mi Blog en: http://www.dgzornoza.com/
    Wednesday, April 20, 2011 7:44 AM
  • ¡Hola!

     

    Y si le quitas MustInherit: ya que especifica que una clase sólo se puede utilizar como una clase base y que no se puede crear directamente un objeto a partir de ella y el error que te da es que CreateInstance necesita de un constructor público para la librería: 'System.Windows.Data.Binding'

     

    Saludos,

     

     

     

    Wednesday, April 20, 2011 7:45 AM
  • Buenas a todos,

    David, si, ya tenía el recurso implementado pero nada. CorsarioVasco, al final le he quitado el MustInherit y si, efectivamente ya no da error de compilación. La aplicación se ejecuta correctamente pero no entra a la función Validate para nada, vamos, como si no existiese ese ValidationRules.

     

    Gracias a los 2 por ayudarme ;)

     

    Salu2

     

    Wednesday, April 20, 2011 8:05 AM
  • Hola igor.

    Solo llama a la validacion cuando realiza el binding.

    ¿puedes poner el codigo xaml y el modelo del binding? para ver donde esta el problema.


    Saludos
    David González
    MCP, MCTS
    Visita mi Blog en: http://www.dgzornoza.com/
    Wednesday, April 20, 2011 9:04 AM
  • Buenas David,

    El que me quiero utilizar para mi proyecto es:

          <TextBox Name="_fechaIniTextBox" Grid.Column="1" Grid.Row="7" Height="20" Margin="26.091,6.5,30,0" VerticalAlignment="Top">
            <TextBox.Text>
              <Binding Path="FechaIni">
                <Binding.ValidationRules>
                  <local:DatetimeValidationRule/>
                </Binding.ValidationRules>
              </Binding>
            </TextBox.Text>
          </TextBox>
    

    Como no me funciona, he creado una aplicación de prueba para implementar la solución que me has escrito :

     

        <TextBox Height="23" Margin="60,0,98,106" x:Name="Fecha" >
          <TextBox.Text>
            <Binding Path="date" Source="{StaticResource DateTimeRule}" >
              <Binding.ValidationRules>
                <local:DateTimeRule />
              </Binding.ValidationRules>
            </Binding>
          </TextBox.Text>
        </TextBox><br/><br/><pre lang="x-xml">  xmlns:local="clr-namespace:ValidationRules" >
      
      
      <Window.Resources>
        <local:DateTimeRule x:Key="DateTimeRule" />
      </Window.Resources>
    

    Y lo que quiero -ya que hay una aplicación que conozco que lo hace- es que al salir del textbox si por ejemplo has escrito '1/1/11' , al salir del textbox te aparezca '01/01/2011 0:00:00' 

    Y que si escribes algo erroneo (p.e. un carácter), al salir te salgo algún tick en rojo.

     

    Gracias

    Wednesday, April 20, 2011 10:10 AM
  • Hola Igor.

    ya que estamos puestos, te he realizado un ejemplillo con todo eso, y de ahi tu ya sacas lo que necesites, en un principio, se puede hacer de forma mas sencilla con propiedades DateTime, pero lo he realizado de esta forma para poder personalizarlo "al gusto".

    Bien, comenzamos con el codigo .xaml que quedaria algo asi:

      <Window.Resources>
        <local:model x:Key="model" />
        <local:DateConverter x:Key="DateConverter" />
      </Window.Resources>
      
      <Grid>
        <TextBox Height="23" Margin="60,0,98,106" x:Name="Fecha" >
          <TextBox.Text>
            <Binding Path="Date" Source="{StaticResource model}" Converter="{StaticResource DateConverter}">
              <Binding.ValidationRules>
                <local:DateTimeRule />
              </Binding.ValidationRules>
            </Binding>
          </TextBox.Text>
        </TextBox>
        
        <TextBox Height="23" HorizontalAlignment="Left" Margin="60,186,0,0" Name="textBox1" VerticalAlignment="Top" Width="172" />
        
      </Grid>
    

    En este codigo, he puesto 2 textbox, el primero para probar a insertar la fecha y el segundo para poder retirar el foco (claro esta).

    Como se puede observar, implemento una regla de validacion y un converter para modificar el resultado que se muestra.

    (Hace falta añadir el namespace 'local' con la ruta donde residan las clases del codigo .cs)

     

    El codigo .cs:

      public class model : INotifyPropertyChanged
      {
        /// <summary>Variable miembro para guardar una fecha</summary>
        private string m_date;
    
        /// <summary>
        /// Propiedad con la fecha
        /// </summary>
        public string Date
        {
          get { return m_date; }
          set
          {
            m_date = value;
            OnPropertyChanged("Date");
          }
        }
    
        #region [INotifyPropertyChanged]
    
        /// <summary>
        /// declarar el evento ocurrido cuando una propiedad de este objeto tiene un nuevo valor
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
    
        /// <summary>
        /// Definicion del evento PropertyChanged que sera llamado cuando un valor de una propiedad sea modificado
        /// </summary>
        /// <param name="_propertyName">El nombre de la propiedad con el nuevo valor</param>
        protected virtual void OnPropertyChanged(string _propertyName)
        {
          // añadir el manejador del evento
          PropertyChangedEventHandler handler = this.PropertyChanged;
          // si existe el manejador del evento, se invoca
          if (handler != null)
          {
            var e = new PropertyChangedEventArgs(_propertyName);
            handler(this, e);
          }
        }
    
        #endregion [INotifyPropertyChanged]
    
    
      }
    
      /// <summary>
      /// Clase conversora para una propiedad de fecha
      /// </summary>
      public class DateConverter : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
          return (null == value) ? "" : string.Format("{0:dd/MM/yyyy}", System.Convert.ToDateTime((string)value));
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
          DateTime resultDateTime;
          if (DateTime.TryParse((string)value, out resultDateTime))
          {
            return string.Format("{0:dd/MM/yyyy}", resultDateTime);
          }
          return DependencyProperty.UnsetValue;
        }
      }
    
      /// <summary>
      /// Clase con las reglas de validacion para una fecha valida
      /// </summary>
      public class DateTimeRule : ValidationRule
      {
        public override ValidationResult Validate(object _value, System.Globalization.CultureInfo _cultureInfo)
        {
          // expresion regular para fechas en formato dd/mm/yyyy
          System.Text.RegularExpressions.Regex regex =
           new System.Text.RegularExpressions.Regex(@"^(((0?[1-9]|[12]\d|3[01])[\.\-\/](0?[13578]|1[02])[\.\-\/]((1[6-9]|[2-9]\d)?" +
             @"\d{2}|\d))|((0?[1-9]|[12]\d|30)[\.\-\/](0?[13456789]|1[012])[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|((0?[1-9]|1\d|2[0-8])" +
            @"[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|(29[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|" +
            @"((16|[2468][048]|[3579][26])00)|00|[048])))$");
    
          return new ValidationResult(regex.IsMatch((string)_value), null);
        }
      }
    

     

    Bueno, este codigo, tampoco hay que hablar mucho de el, tan solo son 2 clases, 1 con la regla de validacion (en la cual he modificado la expresion regular para poder insertar fechas de tipo 'd/m/yyyy' o 'dd/mm/yyyy' para probar.

    La otra clase es un modelo CLR de prueba, que sera reemplazado por el tipo de modelo que tu quieras.

    Bueno, en principio, ha quedado bastante chulo ;), se modifica la fecha y todo.

    Pruebalo y me cuentas que tal.

     


    Saludos
    David González
    MCP, MCTS
    Visita mi Blog en: http://www.dgzornoza.com/
    Wednesday, April 20, 2011 1:51 PM
  • Buenas,

    Muchisimas gracias

     

    Todavia no lo he probado (lo tengo que pasar a VB). Cuando lo haga os comento,

     

    Salu2

    Thursday, April 28, 2011 9:03 AM