2010-03-26 5 views
11

Aquí está un marco de prueba para mostrar lo que estoy haciendo:Forzar a una casilla de verificación unido a una fuente de datos para actualizar cuando no ha sido visto aún

  1. crear un nuevo proyecto
  2. agregar un control de pestañas
  3. en la ficha 1 poner un botón
  4. en la pestaña 2 poner una casilla de verificación
  5. pega este código para su código

(nombres predeterminados de uso de los controles)

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"); 
    } 
} 

La cuestión es si se ejecuta el programa y mira pestaña 2 y pulse el botón en la pestaña 1 El programa funciona como se espera, sin embargo, si se pulsa el botón en la pestaña 1 luego observe la pestaña 2 el evento para la casilla de verificación no se disparará hasta que vea la pestaña 2.

La razón para esto es que el control en la pestaña 2 no está en el estado "creado", por lo que su enlace para cambiar la la casilla de verificación desde no marcada a marcada no ocurre hasta que el control haya sido "Creado".

checkbox1.CreateControl() no hace nada porque según MSDN

CreateControl no crea un mango control si la propiedad Visible del control es falsa. Puede o bien llamar al método CreateHandle o acceso a la propiedad de la manija para crear el identificador del control independientemente de la visibilidad del control , pero en este caso , no hay identificadores de ventana son creados para los niños del control.

he intentado conseguir el valor de la manija (no hay pública CreateHandle() para la casilla de verificación), pero sigue siendo el mismo resultado.

¿Alguna otra sugerencia que no sea hacer que el programa muestre rápidamente todas las pestañas que tienen casillas de verificación unidas a datos cuando se cargan por primera vez?

EDIT-- por sugerencia de Jaxidian que creó una nueva clase

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

llamo CreateHandle() justo después de updating = true mismos resultados que antes.

+2

Entonces, ¿qué pasa con el uso de CreateHandle como la documentación de MSDN sugiere entonces? – Jaxidian

+0

CreateHandle es un método protegido, no se puede invocar desde el código a menos que se crea una nueva clase heredada. –

+1

De acuerdo con los documentos, el equivalente a llamar CreateHandle es simplemente acceder a la propiedad Handle en el control. Sin embargo, incluso hacerlo no ayudó, ya que WinForms todavía no "ve" el control y dispara el evento CheckedChanged. – Thomas

Respuesta

11

Creo que tengo una solución. El problema no es que no puedas crear una Manija. Puede hacerlo simplemente accediendo al acceso de obtención de Handle en el Control. El problema es que WinForms no crea el control porque no está visible. Como resulta, detrás de las escenas, un System.Windows.Forms.Control tiene dos sobrecargas para CreateControl. La primera, que es pública, no toma parámetros y llama a la segunda que es internal que toma un solo parámetro boolean: ignoreVisible que, como su nombre lo indica, permite que el código de llamada cree el control incluso si no está visible. El método CreateControl sin argumentos pasa falso a este método interno, lo que significa que si el control no está visible, no se crea. Entonces, el truco es usar Reflection para llamar al método interno.En primer lugar, he creado dos métodos para crear controles:

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 }); 
} 

Ahora, añadimos una llamada a CreateControls para la segunda pestaña:

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); 
} 

Además, he añadido algunos mensajes de depuración para que pudiera ver si el evento disparado:

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"); 
    } 
} 

Ahora, si se desplaza a la segunda pestaña o no, al hacer clic en el botón en la primera pestaña se disparará el procedimiento checkbox1_Changed evento. Dado el diseño que ya ha proporcionado, si hace clic en el botón, no se mostrará el cuadro de mensaje porque updating será cierto. Sin embargo, el Debug.WriteLine mostrará que se activó en la ventana de resultados.

+0

voy a probar esto el lunes para ver si esto funciona en mi código real si lo hace a obtener el 100 rep. –

Cuestiones relacionadas