且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何将 CheckBox 绑定到可为空的布尔类型 DbColumn?

更新时间:2021-12-17 15:35:06

您是否尝试过将 CheckBox.CheckState 绑定到 DataColumn 而不附加到 Parse 和 Format 事件或弄乱 Binding?

Have you tried binding CheckBox.CheckState to the DataColumn without attaching to Parse and Format events or messing with the Binding?

很遗憾,我没有可用的 Visual Studio 2005 实例,但我在 Visual Studio 2008 中组装了一个快速表单,它完全符合您指定的要求:

Unfortunately I don’t have an instance of Visual Studio 2005 available but I assembled a quick form in Visual Studio 2008 and it did exactly what you specified:

注意:DBNull 值仅在来自 DataSet 时才可接受(这意味着该值从未设置过).但是用户应该只能通过 CheckBox 将值设置为 True 或 False.

As a note : a DBNull value is acceptable only when coming from the DataSet (it means the value has never been set). But the user should only be able to set the value to True or False via the CheckBox.

我可能是 Parse、Format 或 Binding 妨碍了你,也可能是 Windows 窗体在 2008 年的行为与 2005 年不同

I may be the Parse, Format or Binding getting in your way or it may be that Windows Forms behaves differently in 2008 than in 2005

8 月 18 日更新:它也可以通过设计器和代码在 Visual Studio 2005 上运行.这是演示它工作的代码:

UPDATE Aug 18: It works on Visual Studio 2005 too both through the designer and through code. Here's the code that demonstrates it working:


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 &lt 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 has a private method called FormatObject which is responsible for obtaining a representation of the value coming from the data source that is appropriate for being shown on the control.

启用格式化后,Binding.FormatObject() 将通过代码路径运行,该代码路径将调用 Binding.Format 事件的最终处理程序.如果任何处理程序更改了通过 ConvertEventArgs.Value 从数据源传播到控件的值,则将使用该值.否则,它将在名为 System.Windows.Forms.Formatter 的内部类上调用名为 FormatObject 的默认格式化程序.

When formatting is enabled, Binding.FormatObject() will run through a code path that will call eventual handlers you have for the Binding.Format event. If any handler changes the value being propagated from the data source to the control through ConvertEventArgs.Value, that value will be used. Otherwise, it will call a default formatter called FormatObject on an internal class called System.Windows.Forms.Formatter.

源码状态注释:

真正的转换工作发生在 FormatObjectInternal() 内部"

"The real conversion work happens inside FormatObjectInternal()"

FormatObjectInternal 状态的注释:

The comments for FormatObjectInternal state:

执行一些特殊情况的转换(例如,布尔到 CheckState)"

"Performs some special-case conversions (eg. Boolean to CheckState)"

在 FormatObjectInternal 内部,它检查来自数据源的值是 null 还是 DBNull,如果是这种情况,它检查被绑定的属性的类型是否为 CheckState.如果是这种情况,则返回 CheckState.Indeterminate.

Inside of FormatObjectInternal it checks to see if the value coming from the data source is null or DBNull and if that is the case, it checks to see if the type of the property being bound is of CheckState. If that is the case, it returns CheckState.Indeterminate.

如您所见,这种情况非常常见,令人惊讶的是它在 Windows Forms 1.x 上不起作用.幸运的是,它已在 2.0 及更高版本上修复.

As you can see, this is such a common case that it is a surprise it didn't work on Windows Forms 1.x. Luckily, the fixed it on 2.0 and beyond.