2010-03-26 16 views
11

Hier ist ein Test-Framework zu zeigen, was ich tue:eine Checkbox Erzwingen zu einer Datasource gebunden zu aktualisieren, wenn es noch nicht angesehen wurde

  1. ein neues Projekt
  2. fügen Sie ein Registersteuer
  3. auf der Registerkarte 1 setzen auf eine Schaltfläche
  4. auf 2 Registerkarte ein Kontrollkästchen
  5. diesen Code
  6. für seinen Code einfügen setzen

(verwenden Sie die Standardnamen für Kontrollen)

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

Das Problem ist, wenn Sie das Programm und sehen Sie Tab 2 und drücken Sie die Taste auf der Registerkarte 1 das Programm funktioniert wie erwartet, aber wenn Sie auf der Registerkarte drücken Sie die Taste ausführen 1 dann auf Registerkarte 2 das Ereignis für das Kontrollkästchen wird nicht ausgelöst, bis Sie auf Registerkarte 2 schauen.

Der Grund dafür ist die Kontrolle auf Registerkarte 2 ist nicht in der "erstellt" -Zustand, so dass ihre Bindung zu ändern Checkbox von unchecked zu checked passiert erst, nachdem das Steuerelement "Created" wurde.

checkbox1.CreateControl() tut nichts, weil nach MSDN

Create keine Steuergriff erstellen, wenn die Kontrolle Visible-Eigenschaft falsch ist. Sie können entweder rufen Sie die Methode Create oder Zugriff auf die Eigenschaft Handle der Kontrolle des Griffs unabhängig von der Kontrolle der Sichtbarkeit, aber in diesem Fall zu erstellen, werden keine Fenstergriffe für die Kontrolle der Kinder geschaffen.

Ich habe versucht, den Wert des Griffes bekommen (es gibt keinen öffentlichen Create() für CheckBox), aber immer noch das gleiche Ergebnis.

Haben andere Vorschläge als das Programm schnell alle meine Registerkarten blinken, die datengebundene Kontrollkästchen beim ersten Laden haben?

EDIT-- pro Jaxidian Vorschlag habe ich eine neue Klasse

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

Ich nenne Create() direkt nach updating = true gleichen Ergebnisse wie zuvor.

+2

Was ist also falsch an der Verwendung von CreateHandle, wie die MSDN-Dokumentation dann vorschlägt? – Jaxidian

+0

CreateHandle ist eine geschützte Methode, sie kann nicht aus Code aufgerufen werden, wenn ich keine neue geerbte Klasse erstelle. –

+1

Laut den Dokumenten entspricht das Aufrufen von CreateHandle einfach dem Zugriff auf die Handle-Eigenschaft des Steuerelements. Aber auch das half nicht, da WinForms das Steuerelement immer noch nicht "sieht" und das CheckedChanged-Ereignis auslöst. – Thomas

Antwort

11

Ich denke, ich habe eine Lösung. Das Problem besteht nicht darin, dass Sie kein Handle erstellen können. Sie können dies tun, indem Sie einfach auf den Access-Zugriffspunkt Zugriff auf das Steuerelement zugreifen. Das Problem besteht darin, dass WinForms das Steuerelement nicht erstellt, da es nicht sichtbar ist. Wie sich herausstellt, hat ein System.Windows.Forms.Control hinter den Kulissen zwei Überladungen für CreateControl. Der erste, der öffentlich ist, nimmt keine Parameter und ruft den zweiten auf, der internal ist, der einen einzigen boolean Parameter verwendet: ignoreVisible, der es dem aufrufenden Code ermöglicht, das Steuerelement zu erstellen, auch wenn es nicht sichtbar ist. Die Methode CreateControl ohne Argumente übergibt false an diese interne Methode. Wenn das Steuerelement nicht sichtbar ist, wird es nicht erstellt. Der Trick besteht also darin, Reflection zum Aufruf der internen Methode zu verwenden.Zuerst habe ich erstellt zwei Methoden für die Erstellung von Kontrollen:

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

Nun fügen wir einen Aufruf an CreateControls für die zweite Registerkarte:

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

Darüber hinaus habe ich einige Debug-Nachrichten hinzugefügt, damit ich sehen konnte, wenn das Ereignis ausgelöst:

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

Nun, ob Sie auf die zweite Registerkarte oder nicht, wird durch klicken auf die Schaltfläche auf der ersten Registerkarte die checkbox1_Changed Ereignisprozedur wird ausgelöst navigieren. Wenn Sie auf das Symbol klicken, wird die MessageBox nicht angezeigt, weil updating wahr ist. Die Debug.WriteLine zeigt jedoch, dass es im Ausgabefenster ausgelöst wurde.

+0

Ich werde dies am Montag testen, um zu sehen, ob das in meinem echten Code funktioniert, wenn es die 100 rep. –