2010-07-26 5 views
7

Das ist wirklich einfach..Net TableLayoutPanel - Löschen von Steuerelementen ist sehr langsam

Ich habe ein TableLayoutPanel, das basierend auf einer Datenbankabfrage mit Steuerelementen (nur Labels, Schaltflächen und einige Panels mit Schaltflächen) gefüllt wird. Wenn die Daten aktualisiert werden müssen, verwende ich TableLayoutPanel.Controls.Clear(). Leider ist dies ein sehr langsamer Vorgang. Ich würde erwarten, dass es schneller ist als der Code, der die Tabelle füllt, aber es ist mindestens 3 oder 4 mal langsamer.

Ich habe definitiv bewiesen, dass die Langsamkeit ist, wenn Sie Controls.Clear() ausführen, indem Sie dies als das einzige getan, um das TableLayoutPanel getan, nachdem ein Meldungsfeld angezeigt wird (dann kehrt die Prozedur zurück). Die Kontrollen verschwinden sichtbar von unten nach oben. Wenn das Re-Cord-Set verwandt wird, um das TableLayoutPanel erneut zu befüllen, ist die Geschwindigkeit der Steuerelemente, die von Oben nach Unten angezeigt werden, fast schneller, als ich sehen kann.

Ich mache bereits TableLayoutPanel.SuspendLayout() und ResumeLayout().

Mit this.DoubleBuffered = true auf dem Formular scheint nichts zu tun.

Ich könnte nur die gesamte Steuerung Dispose und neu erstellen es durch Code, aber das ist ein großer Schmerz und macht eine nette Form Designer GUI sinnlos. Ich müsste in jede Eigenschaft, die ich auf dem Steuerelement festgelegt habe, graben und eine Codezeile dafür erstellen (obwohl ich denke, dass ich das aus dem Designer-Code selbst herausholen könnte, fühlt es sich immer noch falsch an).

Haben Sie Ideen, wie Sie Ihre Arbeit schneller erledigen können? Ich bin sogar offen für die Verwendung anderer Methoden neben einem TableLayoutPanel ... Ich brauche nur die Freiheit, mehrere Schaltflächen pro Zelle zu setzen oder zu sperren, um Spalten in der Tabellenüberschrift zu überspannen.

Kann C# mindestens das gesamte Formular einfrieren, während es neu gezeichnet und dann auf einmal gezeichnet wird?

+0

Sie erwähnen TableLayoutPanel und FlowLayoutPanel. –

+0

Haben Sie einen Profiler darauf ausgeführt, um genau diese eine Codezeile zu beweisen? Ist es möglich, dass Sie mit dieser Codezeile Nebenwirkungen verursachen? Ereignisse, bei denen die Steuerung unsichtbar gemacht wird oder ähnliches? – WillfulWizard

+0

@Willfulwizard Ich habe meinen Beitrag mit dem Grund aktualisiert, warum ich glaube, dass es die Controls.Clear() ist, die eine lange Zeit braucht. – ErikE

Antwort

9

Ich habe Probleme mit der Langsamkeit mit TableLayoutPanels auch aufgetreten.Anstatt sich auf die Form der DoubleBuffered-Eigenschaft, die beste Lösung, die ich gefunden habe, ist eine neue Klasse zu erstellen, die von Table erbt, und in dieser Klasse Konstruktor aktivieren Double-Buffering:

public class DoubleBufferedTableLayoutPanel : TableLayoutPanel 
{ 
    public DoubleBufferedTableLayoutPanel() 
    { 
     DoubleBuffered = true; 
    } 
} 

Verwenden Sie dann die DoubleBufferedTableLayoutPanel, wo immer Sie normalerweise ein TableLayoutPanel verwenden würden.

+0

Können Sie darüber spekulieren, warum Sie das denken? Das TableLayoutPanel hat eine DoubleBuffered-Eigenschaft, selbst ... warum nicht einfach zur Entwurfszeit einstellen (ich gehe davon aus, dass das nicht funktioniert)? Also, was ist der Deal? – ErikE

+1

In der .NET-Version, die ich verwende (2008, SP1), listet weder die Symbolleiste Eigenschaften noch Intellisense die DoubleBuffered-Eigenschaft für TableLayoutPanels auf. Wenn Sie über eine Instanz eines TableLayoutPanel verfügen, myTableLayoutPanel sagen und versuchen, myTableLayoutPanel.DoubleBuffered = true festzulegen, zeigt der Compiler den Fehler "System.Windows.Forms.Control.DoubleBuffered" kann nicht auf den geschützten Member zugreifen. Wenn Ihre Version von .NET tatsächlich die DoubleBuffered-Eigenschaft auf dem gewöhnlichen TableLayoutPanel anbietet, würde ich mir vorstellen, sie dort zu setzen, würde gut funktionieren. –

+0

Ich muss sagen, ich hätte nie erwartet, dass ich diese Art von Optimierungen vornehmen muss, geschweige denn, dass sie die Leistung auf solch eine erstaunlich positive Weise beeinflussen. Ordentliches Zeug! – xDisruptor

0

Wenn ich etwas dynamisches GUI aufbauen werde, werde ich das immer im Code machen. Aber an einem Startpunkt beginne ich einfach mit dem Designer auf einem Dummy-Formular und style jede Kontrolle die Art, wie ich (oder besser der Kunde) mag (s). Danach nehme ich einen Blick in die Designer.cs Datei und kopieren Sie die notwendigen Einstellungen der Eigenschaften aus der es in eine Fabrik Funktion wie

private TextBox CreateTextBox(string name, /* maybe other parameters */) 
{ 
    var textBox = new TextBox(); 
    textBox.Name = name; 
    //Other settings from given parameters... 

    //Further settings which are all the same for these kind of control 
    textBox.KeyDown += (sender, e) => {}; 

    return textBox; 
} 

Also ich sicher, dass jede Kontrolle fühlt und sieht genauso auf meiner GUI. Dies wird auf jeder Ebene innerhalb meiner Oberfläche durchgeführt werden (beginnend mit den Kleinsteuerungen wie TextBox und geht bis zu den Behältern wie GroupBox oder TableLayoutPanel.

In einigen Fällen ist dies bis zu einem Punkt führt, wo eine Fabrik-Funktion mehrere andere Fabrik Funktionen aufruft . wenn dies der Fall immer ist es Zeit, über Einkapselung dieser Kontrollen in einem einzigen UserControl, aber wie immer es hängt zu denken, wenn dies erforderlich ist oder nicht.

Von meiner Seite kann ich Sie nur ermutigen, Ihren Code aus bewegen vom Designer in eine selbstgeschriebene Funktion, am Anfang ist es (wie immer) mehr Arbeit, aber danach ist es einfacher, noch größeren Cha zu machen nges zum Layout.

3

Dies scheint für meine Anwendungen zu arbeiten:

tableLayoutPanel.Visible = false; 
tableLayoutPanel.Clear(); 
/* Add components to it */ 
tableLayoutPanel.Visible = true; 
3

Es besteht keine Notwendigkeit TableLayoutPanel wie in Chris Ryan's answer Unterklasse ist. Ich hatte das gleiche Problem und löste es, indem ich die Eigenschaft durch Reflexion einstellte:

typeof(TableLayoutPanel) 
    .GetProperty("DoubleBuffered", 
     System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) 
    .SetValue(myTableLayoutPanel, true, null);