2010-07-26 14 views
7

Questo è veramente semplice.. Net TableLayoutPanel - I controlli di schiarimento sono molto lenti

Ho un TableLayoutPanel che è popolato con controlli (solo etichette, pulsanti e alcuni pannelli con pulsanti) basato su una query di database. Quando i dati devono essere aggiornati, utilizzo TableLayoutPanel.Controls.Clear(). Sfortunatamente, questa è un'operazione molto lenta. Mi aspetterei che fosse più veloce del codice che popola la tabella, ma è almeno 3 o 4 volte più lento.

Ho definitivamente dimostrato che la lentezza si ha quando si esegue Controls.Clear() eseguendo questa operazione come singola cosa eseguita su TableLayoutPanel dopo che viene visualizzata una finestra di messaggio (quindi la procedura restituisce). I controlli spariscono visibilmente dal basso verso l'alto. Quando si utilizza il recordset per ripopolare TableLayoutPanel, la velocità dei controlli visualizzati dall'alto verso il basso è quasi più veloce di quanto possa vedere.

Sto già facendo TableLayoutPanel.SuspendLayout() e ResumeLayout().

L'utilizzo di this.DoubleBuffered = true nel modulo non sembra fare nulla.

Potrei semplicemente eliminare l'intero controllo e ricrearlo attraverso il codice, ma questo è un grosso problema e rende inutile avere una bella GUI di progettazione dei form. Dovrei scavare in tutte le proprietà che ho impostato sul controllo e creare una linea di codice per questo (anche se penso che potrei ottenere questo dal codice del designer stesso, sembra ancora sbagliato).

Qualche idea su come svolgere il lavoro più velocemente? Sono persino aperto all'utilizzo di altri metodi oltre a un TableLayoutPanel ... Ho solo la libertà di inserire più pulsanti per cella o di escludere tale da poter estendere le colonne nell'intestazione della tabella.

Can C# può almeno congelare l'intero modulo mentre si ridisegna e quindi dipingere tutto in una volta?

+0

Si parla di TableLayoutPanel e FlowLayoutPanel. –

+0

Hai eseguito un profiler su di esso per dimostrare esattamente quella riga di codice? È possibile che si verifichino effetti collaterali con questa riga di codice? Gli eventi vengono chiamati per rendere i controlli invisibili o simili? – WillfulWizard

+0

@Willfulwizard ho aggiornato il mio post con il motivo per cui credo che sia il Controls.Clear() che sta prendendo molto tempo. – ErikE

risposta

9

Ho incontrato problemi con lentezza anche con TableLayoutPanels.Invece di impostare la proprietà DoubleBuffered sulla forma, la soluzione migliore che ho trovato è quello di creare una nuova classe che eredita da TableLayoutPanel, e in quella classe costruttore, abilitare il doppio buffer:

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

Quindi, utilizzare la DoubleBufferedTableLayoutPanel ovunque si utilizzi normalmente un TableLayoutPanel.

+0

Potresti speculare sul motivo per cui pensi che sia? TableLayoutPanel ha una proprietà DoubleBuffered, di per sé ... perché non impostarlo in fase di progettazione (presumo che non funzioni comunque)? Allora, qual è l'affare? – ErikE

+1

Nella versione di .NET sto usando (2008, SP1), né la barra degli strumenti Proprietà né Intellisense elenca la proprietà DoubleBuffered per TableLayoutPanels. Se si dispone di un'istanza di un TableLayoutPanel, dire myTableLayoutPanel e tentare di impostare myTableLayoutPanel.DoubleBuffered = true, il compilatore verrà visualizzato un "Impossibile accedere membro protetto 'System.Windows.Forms.Control.DoubleBuffered'" errore. Se la tua versione di .NET effettivamente offre la proprietà DoubleBuffered sul TableLayoutPanel ordinario, allora immagino che impostarla lì funzionerebbe correttamente. –

+0

Devo dire che non mi sarei mai aspettato di dover fare questo tipo di ritocco e tanto meno di avere un impatto sulle prestazioni in un modo così sorprendentemente positivo. Roba ordinata! – xDisruptor

0

Se ho intenzione di creare qualche gui dinamico, lo farò sempre in codice. Ma a un punto di partenza comincio con il progettista su una forma fittizia e stile ogni controllo il modo in cui io (o meglio il cliente) come (s). Successivamente prendo uno sguardo nel file Designer.cs e copiare le impostazioni di proprietà necessarie fuori di esso in qualche funzione di fabbrica come

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

Così ho assicurarsi che ogni controllo sente e si presenta lo stesso sul mio GUI. Questo sarà fatto ad ogni livello all'interno della mia superficie (a partire dai piccoli controlli come TextBox e va fino ai contenitori come GroupBox o TableLayoutPanel.

In alcuni casi questo porta ad un punto in cui una funzione di fabbrica chiama diverse altre funzioni factory . Se questo sta diventando vero è il momento di pensare a incapsulare questi controlli in un unico UserControl, ma come sempre dipende se questo è necessario o meno.

da parte mia posso solo incoraggiarvi a spostare il codice fuori del progettista in una funzione autodidatta, all'inizio è (come sempre) più lavoro, ma in seguito è più facile creare cha più grandi fino al layout.

3

Questo sembra funzionare per i miei usi:

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

Non v'è alcuna necessità di creare una sottoclasse TableLayoutPanel come in Chris Ryan's answer. Ho avuto lo stesso problema e l'ho risolto impostando la proprietà tramite il riflesso:

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