如何将 CheckBox 绑定到可为空的布尔类型 DbColumn?
Posted
技术标签:
【中文标题】如何将 CheckBox 绑定到可为空的布尔类型 DbColumn?【英文标题】:How to bind a CheckBox to a bool typed DbColumn that is nullable? 【发布时间】:2010-11-19 07:35:43 【问题描述】:在 Windows 窗体(.NET 2.0,Visual Studio 2005 SP1)中:我有一个类型为 DataSet
的列,其类型为 System.Boolean
,它可以为空,默认值为 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
时才可接受(这意味着该值从未设置过)。但用户应该只能通过CheckBox
将值设置为True
或False
。
供参考,这里是解析和格式化方法的代码:
internal static CheckState DoParse(object value)
if ((value==null) || (value is DBNull))
return CheckState.Indeterminate;
bool v=Convert.ToBoolean(value);
return (v ? CheckState.Checked : CheckState.Unchecked);
internal static object DoFormat(CheckState value)
switch (value)
case CheckState.Checked:
return true;
case CheckState.Indeterminate:
return DBNull.Value;
case CheckState.Unchecked:
return false;
return null;
【问题讨论】:
我已在答案末尾添加了有关 *为什么会起作用 的信息。 【参考方案1】:您是否尝试过将 CheckBox.CheckState 绑定到 DataColumn 而不附加到 Parse 和 Format 事件或弄乱绑定?
很遗憾,我没有可用的 Visual Studio 2005 实例,但我在 Visual Studio 2008 中组装了一个快速表单,它完全按照您指定的方式完成:
注意:DBNull 值仅在来自 DataSet 时才可接受(这意味着该值从未设置过)。但是用户应该只能通过 CheckBox 将值设置为 True 或 False。
我可能是 Parse、Format 或 Binding 妨碍了你,也可能是 Windows 窗体在 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 的默认格式化程序。
源代码状态上的cmets:
“真正的转换工作发生在 FormatObjectInternal() 内部”
FormatObjectInternal 状态的 cmets:
“执行一些特殊情况的转换(例如,布尔到 CheckState)”
在 FormatObjectInternal 内部,它检查来自数据源的值是 null 还是 DBNull,如果是这种情况,它检查被绑定的属性的类型是否为 CheckState。如果是这种情况,则返回 CheckState.Indeterminate。
如您所见,这是一种常见的情况,令人惊讶的是它在 Windows Forms 1.x 上不起作用。幸运的是,它已在 2.0 及更高版本上修复。
【讨论】:
我认为将布尔数据绑定到枚举类型(有 3 个可能的值!)会伤害我的头(很多),但出于好奇,我无论如何都会尝试...跨度> 我在 Visual Studio 2005 上试过,它也可以。通过设计器和代码。 您的示例有效,但对于这个问题不正确。 @Mac 想要“DBNull 可以从行填充到控件,但不能从控件填充到行”。 “MyColumn”和“CheckState”之间的数据绑定没有实现它。要获得正确的行为,您需要挂钩 Format/Parse 事件并编辑传递值。 - 如果是@Max经常写的场景,最好使用一些可重用的解决方案。 我认为你们需要冷静一下...@Alfred Myers:感谢您的回答。由于个人喜好,我不会使用它(对我来说看起来太老套了),但是当我发现它为什么有效(当我认为它不应该)时,我肯定会学到很多东西。 @TcKs:他明确指出,不允许用户从控件将值设置为 DBNull:“只有来自 DataSet 时才可以接受 DBNull 值(这意味着值从未设置过)。但用户应该只能通过 CheckBox 将值设置为 True 或 False。"【参考方案2】:我知道的最简单的方法是从 CheckBox 类派生,添加可以处理 DBNull 值的“DataValue”属性并将数据绑定到“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;
【讨论】:
聪明但并不真正需要,因为 CheckBox 支持数据绑定到可空 (DBNull) 列,正如我所演示的那样。以上是关于如何将 CheckBox 绑定到可为空的布尔类型 DbColumn?的主要内容,如果未能解决你的问题,请参考以下文章