Я думаю, у меня есть решение. Проблема не в том, что вы не можете создать дескриптор. Вы можете сделать это, просто получив доступ к дескриптору Getle на Control. Проблема в том, что WinForms не создает элемент управления, потому что он не виден. Как оказалось, за кулисами System.Windows.Forms.Control
имеет две перегрузки для CreateControl
. Первый, который является общедоступным, не принимает параметров и вызывает второй, который является 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
будет истинным. Тем не менее, Debug.WriteLine
покажет, что оно сработало в окне вывода.