usar - que es un datetimepicker en c#
El evento C#DateTimePicker DataBinding Parse no funciona (5)
Tengo un datetimepicker que estoy vinculando con la columna de fecha / hora nullable en el conjunto de datos. Apliqué el evento Format con éxito para el valor del objeto nulo y no nulo. Pero, cuando desactivo el control dtp, no se establece como nulo en el conjunto de datos. Este es mi código:
dtpBirthdate.DataBindings.Add(new Binding("Value", bsStaff, "birthDate", true));
dtpBirthdate.DataBindings["Value"].Format += new ConvertEventHandler(dtpFormat);
dtpBirthdate.DataBindings["Value"].Parse += new ConvertEventHandler(dtpParse);
Formatear y analizar eventos
private void dtpFormat(object sender, ConvertEventArgs e)
{
Binding b = sender as Binding;
if(b != null)
{
DateTimePicker dtp = (b.Control as DateTimePicker);
if(dtp != null)
{
if (e.Value == null || e.Value == DBNull.Value)
{
dtp.Checked = false;
dtp.CustomFormat = " ";
e.Value = false;
}
else
{
dtp.Checked = true;
dtp.CustomFormat = "dd-MMM-yyyy";
dtp.Value = (DateTime) e.Value;
}
}
}
}
private void dtpParse(object sender, ConvertEventArgs e)
{
Binding b = sender as Binding;
if (b != null)
{
DateTimePicker dtp = (b.Control as DateTimePicker);
if (dtp != null)
{
if (dtp.Checked == false)
{
e.Value = DBNull.Value;
}
else
{
e.Value = dtp.Value;
}
}
}
}
Después de la depuración, descubrí que va al ciclo infinito entre los eventos de análisis y formato. ¿Qué pasa con mi código?
Editar: También hay un datagridview enlazado a bsStaff bindingsource.
dtpParse está configurando e.Value = dbNull.Value que disparará el dtpFormat a medida que el valor ha cambiado, lo que a su vez establece e.Value = false, que es diferente de dbNull.Value, que de nuevo activará dtpParse. Intente eliminar e.Value = false de dtpFormat
Está emitiendo "Encuadernación b = remitente como encuadernación" antes de la comprobación nula. verifica si el remitente es nulo antes de enviar y estarás bien.
Me di cuenta de que está utilizando una captura de eventos de enlace de datos para ambos controles, pero en su primer manejador de eventos dtpFormat no comprueba primero los valores de enlace de datos.
Imho esta línea de código:
if (e.Value == null || e.Value == DBNull.Value)
necesita ser cambiado a
if (e.Value == DBNull.Value || e.Value == null)
El problema es que debes establecer e.Value en algo; pero si lo cambias, se iniciará el análisis de nuevo. Intenta configurarlo con su valor original.
e.Value = dtp.Value;
Aquí hay un enlace a alguien que se encontró con esto antes. No usaban su DbNull.Value, pero aparte de eso, es casi idéntico a lo que está haciendo.
http://blogs.interknowlogy.com/2007/01/21/winforms-databinding-datetimepicker-to-a-nullable-type/
Lo siguiente debería solucionar el problema (ver los comentarios en el código):
private void dtpFormat(object sender, ConvertEventArgs e)
{
Binding b = sender as Binding;
if(b != null)
{
DateTimePicker dtp = (b.Control as DateTimePicker);
if (dtp != null)
{
if (e.Value == null || e.Value == DBNull.Value)
{
dtp.Checked = false;
dtp.CustomFormat = " ";
// e.Value = false;
// To prevent dtp.Value property setter setting Checked back to true
e.Value = dtp.Value;
}
else
{
dtp.Checked = true;
dtp.CustomFormat = "dd-MMM-yyyy";
//dtp.Value = (DateTime) e.Value;
// dtp.Value will be set to e.Value from databinding anyway
}
}
}
}
private void dtpParse(object sender, ConvertEventArgs e)
{
Binding b = sender as Binding;
if (b != null)
{
DateTimePicker dtp = (b.Control as DateTimePicker);
if (dtp != null)
{
if (dtp.Checked == false)
{
e.Value = DBNull.Value;
}
else
{
//e.Value = dtp.Value;
// Do nothing, e.Value is already populated with dtp.Value
}
}
}
}
Pero la idea general es incorrecta desde el principio porque está basada en piratería de infraestructura de enlace de datos (el problema XY típico: ¿superar la falta de propiedad de valor DateTime?
En DTP). Convert
eventos Convert
y Parse
deben realizar una conversión de valor desde el origen de datos a un valor de control y viceversa. No se supone que e.Value
leer o escribir propiedades de control (rompe la encapsulación completa), la información se proporciona a través de e.Value
y e.DesiredType
y se supone que los manipuladores deben cambiar el e.Value
función de esa información.
La forma correcta es crear control personalizado heredando DateTimePicker
e implementando un (sombra) DateTime? Value
Propiedad de DateTime? Value
El getter y setter de propiedades pueden aplicar la lógica necesaria (se les permite leer / modificar otras propiedades). Luego reemplace los controles DTP con ese control personalizado y simplemente conéctese a la propiedad "Valor" sin ningún controlador de eventos vinculantes.
Actualización: Aquí se menciona una implementación rápida y sucia de un enfoque no vinculante:
public class CustomDateTimePicker : DateTimePicker
{
public CustomDateTimePicker()
{
Format = DateTimePickerFormat.Custom;
SetValueCore(null);
}
new public DateTime? Value
{
get { return Checked ? base.Value : (DateTime?)null; }
set
{
if (Value != value)
SetValueCore(value);
}
}
private void SetValueCore(DateTime? value)
{
if (value == null)
Checked = false;
else
base.Value = value.Value;
UpdateCustomFormat();
}
protected override void OnValueChanged(EventArgs eventargs)
{
UpdateCustomFormat();
base.OnValueChanged(eventargs);
}
private void UpdateCustomFormat()
{
CustomFormat = Value != null ? "dd-MMM-yyyy" : " ";
}
}