我有一个datetimepicker,我在数据集中绑定了可以为空的Date / Time列。我成功地将Format事件应用于null而不是null对象值。但是,当我取消选中dtp控件时,它不会在数据集中设置为null。 这是我的代码:
dtpBirthdate.DataBindings.Add(new Binding("Value", bsStaff, "birthDate", true));
dtpBirthdate.DataBindings["Value"].Format += new ConvertEventHandler(dtpFormat);
dtpBirthdate.DataBindings["Value"].Parse += new ConvertEventHandler(dtpParse);
格式化和解析事件:
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;
}
}
}
}
调试后,我发现它在解析和格式事件之间进行无限循环。我的代码出了什么问题?
编辑:还有一个绑定到bsStaff bindingsource的datagridview。
答案 0 :(得分:2)
以下内容应解决问题(请参阅代码中的注释):
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
}
}
}
}
但是整个想法从一开始就是错误的,因为它基于数据绑定基础架构攻击(典型的XY问题 - 克服DTP中缺少DateTime?
值属性)。 Convert
和Parse
事件应该执行从数据源值到控制值的值转换,反之亦然。它们不应该读取或写入控制属性(它打破了整个封装),信息通过e.Value
和e.DesiredType
提供,处理程序应该基于此更改e.Value
信息。
正确的方法是创建继承DateTimePicker
并实现(shadow)DateTime? Value
属性的自定义控件。属性getter和setter可以应用必要的逻辑(允许它们读取/修改其他属性)。然后用该自定义控件替换DTP控件,并简单地绑定到" Value"没有任何绑定事件处理程序的属性。
更新:这是一个快速而肮脏的非绑定方法实现:
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" : " ";
}
}
答案 1 :(得分:1)
在null检查之前,您正在“绑定b = sender as Binding”。在投票前检查发件人是否为空,你应该没事。
答案 2 :(得分:1)
我注意到您正在为两个控件使用数据绑定事件捕获,但是在第一个dtpFormat事件处理程序中,您不首先检查数据绑定值。
Imho这行代码:
if (e.Value == null || e.Value == DBNull.Value)
需要更改为
if (e.Value == DBNull.Value || e.Value == null)
答案 3 :(得分:1)
问题是你需要将e.Value设置为某种东西;但如果你改变它,它将再次解析。尝试将其设置为原始值。
e.Value = dtp.Value;
这是一个链接到之前遇到此问题的人。他们没有使用你的DbNull.Value,但除此之外它几乎与你正在做的相同。
http://blogs.interknowlogy.com/2007/01/21/winforms-databinding-datetimepicker-to-a-nullable-type/
答案 4 :(得分:0)
dtpParse正在设置e.Value = dbNull.Value,它会在值发生变化时触发dtpFormat,然后设置e.Value = false,这与dbNull.Value不同,后者将再次触发dtpParse。尝试从dtpFormat
中删除e.Value = false