2011-01-06 17 views
8

Estoy intentando rastrear la causa de un molesto error de interfaz en una aplicación que se actualizó recientemente de VS2003 a VS2008 (el error no existía antes de la migración). Lo que sucede es esto:No se puede escapar del cuadro de texto vacío

1) El usuario hace clic en el cuadro de texto que contiene una fecha.
2) El usuario borra la fecha
3) El usuario intenta moverse a otro campo, pero no puede. No aparecen mensajes de error, es como si la validación hubiera fallado.

Más información:

1) la propiedad text del cuadro de texto está vinculado a un DataView que utiliza una tabla de datos como su fuente. El campo vinculado es un campo de fecha y hora anulable sin restricciones ni valores predeterminados.
2) El evento Validating se activa y la propiedad CancelEventArgs no está configurada en Cancelar. Los eventos Validated, LostFocus y Leave se activan también, yendo LostFocus> Leave> Validating
3) No puedo ver ningún cambio de código relacionado con el control o el origen de datos con algunas excepciones. La primera es que esto:

Me.txtRangeEnd.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.dvClientNos, "RangeEnd")) 

ha cambiado ahora a esto:

Me.txtRangeEnd.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.dvClientNos, "RangeEnd", True)) 

La segunda es que esto:

Me.dcolRangeEnd.DataType = GetType(System.DateTime) 

ha cambiado ahora a esto:

Me.dcolRangeEnd.DataType = GetType(Date) 

También hay esto, que ha estado en el código desde el primer día:

AddHandler txtRangeEnd.DataBindings("Text").Format, AddressOf FormatBoxToDate 

Private Sub FormatBoxToDate(ByVal sender As Object, ByVal e As ConvertEventArgs) 
Try 
    If Not e.Value Is DBNull.Value Then 
      e.Value = Format(e.Value, "d") 
     End If 
    End Try 
End Sub 

Ahora, si quito la "verdadera" de la adición del enlace de datos entonces puede salir del control con un valor en blanco, pero luego vuelve a su valor original. La eliminación del formato de fecha parece no tener ningún efecto en esto (solo vuelve a mostrar 06/01/2011 00:00:00 en lugar del deseado 01/06/2010). Ningún otro código se refiere a ese cuadro de texto en absoluto. Estoy pensando que algo debe haber cambiado en la validación de los controles de datos entre VS2003 y VS2008, pero es tan probable que me esté perdiendo algo increíblemente obvio.

¿Alguna idea?

Respuesta

7

La razón por la que está viendo el comportamiento observado tiene que ver con cómo Windows Forms y su enlace de datos maneja valores de base de datos NULL.

El TL;DR razón:

Ver esta sugerencia de Microsoft Connect: Provide better databinding support for nullable types

La versión larga:

lo que es esencialmente sucediendo es que a medida que se borre el cuadro de texto (a un vacío cadena) y, a continuación, tabular, el enlace está convirtiendo su cadena vacía a un valor DBNull que luego se propaga a la fuente de datos sin embargo el enlace, ya que es dos -way, luego intenta volver a llenar el control vinculado (el TextBox) con el formato apropiado, y falla, haciendo que el cuadro de texto muestre el extraño comportamiento de no permitir que se elimine el foco de él.

Esto está sucediendo debido a la propiedad DataSourceNullValue del Binding class. Esto se puede ajustar con una de las sobrecargas clases constructor de unión, o ajustar por separado a través de un valor de la propiedad, sin embargo, si no se establece de manera explícita esta propiedad, es importante tener en cuenta que:

El valor por defecto es DBNull de tipos de valor y nulo para tipos sin valor.

Parece que usted no está establecer explícitamente esto, por lo que el valor predeterminado es la aplicación, y con ser su fecha y hora Un value type, es el uso de DBNull.

Una vez que la fuente de datos se ha actualizado (a DBNull), el mecanismo de enlace intentará volver a llenar el cuadro de texto con el valor de fuente de datos recientemente actualizado. Cuando el valor de origen de datos subyacente es DBNull, el valor utilizado para el control vinculado se rige por NullValue property de la clase de enlace. Una vez más, si esta propiedad no se establece explícitamente, ya sea mediante el argumento constructor sobrecargado correspondiente o mediante la propiedad entorno en sí, se aplicará el valor predeterminado, que es:

el objeto que se fija como el control de propiedad cuando el la fuente de datos contiene un valor DBNull. El valor predeterminado es nulo.

