在Windows窗体(.NET 2.0,Visual Studio 2005 SP1)中:我有一个类型为DataSet
的列,其类型为System.Boolean
,可以为空,默认值为{{1 }}。我有一个DBNull
,其中包含一个Form
控件,我希望将其绑定到之前的列值。
CheckBox
属性绑定到列:只有当列的默认值设置为Checked
或True
时,它才能正常工作。 我试图通过设计器将False
属性绑定到列,并附加我自己的CheckState
和Format
事件处理程序,但它们永远不会被调用:
Parse
我尝试在代码中创建自定义b.Format+=delegate(object sender, ConvertEventArgs cevent) {
cevent.Value=DoFormat((CheckState)cevent.Value); // cf. end of the question
};
b.Parse+=delegate(object sender, ConvertEventArgs cevent) {
cevent.Value=DoParse(cevent.Value); // cf. end of the question
};
实例,附加我的事件处理程序并将其添加到Binding
绑定:事件处理程序仍然永远不会被调用...
CheckBox
作为注释:Binding b=new Binding("CheckState", _BindingSource, "MyColumn", false, DataSourceUpdateMode.OnPropertyChanged, DBNull.Value);
值仅在来自DBNull
时才可接受(这意味着该值从未设置过)。但是,用户应该只能通过DataSet
将值设置为True
或False
。
供参考,以下是解析和格式化方法的代码:
CheckBox
答案 0 :(得分:7)
您是否尝试将CheckBox.CheckState绑定到DataColumn而不附加Parse和Format事件或搞乱Binding?
不幸的是我没有可用的Visual Studio 2005实例,但我在Visual Studio 2008中组装了一个快速表单,它确实完全你指定的内容:
作为注释:仅当来自DataSet时,DBNull值才可接受(这意味着该值从未设置过)。但是用户应该只能通过CheckBox将值设置为True或False。
我可能是Parse,Format或Binding妨碍你或者可能是Windows Forms在2008年的表现与2005年不同
8月18日更新: 它也可以通过设计器和代码在Visual Studio 2005上运行。 这是演示它工作的代码:
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
DataTable table = new DataTable();
public Form1() {
InitializeComponent();
//Creates the table structure
table.Columns.Add("Name", typeof(string));
table.Columns.Add("MyColumn", typeof(bool));
//Populates the table with some stuff
for (int i = 0; i < 5; i++) {
table.Rows.Add(i.ToString());
}
//Creates the controls and puts them on the form.
TextBox textBox = new TextBox();
textBox.Location = new Point(10, 10);
textBox.DataBindings.Add("Text", table, "Name");
CheckBox checkBox = new CheckBox();
checkBox.Left = textBox.Left;
checkBox.Top = textBox.Bottom + 10;
//Without true on the last argument, it will not work properly.
checkBox.DataBindings.Add("CheckState", table, "MyColumn", true);
Button previous = new Button();
previous.Text = "";
next.Top = previous.Top;
next.Left = previous.Right + 5;
next.Click += new EventHandler(next_Click);
this.Controls.AddRange(new Control[] { textBox, checkBox, previous, next });
}
void next_Click(object sender, EventArgs e) {
this.BindingContext[this.table].Position++;
}
void previous_Click(object sender, EventArgs e) {
this.BindingContext[this.table].Position--;
}
}
}
8月23日更新:
为什么会有效
Binding有一个名为FormatObject的私有方法,它负责获取适合在控件上显示的来自数据源的值的表示。
启用格式化后,Binding.FormatObject()将运行一个代码路径,该路径将调用您对Binding.Format事件的最终处理程序。如果任何处理程序通过ConvertEventArgs.Value更改从数据源传播到控件的值,则将使用该值。否则,它将在名为System.Windows.Forms.Formatter的内部类上调用名为FormatObject的默认格式化程序。
对源代码状态的评论:
“真正的转换工作发生在FormatObjectInternal()”
中FormatObjectInternal状态的注释:
“执行一些特殊情况转换(例如布尔到CheckState)”
在FormatObjectInternal内部,它检查来自数据源的值是否为null或DBNull,如果是这种情况,它会检查绑定的属性的类型是否为CheckState。如果是这种情况,则返回CheckState.Indeterminate。
正如您所看到的,这是一个常见的情况,令人惊讶的是它无法在Windows Forms 1.x上运行。幸运的是,将其修复为2.0及更高版本。
答案 1 :(得分:1)
我知道的简单方法是从CheckBox类派生,添加“DataValue”属性,它可以处理DBNull值并将数据绑定到“DataValue”属性:
public class DataCheckBox : CheckBox {
public virtual object DataValue {
get { return this.Checked; }
set {
if ( value == null || value is DBNull ) {
this.CheckState = CheckState.Indeterminate;
}
else {
this.Checked = (bool)value;
}
}
}
}