JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

Comportamiento extraño con el formato de fechas en los GridView

Cuando estamos usando un GridView para mostrar datos obtenidos de una base de datos resulta muy cómodo usar el editor de columnas para definir cómo se deben mostrar los datos en el listado que se genera.

Una propiedad muy interesante de las columnas enlazadas en DataFormatString, que nos permite decidir qué estilo queremos aplicar a las columnas.

Sin embargo con los campos que contienen fechas pasa unacosa muy rara...

Si tenemos un campo que es una Fecha y definimos una columna enlazada de modo similar a este:

<asp:BoundField DataField="FechaFin" DataFormatString="{0:d}" HeaderText="Final">

esperaremos ver algo similar a lo siguiente en la columna: 13/7/2006.

Sin embargo por más que cambiemos el formato veremos algo como esto: 13/7/2006 00:00:00

Es decir, no hace caso y mete el formato de fecha y hora cortas.

Si queremos que una columna de tipo fecha haga caso al formato tenemos dos soluciones:

1.- Convertirla en una plantilla. Con esto funcionará sin problemas el formato.

2.- Usar el atributo HtmlEncode con el valor 'false', así:

<asp:BoundField DataField="FechaFin" DataFormatString="{0:d}" HtmlEncode="false" HeaderText="Final">

Con este último conseguiremos el resultado esperado.

Este problema puede volver loco a más de uno ya que no es nada obvio. Así que espero que os sirva de algo :-)

NOTA: Explicación de este efecto a raíz del requerimiento de un lector...

Aquí está el código del método FormatDataValue de la clase BoundColumn que es el que se encarga de renderizar el contenido de la celda (extraido con NetReflector):

protected virtual string FormatDataValue(object dataValue, bool encode)
{
  string text1 = string.Empty;
  if (!DataBinder.IsNull(dataValue))
  {
    string text2 = dataValue.ToString();
    string text3 = this.DataFormatString;
    int num1 = text2.Length;
    if ((num1 > 0) && encode)
    {
      text2 = HttpUtility.HtmlEncode(text2);
    }
    if ((num1 == 0) && this.ConvertEmptyStringToNull)
    {
      return this.NullDisplayText;
    }
    if (text3.Length == 0)
    {
      return text2;
    }
    if (encode)
    {
      return string.Format(CultureInfo.CurrentCulture, text3, new object[] { text2 });
    }
    return string.Format(CultureInfo.CurrentCulture, text3, new object[] { dataValue });
  }
  return this.NullDisplayText;
}

Si te fijas, cuando se escoge la opción de formatear el contenido (HtmlEncode = true, valor por defecto), el valor de codificación se obtiene de la representación de texto del valor (text2, que si te fijas arriba es dataValue.ToString(). Esto hace que en el caso de las fechas el valor tenga al final la hora también, con lo que en el último condicional se usa para dar formato al texto. Si desactivas la codificación la cadena para la celda se genera directamente desde el valor del dato con el formato especificado, sin pasarlo a texto antes.

Para mi esto es un "bug" que deberían corregir porque se debería obtener el mismo resultado por los dos caminos.

José Manuel Alarcón
Banner

Comentarios (2) -

Aquí tienes el código del método FormatDataValue de la clase BoundColumn que es el que se encarga de renderizar el contenido de la celda (extraido con NetReflector):

protected virtual string FormatDataValue(object dataValue, bool encode)
{
      string text1 = string.Empty;
      if (!DataBinder.IsNull(dataValue))
      {
            string text2 = dataValue.ToString();
            string text3 = this.DataFormatString;
            int num1 = text2.Length;
            if ((num1 > 0) && encode)
            {
                  text2 = HttpUtility.HtmlEncode(text2);
            }
            if ((num1 == 0) && this.ConvertEmptyStringToNull)
            {
                  return this.NullDisplayText;
            }
            if (text3.Length == 0)
            {
                  return text2;
            }
            if (encode)
            {
                  return string.Format(CultureInfo.CurrentCulture, text3, new object[] { text2 });
            }
            return string.Format(CultureInfo.CurrentCulture, text3, new object[] { dataValue });
      }
      return this.NullDisplayText;
}


Si te fijas, cuando se escoge la opción de formatear el contenido (HtmlEncode = true, valor por defecto), el valor de codificación se obtiene de la representación de texto del valor (text2, que si te fijas arriba es dataValue.ToString(). Esto hace que en el caso de las fechas el valor tenga al final la hora también, con lo que en el último condicional se usa para dar formato al texto. Si desactivas la codificación la cadena para la celda se genera directamente desde el valor del dato con el formato especificado, sin pasarlo a texto antes.

Para mi esto es un "bug" que deberían corregir porque se debería obtener el mismo resultado por los dos caminos.

Responder

He visto en Connect si había algo sobre este Bug y en efecto lo hay y varias personas lo han comentado, pero el equipo de .NET dice que es por diseño (connect.microsoft.com/.../ViewFeedback.aspx), lo cual francamente me parece que es un error ya que no es lógico que pase algo como lo descrito por "evitar problemas de inyección de código HTML". Entiendo que por defecto vaya HtmlEncode = true por este motivo, pero eso no siginifica que deba pasar esta situación ya que simplemente podrían aplicar la codificación HTML después del formato y no ocurriría ¿no?

Responder

Agregar comentario