强制绑定到DataSource的复选框在尚未查看时进行更新

这是一个测试框架,用于显示我正在做的事情:

  1. 创建一个新项目
  2. 添加选项卡式控件
  3. 在标签1上放一个按钮
  4. 在选项卡2上放置一个复选框
  5. 将此代码粘贴到其代码中

(使用控件的默认名称)

public partial class Form1 : Form { private List boolList = new List(); BindingSource bs = new BindingSource(); public Form1() { InitializeComponent(); boolList.Add(false); bs.DataSource = boolList; checkBox1.DataBindings.Add("Checked", bs, ""); this.button1.Click += new System.EventHandler(this.button1_Click); this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged); } bool updating = false; private void button1_Click(object sender, EventArgs e) { updating = true; boolList[0] = true; bs.ResetBindings(false); Application.DoEvents(); updating = false; } private void checkBox1_CheckedChanged(object sender, EventArgs e) { if (!updating) MessageBox.Show("CheckChanged fired outside of updating"); } } 

问题是如果您运行程序并查看选项卡2然后按选项卡1上的按钮,程序按预期工作,但是如果您按下选项卡1上的按钮然后查看选项卡2,复选框的事件将不会触发,直到您看看标签2。

这样做的原因是选项卡2上的控件未处于“已创建”状态,因此直到控件被“创建”之后才会发生将其从未选中状态更改为已选中状态的绑定。

checkbox1.CreateControl()没有做任何事情,因为根据MSDN

如果控件的Visible属性为false,CreateControl不会创建控件句柄。 无论控件的可见性如何,您都可以调用CreateHandle方法或访问Handle属性来创建控件的句柄,但在这种情况下,不会为控件的子项创建窗口句柄。

我尝试获取Handle的值(CheckBox没有公共 CreateHandle()),但结果仍然相同。

除了让程序快速刷新所有带有数据绑定复选框的选项卡的任何建议在第一次加载时?

编辑 – 根据Jaxidian的建议,我创建了一个新课程

 public class newcheckbox : CheckBox { public new void CreateHandle() { base.CreateHandle(); } } 

我在updating = true之后立即调用CreateHandle(),与之前的结果相同。

我想我有一个解决方案。 问题不在于您无法创建句柄。 您只需访问Control上的Handle get访问器即可。 问题是WinForms不会创建控件,因为它不可见。 事实certificate,在幕后, System.Windows.Forms.Control有两个CreateControl重载。 第一个是public,它不带参数,它调用第二个internal函数,它接受一个boolean参数:ignoreVisible,顾名思义允许调用代码创建控件,即使它不可见。 不带参数的CreateControl方法将false传递给此内部方法,这意味着如果控件不可见,则不会创建它。 因此,诀窍是使用Reflection来调用内部方法。 首先,我创建了两种创建控件的方法:

 private static void CreateControls( Control control ) { CreateControl( control ); foreach ( Control subcontrol in control.Controls ) { CreateControl( subcontrol ); } } private static void CreateControl( Control control ) { var method = control.GetType().GetMethod( "CreateControl", BindingFlags.Instance | BindingFlags.NonPublic ); var parameters = method.GetParameters(); Debug.Assert( parameters.Length == 1, "Looking only for the method with a single parameter" ); Debug.Assert( parameters[0].ParameterType == typeof ( bool ), "Single parameter is not of type boolean" ); method.Invoke( control, new object[] { true } ); } 

现在,我们为第二个选项卡添加对CreateControls的调用:

 public Form1() { InitializeComponent(); boolList.Add( false ); bs.DataSource = boolList; checkBox1.DataBindings.Add( "Checked", bs, "" ); this.button1.Click += this.button1_Click; this.checkBox1.CheckedChanged += this.checkBox1_CheckedChanged; CreateControls( this.tabPage2 ); } 

另外,我添加了一些调试消息,以便我可以看到事件是否被触发:

 private void button1_Click( object sender, EventArgs e ) { Debug.WriteLine( "button1_Click" ); updating = true; boolList[0] = true; bs.ResetBindings( false ); Application.DoEvents(); updating = false; } private void checkBox1_CheckedChanged( object sender, EventArgs e ) { Debug.WriteLine( "checkBox1_CheckedChanged" ); if ( !updating ) { Debug.WriteLine( "!updating" ); MessageBox.Show( "CheckChanged fired outside of updating" ); } } 

现在,无论您是否导航到第二个选项卡,单击第一个选项卡上的按钮将触发checkbox1_Changed事件过程。 根据您提供的设计,如果单击按钮,它将不会显示MessageBox,因为updating将为true。 但是, Debug.WriteLine将显示它在“输出”窗口中触发。