C# 在尚未查看数据源时强制更新绑定到该数据源的复选框
下面是一个测试框架,展示了我正在做的事情:C# 在尚未查看数据源时强制更新绑定到该数据源的复选框,c#,winforms,controls,deferred-loading,C#,Winforms,Controls,Deferred Loading,下面是一个测试框架,展示了我正在做的事情: 创建新项目 添加选项卡式控件 在选项卡1上,放置一个按钮 在选项卡2上,选中一个复选框 粘贴此代码作为其代码 (使用控件的默认名称) 我在update=true之后立即调用CreateHandle()。我想我有一个解决方案。问题不是不能创建句柄。您可以通过访问控件上的句柄get访问器来实现这一点。问题是WinForms不创建控件,因为它不可见。事实证明,在幕后,System.Windows.Forms.Control有两个重载用于CreateContr
我在
update=true之后立即调用CreateHandle()。我想我有一个解决方案。问题不是不能创建句柄。您可以通过访问控件上的句柄get访问器来实现这一点。问题是WinForms不创建控件,因为它不可见。事实证明,在幕后,System.Windows.Forms.Control
有两个重载用于CreateControl
。第一个是公共的,不接受任何参数,它调用第二个是internal
,它接受一个boolean
参数:ignoreVisible,顾名思义,它允许调用代码创建控件,即使控件不可见。不带参数的CreateControl
方法将false传递给此内部方法,这意味着如果控件不可见,则不会创建它。所以,诀窍是使用反射来调用内部方法。首先,我创建了两种创建控件的方法:
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" );
}
}
现在,无论您是否导航到第二个选项卡,单击第一个选项卡上的按钮都将触发复选框1\u Changed
事件过程。根据您提供的设计,如果单击按钮,它将不会显示消息框,因为更新将为真。但是,Debug.WriteLine
将显示它在输出窗口中被激发。那么,按照MSDN文档的建议使用CreateHandle有什么错呢?CreateHandle是一个受保护的方法,除非我创建一个新的继承类,否则不能从代码中调用它。根据文档,调用CreateHandle的等效方法是简单地访问控件上的Handle属性。但是,即使这样做也没有帮助,因为WinForms仍然无法“查看”控件并触发CheckedChanged事件。
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" );
}
}