Принудительное обновление флажка, связанного с источником данных, когда он еще не был просмотрен - PullRequest
12 голосов
/ 26 марта 2010

Вот тестовый фреймворк, чтобы показать, что я делаю:

  1. создать новый проект
  2. добавить элемент управления с вкладками
  3. на вкладке 1 поставить кнопку
  4. на вкладке 2 поставить флажок
  5. вставьте этот код для его кода

(используйте имена по умолчанию для элементов управления)

public partial class Form1 : Form
{
    private List<bool> boolList = new List<bool>();
    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

CreateControl не создает ручка управления, если контроль Видимое свойство ложно. Вы можете либо вызовите метод CreateHandle, либо получить доступ к свойству Handle для создания ручка управления независимо от контроль видимости, но в этом случай, никакие оконные дескрипторы не созданы для детей контроля.

Я попытался получить значение Handle (нет public CreateHandle () для CheckBox), но все равно тот же результат.

Есть ли какие-либо предложения, кроме того, чтобы программа быстро высвечивала все мои вкладки с флажками привязки к данным при первой загрузке?

РЕДАКТИРОВАТЬ- согласно предложению Джаксидиана, я создал новый класс

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

Я вызываю CreateHandle () сразу после updating = true тех же результатов, что и раньше.

1 Ответ

12 голосов
/ 03 апреля 2010

Я думаю, у меня есть решение. Проблема не в том, что вы не можете создать дескриптор. Вы можете сделать это, просто получив доступ к дескриптору 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 покажет, что оно сработало в окне вывода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...