Por supuesto, un Textbox's Text property solamente se puede ajustar a un objeto de tipo System.String y no un valor nulo (Nada en VB), por lo que el cuadro de texto no puede enlazar el valor representativo (null/nada) de los datos el valor de la fuente (DBNull) para el control vinculado.

La forma de corregir este comportamiento es garantizar que el Binding class's NullValue property se establezca explícitamente en un valor adecuado. En este caso, una cadena de longitud cero será suficiente para corregir el problema.

Una forma de lograr esto es cambiar la línea:

Me.txtRangeEnd.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.dvClientNos, "RangeEnd", True)) 

a:

Me.txtRangeEnd.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.dvClientNos, "RangeEnd", True, DataSourceUpdateMode.OnValidation, "")) 

La clave aquí es el último parámetro, que es la NullValue, ajustado a un cero cadena de longitud (El DataSourceUpdateMode también se especifica explícitamente debido a los argumentos del constructor, pero se establece de todos modos en su valor predeterminado).

A pesar de todo esto, parece ser un comportamiento algo "extraño", si no es un error real. Esto también es evidenciado por otros que parecen estar experimentando el mismo problema (¡que aún prevalece en Visual Studio 2010/.NET 4.0!). This thread en los foros social.msdn.microsoft.com contiene a alguien que experimenta el mismo problema con algunas posibles explicaciones interesantes sobre por qué sucede esto, y por qué Microsoft lo diseñó de esta manera.

También hay un Microsoft Connect suggestion que se informó en 2005 que destaca el problema. Esta sugerencia ha sido "Cerrada como pospuesta". Parece que Microsoft no lo considera un error, ya que existe una solución muy razonable (la configuración explícita de la propiedad NullValue de Binding) que, sin duda, debería hacerse de todos modos por razones de legibilidad. Al parecer, considerarán la sugerencia en el futuro.

Volviendo a por qué no existía esto, pre.NET 2.0 (Visual Studio 2005) parece deberse al hecho de que todo el mecanismo de enlace de datos se renovó por completo para el lanzamiento de .NET Framework 2.0. Su solución original, al ser un proyecto VS2003, usa .NET Framework 1.1 que no tiene un conjunto de funciones de enlace de datos tan completo. Aunque ya no tengo a mano una copia de VS2003 para probar esto, supongo que el mecanismo de enlace en .NET 1.1 hizo mucho más uso de conversiones implícitas entre el valor del control y el valor de la fuente de datos. Este aparece como cuando se examina la clase de enlace de .NET 1.1, en comparación con .NET 2.0 (o superior). Por ejemplo, no había manera de (fácilmente) controlar el enlace bidireccional real en sí (y cómo se convierten los valores entre el formulario y el origen de datos) o el formateo de dichos valores.

+0

Ese pequeño método FormatBoxToDate se creó porque .NET 2003 no tenía otra forma de hacerlo. Ahora se puede acceder a la propiedad de valor nulo a través del menú de enlaces de datos avanzados; sin embargo, intentar establecer esto en una cadena vacía utilizando el IDE en realidad establece el valor en Nothing en el código ... lo cual no hace ninguna diferencia. – MartW

+0

En cambio, lo he pirateado manualmente en String.Empty (nunca me gustó poner "") y ahora funciona. Yo llamo a esa recompensa bien merecida: D – MartW

+0

Muy viejo, pero muy útil ya que todavía se aplica en VS2013! pero una pregunta complementaria: la línea para cambiar funcionó muy bien para mí ... pero tengo todo lo demás mantenido en las propiedades del diseñador ... si lo entiendo bien, es una cuestión de agregar el valor nulo en las siguientes propiedades de cuadro de texto -> (Enlaces de datos) -> (Avanzado) -> seleccione la propiedad del texto, seleccione un formato de fecha (en mi caso), luego complete el valor nulo. Sin embargo, una cadena vacía no parece funcionar allí. algún consejo sobre cómo hacerlo en el diseñador? –

0

He tenido este tipo de error antes y tuve que asegurarme de que la fuente de datos subyacente (en mi caso era un conjunto de datos) no estaba configurada solo como lectura y que la columna permitía valores `nulos '.

Una vez que hice esto todo funcionó bien. Parecía que el error que se estaba lanzando en los enlaces de datos se tragó en algún lugar y no se propagó.

Cuestiones relacionadas