I have a datetimepicker that I am binding with nullable Date/Time column in dataset. I applied Format event successfully for null and not null object value. But, when I uncheck dtp control it does not get set to null in the dataset. This is my code:
dtpBirthdate.DataBindings.Add(new Binding("Value", bsStaff, "birthDate", true));
dtpBirthdate.DataBindings["Value"].Format += new ConvertEventHandler(dtpFormat);
dtpBirthdate.DataBindings["Value"].Parse += new ConvertEventHandler(dtpParse);
Format and Parse events:
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;
}
}
}
}
After debugging, I found that it goes to infinite loop between parse and format events. What is wrong with my code?
Edit: There is also a datagridview binded to bsStaff bindingsource.
You are casting "Binding b = sender as Binding" before the null check. check if the sender is null before casting and you should be fine.
The following should fix the issue (see the comments in code):
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
}
}
}
}
But the whole idea is wrong from the beginning because it's based on data binding infrastructure hacks (the typical XY problem - to overcome the lack of DateTime?
value property in DTP). Convert
and Parse
events are supposed to perform value conversion from data source value to control value and vice versa. They are not supposed to read or write control properties (it breaks the whole encapsulation), the information is provided through e.Value
and e.DesiredType
and the handlers are supposed to change the e.Value
based on that information.
The right way is to create custom control inheriting DateTimePicker
and implementing a (shadow) DateTime? Value
property. The property getter and setter can apply the necessary logic (they are allowed to read/modify other properties). Then replace DTP controls with that custom control and simply bind to "Value" property w/o any binding event handlers.
Update: Here is a quick and dirty implementation of non binding approach mentioned:
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" : " ";
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With